diff --git a/app/assets/images/common/code_languages/c_icon.png b/app/assets/images/common/code_languages/c_icon.png
new file mode 100755
index 000000000..99cd55241
Binary files /dev/null and b/app/assets/images/common/code_languages/c_icon.png differ
diff --git a/app/assets/images/common/code_languages/c_small.png b/app/assets/images/common/code_languages/c_small.png
new file mode 100644
index 000000000..23ba119bb
Binary files /dev/null and b/app/assets/images/common/code_languages/c_small.png differ
diff --git a/app/assets/images/common/code_languages/clojure_icon.png b/app/assets/images/common/code_languages/clojure_icon.png
new file mode 100755
index 000000000..7152f84c0
Binary files /dev/null and b/app/assets/images/common/code_languages/clojure_icon.png differ
diff --git a/app/assets/images/common/code_languages/clojure_small.png b/app/assets/images/common/code_languages/clojure_small.png
new file mode 100644
index 000000000..606af0433
Binary files /dev/null and b/app/assets/images/common/code_languages/clojure_small.png differ
diff --git a/app/assets/images/common/code_languages/coffeescript_icon.png b/app/assets/images/common/code_languages/coffeescript_icon.png
new file mode 100755
index 000000000..502db9b06
Binary files /dev/null and b/app/assets/images/common/code_languages/coffeescript_icon.png differ
diff --git a/app/assets/images/common/code_languages/coffeescript_small.png b/app/assets/images/common/code_languages/coffeescript_small.png
new file mode 100644
index 000000000..86e49ea1c
Binary files /dev/null and b/app/assets/images/common/code_languages/coffeescript_small.png differ
diff --git a/app/assets/images/common/code_languages/cpp_icon.png b/app/assets/images/common/code_languages/cpp_icon.png
new file mode 100755
index 000000000..c3067378c
Binary files /dev/null and b/app/assets/images/common/code_languages/cpp_icon.png differ
diff --git a/app/assets/images/common/code_languages/cpp_small.png b/app/assets/images/common/code_languages/cpp_small.png
new file mode 100644
index 000000000..df701f002
Binary files /dev/null and b/app/assets/images/common/code_languages/cpp_small.png differ
diff --git a/app/assets/images/common/code_languages/csharp_icon.png b/app/assets/images/common/code_languages/csharp_icon.png
new file mode 100755
index 000000000..d3eff9260
Binary files /dev/null and b/app/assets/images/common/code_languages/csharp_icon.png differ
diff --git a/app/assets/images/common/code_languages/csharp_small.png b/app/assets/images/common/code_languages/csharp_small.png
new file mode 100644
index 000000000..86c26aea3
Binary files /dev/null and b/app/assets/images/common/code_languages/csharp_small.png differ
diff --git a/app/assets/images/common/code_languages/go_icon.png b/app/assets/images/common/code_languages/go_icon.png
new file mode 100755
index 000000000..ecbfb0d6a
Binary files /dev/null and b/app/assets/images/common/code_languages/go_icon.png differ
diff --git a/app/assets/images/common/code_languages/go_small.png b/app/assets/images/common/code_languages/go_small.png
new file mode 100644
index 000000000..7ff974e07
Binary files /dev/null and b/app/assets/images/common/code_languages/go_small.png differ
diff --git a/app/assets/images/common/code_languages/io_icon.png b/app/assets/images/common/code_languages/io_icon.png
new file mode 100644
index 000000000..0b6c58fe4
Binary files /dev/null and b/app/assets/images/common/code_languages/io_icon.png differ
diff --git a/app/assets/images/common/code_languages/io_small.png b/app/assets/images/common/code_languages/io_small.png
new file mode 100644
index 000000000..2bbd5c51e
Binary files /dev/null and b/app/assets/images/common/code_languages/io_small.png differ
diff --git a/app/assets/images/common/code_languages/java_icon.png b/app/assets/images/common/code_languages/java_icon.png
new file mode 100755
index 000000000..e39879cae
Binary files /dev/null and b/app/assets/images/common/code_languages/java_icon.png differ
diff --git a/app/assets/images/common/code_languages/java_small.png b/app/assets/images/common/code_languages/java_small.png
new file mode 100644
index 000000000..76126650c
Binary files /dev/null and b/app/assets/images/common/code_languages/java_small.png differ
diff --git a/app/assets/images/common/code_languages/javascript_icon.png b/app/assets/images/common/code_languages/javascript_icon.png
new file mode 100644
index 000000000..4580f350b
Binary files /dev/null and b/app/assets/images/common/code_languages/javascript_icon.png differ
diff --git a/app/assets/images/common/code_languages/javascript_small.png b/app/assets/images/common/code_languages/javascript_small.png
new file mode 100644
index 000000000..4472bea9d
Binary files /dev/null and b/app/assets/images/common/code_languages/javascript_small.png differ
diff --git a/app/assets/images/common/code_languages/lua_icon.png b/app/assets/images/common/code_languages/lua_icon.png
new file mode 100755
index 000000000..e97873a33
Binary files /dev/null and b/app/assets/images/common/code_languages/lua_icon.png differ
diff --git a/app/assets/images/common/code_languages/lua_small.png b/app/assets/images/common/code_languages/lua_small.png
new file mode 100644
index 000000000..c1f183c58
Binary files /dev/null and b/app/assets/images/common/code_languages/lua_small.png differ
diff --git a/app/assets/images/common/code_languages/php_icon.png b/app/assets/images/common/code_languages/php_icon.png
new file mode 100755
index 000000000..35757de0b
Binary files /dev/null and b/app/assets/images/common/code_languages/php_icon.png differ
diff --git a/app/assets/images/common/code_languages/php_small.png b/app/assets/images/common/code_languages/php_small.png
new file mode 100644
index 000000000..62a5010f3
Binary files /dev/null and b/app/assets/images/common/code_languages/php_small.png differ
diff --git a/app/assets/images/common/code_languages/python_icon.png b/app/assets/images/common/code_languages/python_icon.png
new file mode 100755
index 000000000..b8575c4f8
Binary files /dev/null and b/app/assets/images/common/code_languages/python_icon.png differ
diff --git a/app/assets/images/common/code_languages/python_small.png b/app/assets/images/common/code_languages/python_small.png
new file mode 100644
index 000000000..aa303a518
Binary files /dev/null and b/app/assets/images/common/code_languages/python_small.png differ
diff --git a/app/assets/images/common/code_languages/ruby_icon.png b/app/assets/images/common/code_languages/ruby_icon.png
new file mode 100755
index 000000000..7e1192d7a
Binary files /dev/null and b/app/assets/images/common/code_languages/ruby_icon.png differ
diff --git a/app/assets/images/common/code_languages/ruby_small.png b/app/assets/images/common/code_languages/ruby_small.png
new file mode 100644
index 000000000..9839340f7
Binary files /dev/null and b/app/assets/images/common/code_languages/ruby_small.png differ
diff --git a/app/assets/images/common/code_languages/swift_icon.png b/app/assets/images/common/code_languages/swift_icon.png
new file mode 100755
index 000000000..e789c1516
Binary files /dev/null and b/app/assets/images/common/code_languages/swift_icon.png differ
diff --git a/app/assets/images/common/code_languages/swift_small.png b/app/assets/images/common/code_languages/swift_small.png
new file mode 100644
index 000000000..95d9c049a
Binary files /dev/null and b/app/assets/images/common/code_languages/swift_small.png differ
diff --git a/app/assets/images/pages/home/language_js.png b/app/assets/images/pages/home/language_js.png
index 75db0f254..9da73cf33 100644
Binary files a/app/assets/images/pages/home/language_js.png and b/app/assets/images/pages/home/language_js.png differ
diff --git a/app/assets/images/pages/home/language_logo_clojure.png b/app/assets/images/pages/home/language_logo_clojure.png
deleted file mode 100644
index 38f4ae07a..000000000
Binary files a/app/assets/images/pages/home/language_logo_clojure.png and /dev/null differ
diff --git a/app/assets/images/pages/home/language_logo_coffeescript.png b/app/assets/images/pages/home/language_logo_coffeescript.png
deleted file mode 100644
index 8eb9742ea..000000000
Binary files a/app/assets/images/pages/home/language_logo_coffeescript.png and /dev/null differ
diff --git a/app/assets/images/pages/home/language_logo_io.png b/app/assets/images/pages/home/language_logo_io.png
deleted file mode 100644
index c9d3360df..000000000
Binary files a/app/assets/images/pages/home/language_logo_io.png and /dev/null differ
diff --git a/app/assets/images/pages/home/language_logo_javascript.png b/app/assets/images/pages/home/language_logo_javascript.png
deleted file mode 100644
index ec8b134ae..000000000
Binary files a/app/assets/images/pages/home/language_logo_javascript.png and /dev/null differ
diff --git a/app/assets/images/pages/home/language_logo_lua.png b/app/assets/images/pages/home/language_logo_lua.png
deleted file mode 100644
index 724fa0cfc..000000000
Binary files a/app/assets/images/pages/home/language_logo_lua.png and /dev/null differ
diff --git a/app/assets/images/pages/home/language_logo_python.png b/app/assets/images/pages/home/language_logo_python.png
deleted file mode 100644
index f16d48c07..000000000
Binary files a/app/assets/images/pages/home/language_logo_python.png and /dev/null differ
diff --git a/app/assets/images/pages/home/language_python.png b/app/assets/images/pages/home/language_python.png
index 80e09da9e..71f23d4ad 100644
Binary files a/app/assets/images/pages/home/language_python.png and b/app/assets/images/pages/home/language_python.png differ
diff --git a/app/lib/Angel.coffee b/app/lib/Angel.coffee
index 4beeffa97..3b5f59a75 100644
--- a/app/lib/Angel.coffee
+++ b/app/lib/Angel.coffee
@@ -213,6 +213,8 @@ module.exports = class Angel extends CocoClass
     work.t1 = now()
     Math.random = work.testWorld.rand.randf  # so user code is predictable
     Aether.replaceBuiltin('Math', Math)
+    replacedLoDash = _.runInContext(window)
+    _[key] = replacedLoDash[key] for key, val of replacedLoDash
     i = 0
     while i < work.testWorld.totalFrames
       frame = work.testWorld.getFrame i++
diff --git a/app/lib/Router.coffee b/app/lib/Router.coffee
index 31fcf6a85..2c3a026a3 100644
--- a/app/lib/Router.coffee
+++ b/app/lib/Router.coffee
@@ -1,4 +1,7 @@
 gplusClientID = '800329290710-j9sivplv2gpcdgkrsis9rff3o417mlfa.apps.googleusercontent.com'
+# TODO: Move to GPlusHandler
+
+NotFoundView = require('views/NotFoundView')
 
 go = (path) -> -> @routeDirectly path, arguments
 
@@ -8,20 +11,44 @@ module.exports = class CocoRouter extends Backbone.Router
     Backbone.Mediator.subscribe 'router:navigate', @onNavigate, @
 
   routes:
-    # every abnormal view gets listed here
-    '': 'home'
-    'preview': 'home'
-    'beta': 'home'
+    '': go('HomeView')
+
+    'about': go('AboutView')
+    'admin': go('AdminView')
+
+    'beta': go('HomeView')
+
+    'cla': go('CLAView')
+    'community': go('CommunityView')
+    'contribute': go('contribute/MainContributeView')
+    'contribute/adventurer': go('contribute/AdventurerView')
+    'contribute/ambassador': go('contribute/AmbassadorView')
+    'contribute/archmage': go('contribute/ArchmageView')
+    'contribute/artisan': go('contribute/ArtisanView')
+    'contribute/diplomat': go('contribute/DiplomatView')
+    'contribute/scribe': go('contribute/ScribeView')
+
+    'demo(/*subpath)': go('DemoView')
+    
+    'editor': go('editor/MainEditorView')
+    'employers': go('EmployersView')
+    
+    'legal': go('LegalView')
+    
+    'multiplayer': go('MultiplayerView')
+
+    'play': go('play/MainPlayView')
+    'preview': go('HomeView')
+
+    'teachers': go('TeachersView')
+    'test(/*subpath)': go('TestView')
+
 
     # editor views tend to have the same general structure
     'editor/:model(/:slug_or_id)(/:subview)': 'editorModelView'
 
     # Direct links
-    'test': go('TestView')
-    'test/*subpath': go('TestView')
 
-    'demo': go('DemoView')
-    'demo/*subpath': go('DemoView')
 
     'play/ladder/:levelID': go('play/ladder/ladder_view')
     'play/ladder': go('play/ladder_home')
@@ -134,7 +161,6 @@ module.exports = class CocoRouter extends Backbone.Router
         throw error
 
   notFoundView: ->
-    NotFoundView = require('views/not_found')
     view = new NotFoundView()
     view.render()
 
diff --git a/app/lib/surface/CocoSprite.coffee b/app/lib/surface/CocoSprite.coffee
index 3bc8e7330..b05fe99db 100644
--- a/app/lib/surface/CocoSprite.coffee
+++ b/app/lib/surface/CocoSprite.coffee
@@ -82,7 +82,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
     if @thangType.isFullyLoaded()
       @setupSprite()
     else
-      @thangType.fetch()
+      @thangType.fetch() unless @thangType.loading
       @listenToOnce(@thangType, 'sync', @setupSprite)
 
   setupSprite: ->
@@ -442,7 +442,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
       console.warn 'Cannot show action', action, 'for', @thangType.get('name'), 'because it DNE' unless @warnedFor[action]
       @warnedFor[action] = true
       return if @action is 'idle' then null else 'idle'
-    action = 'break' if @actions.break? and @thang?.erroredOut
+    #action = 'break' if @actions.break? and @thang?.erroredOut  # This makes it looks like it's dead when it's not: bad in Brawlwood.
     action = 'die' if @actions.die? and thang?.health? and thang.health <= 0
     @actions[action]
 
diff --git a/app/lib/surface/Surface.coffee b/app/lib/surface/Surface.coffee
index f435f8110..bd6cf7df1 100644
--- a/app/lib/surface/Surface.coffee
+++ b/app/lib/surface/Surface.coffee
@@ -115,7 +115,8 @@ module.exports = Surface = class Surface extends CocoClass
 
   setWorld: (@world) ->
     @worldLoaded = true
-    @world.getFrame(Math.min(@getCurrentFrame(), @world.totalFrames - 1)).restoreState() unless @options.choosing
+    lastFrame = Math.min(@getCurrentFrame(), @world.totalFrames - 1)
+    @world.getFrame(lastFrame).restoreState() unless @options.choosing
     @spriteBoss.world = @world
 
     @showLevel()
@@ -241,7 +242,7 @@ module.exports = Surface = class Surface extends CocoClass
     @onFrameChanged()
 
   getCurrentFrame: ->
-    return Math.max(0, Math.min(Math.floor(@currentFrame), @world.totalFrames - 1))
+    return Math.max(0, Math.min(Math.floor(@currentFrame), @world.frames.length - 1))
 
   getProgress: -> @currentFrame / @world.totalFrames
 
diff --git a/app/locale/ar.coffee b/app/locale/ar.coffee
index 0d95ef171..40f349b61 100644
--- a/app/locale/ar.coffee
+++ b/app/locale/ar.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "العربية", englishDescription: "Arabi
 #    for_beginners: "For Beginners"
 #    multiplayer: "Multiplayer"
 #    for_developers: "For Developers"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
 #  play:
 #    choose_your_level: "Choose Your Level"
diff --git a/app/locale/bg.coffee b/app/locale/bg.coffee
index 5620a6b60..0609ffaf8 100644
--- a/app/locale/bg.coffee
+++ b/app/locale/bg.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "български език", englishDescri
 #    for_beginners: "For Beginners"
 #    multiplayer: "Multiplayer"
 #    for_developers: "For Developers"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
   play:
     choose_your_level: "Избери своето ниво"
diff --git a/app/locale/ca.coffee b/app/locale/ca.coffee
index 3a1a35800..0ab50115a 100644
--- a/app/locale/ca.coffee
+++ b/app/locale/ca.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "Català", englishDescription: "Catalan", tr
     for_beginners: "Per a principiants"
     multiplayer: "Multijugador"
     for_developers: "Per a Desenvolupadors"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
   play:
     choose_your_level: "Escull el teu nivell"
diff --git a/app/locale/cs.coffee b/app/locale/cs.coffee
index 5836d1889..cd470a43b 100644
--- a/app/locale/cs.coffee
+++ b/app/locale/cs.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "čeština", englishDescription: "Czech", tr
 #    for_beginners: "For Beginners"
 #    multiplayer: "Multiplayer"
 #    for_developers: "For Developers"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
   play:
     choose_your_level: "Zvolte si úroveň"
diff --git a/app/locale/da.coffee b/app/locale/da.coffee
index 470764cd8..1ffef227c 100644
--- a/app/locale/da.coffee
+++ b/app/locale/da.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "dansk", englishDescription: "Danish", trans
     for_beginners: "For Begyndere"
     multiplayer: "Multiplayer"
     for_developers: "For Udviklere"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
   play:
     choose_your_level: "Vælg Dit Level"
diff --git a/app/locale/de-AT.coffee b/app/locale/de-AT.coffee
index 1242212fd..9c4c0c144 100644
--- a/app/locale/de-AT.coffee
+++ b/app/locale/de-AT.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "Deutsch (Österreich)", englishDescription:
 #    for_beginners: "For Beginners"
 #    multiplayer: "Multiplayer"
 #    for_developers: "For Developers"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
 #  play:
 #    choose_your_level: "Choose Your Level"
diff --git a/app/locale/de-CH.coffee b/app/locale/de-CH.coffee
index b8b40dbac..d83d4959a 100644
--- a/app/locale/de-CH.coffee
+++ b/app/locale/de-CH.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "Deutsch (Schweiz)", englishDescription: "Ge
     for_beginners: "Für Afänger"
     multiplayer: "Multiplayer"
     for_developers: "Für Entwickler"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
   play:
     choose_your_level: "Wähl dis Level us"
diff --git a/app/locale/de-DE.coffee b/app/locale/de-DE.coffee
index 69570107d..d94fbbbfd 100644
--- a/app/locale/de-DE.coffee
+++ b/app/locale/de-DE.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "Deutsch (Deutschland)", englishDescription:
     for_beginners: "Für Anfänger"
     multiplayer: "Mehrspieler"
     for_developers: "Für Entwickler"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
   play:
     choose_your_level: "Wähle dein Level"
diff --git a/app/locale/de.coffee b/app/locale/de.coffee
index 4f83a118e..aa72ab375 100644
--- a/app/locale/de.coffee
+++ b/app/locale/de.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "Deutsch", englishDescription: "German", tra
     for_beginners: "Für Anfänger"
     multiplayer: "Mehrspieler"
     for_developers: "Für Entwickler"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
   play:
     choose_your_level: "Wähle dein Level"
diff --git a/app/locale/el.coffee b/app/locale/el.coffee
index 41d735d5d..0405a50f3 100644
--- a/app/locale/el.coffee
+++ b/app/locale/el.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "ελληνικά", englishDescription: "Gre
     for_beginners: "Για αρχάριους"
 #    multiplayer: "Multiplayer"
     for_developers: "Για προγραμματιστές"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
   play:
     choose_your_level: "Διάλεξε την πίστα σου"
diff --git a/app/locale/en-AU.coffee b/app/locale/en-AU.coffee
index 29d87cbe7..772111136 100644
--- a/app/locale/en-AU.coffee
+++ b/app/locale/en-AU.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "English (AU)", englishDescription: "English
 #    for_beginners: "For Beginners"
 #    multiplayer: "Multiplayer"
 #    for_developers: "For Developers"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
 #  play:
 #    choose_your_level: "Choose Your Level"
diff --git a/app/locale/en-GB.coffee b/app/locale/en-GB.coffee
index 0ba3466cc..e6fadc26e 100644
--- a/app/locale/en-GB.coffee
+++ b/app/locale/en-GB.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "English (UK)", englishDescription: "English
 #    for_beginners: "For Beginners"
 #    multiplayer: "Multiplayer"
 #    for_developers: "For Developers"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
 #  play:
 #    choose_your_level: "Choose Your Level"
diff --git a/app/locale/en-US.coffee b/app/locale/en-US.coffee
index ebecb2bd2..61513d098 100644
--- a/app/locale/en-US.coffee
+++ b/app/locale/en-US.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "English (US)", englishDescription: "English
 #    for_beginners: "For Beginners"
 #    multiplayer: "Multiplayer"
 #    for_developers: "For Developers"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
 #  play:
 #    choose_your_level: "Choose Your Level"
diff --git a/app/locale/en.coffee b/app/locale/en.coffee
index a3cf8152b..2b8549b5e 100644
--- a/app/locale/en.coffee
+++ b/app/locale/en.coffee
@@ -100,6 +100,12 @@
     for_beginners: "For Beginners"
     multiplayer: "Multiplayer"
     for_developers: "For Developers"
+    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+    coffeescript_blurb: "Nicer JavaScript syntax."
+    clojure_blurb: "A modern Lisp."
+    lua_blurb: "Game scripting language."
+    io_blurb: "Simple but obscure."
 
   play:
     choose_your_level: "Choose Your Level"
diff --git a/app/locale/es-419.coffee b/app/locale/es-419.coffee
index 84d5ddd86..6d4b7892c 100644
--- a/app/locale/es-419.coffee
+++ b/app/locale/es-419.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "español (América Latina)", englishDescrip
     for_beginners: "Para Principiantes"
     multiplayer: "Multijugador"
     for_developers: "Para Desarrolladores"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
   play:
     choose_your_level: "Elige tu nivel"
diff --git a/app/locale/es-ES.coffee b/app/locale/es-ES.coffee
index 565025b19..956682ba2 100644
--- a/app/locale/es-ES.coffee
+++ b/app/locale/es-ES.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "español (ES)", englishDescription: "Spanis
     for_beginners: "Para principiantes"
     multiplayer: "Multijugador"
     for_developers: "Para programadores"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
   play:
     choose_your_level: "Elige tu nivel"
diff --git a/app/locale/es.coffee b/app/locale/es.coffee
index dcc2e7ff1..3382d263f 100644
--- a/app/locale/es.coffee
+++ b/app/locale/es.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "español", englishDescription: "Spanish", t
     for_beginners: "Para principiantes"
     multiplayer: "Multijugador"
     for_developers: "Para desarrolladores"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
   play:
     choose_your_level: "Elige tu nivel"
diff --git a/app/locale/fa.coffee b/app/locale/fa.coffee
index e043269ae..5643e4646 100644
--- a/app/locale/fa.coffee
+++ b/app/locale/fa.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "فارسی", englishDescription: "Persian",
 #    for_beginners: "For Beginners"
 #    multiplayer: "Multiplayer"
 #    for_developers: "For Developers"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
   play:
     choose_your_level: "مرحله خود را انتخاب کنید"
diff --git a/app/locale/fi.coffee b/app/locale/fi.coffee
index cd1da3699..d045279e8 100644
--- a/app/locale/fi.coffee
+++ b/app/locale/fi.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "suomi", englishDescription: "Finnish", tran
 #    for_beginners: "For Beginners"
 #    multiplayer: "Multiplayer"
 #    for_developers: "For Developers"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
 #  play:
 #    choose_your_level: "Choose Your Level"
diff --git a/app/locale/fr.coffee b/app/locale/fr.coffee
index 94a3dd46d..1d717c739 100644
--- a/app/locale/fr.coffee
+++ b/app/locale/fr.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "français", englishDescription: "French", t
     for_beginners: "Pour débutants"
     multiplayer: "Multijoueurs"
     for_developers: "Pour développeurs"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
   play:
     choose_your_level: "Choisissez votre niveau"
diff --git a/app/locale/he.coffee b/app/locale/he.coffee
index 7dda67ac8..4621f2dce 100644
--- a/app/locale/he.coffee
+++ b/app/locale/he.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "עברית", englishDescription: "Hebrew",
     for_beginners: "למתחילים"
     multiplayer: "רב-משתתפים"
     for_developers: "למומחים"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
   play:
     choose_your_level: "בחר את השלב"
diff --git a/app/locale/hi.coffee b/app/locale/hi.coffee
index 85ccf7dac..ca51ba569 100644
--- a/app/locale/hi.coffee
+++ b/app/locale/hi.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "मानक हिन्दी", englishDe
 #    for_beginners: "For Beginners"
 #    multiplayer: "Multiplayer"
 #    for_developers: "For Developers"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
 #  play:
 #    choose_your_level: "Choose Your Level"
diff --git a/app/locale/hu.coffee b/app/locale/hu.coffee
index 2aef84d38..390e20a98 100644
--- a/app/locale/hu.coffee
+++ b/app/locale/hu.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "magyar", englishDescription: "Hungarian", t
     for_beginners: "Kezdőknek"
 #    multiplayer: "Multiplayer"
     for_developers: "Fejlesztőknek"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
   play:
     choose_your_level: "Válaszd ki a pályát!"
diff --git a/app/locale/id.coffee b/app/locale/id.coffee
index ae972660d..fe9958166 100644
--- a/app/locale/id.coffee
+++ b/app/locale/id.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "Bahasa Indonesia", englishDescription: "Ind
 #    for_beginners: "For Beginners"
 #    multiplayer: "Multiplayer"
 #    for_developers: "For Developers"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
 #  play:
 #    choose_your_level: "Choose Your Level"
diff --git a/app/locale/it.coffee b/app/locale/it.coffee
index e1535c040..a1ed0fbaf 100644
--- a/app/locale/it.coffee
+++ b/app/locale/it.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "Italiano", englishDescription: "Italian", t
     for_beginners: "Per Principianti"
 #    multiplayer: "Multiplayer"
     for_developers: "Per Sviluppatori"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
   play:
     choose_your_level: "Scegli il tuo livello"
diff --git a/app/locale/ja.coffee b/app/locale/ja.coffee
index fce997c9a..acdc9ffb6 100644
--- a/app/locale/ja.coffee
+++ b/app/locale/ja.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "日本語", englishDescription: "Japanese",
     for_beginners: "初心者向け"
     multiplayer: "マルチプレイヤー"
     for_developers: "開発者向け"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
   play:
     choose_your_level: "レベル選択"
diff --git a/app/locale/ko.coffee b/app/locale/ko.coffee
index 791630d0e..25b6159ac 100644
--- a/app/locale/ko.coffee
+++ b/app/locale/ko.coffee
@@ -90,20 +90,26 @@ module.exports = nativeDescription: "한국어", englishDescription: "Korean", t
 #    required: "You need to log in before you can go that way."
 
   home:
-    slogan: "쉽고 간단한 게임배우기"
+    slogan: "쉽고 간단한 게임 배우기"
     no_ie: "죄송하지만 코드컴뱃은 인터넷 익스플로러 9에서는 동작하지 않습니다."
     no_mobile: "코드 컴뱃은 모바일 기기용으로 제작되지 않았습니다. 아마 동작하지 않을 가능성이 높습니다."
     play: "시작"
-    old_browser: "브라우저가 너무 오래된 버전이라 코드컴뱃을 실행할 수 없습니다."
+    old_browser: "브라우저가 너무 오래된 버전이라 코드 컴뱃을 실행할 수 없습니다."
     old_browser_suffix: "시도해볼 수는 있겠지만..안될수도 있습니다."
     campaign: "캠페인"
     for_beginners: "초보자용"
     multiplayer: "멀티플레이어"
     for_developers: "개발자용"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
   play:
     choose_your_level: "레벨을 선택하세요."
-    adventurer_prefix: "아래에 있는 어떤 레벨도 바로 시작하실 수 있습니다.또는 포럼에서 레벨에 관해 토론하세요 :"
+    adventurer_prefix: "아래에 있는 아무 레벨이나 바로 시작하실 수 있습니다. 또는 포럼에서 레벨에 관해 토론하세요 :"
     adventurer_forum: "모험가들의 포럼"
     adventurer_suffix: "."
     campaign_beginner: "초보자 캠페인"
@@ -119,7 +125,7 @@ module.exports = nativeDescription: "한국어", englishDescription: "Korean", t
     spectate: "관중모드"
 
   contact:
-    contact_us: "코드컴뱃에 전할말"
+    contact_us: "코드컴뱃에 전할 말"
     welcome: "의견은 언제든지 환영합니다. 이 양식을 이메일에 사용해 주세요!"
     contribute_prefix: "혹시 같이 코드컴뱃에 공헌하고 싶으시다면 홈페이지에 들러주세요 "
     contribute_page: "참여하기 페이지"
@@ -133,15 +139,15 @@ module.exports = nativeDescription: "한국어", englishDescription: "Korean", t
 
   diplomat_suggestion:
     title: "코드 컴뱃 번역을 도와주세요!"
-    sub_heading: "우리는 당신의 언어 능력이필요합니다."
-    pitch_body: "우리는 영어로 코드컴뱃을 개발하기 시작했지만, 이미 전세계의 유저들이 코드컴뱃을 이용하고 있습니다. 그중 많은 사람들이 한국어로 플레이하기를 바랍니다. 혹시 당신이 영어/한국어에 모두 능숙하다면, Diplomat 으로 코드컴뱃에 참여해서 모든 레벨 뿐 아니라 웹사이트를 한국어로 번역할 수 있습니다."
+    sub_heading: "우리는 당신의 언어 능력이 필요합니다."
+    pitch_body: "우리는 영어로 코드컴뱃을 개발하기 시작했지만, 이미 전세계의 유저들이 코드컴뱃을 이용하고 있습니다. 그 중 많은 사람들이 한국어로 플레이하기를 바랍니다. 혹시 당신이 영어/한국어에 모두 능숙하다면, Diplomat 으로 코드컴뱃에 참여해서 모든 레벨 뿐 아니라 웹사이트를 한국어로 번역할 수 있습니다."
     missing_translations: "우리가 모든 내용을 한국어로 번역할때까지 기본은 영어로 제공됩니다."
-    learn_more: "외교관에 대해서 좀더 자세히알기"
-    subscribe_as_diplomat: "훌륭한 외교관으로써, 정기 구독하기"
+    learn_more: "외교관에 대해서 좀 더 자세히 알아보기"
+    subscribe_as_diplomat: "외교관을 위한 정기 구독"
 
   wizard_settings:
     title: "마법사 설장"
-    customize_avatar: "당신의 분신을 직접 꾸미세요"
+    customize_avatar: "당신의 아바타를 직접 꾸미세요"
 #    active: "Active"
 #    color: "Color"
 #    group: "Group"
@@ -157,7 +163,7 @@ module.exports = nativeDescription: "한국어", englishDescription: "Korean", t
 
   account_settings:
     title: "계정 설정"
-    not_logged_in: "로그인 하시거나 계정을 생성하여 주세요."
+    not_logged_in: "로그인하시거나 계정을 생성하세요."
     autosave: "변경 사항은 자동 저장 됩니다"
     me_tab: "나"
     picture_tab: "사진"
@@ -186,17 +192,17 @@ module.exports = nativeDescription: "한국어", englishDescription: "Korean", t
     error_saving: "오류 저장"
     saved: "변경사항 저장 완료"
     password_mismatch: "비밀번호가 일치하지 않습니다."
-#    password_repeat: "Please repeat your password."
+    password_repeat: "비밀번호를 한번 더 입력해 주세요."
 #    job_profile: "Job Profile"
 #    job_profile_approved: "Your job profile has been approved by CodeCombat. Employers will be able to see it until you either mark it inactive or it has not been changed for four weeks."
 #    job_profile_explanation: "Hi! Fill this out, and we will get in touch about finding you a software developer job."
 #    sample_profile: "See a sample profile"
-#    view_profile: "View Your Profile"
+    view_profile: "나의 프로필 보기"
 
   account_profile:
-#    settings: "Settings"
-#    edit_profile: "Edit Profile"
-#    done_editing: "Done Editing"
+    settings: "설정"
+    edit_profile: "프로필 수정하기"
+    done_editing: "수정 완료"
     profile_for_prefix: "프로필 "
     profile_for_suffix: ""
 #    featured: "Featured"
@@ -351,10 +357,10 @@ module.exports = nativeDescription: "한국어", englishDescription: "Korean", t
     multiplayer: "멀티 플레이어"
     restart: "재시작"
     goals: "목표"
-#    success: "Success!"
-#    incomplete: "Incomplete"
-#    timed_out: "Ran out of time"
-#    failing: "Failing"
+    success: "성공!"
+    incomplete: "목표 미완료"
+    timed_out: "제한 시간 초과"
+    failing: "다시 한번 더 도전해보세요."
     action_timeline: "액션 타임라인"
     click_to_select: "유닛을 선택하기 위해서 유닛을 마우스로 클릭하세요."
     reload_title: "모든 코드가 다시 로딩 되었나요?"
@@ -394,8 +400,8 @@ module.exports = nativeDescription: "한국어", englishDescription: "Korean", t
     editor_config: "에디터 설정"
     editor_config_title: "에디터 설정"
 #    editor_config_level_language_label: "Language for This Level"
-#    editor_config_level_language_description: "Define the programming language for this particular level."
-#    editor_config_default_language_label: "Default Programming Language"
+    editor_config_level_language_description: "이 레벨에서 사용할 언어를 선택하세요."
+    editor_config_default_language_label: "기본 프로그래밍 언어"
 #    editor_config_default_language_description: "Define the programming language you want to code in when starting new levels."
     editor_config_keybindings_label: "단축키 설정"
     editor_config_keybindings_default: "기본(Ace)"
@@ -408,7 +414,7 @@ module.exports = nativeDescription: "한국어", englishDescription: "Korean", t
     editor_config_indentguides_description: "들여쓰기 확인위해 세로줄 표시하기."
     editor_config_behaviors_label: "자동 기능"
     editor_config_behaviors_description: "괄호, 인용부호, 따옴표 자동 완성."
-#    keyboard_shortcuts: "Key Shortcuts"
+    keyboard_shortcuts: "단축키"
 #    loading_ready: "Ready!"
 #    tip_insert_positions: "Shift+Click a point on the map to insert it into the spell editor."
 #    tip_toggle_play: "Toggle play/paused with Ctrl+P."
diff --git a/app/locale/lt.coffee b/app/locale/lt.coffee
index dd8420fff..c34b07ae6 100644
--- a/app/locale/lt.coffee
+++ b/app/locale/lt.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "lietuvių kalba", englishDescription: "Lith
 #    for_beginners: "For Beginners"
 #    multiplayer: "Multiplayer"
 #    for_developers: "For Developers"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
 #  play:
 #    choose_your_level: "Choose Your Level"
diff --git a/app/locale/ms.coffee b/app/locale/ms.coffee
index 7149e3b19..62d60bdb5 100644
--- a/app/locale/ms.coffee
+++ b/app/locale/ms.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "Bahasa Melayu", englishDescription: "Bahasa
 #    for_beginners: "For Beginners"
 #    multiplayer: "Multiplayer"
 #    for_developers: "For Developers"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
 #  play:
 #    choose_your_level: "Choose Your Level"
diff --git a/app/locale/nb.coffee b/app/locale/nb.coffee
index 855b05b2b..cfcf2cd07 100644
--- a/app/locale/nb.coffee
+++ b/app/locale/nb.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "Norsk Bokmål", englishDescription: "Norweg
 #    for_beginners: "For Beginners"
 #    multiplayer: "Multiplayer"
 #    for_developers: "For Developers"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
   play:
     choose_your_level: "Velg Ditt Nivå"
diff --git a/app/locale/nl-BE.coffee b/app/locale/nl-BE.coffee
index 42221b38d..20eef3d90 100644
--- a/app/locale/nl-BE.coffee
+++ b/app/locale/nl-BE.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "Nederlands (België)", englishDescription:
     for_beginners: "Voor Beginners"
     multiplayer: "Multiplayer"
     for_developers: "Voor ontwikkelaars"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
   play:
     choose_your_level: "Kies Je Level"
diff --git a/app/locale/nl-NL.coffee b/app/locale/nl-NL.coffee
index f54d02efd..5db7557ee 100644
--- a/app/locale/nl-NL.coffee
+++ b/app/locale/nl-NL.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "Nederlands (Nederland)", englishDescription
     for_beginners: "Voor Beginners"
     multiplayer: "Multiplayer"
     for_developers: "Voor ontwikkelaars"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
   play:
     choose_your_level: "Kies Je Level"
diff --git a/app/locale/nl.coffee b/app/locale/nl.coffee
index 74b8c35b4..0fccad1af 100644
--- a/app/locale/nl.coffee
+++ b/app/locale/nl.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "Nederlands", englishDescription: "Dutch", t
     for_beginners: "Voor Beginners"
     multiplayer: "Multiplayer"
     for_developers: "Voor ontwikkelaars"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
   play:
     choose_your_level: "Kies Je Level"
diff --git a/app/locale/nn.coffee b/app/locale/nn.coffee
index c7e58789f..180420e6a 100644
--- a/app/locale/nn.coffee
+++ b/app/locale/nn.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "Norwegian Nynorsk", englishDescription: "No
 #    for_beginners: "For Beginners"
 #    multiplayer: "Multiplayer"
 #    for_developers: "For Developers"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
 #  play:
 #    choose_your_level: "Choose Your Level"
diff --git a/app/locale/no.coffee b/app/locale/no.coffee
index 4085d5128..d319665ee 100644
--- a/app/locale/no.coffee
+++ b/app/locale/no.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "Norsk", englishDescription: "Norwegian", tr
 #    for_beginners: "For Beginners"
 #    multiplayer: "Multiplayer"
 #    for_developers: "For Developers"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
   play:
     choose_your_level: "Velg Ditt Nivå"
diff --git a/app/locale/pl.coffee b/app/locale/pl.coffee
index 6cbdc2007..a047b1f31 100644
--- a/app/locale/pl.coffee
+++ b/app/locale/pl.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "język polski", englishDescription: "Polish
     for_beginners: "Dla początkujących"
 #    multiplayer: "Multiplayer"
     for_developers: "Dla developerów"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
   play:
     choose_your_level: "Wybierz poziom"
diff --git a/app/locale/pt-BR.coffee b/app/locale/pt-BR.coffee
index f7758b9be..21ef4fcf3 100644
--- a/app/locale/pt-BR.coffee
+++ b/app/locale/pt-BR.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "português do Brasil", englishDescription:
     for_beginners: "Para Iniciantes"
     multiplayer: "Multijogador"
     for_developers: "Para Desenvolvedores"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
   play:
     choose_your_level: "Escolha seu estágio"
diff --git a/app/locale/pt-PT.coffee b/app/locale/pt-PT.coffee
index 278fc30f6..47879bfe7 100644
--- a/app/locale/pt-PT.coffee
+++ b/app/locale/pt-PT.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "Português (Portugal)", englishDescription:
     for_beginners: "Para Iniciantes"
     multiplayer: "Multijogador"
     for_developers: "Para Programadores"
+#    javascript_blurb: "A linguagem da web. Ótima para escrever websites, aplicações da web, jogos HTML5 e servidores."
+#    python_blurb: "Simples mas poderoso, o Python é uma linguagem de programação ótima para propósitos gerais."
+#    coffeescript_blurb: "Sintaxe do Javascript mais agradável."
+#    clojure_blurb: "Um Lisp moderno"
+#    lua_blurb: "Linguagem para scripts de jogos"
+#    io_blurb: "Simples mas obscuro"
 
   play:
     choose_your_level: "Escolha o Seu Nível"
@@ -186,7 +192,7 @@ module.exports = nativeDescription: "Português (Portugal)", englishDescription:
     error_saving: "Erro ao Guardar"
     saved: "Alterações Guardadas"
     password_mismatch: "As palavras-passe não coincidem."
-#    password_repeat: "Please repeat your password."
+    password_repeat: "Por favor repita a sua palavra-passe."
     job_profile: "Perfil de Emprego"
     job_profile_approved: "O seu perfil de emprego foi aprovado pelo CodeCombat. Os empregadores poderão vê-lo até que o defina como inativo ou não o tenha alterado à 4 semanas."
     job_profile_explanation: "Olá! Preencha isto e entraremos em contacto consigo sobre encontrar um emprego de desenvolvedor de software para si."
@@ -327,7 +333,7 @@ module.exports = nativeDescription: "Português (Portugal)", englishDescription:
 #    pass_screen_blurb: "Review each candidate's code before reaching out. One employer found that 5x as many of our devs passed their technical screen than hiring from Hacker News."
 #    make_hiring_easier: "Make my hiring easier, please."
     what: "O que é o CodeCombat?"
-    what_blurb: "O CodeCombat é um jogo de programação, no navegador e multijogador. Os jogadores escrevem código para controlar as forças deles em batalha contra outros desenvolvedores. Nós suportamos JavaScript, Python, Lua, Clojure, CoffeeScript e Io."
+    what_blurb: "O CodeCombat é um jogo de programação, no navegador e multijogador. Os jogadores escrevem código para controlar as forças deles em batalha contra outros desenvolvedores. Os nossos jogadores têm experiência com todos os conceitos tecnológicos principais."
     cost: "Quanto é que cobramos?"
     cost_blurb: "Cobramos 15% do salário do primeiro ano e ofereçemos uma garantia de devolução de 100% do dinheiro durante 90 dias. Não cobramos por candidatos que já estejam a ser ativamente entrevistados na sua companhia."
     candidate_name: "Nome"
@@ -503,13 +509,13 @@ module.exports = nativeDescription: "Português (Portugal)", englishDescription:
     pick_a_terrain: "Escolha Um Terreno"
     small: "Pequeno"
     grassy: "Com Relva"
-#    fork_title: "Fork New Version"
-#    fork_creating: "Creating Fork..."
+    fork_title: "Bifurcar Nova Versão"
+    fork_creating: "A Criar Bifurcação..."
 #    randomize: "Randomize"
-#    more: "More"
-#    wiki: "Wiki"
-#    live_chat: "Live Chat"
-    level_some_options: "Algumas opções?"
+    more: "Mais"
+    wiki: "Wiki"
+    live_chat: "Chat Ao Vivo"
+    level_some_options: "Algumas Opções?"
     level_tab_thangs: "Thangs"
     level_tab_scripts: "Scripts"
     level_tab_settings: "Configurações"
@@ -522,19 +528,19 @@ module.exports = nativeDescription: "Português (Portugal)", englishDescription:
 #    delete: "Delete"
 #    duplicate: "Duplicate"
     level_settings_title: "Configurações"
-    level_component_tab_title: "Componentes atuais"
-    level_component_btn_new: "Cria um novo Componente"
-    level_systems_tab_title: "Sistemas atuais"
-    level_systems_btn_new: "Cria um novo Sistema"
-    level_systems_btn_add: "Adiciona um Sistema"
+    level_component_tab_title: "Componentes Atuais"
+    level_component_btn_new: "Criar Novo Componente"
+    level_systems_tab_title: "Sistemas Atuais"
+    level_systems_btn_new: "Cria Novo Sistema"
+    level_systems_btn_add: "Adicionar Sistema"
     level_components_title: "Voltar para Todos os Thangs"
     level_components_type: "Tipo"
     level_component_edit_title: "Editar Componente"
 #    level_component_config_schema: "Config Schema"
     level_component_settings: "Configurações"
     level_system_edit_title: "Editar Sistema"
-    create_system_title: "Criar novo Sistema"
-    new_component_title: "Criar novo Componente"
+    create_system_title: "Criar Novo Sistema"
+    new_component_title: "Criar Novo Componente"
     new_component_field_system: "Sistema"
     new_article_title: "Criar um Novo Artigo"
     new_thang_title: "Criar um Novo Tipo de Thang"
@@ -559,20 +565,20 @@ module.exports = nativeDescription: "Português (Portugal)", englishDescription:
     name: "Nome"
     body: "Corpo"
     version: "Versão"
-    commit_msg: "Mensagem de Commit"
-#    version_history: "Version History"
-    version_history_for: "Histórico de versões por: "
+    commit_msg: "Enviar Mensagem"
+    version_history: "Histórico de Versões"
+    version_history_for: "Histórico de Versões para: "
     result: "Resultado"
     results: "Resultados"
     description: "Descrição"
     or: "ou"
-#    subject: "Subject"
+    subject: "Assunto"
     email: "E-mail"
     password: "Palavra-passe"
     message: "Mensagem"
     code: "Código"
     ladder: "Classificação"
-    when: "quando"
+    when: "Quando"
     opponent: "Adversário"
     rank: "Classificação"
     score: "Resultado"
@@ -768,17 +774,17 @@ module.exports = nativeDescription: "Português (Portugal)", englishDescription:
     ambassador_title_description: "(Suporte)"
 
   ladder:
-    please_login: "Por favor, faz log in antes de jogar um jogo para o campeonato."
-    my_matches: "Os meus jogos"
+    please_login: "Por favor inicie sessão antes de jogar um jogo do campeonato."
+    my_matches: "Os Meus Jogos"
     simulate: "Simular"
-    simulation_explanation: "Simulando jogos podes fazer com que o teu jogo seja classificado mais rapidamente!"
+    simulation_explanation: "Ao simular jogos pode ter o seu jogo classificado mais rapidamente!"
     simulate_games: "Simular Jogos!"
 #    simulate_all: "RESET AND SIMULATE GAMES"
-#    games_simulated_by: "Games simulated by you:"
-#    games_simulated_for: "Games simulated for you:"
-#    games_simulated: "Games simulated"
-#    games_played: "Games played"
-#    ratio: "Ratio"
+    games_simulated_by: "Jogos simulados por si:"
+    games_simulated_for: "Jogos simulados para si:"
+    games_simulated: "Jogos simulados"
+    games_played: "Jogos jogados"
+    ratio: "Rácio"
     leaderboard: "Tabela de Classificação"
     battle_as: "Lutar como "
     summary_your: "As tuas "
@@ -868,29 +874,29 @@ module.exports = nativeDescription: "Português (Portugal)", englishDescription:
 #    server_error: "Server error."
 #    unknown: "Unknown error."
 
-#  resources:
-#    your_sessions: "Your Sessions"
-#    level: "Level"
+  resources:
+    your_sessions: "As Suas Sessões"
+    level: "Nível"
 #    social_network_apis: "Social Network APIs"
 #    facebook_status: "Facebook Status"
-#    facebook_friends: "Facebook Friends"
+    facebook_friends: "Amigos do Facebook"
 #    facebook_friend_sessions: "Facebook Friend Sessions"
-#    gplus_friends: "G+ Friends"
+    gplus_friends: "Amigos do Google+"
 #    gplus_friend_sessions: "G+ Friend Sessions"
-#    leaderboard: "Leaderboard"
+    leaderboard: "Tabela de Classificação"
 #    user_schema: "User Schema"
 #    user_profile: "User Profile"
 #    patches: "Patches"
 #    patched_model: "Source Document"
 #    model: "Model"
-#    system: "System"
-#    component: "Component"
-#    components: "Components"
-#    thang: "Thang"
-#    thangs: "Thangs"
-#    level_session: "Your Session"
-#    opponent_session: "Opponent Session"
-#    article: "Article"
+    system: "Sistema"
+    component: "Componente"
+    components: "Componentes"
+    thang: "Thang"
+    thangs: "Thangs"
+    level_session: "A Sua Sessão"
+    opponent_session: "Sessão Do Oponente"
+    article: "Artigo"
 #    user_names: "User Names"
 #    thang_names: "Thang Names"
 #    files: "Files"
@@ -900,7 +906,7 @@ module.exports = nativeDescription: "Português (Portugal)", englishDescription:
 #    sprite_sheet: "Sprite Sheet"
 #    candidate_sessions: "Candidate Sessions"
 #    user_remark: "User Remark"
-#    versions: "Versions"
+    versions: "Versões"
 
 #  delta:
 #    added: "Added"
diff --git a/app/locale/pt.coffee b/app/locale/pt.coffee
index ea24890d3..e69e86463 100644
--- a/app/locale/pt.coffee
+++ b/app/locale/pt.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "português", englishDescription: "Portugues
 #    for_beginners: "For Beginners"
 #    multiplayer: "Multiplayer"
 #    for_developers: "For Developers"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
   play:
     choose_your_level: "Escolha seu estágio"
diff --git a/app/locale/ro.coffee b/app/locale/ro.coffee
index baefa15fb..145382ca0 100644
--- a/app/locale/ro.coffee
+++ b/app/locale/ro.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "limba română", englishDescription: "Roman
     for_beginners: "Pentru Începători"
     multiplayer: "Multiplayer"
     for_developers: "Pentru dezvoltatori"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
   play:
     choose_your_level: "Alege nivelul"
diff --git a/app/locale/ru.coffee b/app/locale/ru.coffee
index 9ac956a4d..cb96b0e6e 100644
--- a/app/locale/ru.coffee
+++ b/app/locale/ru.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "русский", englishDescription: "Russi
     for_beginners: "Новичкам"
     multiplayer: "Мультиплеер"
     for_developers: "Разработчикам"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
   play:
     choose_your_level: "Выберите ваш уровень"
diff --git a/app/locale/sk.coffee b/app/locale/sk.coffee
index 20be15ee8..135b8acf0 100644
--- a/app/locale/sk.coffee
+++ b/app/locale/sk.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "slovenčina", englishDescription: "Slovak",
     for_beginners: "Pre začiatočníkov"
 #    multiplayer: "Multiplayer"
     for_developers: "Pre vývojárov"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
   play:
     choose_your_level: "Vyber si úroveň"
diff --git a/app/locale/sl.coffee b/app/locale/sl.coffee
index 73c8947f7..6517ac37d 100644
--- a/app/locale/sl.coffee
+++ b/app/locale/sl.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "slovenščina", englishDescription: "Sloven
 #    for_beginners: "For Beginners"
 #    multiplayer: "Multiplayer"
 #    for_developers: "For Developers"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
 #  play:
 #    choose_your_level: "Choose Your Level"
diff --git a/app/locale/sr.coffee b/app/locale/sr.coffee
index 4b748189c..ae0508b0f 100644
--- a/app/locale/sr.coffee
+++ b/app/locale/sr.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "српски", englishDescription: "Serbian
 #    for_beginners: "For Beginners"
 #    multiplayer: "Multiplayer"
 #    for_developers: "For Developers"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
   play:
     choose_your_level: "Изабери ниво"
diff --git a/app/locale/sv.coffee b/app/locale/sv.coffee
index ac9d04d87..1e6356c4f 100644
--- a/app/locale/sv.coffee
+++ b/app/locale/sv.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "Svenska", englishDescription: "Swedish", tr
     for_beginners: "För nybörjare"
     multiplayer: "Flera spelare"
     for_developers: "För utvecklare"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
   play:
     choose_your_level: "Välj din nivå"
diff --git a/app/locale/th.coffee b/app/locale/th.coffee
index debe63e0f..0ffadebae 100644
--- a/app/locale/th.coffee
+++ b/app/locale/th.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "ไทย", englishDescription: "Thai", tra
 #    for_beginners: "For Beginners"
 #    multiplayer: "Multiplayer"
 #    for_developers: "For Developers"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
 #  play:
 #    choose_your_level: "Choose Your Level"
diff --git a/app/locale/tr.coffee b/app/locale/tr.coffee
index 83596230d..6c52344fa 100644
--- a/app/locale/tr.coffee
+++ b/app/locale/tr.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "Türkçe", englishDescription: "Turkish", t
     for_beginners: "Yeni Başlayanlar için"
     multiplayer: "Çoklu-oyuncu Modu"
     for_developers: "Geliştiriciler için"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
   play:
     choose_your_level: "Seviye Seçimi"
diff --git a/app/locale/uk.coffee b/app/locale/uk.coffee
index beb7659ec..65c15f9c3 100644
--- a/app/locale/uk.coffee
+++ b/app/locale/uk.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "українська мова", englishDesc
     for_beginners: "Для новачків"
     multiplayer: "Командна гра"
     for_developers: "Для розробників"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
   play:
     choose_your_level: "Оберіть свій рівень"
diff --git a/app/locale/ur.coffee b/app/locale/ur.coffee
index a0ca20473..9672ccdbd 100644
--- a/app/locale/ur.coffee
+++ b/app/locale/ur.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "اُردُو", englishDescription: "Urdu",
 #    for_beginners: "For Beginners"
 #    multiplayer: "Multiplayer"
 #    for_developers: "For Developers"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
 #  play:
 #    choose_your_level: "Choose Your Level"
diff --git a/app/locale/vi.coffee b/app/locale/vi.coffee
index 55bf539c7..f58f20fb4 100644
--- a/app/locale/vi.coffee
+++ b/app/locale/vi.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "Tiếng Việt", englishDescription: "Vietn
 #    for_beginners: "For Beginners"
 #    multiplayer: "Multiplayer"
 #    for_developers: "For Developers"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
   play:
     choose_your_level: "Chọn Trình của bạn"
diff --git a/app/locale/zh-HANS.coffee b/app/locale/zh-HANS.coffee
index 665af4c82..7523c69af 100644
--- a/app/locale/zh-HANS.coffee
+++ b/app/locale/zh-HANS.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
     for_beginners: "适合初学者"
     multiplayer: "多人游戏"
     for_developers: "适合开发者"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
   play:
     choose_your_level: "选择关卡"
diff --git a/app/locale/zh-HANT.coffee b/app/locale/zh-HANT.coffee
index 96a11fc42..b4a96e647 100644
--- a/app/locale/zh-HANT.coffee
+++ b/app/locale/zh-HANT.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "繁体中文", englishDescription: "Chinese
 #    for_beginners: "For Beginners"
 #    multiplayer: "Multiplayer"
 #    for_developers: "For Developers"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
   play:
     choose_your_level: "選取關卡"
diff --git a/app/locale/zh-WUU-HANS.coffee b/app/locale/zh-WUU-HANS.coffee
index 5d5a8c757..ea129d982 100644
--- a/app/locale/zh-WUU-HANS.coffee
+++ b/app/locale/zh-WUU-HANS.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "吴语", englishDescription: "Wuu (Simplifi
 #    for_beginners: "For Beginners"
 #    multiplayer: "Multiplayer"
 #    for_developers: "For Developers"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
 #  play:
 #    choose_your_level: "Choose Your Level"
diff --git a/app/locale/zh-WUU-HANT.coffee b/app/locale/zh-WUU-HANT.coffee
index 6fdb7dd26..361a86c11 100644
--- a/app/locale/zh-WUU-HANT.coffee
+++ b/app/locale/zh-WUU-HANT.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "吳語", englishDescription: "Wuu (Traditio
     for_beginners: "適合學起頭個人"
     multiplayer: "聚隊打遊戲"
     for_developers: "適合開發個人"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
   play:
     choose_your_level: "揀關數"
diff --git a/app/locale/zh.coffee b/app/locale/zh.coffee
index 7a2b8c97e..811f7a5ca 100644
--- a/app/locale/zh.coffee
+++ b/app/locale/zh.coffee
@@ -100,6 +100,12 @@ module.exports = nativeDescription: "中文", englishDescription: "Chinese", tra
 #    for_beginners: "For Beginners"
 #    multiplayer: "Multiplayer"
 #    for_developers: "For Developers"
+#    javascript_blurb: "The language of the web. Great for writing websites, web apps, HTML5 games, and servers."
+#    python_blurb: "Simple yet powerful, Python is a great general purpose programming language."
+#    coffeescript_blurb: "Nicer JavaScript syntax."
+#    clojure_blurb: "A modern Lisp."
+#    lua_blurb: "Game scripting language."
+#    io_blurb: "Simple but obscure."
 
   play:
     choose_your_level: "选取难度"
diff --git a/app/models/CocoModel.coffee b/app/models/CocoModel.coffee
index 045843306..5da19cab3 100644
--- a/app/models/CocoModel.coffee
+++ b/app/models/CocoModel.coffee
@@ -13,8 +13,10 @@ class CocoModel extends Backbone.Model
 
   getMe: -> @me or @me = require('lib/auth').me
 
-  initialize: ->
-    super()
+  initialize: (attributes, options) ->
+    super(arguments...)
+    options ?= {}
+    @setProjection options.project
     if not @constructor.className
       console.error("#{@} needs a className set.")
     @addSchemaDefaults()
@@ -22,6 +24,8 @@ class CocoModel extends Backbone.Model
     @on 'error', @onError, @
     @on 'add', @onLoaded, @
     @saveBackup = _.debounce(@saveBackup, 500)
+    
+  setProjection: (@project) ->
 
   type: ->
     @constructor.className
@@ -116,8 +120,11 @@ class CocoModel extends Backbone.Model
     console.debug 'Patching', @get('name') or @, keys
     @save(attrs, options)
 
-  fetch: ->
-    @jqxhr = super(arguments...)
+  fetch: (options) ->
+    options ?= {}
+    options.data ?= {}
+    options.data.project = @project.join(',') if @project
+    @jqxhr = super(options)
     @loading = true
     @jqxhr
 
diff --git a/app/schemas/models/level.coffee b/app/schemas/models/level.coffee
index eba42f599..262c02d18 100644
--- a/app/schemas/models/level.coffee
+++ b/app/schemas/models/level.coffee
@@ -230,12 +230,14 @@ _.extend LevelSchema.properties,
     title: 'Next Level',
     description: 'Reference to the next level players will play after beating this one.'
   }
+  employerDescription: { type:'string', format: 'markdown', title: 'Employer Description' }
   scripts: c.array {title: 'Scripts', description: 'An array of scripts that trigger based on what the player does and affect things outside of the core level simulation.', 'default': []}, ScriptSchema
   thangs: c.array {title: 'Thangs', description: 'An array of Thangs that make up the level.', 'default': []}, LevelThangSchema
   systems: c.array {title: 'Systems', description: 'Levels are configured by changing the Systems attached to them.', uniqueItems: true, default: []}, LevelSystemSchema  # TODO: uniqueness should be based on 'original', not whole thing
   victory: c.object {title: 'Victory Screen', default: {}, properties: {'body': {type: 'string', format: 'markdown', title: 'Body Text', description: 'Inserted into the Victory Modal once this level is complete. Tell the player they did a good job and what they accomplished!'}, i18n: {type: 'object', format: 'i18n', props: ['body'], description: 'Help translate this victory message'}}}
   i18n: {type: 'object', format: 'i18n', props: ['name', 'description'], description: 'Help translate this level'}
   icon: {type: 'string', format: 'image-file', title: 'Icon'}
+  banner: {type: 'string', format: 'image-file', title: 'Banner'}
   goals: c.array {title: 'Goals', description: 'An array of goals which are visible to the player and can trigger scripts.'}, GoalSchema
   type: c.shortString(title: 'Type', description: 'What kind of level this is.', 'enum': ['campaign', 'ladder', 'ladder-tutorial'])
   showsGuide: c.shortString(title: 'Shows Guide', description: 'If the guide is shown at the beginning of the level.', 'enum': ['first-time', 'always'])
diff --git a/app/schemas/models/level_session.coffee b/app/schemas/models/level_session.coffee
index f4f629914..92ff0f5ba 100644
--- a/app/schemas/models/level_session.coffee
+++ b/app/schemas/models/level_session.coffee
@@ -13,7 +13,7 @@ LevelSessionPlayerSchema = c.object
   changes:
     type: 'Number'
 
-LevelSessionLevelSchema = c.object {required: ['original', 'majorVersion']},
+LevelSessionLevelSchema = c.object {required: ['original', 'majorVersion'], links: [{rel: 'db', href: '/db/level/{(original)}/version/{(majorVersion)}'}]},
   original: c.objectId({})
   majorVersion:
     type: 'integer'
diff --git a/app/schemas/models/mail_sent.coffee b/app/schemas/models/mail_sent.coffee
new file mode 100644
index 000000000..4cd54e241
--- /dev/null
+++ b/app/schemas/models/mail_sent.coffee
@@ -0,0 +1,17 @@
+c = require './../schemas'
+#This will represent transactional emails which have been sent
+
+MailSentSchema = c.object {
+  title: 'Sent mail'
+  description: 'Emails which have been sent through the system'
+}
+_.extend MailSentSchema.properties,
+  mailTask: c.objectId {}
+  user: c.objectId links: [{rel: 'extra', href: '/db/user/{($)}'}]
+  sent: c.date title: 'Sent', readOnly: true
+  metadata: c.object {}, {}
+
+c.extendBasicProperties MailSentSchema, 'mail.sent'
+
+module.exports = MailSentSchema
+  
\ No newline at end of file
diff --git a/app/schemas/models/user_remark.coffee b/app/schemas/models/user_remark.coffee
index 839ce1380..260164a3b 100644
--- a/app/schemas/models/user_remark.coffee
+++ b/app/schemas/models/user_remark.coffee
@@ -12,7 +12,23 @@ _.extend UserRemarkSchema.properties,
   history: c.array {title: 'History', description: 'Records of our interactions with the user.'},
     c.object {title: 'Record'}, {date: c.date(title: 'Date'), content: {title: 'Content', type: 'string', format: 'markdown'}}
   tasks: c.array {title: 'Tasks', description: 'Task entries: when to email the contact about something.'},
-    c.object {title: 'Task'}, {date: c.date(title: 'Date'), action: {title: 'Action', type: 'string'}}
+    c.object {title: 'Task'}, 
+      date: c.date 
+        title: 'Date'
+      action: 
+        title: 'Action'
+        type: 'string'
+      status: 
+        title: 'Status'
+        description: 'The current status of the task'
+        type: 'string'
+        enum: ['Not started', 'In progress', 'Completed']
+      notes:
+        title: 'Notes'
+        description: 'Notes about the task in progress'
+        type: 'string'
+        format: 'markdown'
+        
 
   # denormalization
   userName: {title: 'Player Name', type: 'string'}
diff --git a/app/styles/account/profile.sass b/app/styles/account/profile.sass
index 05a06f6ee..a661ea611 100644
--- a/app/styles/account/profile.sass
+++ b/app/styles/account/profile.sass
@@ -127,13 +127,14 @@
               text-align: center
 
           ul.links
+            text-align: center
             li.has-icon
               display: inline-block
               img
                 margin: 0 0 10px 0
             li.has-icon:not(:nth-child(5))
               img
-                margin: 0 10px 10px 0
+                margin: 0 5px 10px 5px
 
           #contact-candidate
             margin-top: 20px
diff --git a/app/styles/admin/candidates.sass b/app/styles/admin/candidates.sass
new file mode 100644
index 000000000..1a34e9f12
--- /dev/null
+++ b/app/styles/admin/candidates.sass
@@ -0,0 +1,74 @@
+#admin-candidates-view
+
+  h1, h2, h3
+    font: Arial
+
+  .see-candidates-header
+    margin: 30px
+    text-align: center
+
+    #see-candidates
+      cursor: pointer
+
+  .employer_icon
+    width: 125px
+    float: left
+    margin: 0px 15px 15px 0px
+
+  .information_row
+    height: 150px
+    padding-right: 15px
+
+  #leftside
+    width: 500px
+    float: left
+
+  #rightside
+    width: 500px
+    float: left
+
+  .tablesorter
+    //img
+    //  display: none
+
+    .tablesorter-header
+      cursor: pointer
+      &:hover
+        color: black
+
+      &:first-child
+        // Make sure that "Developer #56" doesn't wrap onto second row
+        min-width: 110px
+
+    .tablesorter-headerAsc
+      background-color: #cfc
+
+    .tablesorter-headerDesc
+      background-color: #ccf
+
+    tr
+      cursor: pointer
+
+    tr.expired
+      opacity: 0.5
+
+    code
+      background-color: rgb(220, 220, 220)
+      color: #555
+      margin: 2px 0
+      display: inline-block
+      text-transform: lowercase
+
+    td:nth-child(3) select
+      min-width: 100px
+    td:nth-child(6) select
+      min-width: 50px
+    td:nth-child(7) select
+      min-width: 100px
+
+#employers-view, #profile-view.viewed-by-employer
+  #outer-content-wrapper, #intermediate-content-wrapper, #inner-content-wrapper
+    background: #949494
+
+  .main-content-area
+    background-color: #EAEAEA
\ No newline at end of file
diff --git a/app/styles/base.sass b/app/styles/base.sass
index eae0d473b..c873d3d0f 100644
--- a/app/styles/base.sass
+++ b/app/styles/base.sass
@@ -24,13 +24,16 @@ h1 h2 h3 h4
   @include box-sizing(border-box)
 
 #outer-content-wrapper
+  background: #B4B4B4
+  
+#outer-content-wrapper.show-background
   background: #8cc63f url(/images/pages/base/repeat-tile.png) top center
 
-#intermediate-content-wrapper
-  background: url(/images/pages/base/sky_repeater.png) repeat-x
+  #intermediate-content-wrapper
+    background: url(/images/pages/base/sky_repeater.png) repeat-x
 
-#inner-content-wrapper
-  background: url(/images/pages/base/background_texture.png) top center no-repeat
+  #inner-content-wrapper
+    background: url(/images/pages/base/background_texture.png) top center no-repeat
 
 #front-summary-points-left
   width: 250px
@@ -70,7 +73,7 @@ h1 h2 h3 h4
   &:hover
     color: $white
 
-a[data-toggle="modal"]
+a
   cursor: pointer
 
 .share-buttons, .partner-badges
diff --git a/app/styles/common/level_session_code_view.sass b/app/styles/common/level_session_code_view.sass
new file mode 100644
index 000000000..270d9a0d3
--- /dev/null
+++ b/app/styles/common/level_session_code_view.sass
@@ -0,0 +1,25 @@
+.level-session-code-view
+  #level-icon
+    max-width: 60%
+    max-height: 150px
+    margin-right: 10px
+    display: inline-block
+    float: right
+    margin-bottom: 20px
+   
+  #level-meta-data
+    width: 35%
+    button
+      float: right
+    
+  #session-code
+    clear: both
+    margin-top: 20px
+    
+    h3
+      font-family: Arial
+      margin: 0
+      
+    .code
+      height: 600px
+      border: 2px solid black
\ No newline at end of file
diff --git a/app/styles/docs/components.sass b/app/styles/docs/components.sass
index 73979ded2..9283eda41 100644
--- a/app/styles/docs/components.sass
+++ b/app/styles/docs/components.sass
@@ -15,8 +15,11 @@
       .doc-name
         color: rgb(139, 69, 19)
 
+    .index-column
+      width: 25%
   
     .documentation-column
+      width: 75%
   
       .specialList
         list-style-type: none
diff --git a/app/styles/home.sass b/app/styles/home.sass
index c58133fb8..f5abd9c0f 100644
--- a/app/styles/home.sass
+++ b/app/styles/home.sass
@@ -167,6 +167,10 @@
         h2
           margin: 15px 0 5px
 
+        p
+          overflow: hidden
+          height: 40px
+
     .secondary-code-languages
       margin-left: -10px
 
@@ -201,17 +205,22 @@
           margin: 0
           padding: 0
 
+        p
+          white-space: nowrap
+          text-overflow: ellipsis
+          overflow: hidden
+
       #coffeescript .code-language-logo
-        background: transparent url(/images/pages/home/language_logo_coffeescript.png) no-repeat center
+        background: transparent url(/images/common/code_languages/coffeescript_small.png) no-repeat center
 
       #clojure .code-language-logo
-        background: transparent url(/images/pages/home/language_logo_clojure.png) no-repeat center
+        background: transparent url(/images/common/code_languages/clojure_small.png) no-repeat center
 
       #lua .code-language-logo
-        background: transparent url(/images/pages/home/language_logo_lua.png) no-repeat center
+        background: transparent url(/images/common/code_languages/lua_small.png) no-repeat center
 
       #io .code-language-logo
-        background: transparent url(/images/pages/home/language_logo_io.png) no-repeat center
+        background: transparent url(/images/common/code_languages/io_small.png) no-repeat center
 
   
 #multiplayer-launch-modal
diff --git a/app/styles/play/ladder/ladder_tab.sass b/app/styles/play/ladder/ladder_tab.sass
index c92726c9c..2529f6280 100644
--- a/app/styles/play/ladder/ladder_tab.sass
+++ b/app/styles/play/ladder/ladder_tab.sass
@@ -53,6 +53,5 @@
 
   .code-language-cell
     padding: 0 10px
-    background: transparent url(/images/pages/home/language_logo_javascript.png) no-repeat center center
-    background-size: contain
-    height: 19px
+    background: transparent url(/images/common/code_languages/javascript_icon.png) no-repeat center center
+    height: 16px
diff --git a/app/styles/play/ladder/my_matches_tab.sass b/app/styles/play/ladder/my_matches_tab.sass
index 741a3a534..13aca340d 100644
--- a/app/styles/play/ladder/my_matches_tab.sass
+++ b/app/styles/play/ladder/my_matches_tab.sass
@@ -40,6 +40,5 @@
 
   .code-language-cell
     padding: 0 10px
-    background: transparent url(/images/pages/home/language_logo_javascript.png) no-repeat center center
-    background-size: contain
-    height: 19px
+    background: transparent url(/images/common/code_languages/javascript_icon.png) no-repeat center center
+    height: 16px
diff --git a/app/styles/play/ladder/play_modal.sass b/app/styles/play/ladder/play_modal.sass
index 3587c557f..6050df159 100644
--- a/app/styles/play/ladder/play_modal.sass
+++ b/app/styles/play/ladder/play_modal.sass
@@ -98,12 +98,12 @@
 
     .code-language
       position: absolute
-      background: transparent url(/images/pages/home/language_logo_javascript.png) no-repeat center center
+      background: transparent url(/images/common/code_languages/javascript_small.png) no-repeat center center
       background-size: contain
-      width: 40px
-      height: 40px
-      right: -5px
-      top: -15px
+      width: 50px
+      height: 50px
+      right: -0px
+      top: -30px
       display: block
 
   .my-name
diff --git a/app/styles/play/level/tome/spell_palette.sass b/app/styles/play/level/tome/spell_palette.sass
index 3e2f78794..6c5a12f32 100644
--- a/app/styles/play/level/tome/spell_palette.sass
+++ b/app/styles/play/level/tome/spell_palette.sass
@@ -70,10 +70,10 @@
 
   .code-language-logo
     position: absolute
-    width: 20px
-    height: 20px
-    left: 12px
-    top: 34px
+    width: 16px
+    height: 16px
+    left: 16px
+    top: 36px
     z-index: 10
     background-color: transparent
     background-repeat: no-repeat
@@ -81,21 +81,27 @@
     cursor: pointer
 
     &.javascript
-      background-image: url(/images/pages/home/language_logo_javascript.png)
+      background-image: url(/images/common/code_languages/javascript_icon.png)
     &.python
-      background-image: url(/images/pages/home/language_logo_python.png)
+      background-image: url(/images/common/code_languages/python_icon.png)
     &.coffeescript
-      background-image: url(/images/pages/home/language_logo_coffeescript.png)
+      background-image: url(/images/common/code_languages/coffeescript_icon.png)
     &.clojure
-      background-image: url(/images/pages/home/language_logo_clojure.png)
+      background-image: url(/images/common/code_languages/clojure_icon.png)
     &.lua
-      background-image: url(/images/pages/home/language_logo_lua.png)
+      background-image: url(/images/common/code_languages/lua_icon.png)
     &.io
-      background-image: url(/images/pages/home/language_logo_io.png)
+      background-image: url(/images/common/code_languages/io_icon.png)
+
+    &:hover
+      outline: 1px outset #ccc
+
+      &:active
+        outline: 1px inset #ccc
 
 html.no-borderimage
   #spell-palette-view
     span.code-palette-background
       display: none
     img.code-palette-background
-      display: block
\ No newline at end of file
+      display: block
diff --git a/app/templates/account/job_profile_code_modal.jade b/app/templates/account/job_profile_code_modal.jade
new file mode 100644
index 000000000..6f5703ef6
--- /dev/null
+++ b/app/templates/account/job_profile_code_modal.jade
@@ -0,0 +1,12 @@
+extends /templates/modal/modal_base
+
+block modal-header-content
+  h3 Applicant Code for
+    span.spl= session.get('levelName')
+
+block modal-body-content
+  .level-session-code-view
+
+block modal-footer
+  .modal-footer
+    button(data-dismiss="modal", data-i18n="modal.close").btn Close
diff --git a/app/templates/account/profile.jade b/app/templates/account/profile.jade
index 11c0d6956..2699a3ac1 100644
--- a/app/templates/account/profile.jade
+++ b/app/templates/account/profile.jade
@@ -181,13 +181,12 @@ block content
               ul.sessions
                 each session in sessions
                   li
-                    - var sessionLink = "/play/level/" + session.levelID + "?team=" + (session.team || 'humans') + (myProfile ? '' : "&session=" + session._id);
-                    a(href=sessionLink)
+                    a.session-link(data-session-id=session._id)
                       span= session.levelName
                       if session.team
-                        span  #{session.team}
+                        span.spl - #{session.team}
                     if session.codeLanguage != 'javascript'
-                      span  - #{{coffeescript: 'CoffeeScript', python: 'Python', lua: 'Lua', io: 'Io', clojure: 'Clojure'}[session.codeLanguage]}
+                      span.spl - #{{coffeescript: 'CoffeeScript', python: 'Python', lua: 'Lua', io: 'Io', clojure: 'Clojure'}[session.codeLanguage]}
 
         .middle-column.full-height-column
           .sub-column
diff --git a/app/templates/admin.jade b/app/templates/admin.jade
index 11ee67ee8..5d583f703 100644
--- a/app/templates/admin.jade
+++ b/app/templates/admin.jade
@@ -25,6 +25,8 @@ block content
       a(href="/admin/level_sessions", data-i18n="admin.av_entities_active_instances_url") Active Instances
     li
       a(href="/admin/employer_list", data-i18n="admin.av_entities_employer_list_url") Employer List
+    li
+      a(href="/admin/candidates") Candidate List
         
   h4(data-i18n="admin.av_other_sub_title") Other
 
diff --git a/app/templates/admin/candidates.jade b/app/templates/admin/candidates.jade
new file mode 100644
index 000000000..0a2d85f96
--- /dev/null
+++ b/app/templates/admin/candidates.jade
@@ -0,0 +1,110 @@
+extends /templates/base
+block content
+  if !me.isAdmin()
+    h1 Admins Only
+  if me.isAdmin()
+    h1(data-i18n="employers.want_to_hire_our_players") Hire CodeCombat Players
+    if !isEmployer && !me.isAdmin()
+      div#info_wrapper
+        div#leftside
+          div.information_row
+            img(class="employer_icon" src="/images/pages/employer/employer_icon1.png")
+            h2(data-i18n="employers.what") What is CodeCombat?
+            p(data-i18n="employers.what_blurb") CodeCombat is a multiplayer browser programming game. Players write code to control their forces in battle against other developers. We support JavaScript, Python, Lua, Clojure, CoffeeScript, and Io.
+          div.information_row
+            img(class="employer_icon" src="/images/pages/employer/employer_icon3.png")
+            h2(data-i18n="employers.who") Who Are the Players?
+            p(data-i18n="employers.who_blurb") CodeCombateers are CTOs, VPs of Engineering, and graduates of top 20 engineering schools. No junior developers here. Our players enjoy playing with code and solving problems.
+          div.information_row
+            img(class="employer_icon" src="/images/pages/employer/employer_icon5.png")
+            h2(data-i18n="employers.cost") Who Are the Players?
+            p(data-i18n="employers.cost_blurb") CodeCombateers are CTOs, VPs of Engineering, and graduates of top 20 engineering schools. No junior developers here. Our players enjoy playing with code and solving problems.
+        div#rightside
+          div.information_row
+            img(class="employer_icon" src="/images/pages/employer/employer_icon2.png")
+            h2(data-i18n="employers.how") How Much Do we Charge?
+            p(data-i18n="employers.how_blurb") We charge 15% of first year's salary and offer a 100% money back guarantee for 90 days. We don't charge for candidates who are already actively being interviewed at your company.
+          div.information_row
+            img(class="employer_icon" src="/images/pages/employer/employer_icon4.png")
+            h2(data-i18n="employers.why") Why Hire Through Us?
+            p
+              span(data-i18n="employers.why_blurb_1") We will save you time. Every CodeCombateer we feaure is 
+              strong(data-i18n="employers.why_blurb_2") looking for work
+              span(data-i18n="employers.why_blurb_3") , has 
+              strong(data-i18n="employers.why_blurb_4") demonstrated top notch technical skills
+              span(data-i18n="employers.why_blurb_5") , and has been 
+              strong(data-i18n="employers.why_blurb_6") personally screened by us
+              span(data-i18n="employers.why_blurb_7") . Stop screening and start hiring.
+          div.information_row
+            img(class="employer_icon" src="/images/pages/employer/employer_icon6.png")
+            h2(data-i18n="employers.response") What's the Response Rate?
+            p(data-i18n="employers.response_blurb") Almost every developer you contact on CodeCombat will respond to inquires whether or not they want to interivew. If you would like help finding a candidate for your role, we can make recommendations.
+    if candidates.length
+      ul.nav.nav-pills
+        li.active
+          a(href="#featured-candidates", data-toggle="tab")
+            span(data-i18n="employers.featured_developers") Featured Developers
+            | (#{featuredCandidates.length})
+        if otherCandidates.length
+          li
+            a(href="#other-candidates", data-toggle="tab")
+              span(data-i18n="employers.other_developers") Other Developers
+              | (#{otherCandidates.length})
+        if me.isAdmin() && inactiveCandidates.length
+          li
+            a(href="#inactive-candidates", data-toggle="tab")
+              span(data-i18n="employers.inactive_developers") Inactive Developers
+              | (#{inactiveCandidates.length})
+      div.tab-content
+        for area, tabIndex in [{id: "featured-candidates", candidates: featuredCandidates}, {id: "other-candidates", candidates: otherCandidates}, {id: "inactive-candidates", candidates: inactiveCandidates}]
+          div(class="tab-pane well" + (tabIndex ? "" : " active"), id=area.id)
+            table.table.table-condensed.table-hover.table-responsive.tablesorter
+              thead
+                tr
+                  th(data-i18n="general.name") Name
+                  th(data-i18n="employers.candidate_location") Location
+                  th(data-i18n="employers.candidate_looking_for") Looking For
+                  th(data-i18n="employers.candidate_role") Role
+                  th(data-i18n="employers.candidate_top_skills") Top Skills
+                  th(data-i18n="employers.candidate_years_experience") Yrs Exp
+                  th(data-i18n="employers.candidate_last_updated") Last Updated
+                  if me.isAdmin()
+                    th(data-i18n="employers.candidate_who") Who
+                  if me.isAdmin() && area.id == 'inactive-candidates'
+                    th ✓?
+              tbody
+                for candidate, index in area.candidates
+                  - var profile = candidate.get('jobProfile');
+                  - var authorized = candidate.id;  // If we have the id, then we are authorized.
+                  - var profileAge = (new Date() - new Date(profile.updated)) / 86400 / 1000;
+                  - var expired = profileAge > 2 * 30.4;
+                  tr(data-candidate-id=candidate.id, id=candidate.id, class=expired ? "expired" : "")
+                    td
+                      if authorized
+                        img(src=candidate.getPhotoURL(50), alt=profile.name, title=profile.name, height=50)
+                        if profile.name
+                          p= profile.name
+                        else if me.isAdmin()
+                          p (#{candidate.get('name')})
+                      else
+                        img(src="/images/pages/contribute/archmage.png", alt="", title="Sign up as an employer to see our candidates", width=50)
+                        p Developer ##{index + 1 + (area.id == 'featured-candidates' ? 0 : featuredCandidates.length)}
+                    if profile.country == 'USA'
+                      td= profile.city
+                    else
+                      td= profile.country
+                    td= profile.lookingFor
+                    td= profile.jobTitle
+                    td
+                      each skill in profile.skills
+                        code= skill
+                        span
+                    td= profile.experience
+                    td(data-profile-age=profileAge)= moment(profile.updated).fromNow()
+                    if me.isAdmin()
+                      td= remarks[candidate.id] ? remarks[candidate.id].get('contactName') : ''
+                    if me.isAdmin() && area.id == 'inactive-candidates'
+                      if candidate.get('jobProfileApproved')
+                        td ✓
+                      else
+                        td ✗
\ No newline at end of file
diff --git a/app/templates/base.jade b/app/templates/base.jade
index 01a67687c..6c18d420c 100644
--- a/app/templates/base.jade
+++ b/app/templates/base.jade
@@ -49,7 +49,7 @@ body
             a.header-font(href='/community', data-i18n="nav.community") Community
 
   block outer_content
-    #outer-content-wrapper
+    #outer-content-wrapper(class=showBackground ? 'show-background' : '')
       #intermediate-content-wrapper
         #inner-content-wrapper
           .main-content-area
diff --git a/app/templates/common/level_session_code.jade b/app/templates/common/level_session_code.jade
new file mode 100644
index 000000000..ad998e89d
--- /dev/null
+++ b/app/templates/common/level_session_code.jade
@@ -0,0 +1,13 @@
+div#session-info
+  img(src='/file/'+levelIcon alt='levelIcon')#level-icon
+  div#level-meta-data
+    a.btn.btn-primary(href=sessionLink, target=_blank) Spectate
+    p!= levelDescription
+  
+div#session-code
+  for spell in levelSpells
+    .panel.panel-success
+      .panel-heading
+        h3= spell.name
+      .panel-body
+        .code(data-height=spell.height)= spell.code
\ No newline at end of file
diff --git a/app/templates/home.jade b/app/templates/home.jade
index 02775696a..6d9d939df 100644
--- a/app/templates/home.jade
+++ b/app/templates/home.jade
@@ -10,14 +10,14 @@ block content
         .code-language#javascript(data-code-language='javascript')
           .code-wizard
           h2 JavaScript
-          p The language of the web. Great for writing websites, web apps, HTML5 games, and servers.
+          p(data-i18n="home.javascript_blurb") The language of the web. Great for writing websites, web apps, HTML5 games, and servers.
 
       .col-md-6
         .code-language.beta#python(data-code-language='python')
           .code-wizard
           .code-language-beta
           h2 Python
-          p Simple yet powerful, Python is a great general purpose programming language.
+          p(data-i18n="home.python_blurb") Simple yet powerful, Python is a great general purpose programming language.
 
     .secondary-code-languages.row
       .col-md-3
@@ -26,7 +26,7 @@ block content
           .code-wizard
           .code-language-beta
           h3 CoffeeScript
-          p Nicer JavaScript syntax
+          p(data-i18n="home.coffeescript_blurb") Nicer JavaScript syntax.
 
       .col-md-3
         .code-language.beta#clojure(data-code-language='clojure')
@@ -34,7 +34,7 @@ block content
           .code-wizard
           .code-language-beta
           h3 Clojure
-          p A modern Lisp
+          p(data-i18n="home.clojure_blurb") A modern Lisp.
 
       .col-md-3
         .code-language.beta#lua(data-code-language='lua')
@@ -42,7 +42,7 @@ block content
           .code-wizard
           .code-language-beta
           h3 Lua
-          p Game scripting language
+          p(data-i18n="home.lua_blurb") Game scripting language.
 
       .col-md-3
         .code-language.beta#io(data-code-language='io', title="Careful: Io is still quite buggy")
@@ -50,7 +50,7 @@ block content
           .code-wizard
           .code-language-beta
           h3 Io
-          p Simple but obscure
+          p(data-i18n="home.io_blurb") Simple but obscure.
 
   .alert.alert-danger.lt-ie10
     strong(data-i18n="home.no_ie") CodeCombat does not run in Internet Explorer 9 or older. Sorry!
diff --git a/app/templates/play/ladder/ladder_tab.jade b/app/templates/play/ladder/ladder_tab.jade
index 4d682243a..515397e1f 100644
--- a/app/templates/play/ladder/ladder_tab.jade
+++ b/app/templates/play/ladder/ladder_tab.jade
@@ -21,7 +21,7 @@ div#columns.row
         for session, rank in topSessions
           - var myRow = session.get('creator') == me.id
           tr(class=myRow ? "success" : "", data-player-id=session.get('creator'), data-session-id=session.id)
-            td.code-language-cell(style="background-image: url(/images/pages/home/language_logo_" + session.get('submittedCodeLanguage') + ".png)")
+            td.code-language-cell(style="background-image: url(/images/common/code_languages/" + session.get('submittedCodeLanguage') + "_icon.png)")
             td.rank-cell= rank + 1
             td.score-cell= Math.round(session.get('totalScore') * 100)
             td.name-col-cell= session.get('creatorName') || "Anonymous"
@@ -35,7 +35,7 @@ div#columns.row
           for session in team.leaderboard.nearbySessions()
             - var myRow = session.get('creator') == me.id
             tr(class=myRow ? "success" : "", data-player-id=session.get('creator'), data-session-id=session.id)
-              td.code-language-cell(style="background-image: url(/images/pages/home/language_logo_" + session.get('submittedCodeLanguage') + ".png)")
+              td.code-language-cell(style="background-image: url(/images/common/code_languages/" + session.get('submittedCodeLanguage') + "_icon.png)")
               td.rank-cell= session.rank
               td.score-cell= Math.round(session.get('totalScore') * 100)
               td.name-col-cell= session.get('creatorName') || "Anonymous"
diff --git a/app/templates/play/ladder/my_matches_tab.jade b/app/templates/play/ladder/my_matches_tab.jade
index a08f6651b..bf4d9e856 100644
--- a/app/templates/play/ladder/my_matches_tab.jade
+++ b/app/templates/play/ladder/my_matches_tab.jade
@@ -39,7 +39,7 @@ div#columns.row
                 span(data-i18n="general.loss").loss Loss
               if match.state === 'tie'
                 span(data-i18n="general.tie").tie Tie
-            td.code-language-cell(style="background-image: url(/images/pages/home/language_logo_" + match.codeLanguage +  ".png)")
+            td.code-language-cell(style="background-image: url(/images/common/code_languages/" + match.codeLanguage +  "_icon.png)")
             td.name-cell= match.opponentName || "Anonymous"
             td.time-cell= match.when
             td.battle-cell
diff --git a/app/templates/play/ladder/play_modal.jade b/app/templates/play/ladder/play_modal.jade
index 841203b2f..c25c3a1f5 100644
--- a/app/templates/play/ladder/play_modal.jade
+++ b/app/templates/play/ladder/play_modal.jade
@@ -33,7 +33,7 @@ block modal-body-content
           span= myName
         div.opponent-name.name-label
           span(data-i18n="ladder.simple_ai") Simple AI
-          //span.code-language(style="background-image: url(/images/pages/home/language_logo_javascript.png)")
+          //span.code-language(style="background-image: url(/images/common/code_languages/javascript_small.png)")
         div.difficulty
           span(data-i18n="ladder.warmup") Warmup
         div(data-i18n="ladder.vs").vs VS
@@ -50,7 +50,7 @@ block modal-body-content
           div.opponent-name.name-label
             span= challengers.easy.opponentName
             if challengers.easy.codeLanguage
-              span.code-language(style="background-image: url(/images/pages/home/language_logo_" + challengers.easy.codeLanguage + ".png)")
+              span.code-language(style="background-image: url(/images/common/code_languages/" + challengers.easy.codeLanguage + "_small.png)")
           div.difficulty
             span(data-i18n="general.easy") Easy
           div(data-i18n="ladder.vs").vs VS
@@ -67,7 +67,7 @@ block modal-body-content
           div.opponent-name.name-label
             span= challengers.medium.opponentName
             if challengers.medium.codeLanguage
-              span.code-language(style="background-image: url(/images/pages/home/language_logo_" + challengers.medium.codeLanguage + ".png)")
+              span.code-language(style="background-image: url(/images/common/code_languages/" + challengers.medium.codeLanguage + "_small.png)")
           div.difficulty
             span(data-i18n="general.medium") Medium
           div(data-i18n="ladder.vs").vs VS
@@ -84,7 +84,7 @@ block modal-body-content
           div.opponent-name.name-label
             span= challengers.hard.opponentName
             if challengers.hard.codeLanguage
-              span.code-language(style="background-image: url(/images/pages/home/language_logo_" + challengers.hard.codeLanguage + ".png)")
+              span.code-language(style="background-image: url(/images/common/code_languages/" + challengers.hard.codeLanguage + "_small.png)")
           div.difficulty
             span(data-i18n="general.hard") Hard
           div(data-i18n="ladder.vs").vs VS
diff --git a/app/templates/teachers.jade b/app/templates/teachers.jade
index 3653491d8..651de1205 100644
--- a/app/templates/teachers.jade
+++ b/app/templates/teachers.jade
@@ -2,7 +2,7 @@ extends /templates/base
 
 block content
 
-  .row
+  p.row
 
     .span5
 
diff --git a/app/views/AboutView.coffee b/app/views/AboutView.coffee
new file mode 100644
index 000000000..b93e9bdc6
--- /dev/null
+++ b/app/views/AboutView.coffee
@@ -0,0 +1,6 @@
+RootView = require 'views/kinds/RootView'
+template = require 'templates/about'
+
+module.exports = class AboutView extends RootView
+  id: 'about-view'
+  template: template
diff --git a/app/views/admin_view.coffee b/app/views/AdminView.coffee
similarity index 90%
rename from app/views/admin_view.coffee
rename to app/views/AdminView.coffee
index 6b0aadcc9..5c23d2ab1 100644
--- a/app/views/admin_view.coffee
+++ b/app/views/AdminView.coffee
@@ -1,8 +1,8 @@
 {backboneFailure, genericFailure} = require 'lib/errors'
-View = require 'views/kinds/RootView'
+RootView = require 'views/kinds/RootView'
 template = require 'templates/admin'
 
-module.exports = class AdminView extends View
+module.exports = class AdminView extends RootView
   id: 'admin-view'
   template: template
 
diff --git a/app/views/cla_view.coffee b/app/views/CLAView.coffee
similarity index 88%
rename from app/views/cla_view.coffee
rename to app/views/CLAView.coffee
index 93f03aa56..08664992f 100644
--- a/app/views/cla_view.coffee
+++ b/app/views/CLAView.coffee
@@ -1,8 +1,8 @@
-View = require 'views/kinds/RootView'
+RootView = require 'views/kinds/RootView'
 template = require 'templates/cla'
 {me} = require 'lib/auth'
 
-module.exports = class CLAView extends View
+module.exports = class CLAView extends RootView
   id: 'cla-view'
   template: template
 
diff --git a/app/views/CommunityView.coffee b/app/views/CommunityView.coffee
new file mode 100644
index 000000000..15d28300a
--- /dev/null
+++ b/app/views/CommunityView.coffee
@@ -0,0 +1,6 @@
+RootView = require 'views/kinds/RootView'
+template = require 'templates/community'
+
+module.exports = class CommunityView extends RootView
+  id: 'community-view'
+  template: template
diff --git a/app/views/DemoView.coffee b/app/views/DemoView.coffee
index a3b65c781..d18190162 100644
--- a/app/views/DemoView.coffee
+++ b/app/views/DemoView.coffee
@@ -35,6 +35,7 @@ module.exports = DemoView = class DemoView extends CocoView
     @loadDemoingLibs() unless DemoView.loaded
 
   loadDemoingLibs: ->
+    DemoView.loaded = true
     @queue = new createjs.LoadQueue()
     @queue.on('complete', @scriptsLoaded, @)
     window.jasmine = {} # so that mock-ajax properly loads. It expects jasmine to be loaded
@@ -81,8 +82,14 @@ module.exports = DemoView = class DemoView extends CocoView
     view = demoFunc()
     return unless view
     @$el.find('#demo-area').empty().append(view.$el)
+    view.afterInsert()
     # TODO, maybe handle root views differently than modal views differently than everything else?
 
   getAllDemoFiles: ->
     allFiles = window.require.list()
     (f for f in allFiles when f.indexOf('.demo') > -1)
+
+  destroy: ->
+    # hack to get jasmine tests to properly run again on clicking links, and make sure if you
+    # leave this page (say, back to the main site) that test stuff doesn't follow you.
+    document.location.reload()
diff --git a/app/views/employers_view.coffee b/app/views/EmployersView.coffee
similarity index 99%
rename from app/views/employers_view.coffee
rename to app/views/EmployersView.coffee
index 03ba35c85..9bbfa1ef6 100644
--- a/app/views/employers_view.coffee
+++ b/app/views/EmployersView.coffee
@@ -1,4 +1,4 @@
-View = require 'views/kinds/RootView'
+RootView = require 'views/kinds/RootView'
 template = require 'templates/employers'
 app = require 'application'
 User = require 'models/User'
@@ -15,7 +15,7 @@ class UserRemarksCollection extends CocoCollection
   url: '/db/user.remark?project=contact,contactName,user'
   model: UserRemark
 
-module.exports = class EmployersView extends View
+module.exports = class EmployersView extends RootView
   id: 'employers-view'
   template: template
 
diff --git a/app/views/home_view.coffee b/app/views/HomeView.coffee
similarity index 92%
rename from app/views/home_view.coffee
rename to app/views/HomeView.coffee
index 40eb72e88..05e9f78f0 100644
--- a/app/views/home_view.coffee
+++ b/app/views/HomeView.coffee
@@ -1,4 +1,4 @@
-View = require 'views/kinds/RootView'
+RootView = require 'views/kinds/RootView'
 template = require 'templates/home'
 WizardSprite = require 'lib/surface/WizardSprite'
 ThangType = require 'models/ThangType'
@@ -6,7 +6,7 @@ Simulator = require 'lib/simulator/Simulator'
 {me} = require '/lib/auth'
 application  = require 'application'
 
-module.exports = class HomeView extends View
+module.exports = class HomeView extends RootView
   id: 'home-view'
   template: template
 
@@ -52,7 +52,7 @@ module.exports = class HomeView extends View
     @updateLanguageLogos codeLanguage
 
   updateLanguageLogos: (codeLanguage) ->
-    @$el.find('.game-mode-wrapper .code-language-logo').css('background-image', "url(/images/pages/home/language_logo_#{codeLanguage}.png)").toggleClass 'inverted', (codeLanguage in ['io', 'coffeescript'])
+    @$el.find('.game-mode-wrapper .code-language-logo').css('background-image', "url(/images/common/code_languages/#{codeLanguage}_small.png)")
 
   onCodeLanguageSelected: (e) ->
     target = $(e.target).closest('.code-language')
diff --git a/app/views/LegalView.coffee b/app/views/LegalView.coffee
new file mode 100644
index 000000000..2dd36473d
--- /dev/null
+++ b/app/views/LegalView.coffee
@@ -0,0 +1,6 @@
+RootView = require 'views/kinds/RootView'
+template = require 'templates/legal'
+
+module.exports = class LegalView extends RootView
+  id: 'legal-view'
+  template: template
diff --git a/app/views/multiplayer_view.coffee b/app/views/MultiplayerView.coffee
similarity index 93%
rename from app/views/multiplayer_view.coffee
rename to app/views/MultiplayerView.coffee
index acfaefe15..9b5737d10 100644
--- a/app/views/multiplayer_view.coffee
+++ b/app/views/MultiplayerView.coffee
@@ -1,4 +1,4 @@
-HomeView = require './home_view'
+HomeView = require './HomeView'
 ModalView = require 'views/kinds/ModalView'
 modalTemplate = require 'templates/multiplayer_launch_modal'
 
diff --git a/app/views/NotFoundView.coffee b/app/views/NotFoundView.coffee
new file mode 100644
index 000000000..11d94cb42
--- /dev/null
+++ b/app/views/NotFoundView.coffee
@@ -0,0 +1,6 @@
+RootView = require 'views/kinds/RootView'
+template = require 'templates/not_found'
+
+module.exports = class NotFoundView extends RootView
+  id: 'not-found-view'
+  template: template
diff --git a/app/views/TeachersView.coffee b/app/views/TeachersView.coffee
new file mode 100644
index 000000000..25d4ec958
--- /dev/null
+++ b/app/views/TeachersView.coffee
@@ -0,0 +1,6 @@
+RootView = require 'views/kinds/RootView'
+template = require 'templates/teachers'
+
+module.exports = class TeachersView extends RootView
+  id: 'teachers-view'
+  template: template
diff --git a/app/views/about_view.coffee b/app/views/about_view.coffee
deleted file mode 100644
index 76988aba8..000000000
--- a/app/views/about_view.coffee
+++ /dev/null
@@ -1,6 +0,0 @@
-View = require 'views/kinds/RootView'
-template = require 'templates/about'
-
-module.exports = class AboutView extends View
-  id: 'about-view'
-  template: template
diff --git a/app/views/account/JobProfileCodeModal.coffee b/app/views/account/JobProfileCodeModal.coffee
new file mode 100644
index 000000000..397de97cf
--- /dev/null
+++ b/app/views/account/JobProfileCodeModal.coffee
@@ -0,0 +1,25 @@
+ModalView = require 'views/kinds/ModalView'
+template = require 'templates/account/job_profile_code_modal'
+LevelSessionCodeView = require 'views/common/LevelSessionCodeView'
+console.log 'template', template
+
+module.exports = class JobProfileCodeModal extends ModalView
+  id: 'job_profile_code_modal'
+  template: template
+  modalWidthPercent: 90
+  plain: true
+  
+  constructor: (options) ->
+    super(arguments...)
+    @session = options.session
+    
+  getRenderData: ->
+    c = super()
+    c.session = @session
+    c
+
+  afterRender: ->
+    super()
+    codeView = new LevelSessionCodeView({session:@session})
+    @insertSubView(codeView, @$el.find('.level-session-code-view'))
+    
\ No newline at end of file
diff --git a/app/views/account/profile_view.coffee b/app/views/account/profile_view.coffee
index 213b89a97..ca33ba8e8 100644
--- a/app/views/account/profile_view.coffee
+++ b/app/views/account/profile_view.coffee
@@ -1,4 +1,4 @@
-View = require 'views/kinds/RootView'
+RootView = require 'views/kinds/RootView'
 template = require 'templates/account/profile'
 User = require 'models/User'
 LevelSession = require 'models/LevelSession'
@@ -9,6 +9,7 @@ JobProfileView = require 'views/account/job_profile_view'
 UserRemark = require 'models/UserRemark'
 forms = require 'lib/forms'
 ModelModal = require 'views/modal/model_modal'
+JobProfileCodeModal = require './JobProfileCodeModal'
 
 class LevelSessionsCollection extends CocoCollection
   url: -> "/db/user/#{@userID}/level.sessions/employer"
@@ -25,9 +26,11 @@ adminContacts = [
   {id: '52a57252a89409700d0000d9', name: 'Ignore'}
 ]
 
-module.exports = class ProfileView extends View
+module.exports = class ProfileView extends RootView
   id: 'profile-view'
   template: template
+  showBackground: false
+
   subscriptions:
     'linkedin-loaded': 'onLinkedInLoaded'
 
@@ -49,6 +52,7 @@ module.exports = class ProfileView extends View
     'keyup .editable-profile .editable-array input': 'onEditArray'
     'click .editable-profile a': 'onClickLinkWhileEditing'
     'change #admin-contact': 'onAdminContactChanged'
+    'click .session-link': 'onSessionLinkPressed'
 
   constructor: (options, @userID) ->
     @userID ?= me.id
@@ -584,3 +588,9 @@ module.exports = class ProfileView extends View
       {name: t('account_profile.next_photo'), weight: 2, container: '#profile-photo-container', fn: modified 'photoURL'}
       {name: t('account_profile.next_active'), weight: 1, fn: modified 'active'}
     ]
+
+  onSessionLinkPressed: (e) ->
+    sessionID = $(e.target).closest('.session-link').data('session-id')
+    session = _.find @sessions.models, (session) -> session.id is sessionID
+    modal = new JobProfileCodeModal({session:session})
+    @openModalView modal
\ No newline at end of file
diff --git a/app/views/account/settings_view.coffee b/app/views/account/settings_view.coffee
index 4f6622232..39a335488 100644
--- a/app/views/account/settings_view.coffee
+++ b/app/views/account/settings_view.coffee
@@ -1,4 +1,4 @@
-View = require 'views/kinds/RootView'
+RootView = require 'views/kinds/RootView'
 template = require 'templates/account/settings'
 {me} = require 'lib/auth'
 forms = require 'lib/forms'
@@ -8,7 +8,7 @@ AuthModalView = require 'views/modal/auth_modal'
 WizardSettingsView = require './wizard_settings_view'
 JobProfileView = require './job_profile_view'
 
-module.exports = class SettingsView extends View
+module.exports = class SettingsView extends RootView
   id: 'account-settings-view'
   template: template
   changedFields: [] # DOM input fields
diff --git a/app/views/admin/candidates_view.coffee b/app/views/admin/candidates_view.coffee
new file mode 100644
index 000000000..c91f16efd
--- /dev/null
+++ b/app/views/admin/candidates_view.coffee
@@ -0,0 +1,207 @@
+RootView = require 'views/kinds/RootView'
+template = require 'templates/admin/candidates'
+app = require 'application'
+User = require 'models/User'
+UserRemark = require 'models/UserRemark'
+{me} = require 'lib/auth'
+CocoCollection = require 'collections/CocoCollection'
+EmployerSignupView = require 'views/modal/employer_signup_modal'
+
+class CandidatesCollection extends CocoCollection
+  url: '/db/user/x/candidates'
+  model: User
+
+class UserRemarksCollection extends CocoCollection
+  url: '/db/user.remark?project=contact,contactName,user'
+  model: UserRemark
+
+module.exports = class EmployersView extends RootView
+  id: "admin-candidates-view"
+  template: template
+
+  events:
+    'click tbody tr': 'onCandidateClicked'
+
+  constructor: (options) ->
+    super options
+    @getCandidates()
+
+  afterRender: ->
+    super()
+    @sortTable() if @candidates.models.length
+
+  afterInsert: ->
+    super()
+    _.delay @checkForEmployerSignupHash, 500
+
+  getRenderData: ->
+    ctx = super()
+    ctx.isEmployer = @isEmployer()
+    ctx.candidates = _.sortBy @candidates.models, (c) -> c.get('jobProfile').updated
+    ctx.activeCandidates = _.filter ctx.candidates, (c) -> c.get('jobProfile').active
+    ctx.inactiveCandidates = _.reject ctx.candidates, (c) -> c.get('jobProfile').active
+    ctx.featuredCandidates = _.filter ctx.activeCandidates, (c) -> c.get('jobProfileApproved')
+    ctx.otherCandidates = _.reject ctx.activeCandidates, (c) -> c.get('jobProfileApproved')
+    ctx.remarks = {}
+    ctx.remarks[remark.get('user')] = remark for remark in @remarks.models
+    ctx.moment = moment
+    ctx._ = _
+    ctx
+
+  isEmployer: ->
+    userPermissions = me.get('permissions') ? []
+    _.contains userPermissions, "employer"
+
+  getCandidates: ->
+    @candidates = new CandidatesCollection()
+    @candidates.fetch()
+    @remarks = new UserRemarksCollection()
+    @remarks.fetch()
+    # Re-render when we have fetched them, but don't wait and show a progress bar while loading.
+    @listenToOnce @candidates, 'all', @renderCandidatesAndSetupScrolling
+    @listenToOnce @remarks, 'all', @renderCandidatesAndSetupScrolling
+
+  renderCandidatesAndSetupScrolling: =>
+    @render()
+    $(".nano").nanoScroller()
+    if window.history?.state?.lastViewedCandidateID
+      $(".nano").nanoScroller({scrollTo:$("#" + window.history.state.lastViewedCandidateID)})
+    else if window.location.hash.length is 25
+      $(".nano").nanoScroller({scrollTo:$(window.location.hash)})
+
+  checkForEmployerSignupHash: =>
+    if window.location.hash is "#employerSignupLoggingIn" and not ("employer" in me.get("permissions"))
+      @openModalView application.router.getView("modal/employer_signup","_modal")
+      window.location.hash = ""
+
+  sortTable: ->
+    # http://mottie.github.io/tablesorter/docs/example-widget-bootstrap-theme.html
+    $.extend $.tablesorter.themes.bootstrap,
+      # these classes are added to the table. To see other table classes available,
+      # look here: http://twitter.github.com/bootstrap/base-css.html#tables
+      table: "table table-bordered"
+      caption: "caption"
+      header: "bootstrap-header" # give the header a gradient background
+      footerRow: ""
+      footerCells: ""
+      icons: "" # add "icon-white" to make them white; this icon class is added to the <i> in the header
+      sortNone: "bootstrap-icon-unsorted"
+      sortAsc: "icon-chevron-up"  # glyphicon glyphicon-chevron-up" # we are still using v2 icons
+      sortDesc: "icon-chevron-down"  # glyphicon-chevron-down" # we are still using v2 icons
+      active: "" # applied when column is sorted
+      hover: "" # use custom css here - bootstrap class may not override it
+      filterRow: "" # filter row class
+      even: "" # odd row zebra striping
+      odd: "" # even row zebra striping
+
+
+    # e = exact text from cell
+    # n = normalized value returned by the column parser
+    # f = search filter input value
+    # i = column index
+    # $r = ???
+    filterSelectExactMatch = (e, n, f, i, $r) -> e is f
+
+    # call the tablesorter plugin and apply the uitheme widget
+    @$el.find(".tablesorter").tablesorter
+      theme: "bootstrap"
+      widthFixed: true
+      headerTemplate: "{content} {icon}"
+      textSorter:
+        6: (a, b, direction, column, table) ->
+          days = []
+          for s in [a, b]
+            n = parseInt s
+            n = 0 unless _.isNumber n
+            n = 1 if /^a/.test s
+            for [duration, factor] in [
+              [/second/i, 1 / (86400 * 1000)]
+              [/minute/i, 1 / 1440]
+              [/hour/i, 1 / 24]
+              [/week/i, 7]
+              [/month/i, 30.42]
+              [/year/i, 365.2425]
+            ]
+              if duration.test s
+                n *= factor
+                break
+            if /^in /i.test s
+              n *= -1
+            days.push n
+          days[0] - days[1]
+      sortList: if @isEmployer() or me.isAdmin() then [[6, 0]] else [[0, 1]]
+    # widget code contained in the jquery.tablesorter.widgets.js file
+    # use the zebra stripe widget if you plan on hiding any rows (filter widget)
+      widgets: ["uitheme", "zebra", "filter"]
+      widgetOptions:
+      # using the default zebra striping class name, so it actually isn't included in the theme variable above
+      # this is ONLY needed for bootstrap theming if you are using the filter widget, because rows are hidden
+        zebra: ["even", "odd"]
+
+      # extra css class applied to the table row containing the filters & the inputs within that row
+        filter_cssFilter: ""
+
+      # If there are child rows in the table (rows with class name from "cssChildRow" option)
+      # and this option is true and a match is found anywhere in the child row, then it will make that row
+      # visible; default is false
+        filter_childRows: false
+
+      # if true, filters are collapsed initially, but can be revealed by hovering over the grey bar immediately
+      # below the header row. Additionally, tabbing through the document will open the filter row when an input gets focus
+        filter_hideFilters: false
+
+      # Set this option to false to make the searches case sensitive
+        filter_ignoreCase: true
+
+      # jQuery selector string of an element used to reset the filters
+        filter_reset: ".reset"
+
+      # Use the $.tablesorter.storage utility to save the most recent filters
+        filter_saveFilters: true
+
+      # Delay in milliseconds before the filter widget starts searching; This option prevents searching for
+      # every character while typing and should make searching large tables faster.
+        filter_searchDelay: 150
+
+      # Set this option to true to use the filter to find text from the start of the column
+      # So typing in "a" will find "albert" but not "frank", both have a's; default is false
+        filter_startsWith: false
+
+        filter_functions:
+          2:
+            "Full-time": filterSelectExactMatch
+            "Part-time": filterSelectExactMatch
+            "Contracting": filterSelectExactMatch
+            "Remote": filterSelectExactMatch
+            "Internship": filterSelectExactMatch
+          5:
+            "0-1": (e, n, f, i, $r) -> n <= 1
+            "2-5": (e, n, f, i, $r) -> 2 <= n <= 5
+            "6+": (e, n, f, i, $r) -> 6 <= n
+          6:
+            "Last day": (e, n, f, i, $r) ->
+              days = parseFloat $($r.find('td')[i]).data('profile-age')
+              days <= 1
+            "Last week": (e, n, f, i, $r) ->
+              days = parseFloat $($r.find('td')[i]).data('profile-age')
+              days <= 7
+            "Last 4 weeks": (e, n, f, i, $r) ->
+              days = parseFloat $($r.find('td')[i]).data('profile-age')
+              days <= 28
+          8:
+            "✓": filterSelectExactMatch
+            "✗": filterSelectExactMatch
+
+  onCandidateClicked: (e) ->
+    id = $(e.target).closest('tr').data('candidate-id')
+    if id
+      if window.history
+        oldState = _.cloneDeep window.history.state ? {}
+        oldState["lastViewedCandidateID"] = id
+        window.history.replaceState(oldState,"")
+      else
+        window.location.hash = id
+      url = "/account/profile/#{id}"
+      window.open url,"_blank"
+    else
+      @openModalView new EmployerSignupView
\ No newline at end of file
diff --git a/app/views/admin/clas_view.coffee b/app/views/admin/clas_view.coffee
index 96828e23e..a384215ed 100644
--- a/app/views/admin/clas_view.coffee
+++ b/app/views/admin/clas_view.coffee
@@ -1,7 +1,7 @@
-View = require 'views/kinds/RootView'
+RootView = require 'views/kinds/RootView'
 template = require 'templates/admin/clas'
 
-module.exports = class CLAsView extends View
+module.exports = class CLAsView extends RootView
   id: 'admin-clas-view'
   template: template
   startsLoading: true
diff --git a/app/views/admin/employer_list_view.coffee b/app/views/admin/employer_list_view.coffee
index b2ec64d77..32c08cd22 100644
--- a/app/views/admin/employer_list_view.coffee
+++ b/app/views/admin/employer_list_view.coffee
@@ -1,4 +1,4 @@
-View = require 'views/kinds/RootView'
+RootView = require 'views/kinds/RootView'
 template = require 'templates/admin/employer_list'
 app = require 'application'
 User = require 'models/User'
@@ -10,7 +10,7 @@ class EmployersCollection extends CocoCollection
   url: '/db/user/x/employers'
   model: User
 
-module.exports = class EmployersView extends View
+module.exports = class EmployersView extends RootView
   id: 'employers-view'
   template: template
 
diff --git a/app/views/admin/level_sessions_view.coffee b/app/views/admin/level_sessions_view.coffee
index cca854cc3..aca163686 100644
--- a/app/views/admin/level_sessions_view.coffee
+++ b/app/views/admin/level_sessions_view.coffee
@@ -1,4 +1,4 @@
-View = require 'views/kinds/RootView'
+RootView = require 'views/kinds/RootView'
 template = require 'templates/admin/level_sessions'
 LevelSession = require 'models/LevelSession'
 
@@ -7,7 +7,7 @@ class LevelSessionCollection extends Backbone.Collection
   url: '/db/level_session/x/active'
   model: LevelSession
 
-module.exports = class LevelSessionsView extends View
+module.exports = class LevelSessionsView extends RootView
   id: 'admin-level-sessions-view'
   template: template
 
diff --git a/app/views/admin/users_view.coffee b/app/views/admin/users_view.coffee
index fa4aa1ba9..7ff58de72 100644
--- a/app/views/admin/users_view.coffee
+++ b/app/views/admin/users_view.coffee
@@ -1,8 +1,8 @@
-View = require 'views/kinds/RootView'
+RootView = require 'views/kinds/RootView'
 template = require 'templates/admin/users'
 User = require 'models/User'
 
-module.exports = class UsersView extends View
+module.exports = class UsersView extends RootView
   # TODO: Pagination, choosing filters on the page itself.
 
   id: 'admin-users-view'
diff --git a/app/views/common/LevelSessionCodeView.coffee b/app/views/common/LevelSessionCodeView.coffee
new file mode 100644
index 000000000..277eb2e3e
--- /dev/null
+++ b/app/views/common/LevelSessionCodeView.coffee
@@ -0,0 +1,50 @@
+CocoView = require 'views/kinds/CocoView'
+template = require 'templates/common/level_session_code'
+
+Level = require 'models/Level'
+LevelSession = require 'models/LevelSession'
+
+module.exports = class LevelSessionCodeView extends CocoView
+  className: 'level-session-code-view'
+  template: template
+
+  constructor: (options) ->
+    super(options)
+    @session = options.session
+    @level = LevelSession.getReferencedModel(@session.get('level'), LevelSession.schema.properties.level)
+    @level.setProjection ['employerDescription', 'name', 'icon', 'banner', 'slug']
+    @supermodel.loadModel @level, 'level'
+
+  getRenderData: ->
+    c = super()
+    c.levelIcon = @level.get('banner') or @level.get('icon')
+    c.levelName = @level.get('name')
+    c.levelDescription = marked(@level.get('employerDescription') or '')
+    c.levelSpells = @organizeCode()
+    c.sessionLink = "/play/level/" + (@level.get('slug') or @level.id) + "?team=" + (@session.get('team') || 'humans') + "&session=" + @session.id
+    c
+    
+  afterRender: ->
+    super()
+    @$el.find('.code').each (index, codeEl) ->
+      height = parseInt($(codeEl).data('height'))
+      $(codeEl).height(height)
+      editor = ace.edit codeEl
+      editor.setReadOnly true
+      aceSession = editor.getSession()
+      aceSession.setMode 'ace/mode/javascript'
+    
+  organizeCode: ->
+    team = @session.get('team') or 'humans'
+    teamSpells = @session.get('teamSpells')[team] or []
+    filteredSpells = []
+    for spell in teamSpells
+      code = @session.getSourceFor(spell) ? ''
+      lines = code.split('\n').length
+      height = lines * 16 + 20
+      filteredSpells.push {
+        code: code
+        name: spell
+        height: height
+      }
+    filteredSpells 
\ No newline at end of file
diff --git a/app/views/community_view.coffee b/app/views/community_view.coffee
deleted file mode 100644
index 69a140269..000000000
--- a/app/views/community_view.coffee
+++ /dev/null
@@ -1,6 +0,0 @@
-View = require 'views/kinds/RootView'
-template = require 'templates/community'
-
-module.exports = class CommunityView extends View
-  id: 'community-view'
-  template: template
diff --git a/app/views/contribute/adventurer_view.coffee b/app/views/contribute/AdventurerView.coffee
similarity index 76%
rename from app/views/contribute/adventurer_view.coffee
rename to app/views/contribute/AdventurerView.coffee
index deda5add5..9ad6a87f4 100644
--- a/app/views/contribute/adventurer_view.coffee
+++ b/app/views/contribute/AdventurerView.coffee
@@ -1,4 +1,4 @@
-ContributeClassView = require 'views/contribute/contribute_class_view'
+ContributeClassView = require './ContributeClassView'
 template = require 'templates/contribute/adventurer'
 {me} = require 'lib/auth'
 
diff --git a/app/views/contribute/ambassador_view.coffee b/app/views/contribute/AmbassadorView.coffee
similarity index 76%
rename from app/views/contribute/ambassador_view.coffee
rename to app/views/contribute/AmbassadorView.coffee
index 73c35bf96..4ac62b277 100644
--- a/app/views/contribute/ambassador_view.coffee
+++ b/app/views/contribute/AmbassadorView.coffee
@@ -1,4 +1,4 @@
-ContributeClassView = require 'views/contribute/contribute_class_view'
+ContributeClassView = require './ContributeClassView'
 template = require 'templates/contribute/ambassador'
 {me} = require 'lib/auth'
 
diff --git a/app/views/contribute/archmage_view.coffee b/app/views/contribute/ArchmageView.coffee
similarity index 95%
rename from app/views/contribute/archmage_view.coffee
rename to app/views/contribute/ArchmageView.coffee
index e29a9be5c..dd21e40ae 100644
--- a/app/views/contribute/archmage_view.coffee
+++ b/app/views/contribute/ArchmageView.coffee
@@ -1,4 +1,4 @@
-ContributeClassView = require 'views/contribute/contribute_class_view'
+ContributeClassView = require './ContributeClassView'
 template = require 'templates/contribute/archmage'
 
 module.exports = class ArchmageView extends ContributeClassView
diff --git a/app/views/contribute/artisan_view.coffee b/app/views/contribute/ArtisanView.coffee
similarity index 92%
rename from app/views/contribute/artisan_view.coffee
rename to app/views/contribute/ArtisanView.coffee
index 7094dba98..40aa5bba0 100644
--- a/app/views/contribute/artisan_view.coffee
+++ b/app/views/contribute/ArtisanView.coffee
@@ -1,4 +1,4 @@
-ContributeClassView = require 'views/contribute/contribute_class_view'
+ContributeClassView = require './ContributeClassView'
 template = require 'templates/contribute/artisan'
 {me} = require 'lib/auth'
 
diff --git a/app/views/contribute/contribute_class_view.coffee b/app/views/contribute/ContributeClassView.coffee
similarity index 93%
rename from app/views/contribute/contribute_class_view.coffee
rename to app/views/contribute/ContributeClassView.coffee
index 3da551ffb..7b403d466 100644
--- a/app/views/contribute/contribute_class_view.coffee
+++ b/app/views/contribute/ContributeClassView.coffee
@@ -1,11 +1,11 @@
 SignupModalView = require 'views/modal/signup_modal'
-View = require 'views/kinds/RootView'
+RootView = require 'views/kinds/RootView'
 {me} = require 'lib/auth'
 contributorSignupAnonymousTemplate = require 'templates/contribute/contributor_signup_anonymous'
 contributorSignupTemplate = require 'templates/contribute/contributor_signup'
 contributorListTemplate = require 'templates/contribute/contributor_list'
 
-module.exports = class ContributeClassView extends View
+module.exports = class ContributeClassView extends RootView
   navPrefix: '/contribute'
 
   events:
diff --git a/app/views/contribute/diplomat_view.coffee b/app/views/contribute/DiplomatView.coffee
similarity index 75%
rename from app/views/contribute/diplomat_view.coffee
rename to app/views/contribute/DiplomatView.coffee
index 00b3dd7a7..32572cce0 100644
--- a/app/views/contribute/diplomat_view.coffee
+++ b/app/views/contribute/DiplomatView.coffee
@@ -1,4 +1,4 @@
-ContributeClassView = require 'views/contribute/contribute_class_view'
+ContributeClassView = require './ContributeClassView'
 template = require 'templates/contribute/diplomat'
 {me} = require 'lib/auth'
 
diff --git a/app/views/contribute_view.coffee b/app/views/contribute/MainContributeView.coffee
similarity index 56%
rename from app/views/contribute_view.coffee
rename to app/views/contribute/MainContributeView.coffee
index fa772c75a..930870110 100644
--- a/app/views/contribute_view.coffee
+++ b/app/views/contribute/MainContributeView.coffee
@@ -1,7 +1,7 @@
-ContributeClassView = require 'views/contribute/contribute_class_view'
+ContributeClassView = require 'views/contribute/ContributeClassView'
 template = require 'templates/contribute/contribute'
 
-module.exports = class ContributeView extends ContributeClassView
+module.exports = class MainContributeView extends ContributeClassView
   id: 'contribute-view'
   template: template
   navPrefix: ''
diff --git a/app/views/contribute/scribe_view.coffee b/app/views/contribute/ScribeView.coffee
similarity index 86%
rename from app/views/contribute/scribe_view.coffee
rename to app/views/contribute/ScribeView.coffee
index d52d0106b..bcaa5f648 100644
--- a/app/views/contribute/scribe_view.coffee
+++ b/app/views/contribute/ScribeView.coffee
@@ -1,4 +1,4 @@
-ContributeClassView = require 'views/contribute/contribute_class_view'
+ContributeClassView = require './ContributeClassView'
 template = require 'templates/contribute/scribe'
 {me} = require 'lib/auth'
 
diff --git a/app/views/editor/MainEditorView.coffee b/app/views/editor/MainEditorView.coffee
new file mode 100644
index 000000000..e5a841279
--- /dev/null
+++ b/app/views/editor/MainEditorView.coffee
@@ -0,0 +1,6 @@
+RootView = require 'views/kinds/RootView'
+template = require 'templates/editor'
+
+module.exports = class MainEditorView extends RootView
+  id: 'editor-nav-view'
+  template: template
diff --git a/app/views/editor/achievement/edit.coffee b/app/views/editor/achievement/edit.coffee
index ce65446dd..8f4379777 100644
--- a/app/views/editor/achievement/edit.coffee
+++ b/app/views/editor/achievement/edit.coffee
@@ -1,9 +1,9 @@
-View = require 'views/kinds/RootView'
+RootView = require 'views/kinds/RootView'
 template = require 'templates/editor/achievement/edit'
 Achievement = require 'models/Achievement'
 ConfirmModal = require 'views/modal/confirm'
 
-module.exports = class AchievementEditView extends View
+module.exports = class AchievementEditView extends RootView
   id: 'editor-achievement-edit-view'
   template: template
   startsLoading: true
diff --git a/app/views/editor/article/edit.coffee b/app/views/editor/article/edit.coffee
index ae9083a2a..70450103f 100644
--- a/app/views/editor/article/edit.coffee
+++ b/app/views/editor/article/edit.coffee
@@ -1,11 +1,11 @@
-View = require 'views/kinds/RootView'
+RootView = require 'views/kinds/RootView'
 VersionHistoryView = require './versions_view'
 template = require 'templates/editor/article/edit'
 Article = require 'models/Article'
 SaveVersionModal = require 'views/modal/save_version_modal'
 PatchesView = require 'views/editor/patches_view'
 
-module.exports = class ArticleEditView extends View
+module.exports = class ArticleEditView extends RootView
   id: 'editor-article-edit-view'
   template: template
   startsLoading: true
diff --git a/app/views/editor/article/preview.coffee b/app/views/editor/article/preview.coffee
index ef4d3455b..9426454bf 100644
--- a/app/views/editor/article/preview.coffee
+++ b/app/views/editor/article/preview.coffee
@@ -1,6 +1,6 @@
-View = require 'views/kinds/RootView'
+RootView = require 'views/kinds/RootView'
 template = require 'templates/editor/article/preview'
 
-module.exports = class PreviewView extends View
+module.exports = class PreviewView extends RootView
   id: 'editor-article-preview-view'
   template: template
diff --git a/app/views/editor/level/add_thangs_view.coffee b/app/views/editor/level/add_thangs_view.coffee
index 7a7070b17..e41f42967 100644
--- a/app/views/editor/level/add_thangs_view.coffee
+++ b/app/views/editor/level/add_thangs_view.coffee
@@ -1,4 +1,4 @@
-View = require 'views/kinds/CocoView'
+CocoView = require 'views/kinds/CocoView'
 add_thangs_template = require 'templates/editor/level/add_thangs'
 ThangType = require 'models/ThangType'
 CocoCollection = require 'collections/CocoCollection'
@@ -10,7 +10,7 @@ class ThangTypeSearchCollection extends CocoCollection
   addTerm: (term) ->
     @url += "&term=#{term}" if term
 
-module.exports = class AddThangsView extends View
+module.exports = class AddThangsView extends CocoView
   id: 'add-thangs-column'
   className: 'add-thangs-palette thangs-column'
   template: add_thangs_template
diff --git a/app/views/editor/level/component/edit.coffee b/app/views/editor/level/component/edit.coffee
index a7bc51149..9e36530ba 100644
--- a/app/views/editor/level/component/edit.coffee
+++ b/app/views/editor/level/component/edit.coffee
@@ -1,11 +1,11 @@
-View = require 'views/kinds/CocoView'
+CocoView = require 'views/kinds/CocoView'
 template = require 'templates/editor/level/component/edit'
 LevelComponent = require 'models/LevelComponent'
 VersionHistoryView = require 'views/editor/component/versions_view'
 PatchesView = require 'views/editor/patches_view'
 SaveVersionModal = require 'views/modal/save_version_modal'
 
-module.exports = class LevelComponentEditView extends View
+module.exports = class LevelComponentEditView extends CocoView
   id: 'editor-level-component-edit-view'
   template: template
   editableSettings: ['name', 'description', 'system', 'codeLanguage', 'dependencies', 'propertyDocumentation', 'i18n']
diff --git a/app/views/editor/level/component/new.coffee b/app/views/editor/level/component/new.coffee
index a1f2985ce..314cf2c86 100644
--- a/app/views/editor/level/component/new.coffee
+++ b/app/views/editor/level/component/new.coffee
@@ -1,10 +1,10 @@
-View = require 'views/kinds/ModalView'
+ModalView = require 'views/kinds/ModalView'
 template = require 'templates/editor/level/component/new'
 LevelComponent = require 'models/LevelComponent'
 forms = require 'lib/forms'
 {me} = require 'lib/auth'
 
-module.exports = class LevelComponentNewView extends View
+module.exports = class LevelComponentNewView extends ModalView
   id: 'editor-level-component-new-modal'
   template: template
   instant: false
diff --git a/app/views/editor/level/components_tab_view.coffee b/app/views/editor/level/components_tab_view.coffee
index 27f91ae87..03c9bb2cf 100644
--- a/app/views/editor/level/components_tab_view.coffee
+++ b/app/views/editor/level/components_tab_view.coffee
@@ -1,4 +1,4 @@
-View = require 'views/kinds/CocoView'
+CocoView = require 'views/kinds/CocoView'
 template = require 'templates/editor/level/components_tab'
 LevelComponent = require 'models/LevelComponent'
 LevelComponentEditView = require './component/edit'
@@ -8,7 +8,7 @@ class LevelComponentCollection extends Backbone.Collection
   url: '/db/level.component'
   model: LevelComponent
 
-module.exports = class ComponentsTabView extends View
+module.exports = class ComponentsTabView extends CocoView
   id: 'editor-level-components-tab-view'
   template: template
   className: 'tab-pane'
diff --git a/app/views/editor/level/edit.coffee b/app/views/editor/level/edit.coffee
index 18bc8edf5..62666f44a 100644
--- a/app/views/editor/level/edit.coffee
+++ b/app/views/editor/level/edit.coffee
@@ -1,4 +1,4 @@
-View = require 'views/kinds/RootView'
+RootView = require 'views/kinds/RootView'
 template = require 'templates/editor/level/edit'
 Level = require 'models/Level'
 LevelSystem = require 'models/LevelSystem'
@@ -16,9 +16,8 @@ LevelForkView = require './fork_view'
 SaveVersionModal = require 'views/modal/save_version_modal'
 PatchesView = require 'views/editor/patches_view'
 VersionHistoryView = require './versions_view'
-ErrorView = require '../../error_view'
 
-module.exports = class EditorLevelView extends View
+module.exports = class EditorLevelView extends RootView
   id: 'editor-level-view'
   template: template
   cache: false
@@ -40,7 +39,7 @@ module.exports = class EditorLevelView extends View
   constructor: (options, @levelID) ->
     super options
     @supermodel.shouldSaveBackups = (model) ->
-      model.constructor.className in ['Level', 'LevelComponent', 'LevelSystem']
+      model.constructor.className in ['Level', 'LevelComponent', 'LevelSystem', 'ThangType']
     @levelLoader = new LevelLoader supermodel: @supermodel, levelID: @levelID, headless: true, editorMode: true
     @level = @levelLoader.level
     @files = new DocumentFiles(@levelLoader.level)
@@ -95,7 +94,10 @@ module.exports = class EditorLevelView extends View
       # Create a new Window with a blank LevelView
       scratchLevelID = @level.get('slug') + '?dev=true'
       scratchLevelID += "&team=#{team}" if team
-      @childWindow = window.open("/play/level/#{scratchLevelID}", 'child_window', 'width=1024,height=560,left=10,top=10,location=0,menubar=0,scrollbars=0,status=0,titlebar=0,toolbar=0', true)
+      if me.get('name') is 'Nick!'
+        @childWindow = window.open("/play/level/#{scratchLevelID}", 'child_window', 'width=2560,height=1080,left=0,top=-1600,location=1,menubar=1,scrollbars=1,status=0,titlebar=1,toolbar=1', true)
+      else
+        @childWindow = window.open("/play/level/#{scratchLevelID}", 'child_window', 'width=1024,height=560,left=10,top=10,location=0,menubar=0,scrollbars=0,status=0,titlebar=0,toolbar=0', true)
       @childWindow.onPlayLevelViewLoaded = (e) => sendLevel()  # still a hack
     @childWindow.focus()
 
diff --git a/app/views/editor/level/fork_view.coffee b/app/views/editor/level/fork_view.coffee
index 522a21b1c..2b3f7cfea 100644
--- a/app/views/editor/level/fork_view.coffee
+++ b/app/views/editor/level/fork_view.coffee
@@ -1,9 +1,9 @@
-View = require 'views/kinds/ModalView'
+ModalView = require 'views/kinds/ModalView'
 template = require 'templates/editor/level/fork'
 forms = require 'lib/forms'
 Level = require 'models/Level'
 
-module.exports = class LevelForkView extends View
+module.exports = class LevelForkView extends ModalView
   id: 'editor-level-fork-modal'
   template: template
   instant: false
diff --git a/app/views/editor/level/modal/world_select.coffee b/app/views/editor/level/modal/world_select.coffee
index adbbd11d3..4274a76ec 100644
--- a/app/views/editor/level/modal/world_select.coffee
+++ b/app/views/editor/level/modal/world_select.coffee
@@ -1,9 +1,9 @@
-View = require 'views/kinds/ModalView'
+ModalView = require 'views/kinds/ModalView'
 template = require 'templates/editor/level/modal/world_select'
 Surface = require 'lib/surface/Surface'
 ThangType = require 'models/ThangType'
 
-module.exports = class WorldSelectModal extends View
+module.exports = class WorldSelectModal extends ModalView
   id: 'select-point-modal'
   template: template
   modalWidthPercent: 80
diff --git a/app/views/editor/level/scripts_tab_view.coffee b/app/views/editor/level/scripts_tab_view.coffee
index 7a3e96c65..ae6813cbf 100644
--- a/app/views/editor/level/scripts_tab_view.coffee
+++ b/app/views/editor/level/scripts_tab_view.coffee
@@ -1,10 +1,10 @@
-View = require 'views/kinds/CocoView'
+CocoView = require 'views/kinds/CocoView'
 template = require 'templates/editor/level/scripts_tab'
 Level = require 'models/Level'
 Surface = require 'lib/surface/Surface'
 nodes = require './treema_nodes'
 
-module.exports = class ScriptsTabView extends View
+module.exports = class ScriptsTabView extends CocoView
   id: 'editor-level-scripts-tab-view'
   template: template
   className: 'tab-pane'
diff --git a/app/views/editor/level/settings_tab_view.coffee b/app/views/editor/level/settings_tab_view.coffee
index b3f99150c..7e2056c2f 100644
--- a/app/views/editor/level/settings_tab_view.coffee
+++ b/app/views/editor/level/settings_tab_view.coffee
@@ -1,11 +1,11 @@
-View = require 'views/kinds/CocoView'
+CocoView = require 'views/kinds/CocoView'
 template = require 'templates/editor/level/settings_tab'
 Level = require 'models/Level'
 Surface = require 'lib/surface/Surface'
 nodes = require './treema_nodes'
 {me} = require 'lib/auth'
 
-module.exports = class SettingsTabView extends View
+module.exports = class SettingsTabView extends CocoView
   id: 'editor-level-settings-tab-view'
   className: 'tab-pane'
   template: template
@@ -13,7 +13,7 @@ module.exports = class SettingsTabView extends View
   # not thangs or scripts or the backend stuff
   editableSettings: [
     'name', 'description', 'documentation', 'nextLevel', 'background', 'victory', 'i18n', 'icon', 'goals',
-    'type', 'showsGuide'
+    'type', 'showsGuide', 'banner', 'employerDescription'
   ]
 
   subscriptions:
diff --git a/app/views/editor/level/system/add.coffee b/app/views/editor/level/system/add.coffee
index 28a362809..f0c3b7490 100644
--- a/app/views/editor/level/system/add.coffee
+++ b/app/views/editor/level/system/add.coffee
@@ -1,4 +1,4 @@
-View = require 'views/kinds/ModalView'
+ModalView = require 'views/kinds/ModalView'
 template = require 'templates/editor/level/system/add'
 availableSystemTemplate = require 'templates/editor/level/system/available_system'
 LevelSystem = require 'models/LevelSystem'
@@ -8,7 +8,7 @@ class LevelSystemSearchCollection extends CocoCollection
   url: '/db/level_system'
   model: LevelSystem
 
-module.exports = class LevelSystemAddView extends View
+module.exports = class LevelSystemAddView extends ModalView
   id: 'editor-level-system-add-modal'
   template: template
   instant: true
diff --git a/app/views/editor/level/system/edit.coffee b/app/views/editor/level/system/edit.coffee
index f9e9646db..de5877bda 100644
--- a/app/views/editor/level/system/edit.coffee
+++ b/app/views/editor/level/system/edit.coffee
@@ -1,11 +1,11 @@
-View = require 'views/kinds/CocoView'
+CocoView = require 'views/kinds/CocoView'
 template = require 'templates/editor/level/system/edit'
 LevelSystem = require 'models/LevelSystem'
 VersionHistoryView = require 'views/editor/system/versions_view'
 PatchesView = require 'views/editor/patches_view'
 SaveVersionModal = require 'views/modal/save_version_modal'
 
-module.exports = class LevelSystemEditView extends View
+module.exports = class LevelSystemEditView extends CocoView
   id: 'editor-level-system-edit-view'
   template: template
   editableSettings: ['name', 'description', 'codeLanguage', 'dependencies', 'propertyDocumentation', 'i18n']
diff --git a/app/views/editor/level/system/new.coffee b/app/views/editor/level/system/new.coffee
index 1ddd8d158..86b959f01 100644
--- a/app/views/editor/level/system/new.coffee
+++ b/app/views/editor/level/system/new.coffee
@@ -1,10 +1,10 @@
-View = require 'views/kinds/ModalView'
+ModalView = require 'views/kinds/ModalView'
 template = require 'templates/editor/level/system/new'
 LevelSystem = require 'models/LevelSystem'
 forms = require 'lib/forms'
 {me} = require 'lib/auth'
 
-module.exports = class LevelSystemNewView extends View
+module.exports = class LevelSystemNewView extends ModalView
   id: 'editor-level-system-new-modal'
   template: template
   instant: false
diff --git a/app/views/editor/level/systems_tab_view.coffee b/app/views/editor/level/systems_tab_view.coffee
index a3b6df3f2..4b4988755 100644
--- a/app/views/editor/level/systems_tab_view.coffee
+++ b/app/views/editor/level/systems_tab_view.coffee
@@ -1,4 +1,4 @@
-View = require 'views/kinds/CocoView'
+CocoView = require 'views/kinds/CocoView'
 template = require 'templates/editor/level/systems_tab'
 Level = require 'models/Level'
 LevelSystem = require 'models/LevelSystem'
@@ -7,7 +7,7 @@ LevelSystemNewView = require './system/new'
 LevelSystemAddView = require './system/add'
 {ThangTypeNode} = require './treema_nodes'
 
-module.exports = class SystemsTabView extends View
+module.exports = class SystemsTabView extends CocoView
   id: 'editor-level-systems-tab-view'
   template: template
   className: 'tab-pane'
diff --git a/app/views/editor/level/thang/edit.coffee b/app/views/editor/level/thang/edit.coffee
index 01eb9c1d1..4dd5b1549 100644
--- a/app/views/editor/level/thang/edit.coffee
+++ b/app/views/editor/level/thang/edit.coffee
@@ -1,9 +1,9 @@
-View = require 'views/kinds/CocoView'
+CocoView = require 'views/kinds/CocoView'
 template = require 'templates/editor/level/thang/edit'
 ThangComponentEditView = require 'views/editor/components/main'
 ThangType = require 'models/ThangType'
 
-module.exports = class LevelThangEditView extends View
+module.exports = class LevelThangEditView extends CocoView
   ###
   In the level editor, is the bar at the top when editing a single thang.
   Everything below is part of the ThangComponentEditView, which is shared with the
diff --git a/app/views/editor/level/thangs_tab_view.coffee b/app/views/editor/level/thangs_tab_view.coffee
index a1b92966a..2fa4cb64c 100644
--- a/app/views/editor/level/thangs_tab_view.coffee
+++ b/app/views/editor/level/thangs_tab_view.coffee
@@ -1,4 +1,4 @@
-View = require 'views/kinds/CocoView'
+CocoView = require 'views/kinds/CocoView'
 AddThangsView = require './add_thangs_view'
 thangs_template = require 'templates/editor/level/thangs_tab'
 Level = require 'models/Level'
@@ -24,7 +24,7 @@ class ThangTypeSearchCollection extends CocoCollection
   url: '/db/thang.type?project=original,name,version,slug,kind,components'
   model: ThangType
 
-module.exports = class ThangsTabView extends View
+module.exports = class ThangsTabView extends CocoView
   id: 'editor-level-thangs-tab-view'
   className: 'tab-pane active'
   template: thangs_template
diff --git a/app/views/editor/thang/edit.coffee b/app/views/editor/thang/edit.coffee
index d21272e6a..b7d04b751 100644
--- a/app/views/editor/thang/edit.coffee
+++ b/app/views/editor/thang/edit.coffee
@@ -5,18 +5,17 @@ CocoSprite = require 'lib/surface/CocoSprite'
 Camera = require 'lib/surface/Camera'
 DocumentFiles = require 'collections/DocumentFiles'
 
-View = require 'views/kinds/RootView'
+RootView = require 'views/kinds/RootView'
 ThangComponentEditView = require 'views/editor/components/main'
 VersionHistoryView = require './versions_view'
 ColorsTabView = require './colors_tab_view'
 PatchesView = require 'views/editor/patches_view'
 SaveVersionModal = require 'views/modal/save_version_modal'
-ErrorView = require '../../error_view'
 template = require 'templates/editor/thang/edit'
 
 CENTER = {x: 200, y: 300}
 
-module.exports = class ThangTypeEditView extends View
+module.exports = class ThangTypeEditView extends RootView
   id: 'editor-thang-type-edit-view'
   template: template
   startsLoading: true
diff --git a/app/views/editor_view.coffee b/app/views/editor_view.coffee
deleted file mode 100644
index aafe00eb1..000000000
--- a/app/views/editor_view.coffee
+++ /dev/null
@@ -1,6 +0,0 @@
-View = require 'views/kinds/RootView'
-template = require 'templates/editor'
-
-module.exports = class EditorView extends View
-  id: 'editor-nav-view'
-  template: template
diff --git a/app/views/error_view.coffee b/app/views/error_view.coffee
deleted file mode 100644
index 3ed6db5fd..000000000
--- a/app/views/error_view.coffee
+++ /dev/null
@@ -1,6 +0,0 @@
-View = require 'views/kinds/RootView'
-template = require 'templates/error'
-
-module.exports = class ErrorView extends View
-  id: 'error-view'
-  template: template
diff --git a/app/views/kinds/RootView.coffee b/app/views/kinds/RootView.coffee
index aac5dc64f..858c9fb48 100644
--- a/app/views/kinds/RootView.coffee
+++ b/app/views/kinds/RootView.coffee
@@ -17,6 +17,8 @@ filterKeyboardEvents = (allowedEvents, func) ->
     return func(splat...)
 
 module.exports = class RootView extends CocoView
+  showBackground: true
+  
   events:
     'click #logout-button': 'logoutAccount'
     'change .language-dropdown': 'onLanguageChanged'
@@ -112,6 +114,11 @@ module.exports = class RootView extends CocoView
     @renderScrollbar()
     #@$('.antiscroll-wrap').antiscroll()  # not yet, buggy
 
+  getRenderData: ->
+    c = super()
+    c.showBackground = @showBackground
+    c
+  
   afterRender: ->
     super(arguments...)
     @chooseTab(location.hash.replace('#', '')) if location.hash
diff --git a/app/views/kinds/SearchView.coffee b/app/views/kinds/SearchView.coffee
index 91b04d4d5..7fdd4cad6 100644
--- a/app/views/kinds/SearchView.coffee
+++ b/app/views/kinds/SearchView.coffee
@@ -1,4 +1,4 @@
-View = require 'views/kinds/RootView'
+RootView = require 'views/kinds/RootView'
 template = require 'templates/kinds/search'
 forms = require 'lib/forms'
 app = require 'application'
@@ -12,7 +12,7 @@ class SearchCollection extends Backbone.Collection
     else @url += 'true'
     @url += "&term=#{term}" if @term
 
-module.exports = class SearchView extends View
+module.exports = class SearchView extends RootView
   template: template
   className: 'search-view'
 
diff --git a/app/views/legal_view.coffee b/app/views/legal_view.coffee
deleted file mode 100644
index 09ae6f2c3..000000000
--- a/app/views/legal_view.coffee
+++ /dev/null
@@ -1,6 +0,0 @@
-View = require 'views/kinds/RootView'
-template = require 'templates/legal'
-
-module.exports = class LegalView extends View
-  id: 'legal-view'
-  template: template
diff --git a/app/views/modal/auth_modal.coffee b/app/views/modal/auth_modal.coffee
index 9d32de0ae..ead7af8b9 100644
--- a/app/views/modal/auth_modal.coffee
+++ b/app/views/modal/auth_modal.coffee
@@ -1,11 +1,11 @@
-View = require 'views/kinds/ModalView'
+ModalView = require 'views/kinds/ModalView'
 template = require 'templates/modal/auth'
 {loginUser, createUser, me} = require 'lib/auth'
 forms = require 'lib/forms'
 User = require 'models/User'
 application  = require 'application'
 
-module.exports = class AuthModalView extends View
+module.exports = class AuthModalView extends ModalView
   id: 'auth-modal'
   template: template
   mode: 'login' # or 'signup'
diff --git a/app/views/modal/contact_modal.coffee b/app/views/modal/contact_modal.coffee
index 0851c9ee9..c8a6db460 100644
--- a/app/views/modal/contact_modal.coffee
+++ b/app/views/modal/contact_modal.coffee
@@ -1,4 +1,4 @@
-View = require 'views/kinds/ModalView'
+ModalView = require 'views/kinds/ModalView'
 template = require 'templates/modal/contact'
 
 forms = require 'lib/forms'
@@ -18,7 +18,7 @@ contactSchema =
       type: 'string'
       minLength: 1
 
-module.exports = class ContactView extends View
+module.exports = class ContactView extends ModalView
   id: 'contact-modal'
   template: template
   closeButton: true
diff --git a/app/views/modal/diplomat_suggestion_modal.coffee b/app/views/modal/diplomat_suggestion_modal.coffee
index 48312ad36..c0abed5e7 100644
--- a/app/views/modal/diplomat_suggestion_modal.coffee
+++ b/app/views/modal/diplomat_suggestion_modal.coffee
@@ -1,9 +1,9 @@
-View = require 'views/kinds/ModalView'
+ModalView = require 'views/kinds/ModalView'
 template = require 'templates/modal/diplomat_suggestion'
 {me} = require 'lib/auth'
 forms = require 'lib/forms'
 
-module.exports = class DiplomatSuggestionView extends View
+module.exports = class DiplomatSuggestionView extends ModalView
   id: 'diplomat-suggestion-modal'
   template: template
 
diff --git a/app/views/modal/employer_signup_modal.coffee b/app/views/modal/employer_signup_modal.coffee
index 5355e26c9..db766d979 100644
--- a/app/views/modal/employer_signup_modal.coffee
+++ b/app/views/modal/employer_signup_modal.coffee
@@ -1,11 +1,11 @@
-View = require 'views/kinds/ModalView'
+ModalView = require 'views/kinds/ModalView'
 template = require 'templates/modal/employer_signup_modal'
 forms = require 'lib/forms'
 User = require 'models/User'
 auth = require 'lib/auth'
 me = auth.me
 
-module.exports = class EmployerSignupView extends View
+module.exports = class EmployerSignupView extends ModalView
   id: 'employer-signup'
   template: template
   closeButton: true
diff --git a/app/views/modal/model_modal.coffee b/app/views/modal/model_modal.coffee
index 50b0cdd8a..a5fbc5ce5 100644
--- a/app/views/modal/model_modal.coffee
+++ b/app/views/modal/model_modal.coffee
@@ -1,7 +1,7 @@
-View = require 'views/kinds/ModalView'
+ModalView = require 'views/kinds/ModalView'
 template = require 'templates/modal/model'
 
-module.exports = class ModelModal extends View
+module.exports = class ModelModal extends ModalView
   id: 'model-modal'
   template: template
   plain: true
diff --git a/app/views/modal/recover_modal.coffee b/app/views/modal/recover_modal.coffee
index c65fc1f8a..5f8e9a17d 100644
--- a/app/views/modal/recover_modal.coffee
+++ b/app/views/modal/recover_modal.coffee
@@ -1,4 +1,4 @@
-View = require 'views/kinds/ModalView'
+ModalView = require 'views/kinds/ModalView'
 template = require 'templates/modal/recover'
 forms = require 'lib/forms'
 {genericFailure} = require 'lib/errors'
@@ -9,7 +9,7 @@ filterKeyboardEvents = (allowedEvents, func) ->
     return unless e.keyCode in allowedEvents or not e.keyCode
     return func(splat...)
 
-module.exports = class RecoverModalView extends View
+module.exports = class RecoverModalView extends ModalView
   id: 'recover-modal'
   template: template
 
diff --git a/app/views/modal/wizard_settings_modal.coffee b/app/views/modal/wizard_settings_modal.coffee
index 12732b28e..d8527ee74 100644
--- a/app/views/modal/wizard_settings_modal.coffee
+++ b/app/views/modal/wizard_settings_modal.coffee
@@ -1,4 +1,4 @@
-View = require 'views/kinds/ModalView'
+ModalView = require 'views/kinds/ModalView'
 template = require 'templates/modal/wizard_settings'
 WizardSprite = require 'lib/surface/WizardSprite'
 ThangType = require 'models/ThangType'
@@ -6,7 +6,7 @@ ThangType = require 'models/ThangType'
 forms = require 'lib/forms'
 User = require 'models/User'
 
-module.exports = class WizardSettingsModal extends View
+module.exports = class WizardSettingsModal extends ModalView
   id: 'wizard-settings-modal'
   template: template
   closesOnClickOutside: false
diff --git a/app/views/not_found.coffee b/app/views/not_found.coffee
deleted file mode 100644
index 95e94921b..000000000
--- a/app/views/not_found.coffee
+++ /dev/null
@@ -1,6 +0,0 @@
-View = require 'views/kinds/RootView'
-template = require 'templates/not_found'
-
-module.exports = class NotFoundView extends View
-  id: 'not-found-view'
-  template: template
diff --git a/app/views/play_view.coffee b/app/views/play/MainPlayView.coffee
similarity index 98%
rename from app/views/play_view.coffee
rename to app/views/play/MainPlayView.coffee
index bd7a412e7..685887eab 100644
--- a/app/views/play_view.coffee
+++ b/app/views/play/MainPlayView.coffee
@@ -1,4 +1,4 @@
-View = require 'views/kinds/RootView'
+RootView = require 'views/kinds/RootView'
 template = require 'templates/play'
 LevelSession = require 'models/LevelSession'
 CocoCollection = require 'collections/CocoCollection'
@@ -11,7 +11,7 @@ class LevelSessionsCollection extends CocoCollection
     super()
     @url = "/db/user/#{me.id}/level.sessions?project=state.complete,levelID"
 
-module.exports = class PlayView extends View
+module.exports = class MainPlayView extends RootView
   id: 'play-view'
   template: template
 
@@ -117,7 +117,7 @@ module.exports = class PlayView extends View
         difficulty: 2
         id: 'emphasis-on-aim'
         image: '/file/db/level/525f384d96cd77000000000f/munchkin_masher_icon.png'
-        description: 'Chose your targets carefully.'
+        description: 'Choose your targets carefully.'
       }
       {
         name: 'Zone of Danger'
diff --git a/app/views/play/ladder/play_modal.coffee b/app/views/play/ladder/play_modal.coffee
index 41bf1e22b..0d7494950 100644
--- a/app/views/play/ladder/play_modal.coffee
+++ b/app/views/play/ladder/play_modal.coffee
@@ -1,11 +1,11 @@
-View = require 'views/kinds/ModalView'
+ModalView = require 'views/kinds/ModalView'
 template = require 'templates/play/ladder/play_modal'
 ThangType = require 'models/ThangType'
 {me} = require 'lib/auth'
 LeaderboardCollection = require 'collections/LeaderboardCollection'
 {teamDataFromLevel} = require './utils'
 
-module.exports = class LadderPlayModal extends View
+module.exports = class LadderPlayModal extends ModalView
   id: 'ladder-play-modal'
   template: template
   closeButton: true
diff --git a/app/views/play/ladder_home.coffee b/app/views/play/ladder_home.coffee
index 1508697c9..502bbd877 100644
--- a/app/views/play/ladder_home.coffee
+++ b/app/views/play/ladder_home.coffee
@@ -1,4 +1,4 @@
-View = require 'views/kinds/RootView'
+RootView = require 'views/kinds/RootView'
 template = require 'templates/play/ladder_home'
 LevelSession = require 'models/LevelSession'
 CocoCollection = require 'collections/CocoCollection'
@@ -11,7 +11,7 @@ class LevelSessionsCollection extends CocoCollection
     super()
     @url = "/db/user/#{me.id}/level.sessions?project=state.complete,levelID"
 
-module.exports = class LadderHomeView extends View
+module.exports = class LadderHomeView extends RootView
   id: 'ladder-home-view'
   template: template
 
diff --git a/app/views/play/level/control_bar_view.coffee b/app/views/play/level/control_bar_view.coffee
index 7a1dd58ec..18102be0f 100644
--- a/app/views/play/level/control_bar_view.coffee
+++ b/app/views/play/level/control_bar_view.coffee
@@ -1,11 +1,11 @@
-View = require 'views/kinds/CocoView'
+CocoView = require 'views/kinds/CocoView'
 template = require 'templates/play/level/control_bar'
 
 DocsModal = require './modal/docs_modal'
 MultiplayerModal = require './modal/multiplayer_modal'
 ReloadModal = require './modal/reload_modal'
 
-module.exports = class ControlBarView extends View
+module.exports = class ControlBarView extends CocoView
   id: 'control-bar-view'
   template: template
 
diff --git a/app/views/play/level/goals_view.coffee b/app/views/play/level/goals_view.coffee
index e55d881b8..1264ada34 100644
--- a/app/views/play/level/goals_view.coffee
+++ b/app/views/play/level/goals_view.coffee
@@ -1,4 +1,4 @@
-View = require 'views/kinds/CocoView'
+CocoView = require 'views/kinds/CocoView'
 template = require 'templates/play/level/goals'
 {me} = require 'lib/auth'
 utils = require 'lib/utils'
@@ -8,7 +8,7 @@ stateIconMap =
   success: 'icon-ok'
   failure: 'icon-remove'
 
-module.exports = class GoalsView extends View
+module.exports = class GoalsView extends CocoView
   id: 'goals-view'
   template: template
 
diff --git a/app/views/play/level/gold_view.coffee b/app/views/play/level/gold_view.coffee
index 42ef28572..479fe8966 100644
--- a/app/views/play/level/gold_view.coffee
+++ b/app/views/play/level/gold_view.coffee
@@ -1,8 +1,8 @@
-View = require 'views/kinds/CocoView'
+CocoView = require 'views/kinds/CocoView'
 template = require 'templates/play/level/gold'
 teamTemplate = require 'templates/play/level/team_gold'
 
-module.exports = class GoldView extends View
+module.exports = class GoldView extends CocoView
   id: 'gold-view'
   template: template
 
diff --git a/app/views/play/level/hud_view.coffee b/app/views/play/level/hud_view.coffee
index 75bc68346..a730bedf9 100644
--- a/app/views/play/level/hud_view.coffee
+++ b/app/views/play/level/hud_view.coffee
@@ -1,10 +1,10 @@
-View = require 'views/kinds/CocoView'
+CocoView = require 'views/kinds/CocoView'
 template = require 'templates/play/level/hud'
 prop_template = require 'templates/play/level/hud_prop'
 action_template = require 'templates/play/level/hud_action'
 DialogueAnimator = require './dialogue_animator'
 
-module.exports = class HUDView extends View
+module.exports = class HUDView extends CocoView
   id: 'thang-hud'
   template: template
   dialogueMode: false
diff --git a/app/views/play/level/level_chat_view.coffee b/app/views/play/level/level_chat_view.coffee
index c581563da..5c4fe650a 100644
--- a/app/views/play/level/level_chat_view.coffee
+++ b/app/views/play/level/level_chat_view.coffee
@@ -1,9 +1,9 @@
-View = require 'views/kinds/CocoView'
+CocoView = require 'views/kinds/CocoView'
 template = require 'templates/play/level/chat'
 {me} = require 'lib/auth'
 LevelBus = require 'lib/LevelBus'
 
-module.exports = class LevelChatView extends View
+module.exports = class LevelChatView extends CocoView
   id: 'level-chat-view'
   template: template
   open: false
diff --git a/app/views/play/level/level_loading_view.coffee b/app/views/play/level/level_loading_view.coffee
index 2ed460796..6c40e9de9 100644
--- a/app/views/play/level/level_loading_view.coffee
+++ b/app/views/play/level/level_loading_view.coffee
@@ -1,7 +1,7 @@
-View = require 'views/kinds/CocoView'
+CocoView = require 'views/kinds/CocoView'
 template = require 'templates/play/level/level_loading'
 
-module.exports = class LevelLoadingView extends View
+module.exports = class LevelLoadingView extends CocoView
   id: 'level-loading-view'
   template: template
 
diff --git a/app/views/play/level/modal/docs_modal.coffee b/app/views/play/level/modal/docs_modal.coffee
index 9970b8916..a046df051 100644
--- a/app/views/play/level/modal/docs_modal.coffee
+++ b/app/views/play/level/modal/docs_modal.coffee
@@ -1,11 +1,11 @@
-View = require 'views/kinds/ModalView'
+ModalView = require 'views/kinds/ModalView'
 template = require 'templates/play/level/modal/docs'
 Article = require 'models/Article'
 utils = require 'lib/utils'
 
 # let's implement this once we have the docs database schema set up
 
-module.exports = class DocsModal extends View
+module.exports = class DocsModal extends ModalView
   template: template
   id: 'docs-modal'
 
diff --git a/app/views/play/level/modal/editor_config_modal.coffee b/app/views/play/level/modal/editor_config_modal.coffee
index 5f8fd878f..c7dc162d1 100644
--- a/app/views/play/level/modal/editor_config_modal.coffee
+++ b/app/views/play/level/modal/editor_config_modal.coffee
@@ -1,8 +1,8 @@
-View = require 'views/kinds/ModalView'
+ModalView = require 'views/kinds/ModalView'
 template = require 'templates/play/level/modal/editor_config'
 {me} = require 'lib/auth'
 
-module.exports = class EditorConfigModal extends View
+module.exports = class EditorConfigModal extends ModalView
   id: 'level-editor-config-modal'
   template: template
   aceConfig: {}
diff --git a/app/views/play/level/modal/infinite_loop_modal.coffee b/app/views/play/level/modal/infinite_loop_modal.coffee
index ff89e229f..6436c7667 100644
--- a/app/views/play/level/modal/infinite_loop_modal.coffee
+++ b/app/views/play/level/modal/infinite_loop_modal.coffee
@@ -1,7 +1,7 @@
-View = require 'views/kinds/ModalView'
+ModalView = require 'views/kinds/ModalView'
 template = require 'templates/play/level/modal/infinite_loop'
 
-module.exports = class InfiniteLoopModal extends View
+module.exports = class InfiniteLoopModal extends ModalView
   id: '#infinite-loop-modal'
   template: template
 
diff --git a/app/views/play/level/modal/keyboard_shortcuts_modal.coffee b/app/views/play/level/modal/keyboard_shortcuts_modal.coffee
index 816bd3f10..41c15df9d 100644
--- a/app/views/play/level/modal/keyboard_shortcuts_modal.coffee
+++ b/app/views/play/level/modal/keyboard_shortcuts_modal.coffee
@@ -1,7 +1,7 @@
-View = require 'views/kinds/ModalView'
+ModalView = require 'views/kinds/ModalView'
 template = require 'templates/play/level/modal/keyboard_shortcuts'
 
-module.exports = class KeyboardShortcutsModal extends View
+module.exports = class KeyboardShortcutsModal extends ModalView
   id: 'keyboard-shortcuts-modal'
   template: template
 
diff --git a/app/views/play/level/modal/multiplayer_modal.coffee b/app/views/play/level/modal/multiplayer_modal.coffee
index c7e02b157..6645ca2f3 100644
--- a/app/views/play/level/modal/multiplayer_modal.coffee
+++ b/app/views/play/level/modal/multiplayer_modal.coffee
@@ -1,9 +1,9 @@
-View = require 'views/kinds/ModalView'
+ModalView = require 'views/kinds/ModalView'
 template = require 'templates/play/level/modal/multiplayer'
 {me} = require 'lib/auth'
 LadderSubmissionView = require 'views/play/common/ladder_submission_view'
 
-module.exports = class MultiplayerModal extends View
+module.exports = class MultiplayerModal extends ModalView
   id: 'level-multiplayer-modal'
   template: template
 
diff --git a/app/views/play/level/modal/reload_modal.coffee b/app/views/play/level/modal/reload_modal.coffee
index f8b454f1c..f7089e05c 100644
--- a/app/views/play/level/modal/reload_modal.coffee
+++ b/app/views/play/level/modal/reload_modal.coffee
@@ -1,9 +1,9 @@
-View = require 'views/kinds/ModalView'
+ModalView = require 'views/kinds/ModalView'
 template = require 'templates/play/level/modal/reload'
 
 # let's implement this once we have the docs database schema set up
 
-module.exports = class ReloadModal extends View
+module.exports = class ReloadModal extends ModalView
   id: '#reload-code-modal'
   template: template
 
diff --git a/app/views/play/level/modal/victory_modal.coffee b/app/views/play/level/modal/victory_modal.coffee
index 6ee9cabef..03c8d72d8 100644
--- a/app/views/play/level/modal/victory_modal.coffee
+++ b/app/views/play/level/modal/victory_modal.coffee
@@ -1,11 +1,11 @@
-View = require 'views/kinds/ModalView'
+ModalView = require 'views/kinds/ModalView'
 template = require 'templates/play/level/modal/victory'
 {me} = require 'lib/auth'
 LadderSubmissionView = require 'views/play/common/ladder_submission_view'
 LevelFeedback = require 'models/LevelFeedback'
 utils = require 'lib/utils'
 
-module.exports = class VictoryModal extends View
+module.exports = class VictoryModal extends ModalView
   id: 'level-victory-modal'
   template: template
 
diff --git a/app/views/play/level/playback_view.coffee b/app/views/play/level/playback_view.coffee
index ecaab7080..f089e3c25 100644
--- a/app/views/play/level/playback_view.coffee
+++ b/app/views/play/level/playback_view.coffee
@@ -1,11 +1,11 @@
-View = require 'views/kinds/CocoView'
+CocoView = require 'views/kinds/CocoView'
 template = require 'templates/play/level/playback'
 {me} = require 'lib/auth'
 
 EditorConfigModal = require './modal/editor_config_modal'
 KeyboardShortcutsModal = require './modal/keyboard_shortcuts_modal'
 
-module.exports = class PlaybackView extends View
+module.exports = class PlaybackView extends CocoView
   id: 'playback-view'
   template: template
 
diff --git a/app/views/play/level/thang_avatar_view.coffee b/app/views/play/level/thang_avatar_view.coffee
index 054fb0d1a..90ea72be1 100644
--- a/app/views/play/level/thang_avatar_view.coffee
+++ b/app/views/play/level/thang_avatar_view.coffee
@@ -1,8 +1,8 @@
-View = require 'views/kinds/CocoView'
+CocoView = require 'views/kinds/CocoView'
 template = require 'templates/play/level/thang_avatar'
 ThangType = require 'models/ThangType'
 
-module.exports = class ThangAvatarView extends View
+module.exports = class ThangAvatarView extends CocoView
   className: 'thang-avatar-view'
   template: template
 
diff --git a/app/views/play/level/tome/cast_button_view.coffee b/app/views/play/level/tome/cast_button_view.coffee
index 1eb85c79f..fe82e4c28 100644
--- a/app/views/play/level/tome/cast_button_view.coffee
+++ b/app/views/play/level/tome/cast_button_view.coffee
@@ -1,8 +1,8 @@
-View = require 'views/kinds/CocoView'
+CocoView = require 'views/kinds/CocoView'
 template = require 'templates/play/level/tome/cast_button'
 {me} = require 'lib/auth'
 
-module.exports = class CastButtonView extends View
+module.exports = class CastButtonView extends CocoView
   id: 'cast-button-view'
   template: template
 
diff --git a/app/views/play/level/tome/problem_alert_view.coffee b/app/views/play/level/tome/problem_alert_view.coffee
index 2a77e1632..1756b2775 100644
--- a/app/views/play/level/tome/problem_alert_view.coffee
+++ b/app/views/play/level/tome/problem_alert_view.coffee
@@ -1,8 +1,8 @@
-View = require 'views/kinds/CocoView'
+CocoView = require 'views/kinds/CocoView'
 template = require 'templates/play/level/tome/problem_alert'
 {me} = require 'lib/auth'
 
-module.exports = class ProblemAlertView extends View
+module.exports = class ProblemAlertView extends CocoView
   className: 'problem-alert'
   template: template
 
diff --git a/app/views/play/level/tome/spell.coffee b/app/views/play/level/tome/spell.coffee
index 0572542b3..72a897ee2 100644
--- a/app/views/play/level/tome/spell.coffee
+++ b/app/views/play/level/tome/spell.coffee
@@ -90,6 +90,7 @@ module.exports = class Spell
           problems = spellThang.aether.problems
         #console.log 'aether transpiled', source.length, 'to', spellThang.aether.pure.length, 'for', thangID, @spellKey
       else
+        spellThang.aether.raw = source
         spellThang.aether.pure = pure
         spellThang.aether.problems = problems
         #console.log 'aether reused transpilation for', thangID, @spellKey
diff --git a/app/views/play/level/tome/spell_debug_view.coffee b/app/views/play/level/tome/spell_debug_view.coffee
index 54fceb2f5..63e01f1b7 100644
--- a/app/views/play/level/tome/spell_debug_view.coffee
+++ b/app/views/play/level/tome/spell_debug_view.coffee
@@ -1,4 +1,4 @@
-View = require 'views/kinds/CocoView'
+CocoView = require 'views/kinds/CocoView'
 template = require 'templates/play/level/tome/spell_debug'
 Range = ace.require('ace/range').Range
 TokenIterator = ace.require('ace/token_iterator').TokenIterator
@@ -9,7 +9,7 @@ serializedClasses =
   Ellipse: require 'lib/world/ellipse'
   LineSegment: require 'lib/world/line_segment'
 
-module.exports = class DebugView extends View
+module.exports = class DebugView extends CocoView
   className: 'spell-debug-view'
   template: template
 
diff --git a/app/views/play/level/tome/spell_list_entry_thangs_view.coffee b/app/views/play/level/tome/spell_list_entry_thangs_view.coffee
index 43f54f2cd..eeba83590 100644
--- a/app/views/play/level/tome/spell_list_entry_thangs_view.coffee
+++ b/app/views/play/level/tome/spell_list_entry_thangs_view.coffee
@@ -1,8 +1,8 @@
-View = require 'views/kinds/CocoView'
+CocoView = require 'views/kinds/CocoView'
 ThangAvatarView = require 'views/play/level/thang_avatar_view'
 template = require 'templates/play/level/tome/spell_list_entry_thangs'
 
-module.exports = class SpellListEntryThangsView extends View
+module.exports = class SpellListEntryThangsView extends CocoView
   className: 'spell-list-entry-thangs-view'
   template: template
 
diff --git a/app/views/play/level/tome/spell_list_entry_view.coffee b/app/views/play/level/tome/spell_list_entry_view.coffee
index cd39559a8..05f18b23a 100644
--- a/app/views/play/level/tome/spell_list_entry_view.coffee
+++ b/app/views/play/level/tome/spell_list_entry_view.coffee
@@ -1,11 +1,11 @@
 # TODO: This still needs a way to send problem states to its Thang
 
-View = require 'views/kinds/CocoView'
+CocoView = require 'views/kinds/CocoView'
 ThangAvatarView = require 'views/play/level/thang_avatar_view'
 SpellListEntryThangsView = require 'views/play/level/tome/spell_list_entry_thangs_view'
 template = require 'templates/play/level/tome/spell_list_entry'
 
-module.exports = class SpellListEntryView extends View
+module.exports = class SpellListEntryView extends CocoView
   tagName: 'div'  #'li'
   className: 'spell-list-entry-view'
   template: template
diff --git a/app/views/play/level/tome/spell_list_view.coffee b/app/views/play/level/tome/spell_list_view.coffee
index f18eacb9b..9212bd04f 100644
--- a/app/views/play/level/tome/spell_list_view.coffee
+++ b/app/views/play/level/tome/spell_list_view.coffee
@@ -4,12 +4,12 @@
 
 # TODO: showTopDivider should change when we reorder
 
-View = require 'views/kinds/CocoView'
+CocoView = require 'views/kinds/CocoView'
 template = require 'templates/play/level/tome/spell_list'
 {me} = require 'lib/auth'
 SpellListEntryView = require './spell_list_entry_view'
 
-module.exports = class SpellListView extends View
+module.exports = class SpellListView extends CocoView
   className: 'spell-list-view'
   id: 'spell-list-view'
   template: template
diff --git a/app/views/play/level/tome/spell_palette_entry_view.coffee b/app/views/play/level/tome/spell_palette_entry_view.coffee
index 1996b1972..e09116876 100644
--- a/app/views/play/level/tome/spell_palette_entry_view.coffee
+++ b/app/views/play/level/tome/spell_palette_entry_view.coffee
@@ -1,10 +1,10 @@
-View = require 'views/kinds/CocoView'
+CocoView = require 'views/kinds/CocoView'
 template = require 'templates/play/level/tome/spell_palette_entry'
 {me} = require 'lib/auth'
 filters = require 'lib/image_filter'
 DocFormatter = require './doc_formatter'
 
-module.exports = class SpellPaletteEntryView extends View
+module.exports = class SpellPaletteEntryView extends CocoView
   tagName: 'div'  # Could also try <code> instead of <div>, but would need to adjust colors
   className: 'spell-palette-entry-view'
   template: template
diff --git a/app/views/play/level/tome/spell_palette_view.coffee b/app/views/play/level/tome/spell_palette_view.coffee
index 4482da630..89914fb3e 100644
--- a/app/views/play/level/tome/spell_palette_view.coffee
+++ b/app/views/play/level/tome/spell_palette_view.coffee
@@ -1,4 +1,4 @@
-View = require 'views/kinds/CocoView'
+CocoView = require 'views/kinds/CocoView'
 template = require 'templates/play/level/tome/spell_palette'
 {me} = require 'lib/auth'
 filters = require 'lib/image_filter'
@@ -8,7 +8,7 @@ EditorConfigModal = require '../modal/editor_config_modal'
 
 N_ROWS = 4
 
-module.exports = class SpellPaletteView extends View
+module.exports = class SpellPaletteView extends CocoView
   id: 'spell-palette-view'
   template: template
   controlsEnabled: true
diff --git a/app/views/play/level/tome/spell_toolbar_view.coffee b/app/views/play/level/tome/spell_toolbar_view.coffee
index a3f86db10..39916d56c 100644
--- a/app/views/play/level/tome/spell_toolbar_view.coffee
+++ b/app/views/play/level/tome/spell_toolbar_view.coffee
@@ -1,7 +1,7 @@
-View = require 'views/kinds/CocoView'
+CocoView = require 'views/kinds/CocoView'
 template = require 'templates/play/level/tome/spell_toolbar'
 
-module.exports = class SpellToolbarView extends View
+module.exports = class SpellToolbarView extends CocoView
   className: 'spell-toolbar-view'
   template: template
   progressHoverDelay: 500
diff --git a/app/views/play/level/tome/spell_view.coffee b/app/views/play/level/tome/spell_view.coffee
index a92b708f5..46fb62e4e 100644
--- a/app/views/play/level/tome/spell_view.coffee
+++ b/app/views/play/level/tome/spell_view.coffee
@@ -1,4 +1,4 @@
-View = require 'views/kinds/CocoView'
+CocoView = require 'views/kinds/CocoView'
 template = require 'templates/play/level/tome/spell'
 {me} = require 'lib/auth'
 filters = require 'lib/image_filter'
@@ -8,7 +8,7 @@ SpellDebugView = require './spell_debug_view'
 SpellToolbarView = require './spell_toolbar_view'
 LevelComponent = require 'models/LevelComponent'
 
-module.exports = class SpellView extends View
+module.exports = class SpellView extends CocoView
   id: 'spell-view'
   className: 'shown'
   template: template
@@ -396,7 +396,7 @@ module.exports = class SpellView extends View
 
   displayAether: (aether, isCast=false) ->
     @displayedAether = aether
-    isCast = isCast or not _.isEmpty(aether.metrics) or _.some aether.problems.errors, {type: 'runtime'}
+    isCast = isCast or not _.isEmpty(aether.metrics) or _.some aether.getAllProblems(), {type: 'runtime'}
     problem.destroy() for problem in @problems  # Just in case another problem was added since clearAetherDisplay() ran.
     @problems = []
     annotations = []
diff --git a/app/views/play/level/tome/thang_list_entry_view.coffee b/app/views/play/level/tome/thang_list_entry_view.coffee
index 79d9bfa27..06756c898 100644
--- a/app/views/play/level/tome/thang_list_entry_view.coffee
+++ b/app/views/play/level/tome/thang_list_entry_view.coffee
@@ -1,13 +1,13 @@
 # TODO: be useful to add error indicator states to the spellsPopoverTemplate
 # TODO: reordering based on errors isn't working yet
 
-View = require 'views/kinds/CocoView'
+CocoView = require 'views/kinds/CocoView'
 ThangAvatarView = require 'views/play/level/thang_avatar_view'
 template = require 'templates/play/level/tome/thang_list_entry'
 spellsPopoverTemplate = require 'templates/play/level/tome/thang_list_entry_spells'
 {me} = require 'lib/auth'
 
-module.exports = class ThangListEntryView extends View
+module.exports = class ThangListEntryView extends CocoView
   tagName: 'div'  #'li'
   className: 'thang-list-entry-view'
   template: template
diff --git a/app/views/play/level/tome/thang_list_view.coffee b/app/views/play/level/tome/thang_list_view.coffee
index a931e06e7..9f34e2977 100644
--- a/app/views/play/level/tome/thang_list_view.coffee
+++ b/app/views/play/level/tome/thang_list_view.coffee
@@ -1,12 +1,12 @@
 # The ThangListView lives in the code area behind the SpellView, so that when you don't have a spell, you can select any Thang.
 # It just ha a bunch of ThangListEntryViews (which are mostly ThangAvatarViews) in a few sections.
 
-View = require 'views/kinds/CocoView'
+CocoView = require 'views/kinds/CocoView'
 template = require 'templates/play/level/tome/thang_list'
 {me} = require 'lib/auth'
 ThangListEntryView = require './thang_list_entry_view'
 
-module.exports = class ThangListView extends View
+module.exports = class ThangListView extends CocoView
   className: 'thang-list-view'
   id: 'thang-list-view'
   template: template
diff --git a/app/views/play/level/tome/tome_view.coffee b/app/views/play/level/tome/tome_view.coffee
index d709797e7..3ef45258c 100644
--- a/app/views/play/level/tome/tome_view.coffee
+++ b/app/views/play/level/tome/tome_view.coffee
@@ -27,7 +27,7 @@
 # The SpellListView shows spells to which your team has read or readwrite access.
 # It doubles as a Thang selector, since it's there when nothing is selected.
 
-View = require 'views/kinds/CocoView'
+CocoView = require 'views/kinds/CocoView'
 template = require 'templates/play/level/tome/tome'
 {me} = require 'lib/auth'
 Spell = require './spell'
@@ -38,7 +38,7 @@ CastButtonView = require './cast_button_view'
 
 window.SHIM_WORKER_PATH = '/javascripts/workers/catiline_worker_shim.js'
 
-module.exports = class TomeView extends View
+module.exports = class TomeView extends CocoView
   id: 'tome-view'
   template: template
   controlsEnabled: true
diff --git a/app/views/play/level_view.coffee b/app/views/play/level_view.coffee
index c15fe7c6e..010479b5f 100644
--- a/app/views/play/level_view.coffee
+++ b/app/views/play/level_view.coffee
@@ -1,4 +1,4 @@
-View = require 'views/kinds/RootView'
+RootView = require 'views/kinds/RootView'
 template = require 'templates/play/level'
 {me} = require 'lib/auth'
 ThangType = require 'models/ThangType'
@@ -35,7 +35,7 @@ InfiniteLoopModal = require './level/modal/infinite_loop_modal'
 
 PROFILE_ME = false
 
-module.exports = class PlayLevelView extends View
+module.exports = class PlayLevelView extends RootView
   id: 'level-view'
   template: template
   cache: false
@@ -84,8 +84,9 @@ module.exports = class PlayLevelView extends View
     @saveScreenshot = _.throttle @saveScreenshot, 30000
 
     if @isEditorPreview
-      # wait to see if it's just given to us through setLevel
-      f = => @load() unless @levelLoader
+      @supermodel.shouldSaveBackups = (model) ->  # Make sure to load possibly changed things from localStorage.
+        model.constructor.className in ['Level', 'LevelComponent', 'LevelSystem', 'ThangType']
+      f = => @load() unless @levelLoader  # Wait to see if it's just given to us through setLevel.
       setTimeout f, 100
     else
       @load()
diff --git a/app/views/play/spectate_view.coffee b/app/views/play/spectate_view.coffee
index 340978693..de9cab929 100644
--- a/app/views/play/spectate_view.coffee
+++ b/app/views/play/spectate_view.coffee
@@ -1,4 +1,4 @@
-View = require 'views/kinds/RootView'
+RootView = require 'views/kinds/RootView'
 template = require 'templates/play/spectate'
 {me} = require 'lib/auth'
 ThangType = require 'models/ThangType'
@@ -33,7 +33,7 @@ InfiniteLoopModal = require './level/modal/infinite_loop_modal'
 
 PROFILE_ME = false
 
-module.exports = class SpectateLevelView extends View
+module.exports = class SpectateLevelView extends RootView
   id: 'spectate-level-view'
   template: template
   cache: false
diff --git a/app/views/sprite_parser_test_view.coffee b/app/views/sprite_parser_test_view.coffee
deleted file mode 100644
index ece70743e..000000000
--- a/app/views/sprite_parser_test_view.coffee
+++ /dev/null
@@ -1,22 +0,0 @@
-View = require 'views/kinds/RootView'
-template = require 'templates/editor/thang/sprite_parser_test'
-SpriteParser = require 'lib/sprites/SpriteParser'
-mixed_samples = require 'lib/sprites/parser_samples'
-samples = require 'lib/sprites/parser_samples_artillery'
-ThangType = require 'models/ThangType'
-
-module.exports = class SpriteParserTestView extends View
-  id: 'sprite-parser-test-view'
-  template: template
-
-  afterRender: ->
-    @parse samples
-
-  parse: (samples) ->
-    thangType = new ThangType()
-    for sample in _.shuffle samples
-      parser = new SpriteParser(thangType)
-      parser.parse(sample)
-    console.log 'thang type is now', thangType
-    console.log JSON.stringify(thangType).length
-#    console.log JSON.stringify(thangType.attributes.raw.animations.tharin_defend.tweens)
diff --git a/app/views/teachers_view.coffee b/app/views/teachers_view.coffee
deleted file mode 100644
index 783f1391e..000000000
--- a/app/views/teachers_view.coffee
+++ /dev/null
@@ -1,6 +0,0 @@
-View = require 'views/kinds/RootView'
-template = require 'templates/teachers'
-
-module.exports = class TeachersView extends View
-  id: 'teachers-view'
-  template: template
diff --git a/package.json b/package.json
index cb317a6f4..27d76ce3b 100644
--- a/package.json
+++ b/package.json
@@ -59,7 +59,7 @@
     "express-useragent": "~0.0.9",
     "gridfs-stream": "0.4.x",
     "stream-buffers": "0.2.x",
-    "sendwithus": "2.0.x",
+    "sendwithus": "2.1.x",
     "aws-sdk": "~2.0.0",
     "bayesian-battle": "0.0.x",
     "redis": "",
diff --git a/server/commons/Handler.coffee b/server/commons/Handler.coffee
index a796b705e..9dfca705b 100644
--- a/server/commons/Handler.coffee
+++ b/server/commons/Handler.coffee
@@ -232,7 +232,11 @@ module.exports = class Handler
       query['version.minor'] = minorVersion unless _.isNaN(minorVersion)
     sort = { 'version.major': -1, 'version.minor': -1 }
     args = [query]
-    args.push PROJECT if req.query.project
+    if req.query.project
+      projection = {}
+      fields = if req.query.project is 'true' then _.keys(PROJECT) else req.query.project.split(',')
+      projection[field] = 1 for field in fields
+      args.push projection
     @modelClass.findOne(args...).sort(sort).exec (err, doc) =>
       return @sendNotFoundError(res) unless doc?
       return @sendUnauthorizedError(res) unless @hasAccessToDocument(req, doc)
diff --git a/server/commons/LockManager.coffee b/server/commons/LockManager.coffee
new file mode 100644
index 000000000..36936b236
--- /dev/null
+++ b/server/commons/LockManager.coffee
@@ -0,0 +1,43 @@
+config = require '../../server_config'
+redis = require 'redis'
+log = require 'winston'
+
+class LockManager
+  constructor: ->
+    unless config.isProduction
+      throw "You shouldn't be instantiating distributed locks unless in production."
+    @redisNotAvailable = true
+    @redisClient = redis.createClient config.redis.port, config.redis.host
+    @redisClient.on "ready", =>
+      log.info "Redis ready!"
+      @redisNotAvailable = false
+    @redisClient.on "error", (err) =>
+      @redisNotAvailable = true
+      log.error "Redis connection error! Err: #{err}"
+    @redisClient.on "end", =>
+      @redisNotAvailable = true
+      log.error "Redis connection ended!"
+    @lockValues = {}
+    @unlockScript = "if redis.call(\"get\",KEYS[1]) == ARGV[1] then return redis.call(\"del\",KEYS[1]) else return 0 end"
+  
+  setLock: (lockName, timeoutMs, cb) =>
+    if @redisNotAvailable is true then return cb "Redis not available!"
+    randomNumber = Math.floor(Math.random() * 1000000000)
+    @redisClient.set [lockName,randomNumber, "NX", "PX", timeoutMs], (err, res) =>
+      if err? then return cb err, null
+      if res is "OK"
+        @lockValues[lockName] = randomNumber
+        return cb null, "Lock set!"
+      unless res 
+        return cb "Lock already set!", null
+      
+  releaseLock: (lockName, cb) =>
+    if @redisNotAvailable is true then return cb "Redis not available!"
+    @redisClient.eval [@unlockScript, 1, lockName, @lockValues[lockName]], (err, res) -> 
+      if err? then return cb err, null
+      if res
+        cb null, "The lock was released!"
+      else
+        cb "The lock was not released.", null
+
+module.exports = new LockManager() 
diff --git a/server/commons/mapping.coffee b/server/commons/mapping.coffee
index 802b33790..69f8abfc0 100644
--- a/server/commons/mapping.coffee
+++ b/server/commons/mapping.coffee
@@ -9,6 +9,7 @@ module.exports.handlers =
   'thang_type': 'levels/thangs/thang_type_handler'
   'user': 'users/user_handler'
   'user_remark': 'users/remarks/user_remark_handler'
+  'mail_sent': 'mail/sent/mail_sent_handler'
   'achievement': 'achievements/achievement_handler'
   'earned_achievement': 'achievements/earned_achievement_handler'
 
diff --git a/server/levels/level_handler.coffee b/server/levels/level_handler.coffee
index bcda60e1c..76d0ed8ac 100644
--- a/server/levels/level_handler.coffee
+++ b/server/levels/level_handler.coffee
@@ -25,6 +25,8 @@ LevelHandler = class LevelHandler extends Handler
     'goals'
     'type'
     'showsGuide'
+    'banner'
+    'employerDescription'
   ]
 
   postEditableProperties: ['name']
diff --git a/server/mail/sent/MailSent.coffee b/server/mail/sent/MailSent.coffee
new file mode 100644
index 000000000..f8479033a
--- /dev/null
+++ b/server/mail/sent/MailSent.coffee
@@ -0,0 +1,11 @@
+mongoose = require 'mongoose'
+plugins = require '../../plugins/plugins'
+jsonschema = require '../../../app/schemas/models/mail_sent'
+
+MailSent = new mongoose.Schema({
+  sent:
+    type: Date
+    'default': Date.now
+}, {strict: false})
+
+module.exports = MailSent = mongoose.model('mail.sent', MailSent)
diff --git a/server/mail/sent/mail_sent_handler.coffee b/server/mail/sent/mail_sent_handler.coffee
new file mode 100644
index 000000000..35e920c2b
--- /dev/null
+++ b/server/mail/sent/mail_sent_handler.coffee
@@ -0,0 +1,12 @@
+MailSent = require './MailSent'
+Handler = require '../../commons/Handler'
+
+class MailSentHandler extends Handler
+  modelClass: MailSent
+  editableProperties: ['mailTask','user','sent']
+  jsonSchema: require '../../../app/schemas/models/mail_sent'
+
+  hasAccess: (req) ->
+    req.user?.isAdmin()
+
+module.exports = new MailSentHandler()
diff --git a/server/routes/auth.coffee b/server/routes/auth.coffee
index 4b038c15e..5bb1cf1a2 100644
--- a/server/routes/auth.coffee
+++ b/server/routes/auth.coffee
@@ -117,7 +117,8 @@ module.exports.setup = (app) ->
     )
   )
 
-  app.get '/auth/unsubscribe', (req, res) ->
+  app.get '/auth/unsubscribe', (req, res) ->  
+    req.query.email = decodeURIComponent(req.query.email)
     email = req.query.email
     unless req.query.email
       return errors.badInput res, 'No email provided to unsubscribe.'
@@ -131,7 +132,7 @@ module.exports.setup = (app) ->
           return errors.serverError res, 'Database failure.' if err
           res.send "Unsubscribed #{req.query.email} from CodeCombat emails for #{session.levelName} #{session.team} ladder updates. Sorry to see you go! <p><a href='/play/ladder/#{session.levelID}#my-matches'>Ladder preferences</a></p>"
           res.end()
-
+    
     User.findOne({emailLower: req.query.email.toLowerCase()}).exec (err, user) ->
       if not user
         return errors.notFound res, "No user found with email '#{req.query.email}'"
@@ -143,7 +144,11 @@ module.exports.setup = (app) ->
         emails.recruitNotes ?= {}
         emails.recruitNotes.enabled = false
         msg = "Unsubscribed #{req.query.email} from recruiting emails."
-
+      else if req.query.employerNotes
+        emails.employerNotes ?= {}
+        emails.employerNotes.enabled = false
+        
+        msg = "Unsubscribed #{req.query.email} from employer emails."
       else
         msg = "Unsubscribed #{req.query.email} from all CodeCombat emails. Sorry to see you go!"
         emailSettings.enabled = false for emailSettings in _.values(emails)
diff --git a/server/routes/mail.coffee b/server/routes/mail.coffee
index 4fdcef128..b75acfce7 100644
--- a/server/routes/mail.coffee
+++ b/server/routes/mail.coffee
@@ -1,18 +1,528 @@
 mail = require '../commons/mail'
+MailSent = require '../mail/sent/MailSent'
+UserRemark = require '../users/remarks/UserRemark'
 User = require '../users/User'
+async = require 'async'
 errors = require '../commons/errors'
 config = require '../../server_config'
 LevelSession = require '../levels/sessions/LevelSession'
 Level = require '../levels/Level'
 log = require 'winston'
 sendwithus = require '../sendwithus'
-
+if config.isProduction and config.redis.host isnt 'localhost'
+  lockManager = require '../commons/LockManager'
 
 module.exports.setup = (app) ->
   app.all config.mail.mailchimpWebhook, handleMailchimpWebHook
   app.get '/mail/cron/ladder-update', handleLadderUpdate
-  
+  if lockManager
+    setupScheduledEmails()
 
+setupScheduledEmails = ->
+  testForLockManager()
+  mailTasks = [
+      taskFunction: candidateUpdateProfileTask
+      frequencyMs: 10 * 60 * 1000 #10 minutes
+    ,
+      taskFunction: internalCandidateUpdateTask
+      frequencyMs: 10 * 60 * 1000 #10 minutes
+    ,
+      taskFunction: employerNewCandidatesAvailableTask
+      frequencyMs: 10 * 60 * 1000 #10 minutes
+    ,
+      taskFunction: unapprovedCandidateFinishProfileTask
+      frequencyMs: 10 * 60 * 1000
+    ,
+      taskFunction: emailUserRemarkTaskRemindersTask
+      frequencyMs: 10 * 60 * 1000
+  ]
+
+  for mailTask in mailTasks
+    setInterval mailTask.taskFunction, mailTask.frequencyMs
+
+testForLockManager = -> unless lockManager then throw "The system isn't configured to do distributed locking!"
+
+### Approved Candidate Update Reminder Task ###
+candidateUpdateProfileTask = ->
+  mailTaskName = "candidateUpdateProfileTask"
+  lockDurationMs = 2 * 60 * 1000
+  currentDate = new Date()
+  timeRanges = []
+  for weekPair in [[4, 2,'two weeks'], [8, 4, 'four weeks'], [52, 8, 'eight weeks']]
+    timeRanges.push
+      start: generateWeekOffset currentDate, weekPair[0]
+      end: generateWeekOffset currentDate, weekPair[1]
+      name: weekPair[2]
+  lockManager.setLock mailTaskName, lockDurationMs, (err) ->
+    if err? then return log.error "Error getting a distributed lock for task #{mailTaskName}: #{err}"
+    async.each timeRanges, emailTimeRange.bind({mailTaskName: mailTaskName}), (err) ->
+      if err
+        log.error "There was an error sending the candidate profile update reminder emails: #{err}"
+      else
+        log.info "Completed mail task #{mailTaskName}"
+      lockManager.releaseLock mailTaskName, (err) ->
+        if err? then return log.error "There was an error releasing the distributed lock for task #{mailTaskName}: #{err}"
+
+generateWeekOffset = (originalDate, numberOfWeeks) ->
+  return (new Date(originalDate.getTime() - numberOfWeeks * 7 * 24 * 60 * 60 * 1000)).toISOString()
+
+emailTimeRange = (timeRange, emailTimeRangeCallback) ->
+  waterfallContext =
+    "timeRange": timeRange
+    "mailTaskName": @mailTaskName
+  async.waterfall [
+    findAllCandidatesWithinTimeRange.bind(waterfallContext)
+    (unfilteredCandidates, cb) ->
+      async.reject unfilteredCandidates, candidateFilter.bind(waterfallContext), cb.bind(null, null)
+    (filteredCandidates, cb) ->
+      async.each filteredCandidates, sendReminderEmailToCandidate.bind(waterfallContext), cb
+  ], emailTimeRangeCallback
+
+findAllCandidatesWithinTimeRange = (cb) ->
+  findParameters =
+    "jobProfile.updated":
+      $gt: @timeRange.start
+      $lte: @timeRange.end
+    "jobProfileApproved": true
+  selection =  "_id email jobProfile.name jobProfile.updated emails" #make sure to check for anyNotes too.
+  User.find(findParameters).select(selection).lean().exec cb
+
+candidateFilter = (candidate, sentEmailFilterCallback) ->
+  if candidate.emails?.anyNotes?.enabled is false or candidate.emails?.recruitNotes?.enabled is false
+    return sentEmailFilterCallback true
+  findParameters =
+    "user": candidate._id
+    "mailTask": @mailTaskName
+    "metadata.timeRangeName": @timeRange.name
+    "metadata.updated": candidate.jobProfile.updated
+  MailSent.find(findParameters).lean().exec (err, sentMail) ->
+    if err?
+      log.error "Error finding mail sent for task #{@mailTaskName} and user #{candidate._id}!"
+      sentEmailFilterCallback true
+    else
+      sentEmailFilterCallback Boolean(sentMail.length)
+
+findEmployersSignedUpAfterDate = (dateObject, cb) ->
+  countParameters =
+    $or: [{"dateCreated": {$gte: dateObject}},{"signedEmployerAgreement":{$gte: dateObject}}]
+    employerAt: {$exists: true}
+    permissions: "employer"
+  User.count countParameters, cb
+
+sendReminderEmailToCandidate = (candidate, sendEmailCallback) ->
+  findEmployersSignedUpAfterDate new Date(candidate.jobProfile.updated), (err, employersAfterCount) =>
+    if err?
+      log.error "There was an error finding employers who signed up after #{candidate.jobProfile.updated}: #{err}"
+      return sendEmailCallback err
+    if employersAfterCount < 2
+      employersAfterCount = 2
+    context =
+      email_id: "tem_CtTLsKQufxrxoPMn7upKiL"
+      recipient:
+        address: candidate.email
+        name: candidate.jobProfile.name
+      email_data:
+        new_company: employersAfterCount
+        company_name: "CodeCombat"
+        user_profile: "http://codecombat.com/account/profile/#{candidate._id}"
+        recipient_address: encodeURIComponent(candidate.email)
+    log.info "Sending #{@timeRange.name} update reminder to #{context.recipient.name}(#{context.recipient.address})"
+    newSentMail =
+      mailTask: @mailTaskName
+      user: candidate._id
+      metadata:
+        timeRangeName: @timeRange.name
+        updated: candidate.jobProfile.updated
+    MailSent.create newSentMail, (err) ->
+      if err? then return sendEmailCallback err
+      sendwithus.api.send context, (err, result) ->
+        log.error "Error sending candidate update reminder email: #{err} with result #{result}" if err
+        sendEmailCallback null
+### End Approved Candidate Update Reminder Task ###
+  
+### Unapproved Candidate Finish Reminder Task ###
+unapprovedCandidateFinishProfileTask = ->
+  mailTaskName = "unapprovedCandidateFinishProfileTask"
+  lockDurationMs = 2 * 60 * 1000
+  currentDate = new Date()
+  timeRanges = []
+  for weekPair in [[4, 2,'two weeks'], [8, 4, 'four weeks'], [52, 8, 'eight weeks']]
+    timeRanges.push
+      start: generateWeekOffset currentDate, weekPair[0]
+      end: generateWeekOffset currentDate, weekPair[1]
+      name: weekPair[2]
+  lockManager.setLock mailTaskName, lockDurationMs, (err) ->
+    if err? then return log.error "Error getting a distributed lock for task #{mailTaskName}: #{err}"
+    async.each timeRanges, emailUnapprovedCandidateTimeRange.bind({mailTaskName: mailTaskName}), (err) ->
+      if err
+        log.error "There was an error sending the candidate profile update reminder emails: #{err}"
+      else
+        log.info "Completed mail task #{mailTaskName}"
+      lockManager.releaseLock mailTaskName, (err) ->
+        if err? then return log.error "There was an error releasing the distributed lock for task #{mailTaskName}: #{err}"
+
+emailUnapprovedCandidateTimeRange = (timeRange, emailTimeRangeCallback) ->
+  waterfallContext =
+    "timeRange": timeRange
+    "mailTaskName": @mailTaskName
+  async.waterfall [
+    findAllUnapprovedCandidatesWithinTimeRange.bind(waterfallContext)
+    (unfilteredCandidates, cb) ->
+      async.reject unfilteredCandidates, ignoredCandidateFilter, cb.bind(null,null)
+    (unfilteredPotentialCandidates, cb) ->
+      async.reject unfilteredPotentialCandidates, unapprovedCandidateFilter.bind(waterfallContext), cb.bind(null, null)
+    (filteredCandidates, cb) ->
+      async.each filteredCandidates, sendReminderEmailToUnapprovedCandidate.bind(waterfallContext), cb
+  ], emailTimeRangeCallback
+
+findAllUnapprovedCandidatesWithinTimeRange = (cb) ->
+  findParameters =
+    "jobProfile":
+      $exists: true
+    "jobProfile.updated":
+      $gt: @timeRange.start
+      $lte: @timeRange.end
+    "jobProfileApproved": false
+  selection =  "_id email jobProfile.name jobProfile.updated emails"
+  User.find(findParameters).select(selection).lean().exec cb
+
+ignoredCandidateFilter = (candidate, cb) ->
+  findParameters = 
+    "user": candidate._id
+    "contactName": "Ignore"
+  UserRemark.count findParameters, (err, results) ->
+    if err? then return true
+    return cb Boolean(results.length)
+    
+unapprovedCandidateFilter = (candidate, sentEmailFilterCallback) ->
+  if candidate.emails?.anyNotes?.enabled is false or candidate.emails?.recruitNotes?.enabled is false
+    return sentEmailFilterCallback true
+  findParameters =
+    "user": candidate._id
+    "mailTask": @mailTaskName
+    "metadata.timeRangeName": @timeRange.name
+    "metadata.updated": candidate.jobProfile.updated
+  MailSent.find(findParameters).lean().exec (err, sentMail) ->
+    if err?
+      log.error "Error finding mail sent for task #{@mailTaskName} and user #{candidate._id}!"
+      sentEmailFilterCallback true
+    else
+      sentEmailFilterCallback Boolean(sentMail.length)
+
+sendReminderEmailToUnapprovedCandidate = (candidate, sendEmailCallback) ->
+  if err?
+    log.error "There was an error finding employers who signed up after #{candidate.jobProfile.updated}: #{err}"
+    return sendEmailCallback err
+  context =
+    email_id: "tem_RXyjzmc7S2HJH287pfoSPN"
+    recipient:
+      address: candidate.email
+      name: candidate.jobProfile.name
+    email_data:
+      user_profile: "http://codecombat.com/account/profile/#{candidate._id}"
+      recipient_address: encodeURIComponent(candidate.email)
+  log.info "Sending #{@timeRange.name} finish profile reminder to #{context.recipient.name}(#{context.recipient.address})"
+  newSentMail =
+    mailTask: @mailTaskName
+    user: candidate._id
+    metadata:
+      timeRangeName: @timeRange.name
+      updated: candidate.jobProfile.updated
+  MailSent.create newSentMail, (err) ->
+    if err? then return sendEmailCallback err
+    sendwithus.api.send context, (err, result) ->
+      log.error "Error sending candidate finish profile reminder email: #{err} with result #{result}" if err
+      sendEmailCallback null
+### End Unapproved Candidate Finish Reminder Task ###
+  
+### Internal Candidate Update Reminder Email ###
+internalCandidateUpdateTask = ->
+  mailTaskName = "internalCandidateUpdateTask"
+  lockDurationMs = 2 * 60 * 1000
+  lockManager.setLock mailTaskName, lockDurationMs, (err) ->
+    if err? then return log.error "Error getting a distributed lock for task #{mailTaskName}: #{err}"
+    emailInternalCandidateUpdateReminder.call {"mailTaskName":mailTaskName}, (err) ->
+      if err
+        log.error "There was an error sending the internal candidate update reminder.: #{err}"
+      else
+        log.info "Sent internal candidate update reminder email!"
+      lockManager.releaseLock mailTaskName, (err) ->
+        if err? then return log.error "There was an error releasing the distributed lock for task #{mailTaskName}: #{err}"
+
+emailInternalCandidateUpdateReminder = (internalCandidateUpdateReminderCallback) ->
+  currentTime = new Date()
+  beginningOfUTCDay = new Date()
+  beginningOfUTCDay.setUTCHours(0,0,0,0)
+  asyncContext =
+    "beginningOfUTCDay": beginningOfUTCDay
+    "currentTime": currentTime
+    "mailTaskName": @mailTaskName
+  async.waterfall [
+    findNonApprovedCandidatesWhoUpdatedJobProfileToday.bind(asyncContext)
+    (unfilteredCandidates, cb) ->
+      async.reject unfilteredCandidates, candidatesUpdatedTodayFilter.bind(asyncContext), cb.bind(null,null)
+    (filteredCandidates, cb) ->
+      async.each filteredCandidates, sendInternalCandidateUpdateReminder.bind(asyncContext), cb
+  ], internalCandidateUpdateReminderCallback
+
+findNonApprovedCandidatesWhoUpdatedJobProfileToday = (cb) ->
+  findParameters =
+    "jobProfile.updated":
+      $lte: @currentTime.toISOString()
+      $gt: @beginningOfUTCDay.toISOString()
+    "jobProfileApproved": false
+  User.find(findParameters).select("_id jobProfile.name jobProfile.updated").lean().exec cb
+
+candidatesUpdatedTodayFilter = (candidate, cb) ->
+  findParameters =
+    "user": candidate._id
+    "mailTask": @mailTaskName
+    "metadata.beginningOfUTCDay": @beginningOfUTCDay
+  MailSent.find(findParameters).lean().exec (err, sentMail) ->
+    if err?
+      log.error "Error finding mail sent for task #{@mailTaskName} and user #{candidate._id}!"
+      cb true
+    else
+      cb Boolean(sentMail.length)
+
+sendInternalCandidateUpdateReminder = (candidate, cb) ->
+  context =
+    email_id: "tem_Ac7nhgKqatTHBCgDgjF5pE"
+    recipient:
+      address: "team@codecombat.com"
+      name: "The CodeCombat Team"
+    email_data:
+      new_candidate_profile: "http://codecombat.com/account/profile/#{candidate._id}"
+  log.info "Sending candidate updated reminder for #{candidate.jobProfile.name}"
+  newSentMail =
+    mailTask: @mailTaskName
+    user: candidate._id
+    metadata:
+      beginningOfUTCDay: @beginningOfUTCDay
+
+  MailSent.create newSentMail, (err) ->
+    if err? then return cb err
+    sendwithus.api.send context, (err, result) ->
+      log.error "Error sending interal candidate update email: #{err} with result #{result}" if err
+      cb null
+
+### End Internal Candidate Update Reminder Email ###
+### Employer New Candidates Available Email ###
+employerNewCandidatesAvailableTask = ->
+  mailTaskName = "employerNewCandidatesAvailableTask"
+  lockDurationMs = 2 * 60 * 1000
+  lockManager.setLock mailTaskName, lockDurationMs, (err) ->
+    if err? then return log.error "Error getting a distributed lock for task #{mailTaskName}: #{err}"
+    emailEmployerNewCandidatesAvailable.call {"mailTaskName":mailTaskName}, (err) ->
+      if err
+        log.error "There was an error completing the new candidates available task: #{err}"
+      else
+        log.info "Completed the employer new candidates available task!"
+      lockManager.releaseLock mailTaskName, (err) ->
+        if err? then return log.error "There was an error releasing the distributed lock for task #{mailTaskName}: #{err}"
+
+emailEmployerNewCandidatesAvailable = (emailEmployerNewCandidatesAvailableCallback) ->
+  currentTime = new Date()
+  asyncContext =
+    "currentTime": currentTime
+    "mailTaskName": @mailTaskName
+
+  async.waterfall [
+    findAllEmployers
+    makeEmployerNamesEasilyAccessible
+    (allEmployers, cb) ->
+      async.reject allEmployers, employersEmailedDigestMoreThanWeekAgoFilter.bind(asyncContext), cb.bind(null,null)
+    (employersToEmail, cb) ->
+      async.each employersToEmail, sendEmployerNewCandidatesAvailableEmail.bind(asyncContext), cb
+  ], emailEmployerNewCandidatesAvailableCallback
+
+findAllEmployers = (cb) ->
+  findParameters =
+    "employerAt":
+      $exists: true
+    permissions: "employer"
+  selection = "_id email employerAt signedEmployerAgreement.data.firstName signedEmployerAgreement.data.lastName activity dateCreated emails"
+  User.find(findParameters).select(selection).lean().exec cb
+
+makeEmployerNamesEasilyAccessible = (allEmployers, cb) ->
+  for employer, index in allEmployers
+    if employer.signedEmployerAgreement?.data?.firstName
+      employer.name = employer.signedEmployerAgreement.data.firstName + " " + employer.signedEmployerAgreement.data.lastName
+      delete employer.signedEmployerAgreement
+    allEmployers[index] = employer
+  cb null, allEmployers
+
+employersEmailedDigestMoreThanWeekAgoFilter = (employer, cb) ->
+  if employer.emails?.employerNotes?.enabled is false
+    return cb true
+  if not employer.signedEmployerAgreement and not employer.activity?.login?
+    return cb true
+  findParameters =
+    "user": employer._id
+    "mailTask": @mailTaskName
+    "sent":
+      $gt: new Date(@currentTime.getTime() - 7 * 24 * 60 * 60 * 1000)
+  MailSent.find(findParameters).lean().exec (err, sentMail) ->
+    if err?
+      log.error "Error finding mail sent for task #{@mailTaskName} and employer #employer._id}!"
+      cb true
+    else
+      cb Boolean(sentMail.length)
+
+sendEmployerNewCandidatesAvailableEmail = (employer, cb) ->
+  lastLoginDate = employer.activity?.login?.last ? employer.dateCreated
+  countParameters =
+    "jobProfileApproved": true
+    $or: [
+        jobProfileApprovedDate:
+          $gt: lastLoginDate.toISOString()
+      ,
+        jobProfileApprovedDate:
+          $exists: false
+        "jobProfile.updated":
+          $gt: lastLoginDate.toISOString()
+    ]
+  User.count countParameters, (err, numberOfCandidatesSinceLogin) =>
+    if err? then return cb err
+    context =
+      email_id: "tem_CCcHKr95Nvu5bT7c7iHCtm"
+      recipient:
+        address: employer.email
+      email_data:
+        new_candidates: numberOfCandidatesSinceLogin
+        employer_company_name: employer.employerAt
+        company_name: "CodeCombat"
+        recipient_address: encodeURIComponent(employer.email)
+    if employer.name
+      context.recipient.name = employer.name
+    log.info "Sending available candidates update reminder to #{context.recipient.name}(#{context.recipient.address})"
+    newSentMail =
+      mailTask: @mailTaskName
+      user: employer._id
+    MailSent.create newSentMail, (err) ->
+      if err? then return cb err
+      sendwithus.api.send context, (err, result) ->
+        log.error "Error sending employer candidates available email: #{err} with result #{result}" if err
+        cb null
+
+### End Employer New Candidates Available Email ###
+  
+### Task Emails ###
+emailUserRemarkTaskRemindersTask = ->
+  mailTaskName = "emailUserRemarkTaskRemindersTask"
+  lockDurationMs = 2 * 60 * 1000
+  lockManager.setLock mailTaskName, lockDurationMs, (err) ->
+    if err? then return log.error "Error getting a distributed lock for task #{mailTaskName}: #{err}"
+    emailUserRemarkTaskReminders.call {"mailTaskName":mailTaskName}, (err) ->
+      if err
+        log.error "There was an error completing the #{mailTaskName}: #{err}"
+      else
+        log.info "Completed the #{mailTaskName}"
+      lockManager.releaseLock mailTaskName, (err) ->
+        if err? then return log.error "There was an error releasing the distributed lock for task #{mailTaskName}: #{err}"
+
+emailUserRemarkTaskReminders = (cb) ->
+  currentTime = new Date()
+  asyncContext =
+    "currentTime": currentTime
+    "mailTaskName": @mailTaskName
+  
+  async.waterfall [
+    findAllIncompleteUserRemarkTasksDue.bind(asyncContext)
+    processRemarksIntoTasks.bind(asyncContext)
+    (allTasks, cb) ->
+      async.reject allTasks, taskReminderAlreadySentThisWeekFilter.bind(asyncContext), cb.bind(null,null)
+    (tasksToRemind, cb) ->
+      async.each tasksToRemind, sendUserRemarkTaskEmail.bind(asyncContext), cb
+  ], cb
+  
+findAllIncompleteUserRemarkTasksDue = (cb) ->
+  findParameters = 
+    tasks:
+      $exists: true
+      $elemMatch:
+        date:
+          $lte: @currentTime.toISOString()
+        status:
+          $ne: 'Completed'
+  selection = "contact user tasks"
+  UserRemark.find(findParameters).select(selection).lean().exec cb
+  
+processRemarksIntoTasks = (remarks, cb) ->
+  tasks = []
+  for remark in remarks
+      for task in remark.tasks
+        taskObject = 
+          date: task.date
+          action: task.action
+          contact: remark.contact
+          user: remark.user
+          remarkID: remark._id
+        tasks.push taskObject
+  cb null, tasks
+
+taskReminderAlreadySentThisWeekFilter = (task, cb) ->
+  findParameters =
+    "user": task.contact
+    "mailTask": @mailTaskName
+    "sent":
+      $gt: new Date(@currentTime.getTime() - 7 * 24 * 60 * 60 * 1000)
+    "metadata":
+      remarkID: task.remarkID
+      taskAction: task.action
+      date: task.date
+  MailSent.count findParameters, (err, count) ->
+    if err? then return cb true
+    return cb Boolean(count)
+  
+sendUserRemarkTaskEmail = (task, cb) ->
+  mailTaskName = @mailTaskName
+  User.findOne("_id":task.contact).select("email").lean().exec (err, contact) ->
+    if err? then return cb err
+    context =
+      email_id: "tem_aryDjyw6JmEmbKtCMTSwAM"
+      recipient:
+        address: contact.email
+      email_data:
+        candidate_link: "http://codecombat.com/account/profile/#{task.user}"
+        due_date: task.date
+    log.info "Sending recruitment task reminder to #{contact.email}"
+    newSentMail =
+      mailTask: mailTaskName
+      user: task.contact
+      "metadata":
+        remarkID: task.remarkID
+        taskAction: task.action
+        date: task.date
+    MailSent.create newSentMail, (err) ->
+      if err? then return cb err
+      sendwithus.api.send context, (err, result) ->
+        log.error "Error sending #{mailTaskName} to #{contact.email}: #{err} with result #{result}" if err
+        cb null
+
+### New Recruit Leaderboard Email ###
+###
+newRecruitLeaderboardEmailTask = ->
+  # tem_kMQFCKX3v4DNAQDsMAsPJC
+  #maxRank and maxRankTime should be recorded if isSimulating is false
+  mailTaskName = "newRecruitLeaderboardEmailTask"
+  lockDurationMs = 6000
+  lockManager.setLock mailTaskName, lockDurationMs, (err, lockResult) ->
+###
+### End New Recruit Leaderboard Email ###
+
+### Employer Matching Candidate Notification Email ###
+###
+employerMatchingCandidateNotificationTask = ->
+  # tem_mYsepTfWQ265noKfZJcbBH
+  #save email filters in their own collection
+  mailTaskName = "employerMatchingCandidateNotificationTask"
+  lockDurationMs = 6000
+  lockManager.setLock mailTaskName, lockDurationMs, (err, lockResult) ->
+###
+### End Employer Matching Candidate Notification Email ###
+### Ladder Update Email ###
+### Employer ignore ###
 DEBUGGING = false
 LADDER_PREGAME_INTERVAL = 2 * 3600 * 1000  # Send emails two hours before players last submitted.
 getTimeFromDaysAgo = (now, daysAgo) ->
@@ -28,6 +538,8 @@ isRequestFromDesignatedCronHandler = (req, res) ->
     return false
   return true
 
+
+
 handleLadderUpdate = (req, res) ->
   log.info('Going to see about sending ladder update emails.')
   requestIsFromDesignatedCronHandler = isRequestFromDesignatedCronHandler req, res
@@ -151,6 +663,7 @@ getScoreHistoryGraphURL = (session, daysAgo) ->
   chartData = times.join(',') + '|' + scores.join(',')
   "https://chart.googleapis.com/chart?chs=600x75&cht=lxy&chtt=Score%3A+#{currentScore}&chts=222222,12,r&chf=a,s,000000FF&chls=2&chd=t:#{chartData}&chxt=y&chxr=0,#{minScore},#{maxScore}"
 
+### End Ladder Update Email ###
 handleMailchimpWebHook = (req, res) ->
   post = req.body
 
diff --git a/server/users/user_handler.coffee b/server/users/user_handler.coffee
index 020d30f20..fbd13ec19 100644
--- a/server/users/user_handler.coffee
+++ b/server/users/user_handler.coffee
@@ -219,6 +219,7 @@ UserHandler = class UserHandler extends Handler
   avatar: (req, res, id) ->
     @modelClass.findById(id).exec (err, document) =>
       return @sendDatabaseError(res, err) if err
+      return @sendNotFoundError(res) unless document
       photoURL = document?.get('photoURL')
       if photoURL
         photoURL = "/file/#{photoURL}"
@@ -232,7 +233,7 @@ UserHandler = class UserHandler extends Handler
   getLevelSessionsForEmployer: (req, res, userID) ->
     return @sendUnauthorizedError(res) unless req.user._id+'' is userID or req.user.isAdmin() or ('employer' in req.user.get('permissions'))
     query = creator: userID, levelID: {$in: ['gridmancer', 'greed', 'dungeon-arena', 'brawlwood', 'gold-rush']}
-    projection = 'levelName levelID team playtime codeLanguage submitted code totalScore'
+    projection = 'levelName levelID team playtime codeLanguage submitted code totalScore teamSpells level'
     LevelSession.find(query).select(projection).exec (err, documents) =>
       return @sendDatabaseError(res, err) if err
       documents = (LevelSessionHandler.formatEntity(req, doc) for doc in documents)
diff --git a/server_config.coffee b/server_config.coffee
index 6018bf84f..13fc4e7d1 100644
--- a/server_config.coffee
+++ b/server_config.coffee
@@ -12,6 +12,10 @@ config.mongo =
   host: process.env.COCO_MONGO_HOST or 'localhost'
   db: process.env.COCO_MONGO_DATABASE_NAME or 'coco'
   mongoose_replica_string: process.env.COCO_MONGO_MONGOOSE_REPLICA_STRING or ''
+  
+config.redis = 
+  port: process.env.COCO_REDIS_PORT or 6379
+  host: process.env.COCO_REDIS_HOST or 'localhost'
 
 if config.unittest
   config.port += 1
diff --git a/test/app/models/CocoModel.spec.coffee b/test/app/models/CocoModel.spec.coffee
index 67e019c9a..7f2529466 100644
--- a/test/app/models/CocoModel.spec.coffee
+++ b/test/app/models/CocoModel.spec.coffee
@@ -14,6 +14,14 @@ class BlandClass extends CocoModel
   urlRoot: '/db/bland'
 
 describe 'CocoModel', ->
+  describe 'setProjection', ->
+    it 'takes an array of properties to project and adds them as a query parameter', ->
+      b = new BlandClass({})
+      b.setProjection ['number', 'object']
+      b.fetch()
+      request = jasmine.Ajax.requests.mostRecent()
+      expect(decodeURIComponent(request.url).indexOf('project=number,object')).toBeGreaterThan(-1)
+  
   describe 'save', ->
 
     it 'saves to db/<urlRoot>', ->
diff --git a/test/demo/views/common/LevelSessionCodeView.demo.coffee b/test/demo/views/common/LevelSessionCodeView.demo.coffee
new file mode 100644
index 000000000..a7aa3810e
--- /dev/null
+++ b/test/demo/views/common/LevelSessionCodeView.demo.coffee
@@ -0,0 +1,13 @@
+LevelSessionCodeView = require 'views/common/LevelSessionCodeView'
+LevelSession = require 'models/LevelSession'
+
+levelSessionData = {"_id":"5317ad4909098828ed071f4d","level":{"original":"53173f76c269d400000543c2","majorVersion":0},"team":"humans","levelID":"dungeon-arena","levelName":"Dungeon Arena","submitted":true,"totalScore":38.4584087145667,"code":{"programmable-librarian":{"chooseAction":"// The Librarian is a spellcaster with a fireball attack\n// plus three useful spells: 'slow', 'regen', and 'haste'.\n// Slow makes a target move and attack at half speed for 5s.\n// Regen makes a target heal 10 hp/s for 10s.\n// Haste speeds up a target by 4x for 5s, once per match.\n\nvar enemies = this.getEnemies();\nif (enemies.length === 0) return;  // Chill if all enemies are dead.\nvar enemy = this.getNearest(enemies);\nif (this.canCast('slow', enemy)) {\n    // Slow the enemy, or chase if out of range (30m).\n    this.castSlow(enemy);\n    if (this.distance(enemy) <= 50)\n        this.say(\"Not so fast, \" + enemy.type + \" \" + enemy.id);\n}\nelse {\n    this.attack(enemy);\n}\nvar base = this.getFriends()[0];\nvar d = base.distance(enemy);\n// You can also command your troops with this.say():\n//this.say(\"Defend!\", {targetPos: {x: 30, y: 30}}));\n//this.say(\"Attack!\", {target: enemy});\n//this.say(\"Move!\", {targetPos: {x: 50, y: 40});\n"},"human-base":{"chooseAction":"// This is the code for your base. Decide which unit to build each frame.\n// Units you build will go into the this.built array.\n// Destroy the enemy base within 60 seconds!\n// Check out the Guide at the top for more info.\n\n// CHOOSE YOUR HERO! You can only build one hero.\nvar hero;\n//hero = 'tharin';  // A fierce knight with battlecry abilities.\nhero = 'hushbaum';  // A fiery spellcaster hero.\n\nif(hero && !this.builtHero) {\n    this.builtHero = this.build(hero);\n    return;\n}\n\n// Soldiers are hard-to-kill, low damage melee units with 2s build cooldown.\n// Archers are fragile but deadly ranged units with 2.5s build cooldown.\nvar buildOrder = ['soldier', 'soldier', 'soldier', 'soldier', 'archer'];\nvar type = buildOrder[this.built.length % buildOrder.length];\n//this.say('Unit #' + this.built.length + ' will be a ' + type);\nthis.build(type);"},"hushbaum":{"chooseAction":"var enemy = this.getNearestEnemy();\nif (enemy) {\n    if (!enemy.hasEffect('slow')) {\n        this.say(\"Not so fast, \" + enemy.type + \" \" + enemy.id);\n        this.castSlow(enemy);\n    }\n    else {\n        this.attack(enemy);\n    }\n}\nelse {\n    this.move({x: 70, y: 30});\n}\n"},"tharin":{"chooseAction":"var enemies = this.getEnemies();\nvar enemy = this.getNearest(enemies);\nif (!this.getCooldown('warcry')) {\n    this.warcry();\n}\nelse if (enemy) {\n    this.attack(enemy);\n}\nelse {\n    this.move({x: 10, y: 30});\n}\n"},"tharin-1":{"chooseAction":"var __interceptThis=(function(){var G=this;return function($this,sandbox){if($this==G){return sandbox;}return $this;};})();\nreturn (function (__global) {\n    var tmp0, tmp1;\n    tmp1 = function () {\n        _aether.logCallStart(this._aetherUserInfo); var enemies, enemy, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9, tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16, tmp17, tmp18, tmp19, tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26;\n        tmp2 = 'use strict';\n        tmp3 = __interceptThis(this, __global);\n        tmp4 = 'getEnemies';\n        _aether.logStatementStart([{ofs: 0, row: 0, col: 0}, {ofs: 32, row: 0, col: 32}]); enemies = tmp3[tmp4](); _aether.vars['enemies'] = typeof enemies == 'undefined' ? undefined : enemies; _aether.vars['enemy'] = typeof enemy == 'undefined' ? undefined : enemy; _aether.vars['chooseAction'] = typeof chooseAction == 'undefined' ? undefined : chooseAction; _aether.logStatement([{ofs: 0, row: 0, col: 0}, {ofs: 32, row: 0, col: 32}], \"var enemies = this.getEnemies();\", this._aetherUserInfo);\n        tmp5 = __interceptThis(this, __global);\n        tmp6 = 'getNearest';\n        tmp7 = enemies;\n        _aether.logStatementStart([{ofs: 33, row: 1, col: 0}, {ofs: 70, row: 1, col: 37}]); enemy = tmp5[tmp6](tmp7); _aether.vars['enemies'] = typeof enemies == 'undefined' ? undefined : enemies; _aether.vars['enemy'] = typeof enemy == 'undefined' ? undefined : enemy; _aether.vars['chooseAction'] = typeof chooseAction == 'undefined' ? undefined : chooseAction; _aether.logStatement([{ofs: 33, row: 1, col: 0}, {ofs: 70, row: 1, col: 37}], \"var enemy = this.getNearest(enemies);\", this._aetherUserInfo);\n        tmp10 = __interceptThis(this, __global);\n        tmp11 = 'getCooldown';\n        _aether.logStatementStart([{ofs: 93, row: 2, col: 22}, {ofs: 101, row: 2, col: 30}]); tmp12 = 'warcry'; _aether.vars['enemies'] = typeof enemies == 'undefined' ? undefined : enemies; _aether.vars['enemy'] = typeof enemy == 'undefined' ? undefined : enemy; _aether.vars['chooseAction'] = typeof chooseAction == 'undefined' ? undefined : chooseAction; _aether.logStatement([{ofs: 93, row: 2, col: 22}, {ofs: 101, row: 2, col: 30}], \"'warcry'\", this._aetherUserInfo);\n        _aether.logStatementStart([{ofs: 76, row: 2, col: 5}, {ofs: 102, row: 2, col: 31}]); tmp9 = tmp10[tmp11](tmp12); _aether.vars['enemies'] = typeof enemies == 'undefined' ? undefined : enemies; _aether.vars['enemy'] = typeof enemy == 'undefined' ? undefined : enemy; _aether.vars['chooseAction'] = typeof chooseAction == 'undefined' ? undefined : chooseAction; _aether.logStatement([{ofs: 76, row: 2, col: 5}, {ofs: 102, row: 2, col: 31}], \"this.getCooldown('warcry')\", this._aetherUserInfo);\n        _aether.logStatementStart([{ofs: 75, row: 2, col: 4}, {ofs: 102, row: 2, col: 31}]); tmp8 = !tmp9; _aether.vars['enemies'] = typeof enemies == 'undefined' ? undefined : enemies; _aether.vars['enemy'] = typeof enemy == 'undefined' ? undefined : enemy; _aether.vars['chooseAction'] = typeof chooseAction == 'undefined' ? undefined : chooseAction; _aether.logStatement([{ofs: 75, row: 2, col: 4}, {ofs: 102, row: 2, col: 31}], \"!this.getCooldown('warcry')\", this._aetherUserInfo);\n        if (tmp8) {\n            tmp13 = __interceptThis(this, __global);\n            tmp14 = 'warcry';\n            _aether.logStatementStart([{ofs: 110, row: 3, col: 4}, {ofs: 123, row: 3, col: 17}]); tmp15 = tmp13[tmp14](); _aether.vars['enemies'] = typeof enemies == 'undefined' ? undefined : enemies; _aether.vars['enemy'] = typeof enemy == 'undefined' ? undefined : enemy; _aether.vars['chooseAction'] = typeof chooseAction == 'undefined' ? undefined : chooseAction; _aether.logStatement([{ofs: 110, row: 3, col: 4}, {ofs: 123, row: 3, col: 17}], \"this.warcry()\", this._aetherUserInfo);\n        } else {\n            tmp16 = enemy;\n            if (tmp16) {\n                tmp17 = __interceptThis(this, __global);\n                tmp18 = 'attack';\n                tmp19 = enemy;\n                _aether.logStatementStart([{ofs: 149, row: 6, col: 4}, {ofs: 167, row: 6, col: 22}]); tmp20 = tmp17[tmp18](tmp19); _aether.vars['enemies'] = typeof enemies == 'undefined' ? undefined : enemies; _aether.vars['enemy'] = typeof enemy == 'undefined' ? undefined : enemy; _aether.vars['chooseAction'] = typeof chooseAction == 'undefined' ? undefined : chooseAction; _aether.logStatement([{ofs: 149, row: 6, col: 4}, {ofs: 167, row: 6, col: 22}], \"this.attack(enemy)\", this._aetherUserInfo);\n            } else {\n                tmp21 = __interceptThis(this, __global);\n                tmp22 = 'move';\n                _aether.logStatementStart([{ofs: 196, row: 9, col: 18}, {ofs: 198, row: 9, col: 20}]); tmp24 = 10; _aether.vars['enemies'] = typeof enemies == 'undefined' ? undefined : enemies; _aether.vars['enemy'] = typeof enemy == 'undefined' ? undefined : enemy; _aether.vars['chooseAction'] = typeof chooseAction == 'undefined' ? undefined : chooseAction; _aether.logStatement([{ofs: 196, row: 9, col: 18}, {ofs: 198, row: 9, col: 20}], \"10\", this._aetherUserInfo);\n                _aether.logStatementStart([{ofs: 203, row: 9, col: 25}, {ofs: 205, row: 9, col: 27}]); tmp25 = 30; _aether.vars['enemies'] = typeof enemies == 'undefined' ? undefined : enemies; _aether.vars['enemy'] = typeof enemy == 'undefined' ? undefined : enemy; _aether.vars['chooseAction'] = typeof chooseAction == 'undefined' ? undefined : chooseAction; _aether.logStatement([{ofs: 203, row: 9, col: 25}, {ofs: 205, row: 9, col: 27}], \"30\", this._aetherUserInfo);\n                _aether.logStatementStart([{ofs: 192, row: 9, col: 14}, {ofs: 206, row: 9, col: 28}]); tmp23 = {\n                    x: tmp24,\n                    y: tmp25\n                }; _aether.vars['enemies'] = typeof enemies == 'undefined' ? undefined : enemies; _aether.vars['enemy'] = typeof enemy == 'undefined' ? undefined : enemy; _aether.vars['chooseAction'] = typeof chooseAction == 'undefined' ? undefined : chooseAction; _aether.logStatement([{ofs: 192, row: 9, col: 14}, {ofs: 206, row: 9, col: 28}], \"{x: 10, y: 30}\", this._aetherUserInfo);\n                _aether.logStatementStart([{ofs: 182, row: 9, col: 4}, {ofs: 207, row: 9, col: 29}]); tmp26 = tmp21[tmp22](tmp23); _aether.vars['enemies'] = typeof enemies == 'undefined' ? undefined : enemies; _aether.vars['enemy'] = typeof enemy == 'undefined' ? undefined : enemy; _aether.vars['chooseAction'] = typeof chooseAction == 'undefined' ? undefined : chooseAction; _aether.logStatement([{ofs: 182, row: 9, col: 4}, {ofs: 207, row: 9, col: 29}], \"this.move({x: 10, y: 30})\", this._aetherUserInfo);\n            }\n        }\n        _aether.logCallEnd(); return;\n    };\n    tmp0 = 'chooseAction';\n    __global[tmp0] = tmp1;\n}(this));"},"programmable-tharin":{"chooseAction":"/*this.getFriends();\nthis.attack(this.getEnemies()[0]);\nreturn;\n*/\n \n\n/* TODO:\n   If they fully base race us, we actually do want to produce archers since they DPS faster\n   The effective DPS on soldiers is better if they attack us\n   but worse if they straight race us\n\n   //not sure if this is good but...\n   if they're attacking our base with a small number of units\n   we should make archers and get them to defend\n*/\n/*\nreturn;\n// Tharin is a melee fighter with shield, warcry, and terrify skills.\n// this.shield() lets him take one-third damage while defending.\n// this.warcry() gives allies within 10m 30% haste for 5s, every 10s.\n// this.terrify() sends foes within 30m fleeing for 5s, once per match.\nvar friends = this.getFriends();\nvar enemies = this.getEnemies();\nif (enemies.length === 0) return;  // Chill if all enemies are dead.\nvar enemy = this.getNearest(enemies);\nvar furthestFriendX = 30;\nfor (var i = 0; i < friends.length; ++i) {\n    var friend = friends[i];\n    furthestFriendX = Math.max(friend.pos.x, furthestFriendX);\n}  \nif (!this.getCooldown('warcry') && friends.length > 5) {\n    this.warcry();\n}  \nelse if ((this.now() > 15 || this.health < 150) && !this.getCooldown('terrify')) {\n    this.terrify();\n}\nelse if (this.health < 75 && this.pos.x > furthestFriendX - 5) {\n    this.move({x: 10, y: 27});\n}\nelse if (this.pos.x > furthestFriendX - 1 && this.now() < 50) {\n    this.shield();\n}\nelse {\n    this.attack(enemy);\n}\nthis.say(\"Defend!\", {targetPos: {x: 30, y: Infinity}});\n\n// You can also command your troops with this.say():\n//this.say(\"Defend!\", {targetPos: {x: 30, y: 30}}));\n//this.say(\"Attack!\", {target: enemy});\n//this.say(\"Move!\", {targetPos: {x: 40, y: 40});\n\n// You can store state on this across frames:\n//this.lastHealth = this.health;\n*/"}},"teamSpells":{"ogres":["programmable-brawler/chooseAction","programmable-shaman/chooseAction","ogre-base/chooseAction"],"humans":["programmable-librarian/chooseAction","programmable-tharin/chooseAction","human-base/chooseAction"]},"submittedCodeLanguage":"javascript","playtime":9753,"codeLanguage":"javascript"}
+levelData = {"_id":"53c997066567c600002a43d0","name":"Dungeon Arena","icon":"db/level/53173f76c269d400000543c2/11_dungeon.png","banner":"db/level/53173f76c269d400000543c2/dungeon_arena.png","employerDescription":"Players:\n* Attempt to destroy the enemy base.\n* Choose and control heroes to attack with.\n* Choose which types of lesser units to build and have limited control over them.\n* Try to write strategies that counter other enemy strategies.\n* Play on a small map.","systems":[],"thangs":[],"scripts":[],"documentation":{"generalArticles":[],"specificArticles":[]},"description":"This level is indescribably flarmy!","version":{"minor":0,"major":0,"isLatestMajor":true,"isLatestMinor":true}};
+
+module.exports = ->
+  session = new LevelSession(levelSessionData)
+  v = new LevelSessionCodeView({session:session})
+  request = jasmine.Ajax.requests.mostRecent()
+  request.response({status: 200, responseText: JSON.stringify(levelData)})
+  console.log 'okay should be fine'
+  v
diff --git a/test/demo/views/user/JobProfileView.demo.coffee b/test/demo/views/user/JobProfileView.demo.coffee
new file mode 100644
index 000000000..17ac8767b
--- /dev/null
+++ b/test/demo/views/user/JobProfileView.demo.coffee
@@ -0,0 +1,576 @@
+ProfileView = require 'views/account/profile_view'
+
+responses =
+  '/db/user/joe/nameToID':'512ef4805a67a8c507000001'
+  
+  '/db/user/512ef4805a67a8c507000001': {
+    "_id": "512ef4805a67a8c507000001",
+    "__v": 47,
+    "email": "livelily@gmail.com",
+    "emailSubscriptions": [
+      "announcement",
+      "notification",
+      "developer",
+      "level_creator",
+      "tester",
+      "article_editor",
+      "translator",
+      "support"
+    ],
+    "facebookID": "4301215",
+    "firstName": "Nick",
+    "gender": "male",
+    "lastName": "Winter",
+    "name": "Nick!",
+    "photoURL": "db/user/512ef4805a67a8c507000001/nick_wizard.png",
+    "volume": 0,
+    "wizardColor1": 0.4,
+    "testGroupNumber": 217,
+    "mailChimp": {
+      "leid": "70264209",
+      "euid": "c4418e2abd",
+      "email": "livelily@gmail.com"
+    },
+    "hourOfCode": true,
+    "hourOfCodeComplete": true,
+    "signedCLA": "Fri Jan 03 2014 14:40:18 GMT-0800 (PST)",
+    "wizard": {
+      "colorConfig": {
+        "boots": {
+          "lightness": 0.1647058823529412,
+          "saturation": 0.023809523809523805,
+          "hue": 0
+        },
+        "spell": {
+          "hue": 0.7490196078431373,
+          "saturation": 0.4106280193236715,
+          "lightness": 0.5941176470588235
+        },
+        "cloud": {
+          "lightness": 0.14,
+          "saturation": 1,
+          "hue": 0
+        },
+        "clothes": {
+          "lightness": 0.1411764705882353,
+          "saturation": 0,
+          "hue": 0
+        },
+        "trim": {
+          "hue": 0.5,
+          "saturation": 0.009900990099009936,
+          "lightness": 0.19803921568627453
+        }
+      }
+    },
+    "aceConfig": {
+      "liveCompletion": true,
+      "indentGuides": true,
+      "invisibles": true,
+      "keyBindings": "emacs",
+      "behaviors": true,
+      "language": "javascript"
+    },
+    "lastLevel": "drink-me",
+    "gplusID": "110703832132860599877",
+    "jobProfile": {
+      "photoURL": "db/user/512ef4805a67a8c507000001/nick_bokeh_small.jpg",
+      "links": [
+#        {
+#          "name": "Twitter",
+#          "link": "https://twitter.com/nwinter"
+#        },
+#        {
+#          "name": "Facebook",
+#          "link": "https://www.facebook.com/nwinter"
+#        },
+        {
+          "name": "LinkedIn",
+          "link": "https://www.linkedin.com/in/nwinter"
+        },
+        {
+          "name": "Blog",
+          "link": "http://blog.nickwinter.net/"
+        },
+        {
+          "name": "Personal Site",
+          "link": "http://www.nickwinter.net/"
+        },
+        {
+          "name": "GitHub",
+          "link": "https://github.com/nwinter"
+        },
+        {
+          "name": "G+",
+          "link": "https://plus.google.com/u/0/+NickWinter"
+        }
+      ],
+      "projects": [
+        {
+          "name": "The Motivation Hacker",
+          "description": "I wrote a book. *The Motivation Hacker* shows you how to summon extreme amounts of motivation to accomplish anything you can think of. From precommitment to rejection therapy, this is your field guide to getting yourself to want to do everything you always wanted to want to do.",
+          "picture": "db/user/512ef4805a67a8c507000001/the_motivation_hacker_thumb.jpg",
+          "link": "http://www.nickwinter.net/motivation-hacker"
+        },
+        {
+          "name": "Quantified Mind",
+          "description": "Quantified Mind is a tool that quickly, reliably, and comprehensively measures your basic cognitive abilities. We've adapted tests used by psychologists to a practical web application that you can use whenever, wherever, and as often as you want.",
+          "picture": "db/user/512ef4805a67a8c507000001/screenshot.png",
+          "link": "http://www.quantified-mind.com/"
+        },
+        {
+          "link": "https://github.com/nwinter/telepath-logger",
+          "name": "Telepath",
+          "description": "A happy Mac keylogger for Quantified Self purposes. It also now serves as a time lapse heads-up-display thing. I used it to make a [time-lapse video of myself working an 120-hour workweek](http://blog.nickwinter.net/the-120-hour-workweek-epic-coding-time-lapse).",
+          "picture": "db/user/512ef4805a67a8c507000001/687474703a2f2f63646e2e736574742e636f6d2f696d616765732f757365722f32303133313131303139353534393937375a30356665633666623234623937323263373733636231303537613130626336365f66726f6e742e6a7067"
+        }
+      ],
+      "education": [
+        {
+          "school": "Oberlin College",
+          "degree": "BA Computer Science, Mathematics, and East Asian Studies, highest honors in CS",
+          "duration": "Aug 2004 - May 2008",
+          "description": "Cofounded Oberlin Street Art and did all sorts of crazy missions without telling anyone about it."
+        }
+      ],
+      "work": [
+        {
+          "employer": "CodeCombat",
+          "role": "Cofounder",
+          "duration": "Jan 2013 - present",
+          "description": "Programming a programming game for learning programming to be a programming programmer of programmatic programs."
+        },
+        {
+          "employer": "Skritter",
+          "role": "Cofounder",
+          "duration": "May 2008 - present",
+          "description": "I coded, I designed, I marketed, I businessed, I wrote, I drudged, I cheffed, I laughed, I cried. But mostly I emailed. God, so much email."
+        }
+      ],
+      "visa": "Authorized to work in the US",
+      "longDescription": "I cofounded Skritter, am working on CodeCombat, helped with Quantified Mind, live in San Francisco, went to Oberlin College, wrote a book about motivation hacking, and can do anything.\n\nI like hacking on startups, pigs with dogs for feet, and Smash Bros. I dislike shoes, mortality, and Java.\n\nDo you love hiring renegade maverick commandos who can't abide the system? Are you looking to hire the sample job profile candidate of the job profile system? Are you just testing this thing? If your answer is yes, yes yes!–then let us talk.",
+      "shortDescription": "Maniac two-time startup cofounder looking to test the system and see what a job profile might look like. Can't nobody hold him down.",
+      "experience": 6,
+      "skills": [
+        "python",
+        "coffeescript",
+        "node",
+        "ios",
+        "objective-c",
+        "javascript",
+        "app-engine",
+        "mongodb",
+        "web dev",
+        "django",
+        "backbone",
+        "chinese",
+        "qs",
+        "writing"
+      ],
+      "country": "USA",
+      "city": "San Francisco",
+      "active": false,
+      "lookingFor": "Full-time",
+      "name": "Nick Winter",
+      "updated": "2014-07-12T01:48:42.980Z",
+      "jobTitle": "Mutant Code Gorilla"
+    },
+    "jobProfileApproved": false,
+    "emails": {
+      "anyNotes": {
+        "enabled": true
+      },
+      "generalNews": {
+        "enabled": true
+      },
+      "archmageNews": {
+        "enabled": true
+      },
+      "artisanNews": {
+        "enabled": true
+      },
+      "adventurerNews": {
+        "enabled": true
+      },
+      "scribeNews": {
+        "enabled": true
+      },
+      "diplomatNews": {
+        "enabled": true
+      },
+      "ambassadorNews": {
+        "enabled": true
+      }
+    },
+    "activity": {
+      "viewed_by_employer": {
+        "last": "2014-06-19T20:21:43.747Z",
+        "count": 6,
+        "first": "2014-06-12T01:37:38.278Z"
+      },
+      "view_candidate": {
+        "first": "2014-06-10T19:59:30.773Z",
+        "count": 661,
+        "last": "2014-07-11T02:14:40.131Z"
+      },
+      "login": {
+        "first": "2014-06-10T21:55:08.968Z",
+        "count": 22,
+        "last": "2014-07-16T16:32:31.661Z"
+      },
+      "contacted_by_employer": {
+        "first": "2014-06-19T20:24:51.870Z",
+        "count": 1,
+        "last": "2014-06-19T20:24:51.870Z"
+      }
+    },
+    "slug": "nick",
+    "jobProfileNotes": "Nick used to be the **#1 Brawlwood player** on CodeCombat. He wrote most of the game engine, so that's totally cheating. Now other players have surpassed him by emulating his moves and improving his strategy. If you like the sixth Rocky movie, you might still want to hire this aging hero even in his fading senescence.",
+    "simulatedFor": 2363,
+    "simulatedBy": 103674,
+    "preferredLanguage": "en-US",
+    "anonymous": false,
+    "permissions": [
+      "admin"
+    ],
+    "autocastDelay": 90019001,
+    "music": false,
+    "dateCreated": "2013-02-28T06:09:04.743Z"
+  },
+
+  '/db/user/512ef4805a67a8c507000001/level.sessions/employer': [
+    {
+      "_id": "53179b49b483edfcdb7ef13e",
+      "level": {
+        "original": "53173f76c269d400000543c2",
+        "majorVersion": 0
+      },
+      "code": {
+      },
+      "submitted": false,
+      "teamSpells": {
+        "ogres": [
+          "programmable-brawler/chooseAction",
+          "programmable-shaman/chooseAction",
+          "ogre-base/chooseAction"
+        ],
+        "humans": [
+          "programmable-librarian/chooseAction",
+          "programmable-tharin/chooseAction",
+          "human-base/chooseAction"
+        ]
+      },
+      "levelID": "dungeon-arena",
+      "levelName": "Dungeon Arena",
+      "submittedCodeLanguage": "javascript",
+      "playtime": 33,
+      "codeLanguage": "javascript"
+    },
+    {
+      "_id": "53336ee91506ed33756f73e5",
+      "level": {
+        "original": "533353722a61b7ca6832840c",
+        "majorVersion": 0
+      },
+      "code": {
+      },
+      "teamSpells": {
+        "humans": [
+          "programmable-coin/chooseAction",
+          "tharin/chooseAction",
+          "wizard-purple/chooseAction"
+        ]
+      },
+      "levelID": "gold-rush",
+      "levelName": "Resource gathering multiplayer",
+      "submittedCodeLanguage": "javascript",
+      "playtime": 0,
+      "codeLanguage": "javascript"
+    },
+    {
+      "_id": "52ae32cbef42c52f1300000d",
+      "level": {
+        "original": "52ae2460ef42c52f13000008",
+        "majorVersion": 0
+      },
+      "levelID": "gridmancer",
+      "levelName": "Gridmancer",
+      "code": {
+      },
+      "teamSpells": {
+        "humans": [
+          "thoktar"
+        ]
+      },
+      "submitted": false,
+      "submittedCodeLanguage": "javascript",
+      "playtime": 302,
+      "codeLanguage": "javascript"
+    },
+    {
+      "_id": "5334901f0a0f9b286f57382c",
+      "level": {
+        "original": "533353722a61b7ca6832840c",
+        "majorVersion": 0
+      },
+      "team": "humans",
+      "code": {
+      },
+      "teamSpells": {
+        "common": [
+          "coin-generator-9000/chooseAction"
+        ],
+        "humans": [
+          "tharin/chooseAction"
+        ],
+        "ogres": [
+          "mak-fod/chooseAction"
+        ]
+      },
+      "levelID": "gold-rush",
+      "levelName": "Gold Rush",
+      "totalScore": 39.23691444835561,
+      "submitted": true,
+      "submittedCodeLanguage": "javascript",
+      "playtime": 1158,
+      "codeLanguage": "javascript"
+    },
+    {
+      "_id": "52dea9b77e486eeb97000001",
+      "level": {
+        "original": "52d97ecd32362bc86e004e87",
+        "majorVersion": 0
+      },
+      "levelID": "brawlwood",
+      "levelName": "Brawlwood",
+      "code": {
+      },
+      "totalScore": 24.138610165979667,
+      "teamSpells": {
+        "humans": [
+          "programmable-artillery/chooseAction",
+          "programmable-artillery/hear",
+          "programmable-soldier/chooseAction",
+          "programmable-soldier/hear",
+          "s-arrow-tower/chooseAction",
+          "programmable-archer/chooseAction",
+          "programmable-archer/hear",
+          "human-base/chooseAction",
+          "human-base/hear"
+        ],
+        "ogres": [
+          "programmable-shaman/chooseAction",
+          "programmable-shaman/hear",
+          "n-beam-tower/chooseAction",
+          "programmable-thrower/chooseAction",
+          "programmable-thrower/hear",
+          "programmable-munchkin/chooseAction",
+          "programmable-munchkin/hear",
+          "ogre-base/chooseAction",
+          "ogre-base/hear"
+        ]
+      },
+      "team": "humans",
+      "submitted": true,
+      "submittedCodeLanguage": "javascript",
+      "playtime": 0,
+      "codeLanguage": "javascript"
+    },
+    {
+      "_id": "535701331bfa9bba14b5e03d",
+      "level": {
+        "original": "53558b5a9914f5a90d7ccddb",
+        "majorVersion": 0
+      },
+      "team": "ogres",
+      "levelID": "greed",
+      "levelName": "Greed",
+      "code": {
+      },
+      "teamSpells": {
+        "humans": [
+          "human-base/chooseAction"
+        ],
+        "ogres": [
+          "ogre-base/chooseAction"
+        ],
+        "common": [
+          "well/chooseAction"
+        ]
+      },
+      "totalScore": 36.77589873873074,
+      "submitted": true,
+      "submittedCodeLanguage": "javascript",
+      "playtime": 12893,
+      "codeLanguage": "javascript"
+    },
+    {
+      "_id": "5356fc2e1bfa9bba14b5e039",
+      "level": {
+        "original": "53558b5a9914f5a90d7ccddb",
+        "majorVersion": 0
+      },
+      "team": "humans",
+      "levelID": "greed",
+      "levelName": "Greed",
+      "code": {
+      },
+      "teamSpells": {
+        "humans": [
+          "human-base/chooseAction"
+        ],
+        "ogres": [
+          "ogre-base/chooseAction"
+        ],
+        "common": [
+          "well/chooseAction"
+        ]
+      },
+      "totalScore": 31.538998178536794,
+      "submitted": true,
+      "submittedCodeLanguage": "javascript",
+      "playtime": 15648,
+      "codeLanguage": "javascript"
+    },
+    {
+      "_id": "52fd5bf7e3c53130231726e1",
+      "level": {
+        "original": "52d97ecd32362bc86e004e87",
+        "majorVersion": 0
+      },
+      "team": "ogres",
+      "levelID": "brawlwood",
+      "levelName": "Brawlwood",
+      "submitted": true,
+      "totalScore": 53.73511062513137,
+      "teamSpells": {
+        "humans": [
+          "programmable-artillery/chooseAction",
+          "programmable-artillery/hear",
+          "programmable-soldier/chooseAction",
+          "programmable-soldier/hear",
+          "s-arrow-tower/chooseAction",
+          "programmable-archer/chooseAction",
+          "programmable-archer/hear",
+          "human-base/chooseAction",
+          "human-base/hear"
+        ],
+        "ogres": [
+          "programmable-shaman/chooseAction",
+          "programmable-shaman/hear",
+          "n-beam-tower/chooseAction",
+          "programmable-thrower/chooseAction",
+          "programmable-thrower/hear",
+          "programmable-munchkin/chooseAction",
+          "programmable-munchkin/hear",
+          "ogre-base/chooseAction",
+          "ogre-base/hear"
+        ]
+      },
+      "code": {
+      },
+      "submittedCodeLanguage": "javascript",
+      "playtime": 178,
+      "codeLanguage": "javascript"
+    },
+    {
+      "_id": "5317ad4909098828ed071f4d",
+      "level": {
+        "original": "53173f76c269d400000543c2",
+        "majorVersion": 0
+      },
+      "team": "humans",
+      "levelID": "dungeon-arena",
+      "levelName": "Dungeon Arena",
+      "submitted": true,
+      "totalScore": 38.19039674380126,
+      "code": {
+      },
+      "teamSpells": {
+        "ogres": [
+          "programmable-brawler/chooseAction",
+          "programmable-shaman/chooseAction",
+          "ogre-base/chooseAction"
+        ],
+        "humans": [
+          "programmable-librarian/chooseAction",
+          "programmable-tharin/chooseAction",
+          "human-base/chooseAction"
+        ]
+      },
+      "submittedCodeLanguage": "javascript",
+      "playtime": 9753,
+      "codeLanguage": "javascript"
+    },
+    {
+      "_id": "53361c80948ad7a777a10d9c",
+      "level": {
+        "original": "533353722a61b7ca6832840c",
+        "majorVersion": 0
+      },
+      "team": "ogres",
+      "levelID": "gold-rush",
+      "levelName": "Gold Rush",
+      "code": {
+      },
+      "teamSpells": {
+        "common": [
+          "coin-generator-9000/chooseAction"
+        ],
+        "humans": [
+          "tharin/chooseAction"
+        ],
+        "ogres": [
+          "mak-fod/chooseAction"
+        ]
+      },
+      "totalScore": 40.73558595296533,
+      "submitted": true,
+      "submittedCodeLanguage": "javascript",
+      "playtime": 1014,
+      "codeLanguage": "javascript"
+    },
+    {
+      "_id": "531920069f44be00001a7aef",
+      "level": {
+        "original": "53173f76c269d400000543c2",
+        "majorVersion": 0
+      },
+      "team": "ogres",
+      "levelID": "dungeon-arena",
+      "levelName": "Dungeon Arena",
+      "submitted": true,
+      "totalScore": 26.50666470188054,
+      "code": {
+      },
+      "teamSpells": {
+        "ogres": [
+          "programmable-brawler/chooseAction",
+          "programmable-shaman/chooseAction",
+          "ogre-base/chooseAction"
+        ],
+        "humans": [
+          "programmable-librarian/chooseAction",
+          "programmable-tharin/chooseAction",
+          "human-base/chooseAction"
+        ]
+      },
+      "submittedCodeLanguage": "javascript",
+      "playtime": 1786,
+      "codeLanguage": "javascript"
+    }
+  ]
+
+module.exports = ->
+  me.isAdmin = -> false
+  me.set('permissions', ['employer'])
+  v = new ProfileView({}, 'joe')
+  for url, responseBody of responses
+    requests = jasmine.Ajax.requests.filter(url)
+    if not requests.length
+      console.error "could not find response for <#{url}>", responses
+      continue
+    request = requests[0]
+    request.response({status: 200, responseText: JSON.stringify(responseBody)})
+  #  v.$el = v.$el.find('.main-content-area')
+  v