diff --git a/app/locale/ar.coffee b/app/locale/ar.coffee
index e3e9a0caf..00b13df29 100644
--- a/app/locale/ar.coffee
+++ b/app/locale/ar.coffee
@@ -296,6 +296,7 @@ module.exports = nativeDescription: "العربية", englishDescription: "Arabi
 #    tip_hofstadters_law: "Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law."
 #    tip_premature_optimization: "Premature optimization is the root of all evil. - Donald Knuth"
 #    tip_brute_force: "When in doubt, use brute force. - Ken Thompson"
+#    tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
 #    customize_wizard: "Customize Wizard"
 
 #  game_menu:
diff --git a/app/locale/bg.coffee b/app/locale/bg.coffee
index d3332d086..9784c59a2 100644
--- a/app/locale/bg.coffee
+++ b/app/locale/bg.coffee
@@ -296,6 +296,7 @@ module.exports = nativeDescription: "български език", englishDescri
 #    tip_hofstadters_law: "Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law."
 #    tip_premature_optimization: "Premature optimization is the root of all evil. - Donald Knuth"
 #    tip_brute_force: "When in doubt, use brute force. - Ken Thompson"
+#    tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
 #    customize_wizard: "Customize Wizard"
 
 #  game_menu:
diff --git a/app/locale/ca.coffee b/app/locale/ca.coffee
index 94f614363..c838b2a69 100644
--- a/app/locale/ca.coffee
+++ b/app/locale/ca.coffee
@@ -296,6 +296,7 @@ module.exports = nativeDescription: "Català", englishDescription: "Catalan", tr
 #    tip_hofstadters_law: "Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law."
 #    tip_premature_optimization: "Premature optimization is the root of all evil. - Donald Knuth"
 #    tip_brute_force: "When in doubt, use brute force. - Ken Thompson"
+#    tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
     customize_wizard: "Personalitza el teu bruixot"
 
   game_menu:
diff --git a/app/locale/cs.coffee b/app/locale/cs.coffee
index 2b3281da2..1b59c262f 100644
--- a/app/locale/cs.coffee
+++ b/app/locale/cs.coffee
@@ -296,6 +296,7 @@ module.exports = nativeDescription: "čeština", englishDescription: "Czech", tr
 #    tip_hofstadters_law: "Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law."
 #    tip_premature_optimization: "Premature optimization is the root of all evil. - Donald Knuth"
 #    tip_brute_force: "When in doubt, use brute force. - Ken Thompson"
+#    tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
     customize_wizard: "Upravit Kouzelníka"
 
   game_menu:
diff --git a/app/locale/da.coffee b/app/locale/da.coffee
index ed5ce5386..29131e1bf 100644
--- a/app/locale/da.coffee
+++ b/app/locale/da.coffee
@@ -296,6 +296,7 @@ module.exports = nativeDescription: "dansk", englishDescription: "Danish", trans
 #    tip_hofstadters_law: "Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law."
 #    tip_premature_optimization: "Premature optimization is the root of all evil. - Donald Knuth"
 #    tip_brute_force: "When in doubt, use brute force. - Ken Thompson"
+#    tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
     customize_wizard: "Tilpas troldmand"
 
   game_menu:
diff --git a/app/locale/de-AT.coffee b/app/locale/de-AT.coffee
index 0087e1ea0..d34585229 100644
--- a/app/locale/de-AT.coffee
+++ b/app/locale/de-AT.coffee
@@ -296,6 +296,7 @@ module.exports = nativeDescription: "Deutsch (Österreich)", englishDescription:
 #    tip_hofstadters_law: "Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law."
 #    tip_premature_optimization: "Premature optimization is the root of all evil. - Donald Knuth"
 #    tip_brute_force: "When in doubt, use brute force. - Ken Thompson"
+#    tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
     customize_wizard: "Bearbeite den Zauberer"
 
   game_menu:
diff --git a/app/locale/de-CH.coffee b/app/locale/de-CH.coffee
index d2bd3ad7e..7b6b1451b 100644
--- a/app/locale/de-CH.coffee
+++ b/app/locale/de-CH.coffee
@@ -296,6 +296,7 @@ module.exports = nativeDescription: "Deutsch (Schweiz)", englishDescription: "Ge
 #    tip_hofstadters_law: "Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law."
 #    tip_premature_optimization: "Premature optimization is the root of all evil. - Donald Knuth"
 #    tip_brute_force: "When in doubt, use brute force. - Ken Thompson"
+#    tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
     customize_wizard: "Zauberer apasse"
 
   game_menu:
diff --git a/app/locale/de-DE.coffee b/app/locale/de-DE.coffee
index c16e3adee..0a3388ea5 100644
--- a/app/locale/de-DE.coffee
+++ b/app/locale/de-DE.coffee
@@ -296,6 +296,7 @@ module.exports = nativeDescription: "Deutsch (Deutschland)", englishDescription:
     tip_hofstadters_law: "Hofstadter's Gesetz: Es dauert immer länger als erwartet, auch wenn du Hofstadter's Gesetz anwendest."
     tip_premature_optimization: "Vorzeitige Optimierung ist die Wurzel allen Übels (oder mindestens des meisten) bei der Programmierung - Donald Knuth"
     tip_brute_force: "Verwende im Zweifelsfall rohe Gewalt. - Ken Thompson"
+#    tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
     customize_wizard: "Bearbeite den Zauberer"
 
   game_menu:
diff --git a/app/locale/el.coffee b/app/locale/el.coffee
index 3947e9500..1ed8c7f4a 100644
--- a/app/locale/el.coffee
+++ b/app/locale/el.coffee
@@ -296,6 +296,7 @@ module.exports = nativeDescription: "Ελληνικά", englishDescription: "Gre
 #    tip_hofstadters_law: "Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law."
 #    tip_premature_optimization: "Premature optimization is the root of all evil. - Donald Knuth"
 #    tip_brute_force: "When in doubt, use brute force. - Ken Thompson"
+#    tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
     customize_wizard: "Προσαρμογή Μάγου"
 
   game_menu:
diff --git a/app/locale/en-AU.coffee b/app/locale/en-AU.coffee
index d4492aa88..e49714380 100644
--- a/app/locale/en-AU.coffee
+++ b/app/locale/en-AU.coffee
@@ -296,6 +296,7 @@ module.exports = nativeDescription: "English (AU)", englishDescription: "English
 #    tip_hofstadters_law: "Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law."
 #    tip_premature_optimization: "Premature optimization is the root of all evil. - Donald Knuth"
 #    tip_brute_force: "When in doubt, use brute force. - Ken Thompson"
+#    tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
 #    customize_wizard: "Customize Wizard"
 
 #  game_menu:
diff --git a/app/locale/en-GB.coffee b/app/locale/en-GB.coffee
index d9ed831b1..57028b941 100644
--- a/app/locale/en-GB.coffee
+++ b/app/locale/en-GB.coffee
@@ -296,6 +296,7 @@ module.exports = nativeDescription: "English (UK)", englishDescription: "English
 #    tip_hofstadters_law: "Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law."
 #    tip_premature_optimization: "Premature optimization is the root of all evil. - Donald Knuth"
 #    tip_brute_force: "When in doubt, use brute force. - Ken Thompson"
+#    tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
     customize_wizard: "Customise Wizard"
 
 #  game_menu:
diff --git a/app/locale/en-US.coffee b/app/locale/en-US.coffee
index eb1fb863c..b2d0a4bec 100644
--- a/app/locale/en-US.coffee
+++ b/app/locale/en-US.coffee
@@ -296,6 +296,7 @@ module.exports = nativeDescription: "English (US)", englishDescription: "English
 #    tip_hofstadters_law: "Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law."
 #    tip_premature_optimization: "Premature optimization is the root of all evil. - Donald Knuth"
 #    tip_brute_force: "When in doubt, use brute force. - Ken Thompson"
+#    tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
 #    customize_wizard: "Customize Wizard"
 
 #  game_menu:
diff --git a/app/locale/en.coffee b/app/locale/en.coffee
index e13714240..e7f15c8c5 100644
--- a/app/locale/en.coffee
+++ b/app/locale/en.coffee
@@ -296,6 +296,7 @@
     tip_hofstadters_law: "Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law."
     tip_premature_optimization: "Premature optimization is the root of all evil. - Donald Knuth"
     tip_brute_force: "When in doubt, use brute force. - Ken Thompson"
+    tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
     customize_wizard: "Customize Wizard"
 
   game_menu:
diff --git a/app/locale/es-419.coffee b/app/locale/es-419.coffee
index a415e6c9f..05054a66c 100644
--- a/app/locale/es-419.coffee
+++ b/app/locale/es-419.coffee
@@ -296,6 +296,7 @@ module.exports = nativeDescription: "español (América Latina)", englishDescrip
     tip_hofstadters_law: "Ley de Hofstadter: Siempre toma más tiempo del que esperas, inclso cuando tienes en cuenta la ley de Hofstadter."
     tip_premature_optimization: "La optimización prematura es la raíz de la maldad. - Donald Knuth"
     tip_brute_force: "Cuando tengas duda, usa la fuerza bruta. - Ken Thompson"
+#    tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
     customize_wizard: "Personalizar Hechicero"
 
   game_menu:
diff --git a/app/locale/es-ES.coffee b/app/locale/es-ES.coffee
index 3a03d1d82..62ce99731 100644
--- a/app/locale/es-ES.coffee
+++ b/app/locale/es-ES.coffee
@@ -296,6 +296,7 @@ module.exports = nativeDescription: "español (ES)", englishDescription: "Spanis
 #    tip_hofstadters_law: "Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law."
     tip_premature_optimization: "La optimizacion prematura es la raiz de todo mal. - Donald Knuth"
     tip_brute_force: "Cuando haya dudas, usa la fuerza bruta. - Ken Thompson"
+#    tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
     customize_wizard: "Personalizar Mago"
 
   game_menu:
diff --git a/app/locale/fa.coffee b/app/locale/fa.coffee
index 5139f5a84..7de7917b8 100644
--- a/app/locale/fa.coffee
+++ b/app/locale/fa.coffee
@@ -296,6 +296,7 @@ module.exports = nativeDescription: "فارسی", englishDescription: "Persian",
 #    tip_hofstadters_law: "Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law."
 #    tip_premature_optimization: "Premature optimization is the root of all evil. - Donald Knuth"
 #    tip_brute_force: "When in doubt, use brute force. - Ken Thompson"
+#    tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
 #    customize_wizard: "Customize Wizard"
 
 #  game_menu:
diff --git a/app/locale/fi.coffee b/app/locale/fi.coffee
index b0fe0d705..5d474dca0 100644
--- a/app/locale/fi.coffee
+++ b/app/locale/fi.coffee
@@ -296,6 +296,7 @@ module.exports = nativeDescription: "suomi", englishDescription: "Finnish", tran
 #    tip_hofstadters_law: "Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law."
 #    tip_premature_optimization: "Premature optimization is the root of all evil. - Donald Knuth"
 #    tip_brute_force: "When in doubt, use brute force. - Ken Thompson"
+#    tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
 #    customize_wizard: "Customize Wizard"
 
 #  game_menu:
diff --git a/app/locale/fr.coffee b/app/locale/fr.coffee
index 972aab0c2..f43a79559 100644
--- a/app/locale/fr.coffee
+++ b/app/locale/fr.coffee
@@ -296,6 +296,7 @@ module.exports = nativeDescription: "français", englishDescription: "French", t
     tip_hofstadters_law: "Loi de Hofstadter: Il faut toujours plus de temps que prévu, même si vous prenez en compte la loi de Hofstadter."
     tip_premature_optimization: "L'optimisation prématurée est la racine de tous les maux. - Donald Knuth"
     tip_brute_force: "En cas de doute, utiliser la force brute. - Ken Thompson"
+#    tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
     customize_wizard: "Personnaliser le magicien"
 
   game_menu:
diff --git a/app/locale/gl.coffee b/app/locale/gl.coffee
index 85f86d333..b969cb6c6 100644
--- a/app/locale/gl.coffee
+++ b/app/locale/gl.coffee
@@ -296,6 +296,7 @@ module.exports = nativeDescription: "Galego", englishDescription: "Galician", tr
 #    tip_hofstadters_law: "Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law."
     tip_premature_optimization: "A optimizacion prematura é a raíz de todo mal. - Donald Knuth"
     tip_brute_force: "Cando hai dúbidas, usa a forza bruta. - Ken Thompson"
+#    tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
     customize_wizard: "Persoalizar Mago"
 
   game_menu:
diff --git a/app/locale/he.coffee b/app/locale/he.coffee
index a4693e33c..dea375e6b 100644
--- a/app/locale/he.coffee
+++ b/app/locale/he.coffee
@@ -296,6 +296,7 @@ module.exports = nativeDescription: "עברית", englishDescription: "Hebrew",
 #    tip_hofstadters_law: "Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law."
 #    tip_premature_optimization: "Premature optimization is the root of all evil. - Donald Knuth"
 #    tip_brute_force: "When in doubt, use brute force. - Ken Thompson"
+#    tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
 #    customize_wizard: "Customize Wizard"
 
 #  game_menu:
diff --git a/app/locale/hi.coffee b/app/locale/hi.coffee
index 7a1fbf1e4..a810e327c 100644
--- a/app/locale/hi.coffee
+++ b/app/locale/hi.coffee
@@ -296,6 +296,7 @@ module.exports = nativeDescription: "मानक हिन्दी", englishDe
 #    tip_hofstadters_law: "Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law."
 #    tip_premature_optimization: "Premature optimization is the root of all evil. - Donald Knuth"
 #    tip_brute_force: "When in doubt, use brute force. - Ken Thompson"
+#    tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
 #    customize_wizard: "Customize Wizard"
 
 #  game_menu:
diff --git a/app/locale/hu.coffee b/app/locale/hu.coffee
index f7e1a85fa..18afa2096 100644
--- a/app/locale/hu.coffee
+++ b/app/locale/hu.coffee
@@ -296,6 +296,7 @@ module.exports = nativeDescription: "magyar", englishDescription: "Hungarian", t
 #    tip_hofstadters_law: "Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law."
 #    tip_premature_optimization: "Premature optimization is the root of all evil. - Donald Knuth"
 #    tip_brute_force: "When in doubt, use brute force. - Ken Thompson"
+#    tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
     customize_wizard: "Varázsló testreszabása"
 
   game_menu:
diff --git a/app/locale/id.coffee b/app/locale/id.coffee
index 6618d5b7a..896eb4f39 100644
--- a/app/locale/id.coffee
+++ b/app/locale/id.coffee
@@ -296,6 +296,7 @@ module.exports = nativeDescription: "Bahasa Indonesia", englishDescription: "Ind
 #    tip_hofstadters_law: "Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law."
 #    tip_premature_optimization: "Premature optimization is the root of all evil. - Donald Knuth"
 #    tip_brute_force: "When in doubt, use brute force. - Ken Thompson"
+#    tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
 #    customize_wizard: "Customize Wizard"
 
 #  game_menu:
diff --git a/app/locale/it.coffee b/app/locale/it.coffee
index c0ca2f6b1..fcffa53e8 100644
--- a/app/locale/it.coffee
+++ b/app/locale/it.coffee
@@ -296,6 +296,7 @@ module.exports = nativeDescription: "Italiano", englishDescription: "Italian", t
 #    tip_hofstadters_law: "Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law."
 #    tip_premature_optimization: "Premature optimization is the root of all evil. - Donald Knuth"
 #    tip_brute_force: "When in doubt, use brute force. - Ken Thompson"
+#    tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
     customize_wizard: "Personalizza il mago"
 
   game_menu:
diff --git a/app/locale/ja.coffee b/app/locale/ja.coffee
index a47d573e4..a3e89d596 100644
--- a/app/locale/ja.coffee
+++ b/app/locale/ja.coffee
@@ -296,6 +296,7 @@ module.exports = nativeDescription: "日本語", englishDescription: "Japanese",
 #    tip_hofstadters_law: "Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law."
 #    tip_premature_optimization: "Premature optimization is the root of all evil. - Donald Knuth"
 #    tip_brute_force: "When in doubt, use brute force. - Ken Thompson"
+#    tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
     customize_wizard: "魔法使いの設定"
 
   game_menu:
diff --git a/app/locale/ko.coffee b/app/locale/ko.coffee
index 619fc2875..c3e1b92fe 100644
--- a/app/locale/ko.coffee
+++ b/app/locale/ko.coffee
@@ -296,6 +296,7 @@ module.exports = nativeDescription: "한국어", englishDescription: "Korean", t
 #    tip_hofstadters_law: "Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law."
 #    tip_premature_optimization: "Premature optimization is the root of all evil. - Donald Knuth"
 #    tip_brute_force: "When in doubt, use brute force. - Ken Thompson"
+#    tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
     customize_wizard: "사용자 정의 마법사"
 
   game_menu:
diff --git a/app/locale/lt.coffee b/app/locale/lt.coffee
index 1cc498d2e..dd4b93dc4 100644
--- a/app/locale/lt.coffee
+++ b/app/locale/lt.coffee
@@ -296,6 +296,7 @@ module.exports = nativeDescription: "lietuvių kalba", englishDescription: "Lith
 #    tip_hofstadters_law: "Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law."
 #    tip_premature_optimization: "Premature optimization is the root of all evil. - Donald Knuth"
 #    tip_brute_force: "When in doubt, use brute force. - Ken Thompson"
+#    tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
 #    customize_wizard: "Customize Wizard"
 
 #  game_menu:
diff --git a/app/locale/ms.coffee b/app/locale/ms.coffee
index d94a7d2d7..7753985d6 100644
--- a/app/locale/ms.coffee
+++ b/app/locale/ms.coffee
@@ -296,6 +296,7 @@ module.exports = nativeDescription: "Bahasa Melayu", englishDescription: "Bahasa
 #    tip_hofstadters_law: "Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law."
 #    tip_premature_optimization: "Premature optimization is the root of all evil. - Donald Knuth"
 #    tip_brute_force: "When in doubt, use brute force. - Ken Thompson"
+#    tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
 #    customize_wizard: "Customize Wizard"
 
 #  game_menu:
diff --git a/app/locale/nb.coffee b/app/locale/nb.coffee
index ff0688d5f..39492f06a 100644
--- a/app/locale/nb.coffee
+++ b/app/locale/nb.coffee
@@ -296,6 +296,7 @@ module.exports = nativeDescription: "Norsk Bokmål", englishDescription: "Norweg
     tip_hofstadters_law: "Hofstadters Lov: Ting tar alltid lenger tid enn du tror, selv når du tar Hofstadters Lov med i beregningen."
 #    tip_premature_optimization: "Premature optimization is the root of all evil. - Donald Knuth"
 #    tip_brute_force: "When in doubt, use brute force. - Ken Thompson"
+#    tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
     customize_wizard: "Tilpass Trollmann"
 
   game_menu:
diff --git a/app/locale/nl-BE.coffee b/app/locale/nl-BE.coffee
index a78c4997b..34683351d 100644
--- a/app/locale/nl-BE.coffee
+++ b/app/locale/nl-BE.coffee
@@ -296,6 +296,7 @@ module.exports = nativeDescription: "Nederlands (België)", englishDescription:
 #    tip_hofstadters_law: "Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law."
 #    tip_premature_optimization: "Premature optimization is the root of all evil. - Donald Knuth"
 #    tip_brute_force: "When in doubt, use brute force. - Ken Thompson"
+#    tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
     customize_wizard: "Pas Tovenaar aan"
 
   game_menu:
diff --git a/app/locale/nl-NL.coffee b/app/locale/nl-NL.coffee
index 01fbe4cef..cbab9b4c3 100644
--- a/app/locale/nl-NL.coffee
+++ b/app/locale/nl-NL.coffee
@@ -296,6 +296,7 @@ module.exports = nativeDescription: "Nederlands (Nederland)", englishDescription
 #    tip_hofstadters_law: "Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law."
 #    tip_premature_optimization: "Premature optimization is the root of all evil. - Donald Knuth"
 #    tip_brute_force: "When in doubt, use brute force. - Ken Thompson"
+#    tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
     customize_wizard: "Pas Tovenaar aan"
 
   game_menu:
diff --git a/app/locale/nn.coffee b/app/locale/nn.coffee
index 47d5b45a0..d2710c50d 100644
--- a/app/locale/nn.coffee
+++ b/app/locale/nn.coffee
@@ -296,6 +296,7 @@ module.exports = nativeDescription: "Norwegian Nynorsk", englishDescription: "No
 #    tip_hofstadters_law: "Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law."
 #    tip_premature_optimization: "Premature optimization is the root of all evil. - Donald Knuth"
 #    tip_brute_force: "When in doubt, use brute force. - Ken Thompson"
+#    tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
 #    customize_wizard: "Customize Wizard"
 
 #  game_menu:
diff --git a/app/locale/no.coffee b/app/locale/no.coffee
index 0be828d6f..1c332da56 100644
--- a/app/locale/no.coffee
+++ b/app/locale/no.coffee
@@ -296,6 +296,7 @@ module.exports = nativeDescription: "Norsk", englishDescription: "Norwegian", tr
 #    tip_hofstadters_law: "Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law."
 #    tip_premature_optimization: "Premature optimization is the root of all evil. - Donald Knuth"
 #    tip_brute_force: "When in doubt, use brute force. - Ken Thompson"
+#    tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
     customize_wizard: "Tilpass trollmann"
 
   game_menu:
diff --git a/app/locale/pl.coffee b/app/locale/pl.coffee
index 0608423e1..60d5e3fb5 100644
--- a/app/locale/pl.coffee
+++ b/app/locale/pl.coffee
@@ -296,6 +296,7 @@ module.exports = nativeDescription: "język polski", englishDescription: "Polish
 #    tip_hofstadters_law: "Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law."
 #    tip_premature_optimization: "Premature optimization is the root of all evil. - Donald Knuth"
 #    tip_brute_force: "When in doubt, use brute force. - Ken Thompson"
+#    tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
     customize_wizard: "Spersonalizuj czarodzieja"
 
   game_menu:
diff --git a/app/locale/pt-BR.coffee b/app/locale/pt-BR.coffee
index bf8c18f41..986ab87aa 100644
--- a/app/locale/pt-BR.coffee
+++ b/app/locale/pt-BR.coffee
@@ -296,6 +296,7 @@ module.exports = nativeDescription: "português do Brasil", englishDescription:
     tip_hofstadters_law: "Lei de Hofstadter: Sempre demora mais do que você espera, mesmo quando você leva em consideração a Lei de Hofstadter."
     tip_premature_optimization: "Uma otimização permatura é a raíz de todos os males. - Donald Knuth"
     tip_brute_force: "Na dúvida, utilize força bruta. - Ken Thompson"
+#    tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
     customize_wizard: "Personalize o feiticeiro"
 
   game_menu:
diff --git a/app/locale/pt-PT.coffee b/app/locale/pt-PT.coffee
index 7ed91940b..2b163f12a 100644
--- a/app/locale/pt-PT.coffee
+++ b/app/locale/pt-PT.coffee
@@ -296,6 +296,7 @@ module.exports = nativeDescription: "Português (Portugal)", englishDescription:
     tip_hofstadters_law: "Lei de Hofstadter: Tudo demora sempre mais do que pensas, mesmo quando levas em conta a Lei de Hofstadter."
     tip_premature_optimization: "Uma otimização permatura é a raíz de todo o mal. - Donald Knuth"
     tip_brute_force: "Quando em dúvida, usa a força bruta. - Ken Thompson"
+#    tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
     customize_wizard: "Personalizar Feiticeiro"
 
   game_menu:
diff --git a/app/locale/ro.coffee b/app/locale/ro.coffee
index 67cff3737..c2db60ea9 100644
--- a/app/locale/ro.coffee
+++ b/app/locale/ro.coffee
@@ -296,6 +296,7 @@ module.exports = nativeDescription: "limba română", englishDescription: "Roman
 #    tip_hofstadters_law: "Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law."
 #    tip_premature_optimization: "Premature optimization is the root of all evil. - Donald Knuth"
 #    tip_brute_force: "When in doubt, use brute force. - Ken Thompson"
+#    tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
     customize_wizard: "Personalizează Wizard-ul"
 
   game_menu:
diff --git a/app/locale/ru.coffee b/app/locale/ru.coffee
index 7756018fc..f356631c7 100644
--- a/app/locale/ru.coffee
+++ b/app/locale/ru.coffee
@@ -296,6 +296,7 @@ module.exports = nativeDescription: "русский", englishDescription: "Russi
     tip_hofstadters_law: "Закон Хофштадтера: Любое дело всегда длится дольше, чем ожидается, даже если учесть закон Хофштадтера."
     tip_premature_optimization: "Поспешная оптимизация - корень всех зол. - Donald Knuth"
     tip_brute_force: "Когда сомневаешься используй грубую силу. - Кен Томпсон"
+#    tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
     customize_wizard: "Настройки волшебника"
 
   game_menu:
@@ -376,13 +377,13 @@ module.exports = nativeDescription: "русский", englishDescription: "Russi
     blocks: "Блокирует" # As in "this shield blocks this much damage"
     skills: "Умения"
     available_for_purchase: "Доступно для покупки"
-    level_to_unlock: "Разблокируется на уровне:" # ToDo: check in interface
+    level_to_unlock: "Разблокируется на уровне:"
     restricted_to_certain_heroes: "Только определенные герои могут играть этот уровень."
 
   skill_docs:
 #    writable: "writable" # Hover over "attack" in Your Skills while playing a level to see most of this
 #    read_only: "read-only"
-    action_name: "имя" # ToDo: check in interface
+    action_name: "имя"
     action_cooldown: "Применяется"
     action_specific_cooldown: "Восстановление"
     action_damage: "Повреждения"
diff --git a/app/locale/sk.coffee b/app/locale/sk.coffee
index 6172439c4..69108f840 100644
--- a/app/locale/sk.coffee
+++ b/app/locale/sk.coffee
@@ -296,6 +296,7 @@ module.exports = nativeDescription: "slovenčina", englishDescription: "Slovak",
 #    tip_hofstadters_law: "Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law."
 #    tip_premature_optimization: "Premature optimization is the root of all evil. - Donald Knuth"
 #    tip_brute_force: "When in doubt, use brute force. - Ken Thompson"
+#    tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
 #    customize_wizard: "Customize Wizard"
 
 #  game_menu:
diff --git a/app/locale/sl.coffee b/app/locale/sl.coffee
index c6dbdc816..46fb45a39 100644
--- a/app/locale/sl.coffee
+++ b/app/locale/sl.coffee
@@ -296,6 +296,7 @@ module.exports = nativeDescription: "slovenščina", englishDescription: "Sloven
 #    tip_hofstadters_law: "Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law."
 #    tip_premature_optimization: "Premature optimization is the root of all evil. - Donald Knuth"
 #    tip_brute_force: "When in doubt, use brute force. - Ken Thompson"
+#    tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
 #    customize_wizard: "Customize Wizard"
 
 #  game_menu:
diff --git a/app/locale/sr.coffee b/app/locale/sr.coffee
index 1aab0fdcf..da99b70eb 100644
--- a/app/locale/sr.coffee
+++ b/app/locale/sr.coffee
@@ -296,6 +296,7 @@ module.exports = nativeDescription: "српски", englishDescription: "Serbian
 #    tip_hofstadters_law: "Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law."
 #    tip_premature_optimization: "Premature optimization is the root of all evil. - Donald Knuth"
 #    tip_brute_force: "When in doubt, use brute force. - Ken Thompson"
+#    tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
     customize_wizard: "Прилагоди Чаробњака"
 
   game_menu:
diff --git a/app/locale/sv.coffee b/app/locale/sv.coffee
index e6737e009..f049ee2ef 100644
--- a/app/locale/sv.coffee
+++ b/app/locale/sv.coffee
@@ -296,6 +296,7 @@ module.exports = nativeDescription: "Svenska", englishDescription: "Swedish", tr
 #    tip_hofstadters_law: "Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law."
 #    tip_premature_optimization: "Premature optimization is the root of all evil. - Donald Knuth"
 #    tip_brute_force: "When in doubt, use brute force. - Ken Thompson"
+#    tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
     customize_wizard: "Skräddarsy trollkarl"
 
   game_menu:
diff --git a/app/locale/th.coffee b/app/locale/th.coffee
index 96652cba4..6dcef569a 100644
--- a/app/locale/th.coffee
+++ b/app/locale/th.coffee
@@ -296,6 +296,7 @@ module.exports = nativeDescription: "ไทย", englishDescription: "Thai", tra
 #    tip_hofstadters_law: "Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law."
 #    tip_premature_optimization: "Premature optimization is the root of all evil. - Donald Knuth"
 #    tip_brute_force: "When in doubt, use brute force. - Ken Thompson"
+#    tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
 #    customize_wizard: "Customize Wizard"
 
   game_menu:
diff --git a/app/locale/tr.coffee b/app/locale/tr.coffee
index cee9ae923..f01928092 100644
--- a/app/locale/tr.coffee
+++ b/app/locale/tr.coffee
@@ -296,6 +296,7 @@ module.exports = nativeDescription: "Türkçe", englishDescription: "Turkish", t
 #    tip_hofstadters_law: "Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law."
 #    tip_premature_optimization: "Premature optimization is the root of all evil. - Donald Knuth"
 #    tip_brute_force: "When in doubt, use brute force. - Ken Thompson"
+#    tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
     customize_wizard: "Sihirbazı Düzenle"
 
   game_menu:
diff --git a/app/locale/uk.coffee b/app/locale/uk.coffee
index 5de3e9a20..d5bd191fa 100644
--- a/app/locale/uk.coffee
+++ b/app/locale/uk.coffee
@@ -296,6 +296,7 @@ module.exports = nativeDescription: "українська мова", englishDesc
 #    tip_hofstadters_law: "Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law."
 #    tip_premature_optimization: "Premature optimization is the root of all evil. - Donald Knuth"
 #    tip_brute_force: "When in doubt, use brute force. - Ken Thompson"
+#    tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
     customize_wizard: "Налаштування персонажа"
 
   game_menu:
diff --git a/app/locale/ur.coffee b/app/locale/ur.coffee
index fe4a58ce2..bda5d5e9c 100644
--- a/app/locale/ur.coffee
+++ b/app/locale/ur.coffee
@@ -296,6 +296,7 @@ module.exports = nativeDescription: "اُردُو", englishDescription: "Urdu",
 #    tip_hofstadters_law: "Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law."
 #    tip_premature_optimization: "Premature optimization is the root of all evil. - Donald Knuth"
 #    tip_brute_force: "When in doubt, use brute force. - Ken Thompson"
+#    tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
 #    customize_wizard: "Customize Wizard"
 
 #  game_menu:
diff --git a/app/locale/vi.coffee b/app/locale/vi.coffee
index 1cc502633..25185e13e 100644
--- a/app/locale/vi.coffee
+++ b/app/locale/vi.coffee
@@ -296,6 +296,7 @@ module.exports = nativeDescription: "Tiếng Việt", englishDescription: "Vietn
 #    tip_hofstadters_law: "Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law."
 #    tip_premature_optimization: "Premature optimization is the root of all evil. - Donald Knuth"
 #    tip_brute_force: "When in doubt, use brute force. - Ken Thompson"
+#    tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
     customize_wizard: "Tùy chỉnh Wizard"
 
   game_menu:
diff --git a/app/locale/zh-HANS.coffee b/app/locale/zh-HANS.coffee
index 8173dce3d..ec3058605 100644
--- a/app/locale/zh-HANS.coffee
+++ b/app/locale/zh-HANS.coffee
@@ -296,6 +296,7 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
     tip_hofstadters_law: "侯世达定律:做事所花费的时间总是比你预期的要长,即使你的预期中考虑了侯世达定律。"
     tip_premature_optimization: "过早的优化是万恶之源。 - 高德纳"
     tip_brute_force: "拿不准时就用穷举法。 - Ken Thompson"
+#    tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
     customize_wizard: "自定义向导"
 
   game_menu:
diff --git a/app/locale/zh-HANT.coffee b/app/locale/zh-HANT.coffee
index 057020f25..493124707 100644
--- a/app/locale/zh-HANT.coffee
+++ b/app/locale/zh-HANT.coffee
@@ -296,6 +296,7 @@ module.exports = nativeDescription: "繁体中文", englishDescription: "Chinese
 #    tip_hofstadters_law: "Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law."
 #    tip_premature_optimization: "Premature optimization is the root of all evil. - Donald Knuth"
 #    tip_brute_force: "When in doubt, use brute force. - Ken Thompson"
+#    tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
     customize_wizard: "自定義巫師"
 
   game_menu:
diff --git a/app/locale/zh-WUU-HANS.coffee b/app/locale/zh-WUU-HANS.coffee
index 325404d2b..d71e50457 100644
--- a/app/locale/zh-WUU-HANS.coffee
+++ b/app/locale/zh-WUU-HANS.coffee
@@ -296,6 +296,7 @@ module.exports = nativeDescription: "吴语", englishDescription: "Wuu (Simplifi
 #    tip_hofstadters_law: "Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law."
 #    tip_premature_optimization: "Premature optimization is the root of all evil. - Donald Knuth"
 #    tip_brute_force: "When in doubt, use brute force. - Ken Thompson"
+#    tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
 #    customize_wizard: "Customize Wizard"
 
 #  game_menu:
diff --git a/app/locale/zh-WUU-HANT.coffee b/app/locale/zh-WUU-HANT.coffee
index e80869dc5..8c9b91c53 100644
--- a/app/locale/zh-WUU-HANT.coffee
+++ b/app/locale/zh-WUU-HANT.coffee
@@ -296,6 +296,7 @@ module.exports = nativeDescription: "吳語", englishDescription: "Wuu (Traditio
 #    tip_hofstadters_law: "Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law."
 #    tip_premature_optimization: "Premature optimization is the root of all evil. - Donald Knuth"
 #    tip_brute_force: "When in doubt, use brute force. - Ken Thompson"
+#    tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
     customize_wizard: "自設定獻路人"
 
   game_menu:
diff --git a/app/schemas/models/user.coffee b/app/schemas/models/user.coffee
index 015145768..1d6396ac0 100644
--- a/app/schemas/models/user.coffee
+++ b/app/schemas/models/user.coffee
@@ -278,6 +278,9 @@ _.extend UserSchema.properties,
     planID: { enum: ['basic'] }
     subscriptionID: { type: 'string' }
     token: { type: 'string' }
+    couponID: { type: 'string' }
+    discountID: { type: 'string' }
+    free: { type: ['boolean', 'string'], format: 'date-time' }
   }
 
 c.extendBasicProperties UserSchema, 'user'
diff --git a/app/styles/play/level/tome/spell.sass b/app/styles/play/level/tome/spell.sass
index b7d2b3169..964288585 100644
--- a/app/styles/play/level/tome/spell.sass
+++ b/app/styles/play/level/tome/spell.sass
@@ -107,6 +107,9 @@
     .executed
       background-color: rgba(110, 110, 110, 0.12)
 
+    .locked-code
+      border: 1px dashed rgba(53, 45, 34, 0.5)
+
     +keyframes(pulseRedBackground)
       from
         background-color: rgba(255, 45, 27, 0.4)
diff --git a/app/templates/play/level/level_loading.jade b/app/templates/play/level/level_loading.jade
index 97babe75c..d2590a7ec 100644
--- a/app/templates/play/level/level_loading.jade
+++ b/app/templates/play/level/level_loading.jade
@@ -52,6 +52,7 @@
     strong.tip.rare(data-i18n='play_level.tip_hofstadters_law') Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.
     strong.tip.rare(data-i18n='play_level.tip_premature_optimization') Premature optimization is the root of all evil - Donald Knuth
     strong.tip.rare(data-i18n='play_level.tip_brute_force') When in doubt, use brute force. - Ken Thompson
+    strong.tip.rare(data-i18n='play_level.tip_extrapolation') There are only two kinds of people: those that can extrapolate from incomplete data...
     strong.tip.rare
       span(data-i18n='play_level.tip_harry') Yer a Wizard, 
       span= me.get('name', true)
diff --git a/app/views/account/PaymentsView.coffee b/app/views/account/PaymentsView.coffee
index 8ec4d888e..931b825a9 100644
--- a/app/views/account/PaymentsView.coffee
+++ b/app/views/account/PaymentsView.coffee
@@ -30,6 +30,7 @@ module.exports = class PaymentsView extends RootView
   onClickStartSubscription: (e) ->
     @openModalView new SubscribeModal()
     window.tracker?.trackEvent 'Show subscription modal', category: 'Subscription', label: 'payments view'
+    window.tracker?.trackPageView "subscription/show-modal", ['Google Analytics']
 
   onSubscribed: ->
     document.location.reload()
diff --git a/app/views/play/WorldMapView.coffee b/app/views/play/WorldMapView.coffee
index 7afe43cad..90e8b05e2 100644
--- a/app/views/play/WorldMapView.coffee
+++ b/app/views/play/WorldMapView.coffee
@@ -124,6 +124,7 @@ module.exports = class WorldMapView extends RootView
         @openModalView? new modal() unless window.currentModal
         if modal is SubscribeModal
           window.tracker?.trackEvent 'Show subscription modal', category: 'Subscription', label: 'world map loadded'
+          window.tracker?.trackPageView "subscription/show-modal", ['Google Analytics']
       , 2000
 
   onSubscribed: ->
@@ -214,6 +215,7 @@ module.exports = class WorldMapView extends RootView
         @openModalView new modal()
         if modal is SubscribeModal
           window.tracker?.trackEvent 'Show subscription modal', category: 'Subscription', label: 'map level clicked'
+          window.tracker?.trackPageView "subscription/show-modal", ['Google Analytics']
       else if $(e.target).attr('disabled')
         Backbone.Mediator.publish 'router:navigate', route: '/contribute/adventurer'
         return
@@ -222,11 +224,13 @@ module.exports = class WorldMapView extends RootView
       else
         @startLevel levelElement
         window.tracker?.trackEvent 'Clicked Level', category: 'World Map', levelID: levelID, ['Google Analytics']
+        window.tracker?.trackPageView "world-map/clicked-level/#{levelID}", ['Google Analytics']
 
   onClickStartLevel: (e) ->
     levelElement = $(e.target).parents('.level-info-container')
     @startLevel levelElement
     window.tracker?.trackEvent 'Clicked Start Level', category: 'World Map', levelID: levelElement.data('level-id'), ['Google Analytics']
+    window.tracker?.trackPageView "world-map/clicked-start-level/#{levelElement.data('level-id')}", ['Google Analytics']
 
   startLevel: (levelElement) ->
     @setupManager?.destroy()
diff --git a/app/views/play/level/LevelLoadingView.coffee b/app/views/play/level/LevelLoadingView.coffee
index 04955721f..99d8150ca 100644
--- a/app/views/play/level/LevelLoadingView.coffee
+++ b/app/views/play/level/LevelLoadingView.coffee
@@ -114,6 +114,7 @@ module.exports = class LevelLoadingView extends CocoView
     @openModalView new modal()
     if modal is SubscribeModal
       window.tracker?.trackEvent 'Show subscription modal', category: 'Subscription', label: 'level loading'
+      window.tracker?.trackPageView "subscription/show-modal", ['Google Analytics']
 
   onSubscribed: ->
     document.location.reload()
diff --git a/app/views/play/level/tome/SpellView.coffee b/app/views/play/level/tome/SpellView.coffee
index 0582b9fb8..06d948f6d 100644
--- a/app/views/play/level/tome/SpellView.coffee
+++ b/app/views/play/level/tome/SpellView.coffee
@@ -273,6 +273,15 @@ module.exports = class SpellView extends CocoView
       return true for range in @readOnlyRanges when leftRange.intersects(range)
       false
 
+    intersectsRight = =>
+      rightRange = @ace.getSelectionRange().clone()
+      if rightRange.end.column < @aceDoc.getLine(rightRange.end.row).length
+        rightRange.setEnd rightRange.end.row, rightRange.end.column + 1
+      else if rightRange.start.row < @aceDoc.getLength() - 1
+        rightRange.setEnd rightRange.end.row + 1, 0
+      return true for range in @readOnlyRanges when rightRange.intersects(range)
+      false
+
     preventReadonly = (next) ->
       return true if intersects()
       next?()
@@ -284,27 +293,16 @@ module.exports = class SpellView extends CocoView
         wrapper => orig.apply obj, args
       obj[method]
 
-    finishRange = (row, startRow, startColumn) =>
-      range = new Range startRow, startColumn, row, @aceSession.getLine(row).length - 1
-      range.start = @aceDoc.createAnchor range.start
-      range.end = @aceDoc.createAnchor range.end
-      range.end.$insertRight = true
-      @readOnlyRanges.push range
+    if @lockedCodeMarkerID?
+      @aceSession.removeMarker @lockedCodeMarkerID
+      @lockedCodeMarkerID = null
 
-    # Create a read-only range for each chunk of text not separated by an empty line
     @readOnlyRanges = []
-    startRow = startColumn = null
-    for row in [0...@aceSession.getLength()]
-      unless /^\s*$/.test @aceSession.getLine(row)
-        unless startRow? and startColumn?
-          startRow = row
-          startColumn = 0
-      else
-        if startRow? and startColumn?
-          finishRange row - 1, startRow, startColumn
-          startRow = startColumn = null
-    if startRow? and startColumn?
-      finishRange @aceSession.getLength() - 1, startRow, startColumn
+    lines = @aceDoc.getAllLines()
+    lastRow = row for line, row in lines when not /^\s*$/.test(line)
+    if lastRow?
+      @readOnlyRanges.push new Range 0, 0, lastRow, lines[lastRow].length - 1
+      @lockedCodeMarkerID = @aceSession.addMarker @readOnlyRanges[0], 'locked-code', 'fullLine'
 
     # Override write operations that intersect with default code
     interceptCommand @ace, 'onPaste', preventReadonly
@@ -319,6 +317,9 @@ module.exports = class SpellView extends CocoView
       if e.command.name in ['Backspace', 'throttle-backspaces'] and intersectsLeft()
         @zatanna?.off?()
         return false
+      if e.command.name is 'del' and intersectsRight()
+        @zatanna?.off?()
+        return false
       if e.command.name in ['enter-skip-delimiters', 'Enter', 'Return']
         if intersects()
           e.editor.navigateDown 1
diff --git a/app/views/play/modal/SubscribeModal.coffee b/app/views/play/modal/SubscribeModal.coffee
index 59b34338b..cc8af4bb7 100644
--- a/app/views/play/modal/SubscribeModal.coffee
+++ b/app/views/play/modal/SubscribeModal.coffee
@@ -45,10 +45,12 @@ module.exports = class SubscribeModal extends ModalView
       container: @$el
     ).on 'shown.bs.popover', =>
       application.tracker?.trackEvent 'Subscription parent hover', {}
+      application.tracker?.trackPageView "subscription/parent-hover", ['Google Analytics']
 
   onClickPurchaseButton: (e) ->
     @playSound 'menu-button-click'
     application.tracker?.trackEvent 'Started subscription purchase', {}
+    application.tracker?.trackPageView "subscription/start-purchase", ['Google Analytics']
     stripeHandler.open({
       description: $.i18n.t('subscribe.stripe_description')
       amount: @product.amount
@@ -69,6 +71,7 @@ module.exports = class SubscribeModal extends ModalView
 
   onSubscriptionSuccess: ->
     application.tracker?.trackEvent 'Finished subscription purchase', {}
+    application.tracker?.trackPageView "subscription/finish-purchase", ['Google Analytics']
     Backbone.Mediator.publish 'subscribe-modal:subscribed', {}
     @playSound 'victory'
     @hide()
diff --git a/server/payments/discount_handler.coffee b/server/payments/discount_handler.coffee
new file mode 100644
index 000000000..64e865c94
--- /dev/null
+++ b/server/payments/discount_handler.coffee
@@ -0,0 +1,48 @@
+# Not paired with a document in the DB, just handles coordinating between
+# the stripe property in the user with what's being stored in Stripe.
+
+Handler = require '../commons/Handler'
+config = require '../../server_config'
+stripe = require('stripe')(config.stripe.secretKey)
+
+class DiscountHandler extends Handler
+  logDiscountError: (req, msg) ->
+    console.warn "Discount Error: #{req.user.get('slug')} (#{req.user._id}): '#{msg}'"
+
+  discountUser: (req, user, done) ->
+    if (not user) or user.isAnonymous()
+      return done({res: 'User must not be anonymous.', code: 403})
+
+    couponID = req.body.stripe.couponID
+    if not couponID
+      @logDiscountError(req, 'Missing couponID.')
+      return done({res: 'Missing couponID.', code: 422})
+      
+    stripe.coupons.retrieve couponID, (err, coupon) =>
+      if (err)
+        return done({res: 'No coupon with id '+couponID, code: 404})
+        
+      if customerID = user.get('stripe')?.customerID
+        options = { coupon: coupon.id }
+        stripe.customers.update customerID, options, (err, customer) =>
+          if err
+            @logDiscountError(req, 'Error applying coupon to customer'+customerID)
+            return done({res: 'Error applying coupon to customer.', code: 500})
+          done()
+        
+      else
+        # couponID will be set on the user by the handler
+        done()
+
+  removeDiscountFromCustomer: (req, user, done) ->
+    customerID = user.get('stripe').customerID
+    return done() unless customerID
+    
+    stripe.customers.deleteDiscount customerID, (err, customer) =>
+      if err
+        console.log 'err?', err
+        @logDiscountError(req, 'Error removing coupon from customer ' + customerID)
+        return done({res: 'Error applying coupon to customer.', code: 500})
+      done()
+      
+module.exports = new DiscountHandler()
\ No newline at end of file
diff --git a/server/payments/payment_handler.coffee b/server/payments/payment_handler.coffee
index f2e4f2bd4..cc077994b 100644
--- a/server/payments/payment_handler.coffee
+++ b/server/payments/payment_handler.coffee
@@ -166,29 +166,34 @@ PaymentHandler = class PaymentHandler extends Handler
   handleStripePaymentPost: (req, res, timestamp, productID, token) ->
 
     # First, make sure we save the payment info as a Customer object, if we haven't already.
-    if not req.user.get('stripe')?.customerID
-      stripe.customers.create({
-        card: token
-        email: req.user.get('email')
-        metadata: {
-          id: req.user._id + ''
-          slug: req.user.get('slug')
-        }
-      }).then(((customer) =>
-        stripeInfo = _.cloneDeep(req.user.get('stripe') ? {})
-        stripeInfo.customerID = customer.id
-        req.user.set('stripe', stripeInfo)
-        req.user.save((err) =>
-          if err
-            @logPaymentError(req, 'Stripe customer id save db error. '+err)
-            return @sendDatabaseError(res, err)
+    if token
+      customerID = req.user.get('stripe')?.customerID
+      
+      if customerID
+        # old customer, new token. Save it.
+        stripe.customers.update customerID, { card: token }, (err, customer) =>
           @beginStripePayment(req, res, timestamp, productID)
-        )
-        ),
-        (err) =>
-          @logPaymentError(req, 'Stripe customer creation error. '+err)
-          return @sendDatabaseError(res, err)
-      )
+          
+      else
+        newCustomer = {
+          card: token
+          email: req.user.get('email')
+          metadata: { id: req.user._id + '', slug: req.user.get('slug') }
+        }
+        
+        stripe.customers.create newCustomer, (err, customer) =>
+          if err
+            @logPaymentError(req, 'Stripe customer creation error. '+err)
+            return @sendDatabaseError(res, err)
+          
+          stripeInfo = _.cloneDeep(req.user.get('stripe') ? {})
+          stripeInfo.customerID = customer.id
+          req.user.set('stripe', stripeInfo)
+          req.user.save (err) =>
+            if err
+              @logPaymentError(req, 'Stripe customer id save db error. '+err)
+              return @sendDatabaseError(res, err)
+            @beginStripePayment(req, res, timestamp, productID)
 
     else
       @beginStripePayment(req, res, timestamp, productID)
diff --git a/server/payments/subscription_handler.coffee b/server/payments/subscription_handler.coffee
index 231f059d4..f1d0531e5 100644
--- a/server/payments/subscription_handler.coffee
+++ b/server/payments/subscription_handler.coffee
@@ -4,6 +4,7 @@
 Handler = require '../commons/Handler'
 config = require '../../server_config'
 stripe = require('stripe')(config.stripe.secretKey)
+discountHandler = require './discount_handler'
 
 subscriptions = {
   basic: {
@@ -19,61 +20,52 @@ class SubscriptionHandler extends Handler
     if (not req.user) or req.user.isAnonymous()
       return done({res: 'You must be signed in to subscribe.', code: 403})
 
-    stripeToken = req.body.stripe?.token
-    extantCustomerID = user.get('stripe')?.customerID
-    if not (stripeToken or extantCustomerID)
+    token = req.body.stripe?.token
+    customerID = user.get('stripe')?.customerID
+    if not (token or customerID)
       @logSubscriptionError(req, 'Missing stripe token or customer ID.')
       return done({res: 'Missing stripe token or customer ID.', code: 422})
 
-    if stripeToken
-      stripe.customers.create({
-        card: stripeToken
-        email: req.user.get('email')
-        metadata: {
-          id: req.user._id + ''
-          slug: req.user.get('slug')
+    if token
+      if customerID
+        stripe.customers.update customerID, { card: token }, (err, customer) =>
+          @checkForExistingSubscription(req, user, customer, done)
+          
+      else
+        newCustomer = {
+          card: token
+          email: req.user.get('email')
+          metadata: { id: req.user._id + '', slug: req.user.get('slug') }
         }
-      }).then(((customer) =>
+
+        stripe.customers.create newCustomer, (err, customer) =>
+          if err
+            if err.type in ['StripeCardError', 'StripeInvalidRequestError']
+              return done({res: 'Card error', code: 402})
+            else
+              @logSubscriptionError(req, 'Stripe customer creation error. '+err)
+              return done({res: 'Database error.', code: 500})
+            
           stripeInfo = _.cloneDeep(req.user.get('stripe') ? {})
           stripeInfo.customerID = customer.id
           req.user.set('stripe', stripeInfo)
-          req.user.save((err) =>
+          req.user.save (err) =>
             if err
               @logSubscriptionError(req, 'Stripe customer id save db error. '+err)
               return done({res: 'Database error.', code: 500})
             @checkForExistingSubscription(req, user, customer, done)
-          )
-        ),
-      (err) =>
-        if err.type in ['StripeCardError', 'StripeInvalidRequestError']
-          done({res: 'Card error', code: 402})
-        else
-          @logSubscriptionError(req, 'Stripe customer creation error. '+err)
-          return done({res: 'Database error.', code: 500})
-      )
 
     else
-      stripe.customers.retrieve(extantCustomerID, (err, customer) =>
+      stripe.customers.retrieve(customerID, (err, customer) =>
         if err
           @logSubscriptionError(req, 'Stripe customer creation error. '+err)
           return done({res: 'Database error.', code: 500})
-        else if not customer
-          # TODO: what actually happens when you try to retrieve a customer and it DNE?
-          @logSubscriptionError(req, 'Stripe customer id is missing! '+err)
-          stripeInfo = _.cloneDeep(req.user.get('stripe') ? {})
-          delete stripeInfo.customerID
-          req.user.set('stripe', stripeInfo)
-          req.user.save (err) =>
-            if err
-              @logSubscriptionError(req, 'Stripe customer id delete db error. '+err)
-              return done({res: 'Database error.', code: 500})
-            @subscribeUser(req, done)
-        else
-          @checkForExistingSubscription(req, user, customer, done)
+        @checkForExistingSubscription(req, user, customer, done)
       )
 
 
   checkForExistingSubscription: (req, user, customer, done) ->
+    couponID = user.get('stripe')?.couponID
     if subscription = customer.subscriptions?.data?[0]
 
       if subscription.cancel_at_period_end
@@ -87,30 +79,34 @@ class SubscriptionHandler extends Handler
             return done({res: 'Database error.', code: 500})
 
           options = { plan: 'basic', trial_end: subscription.current_period_end }
+          options.coupon = couponID if couponID
           stripe.customers.update req.user.get('stripe').customerID, options, (err, customer) =>
             if err
               @logSubscriptionError(req, 'Stripe customer plan setting error. '+err)
               return done({res: 'Database error.', code: 500})
 
-            @updateUser(req, user, customer.subscriptions.data[0], false, done)
+            @updateUser(req, user, customer, false, done)
 
       else
         # can skip creating the subscription
-        return @updateUser(req, user, customer.subscriptions.data[0], false, done)
+        return @updateUser(req, user, customer, false, done)
 
     else
-      stripe.customers.update req.user.get('stripe').customerID, { plan: 'basic' }, (err, customer) =>
+      options = { plan: 'basic' }
+      options.coupon = couponID if couponID
+      stripe.customers.update req.user.get('stripe').customerID, options, (err, customer) =>
         if err
           @logSubscriptionError(req, 'Stripe customer plan setting error. '+err)
           return done({res: 'Database error.', code: 500})
 
-        @updateUser(req, user, customer.subscriptions.data[0], true, done)
+        @updateUser(req, user, customer, true, done)
 
-  updateUser: (req, user, subscription, increment, done) ->
+  updateUser: (req, user, customer, increment, done) ->
+    subscription = customer.subscriptions.data[0]
     stripeInfo = _.cloneDeep(user.get('stripe') ? {})
     stripeInfo.planID = 'basic'
     stripeInfo.subscriptionID = subscription.id
-    stripeInfo.customerID = subscription.customer
+    stripeInfo.customerID = customer.id
     req.body.stripe = stripeInfo # to make sure things work for admins, who are mad with power
     user.set('stripe', stripeInfo)
 
diff --git a/server/users/user_handler.coffee b/server/users/user_handler.coffee
index 083b91ab4..c413d93da 100644
--- a/server/users/user_handler.coffee
+++ b/server/users/user_handler.coffee
@@ -12,6 +12,7 @@ moment = require 'moment'
 LevelSession = require '../levels/sessions/LevelSession'
 LevelSessionHandler = require '../levels/sessions/level_session_handler'
 SubscriptionHandler = require '../payments/subscription_handler'
+DiscountHandler = require '../payments/discount_handler'
 EarnedAchievement = require '../achievements/EarnedAchievement'
 UserRemark = require './remarks/UserRemark'
 {isID} = require '../lib/utils'
@@ -123,6 +124,25 @@ UserHandler = class UserHandler extends Handler
           return callback(err) if err
           return callback(null, req, user)
         )
+
+    # Discount setting
+    (req, user, callback) ->
+      return callback(null, req, user) unless req.user?.isAdmin()
+      hasCoupon = user.get('stripe')?.couponID
+      wantsCoupon = req.body.stripe?.couponID
+
+      return callback(null, req, user) if hasCoupon is wantsCoupon
+      if wantsCoupon and (hasCoupon isnt wantsCoupon)
+        DiscountHandler.discountUser(req, user, (err) ->
+          return callback(err) if err
+          return callback(null, req, user)
+        )
+      else if hasCoupon and not wantsCoupon
+        DiscountHandler.removeDiscountFromCustomer(req, user, (err) ->
+          return callback(err) if err
+          return callback(null, req, user)
+        )
+
   ]
 
   getById: (req, res, id) ->
diff --git a/server_setup.coffee b/server_setup.coffee
index ad056068b..ae76032c2 100644
--- a/server_setup.coffee
+++ b/server_setup.coffee
@@ -56,7 +56,6 @@ setupExpressMiddleware = (app) ->
     express.logger.format('prod', productionLogging)
     app.use(express.logger('prod'))
     app.use express.compress filter: (req, res) ->
-      return false if req.headers.host is 'codecombat.com'  # CloudFlare will gzip it for us on codecombat.com  # But now it's disabled.
       compressible res.getHeader('Content-Type')
   else
     express.logger.format('dev', developmentLogging)
diff --git a/test/server/functional/discount_handler.spec.coffee b/test/server/functional/discount_handler.spec.coffee
new file mode 100644
index 000000000..909b97f41
--- /dev/null
+++ b/test/server/functional/discount_handler.spec.coffee
@@ -0,0 +1,114 @@
+
+config = require '../../../server_config'
+require '../common'
+
+# sample data that comes in through the webhook when you subscribe
+
+
+describe '/db/user, editing stripe.couponID property', ->
+
+  stripe = require('stripe')(config.stripe.secretKey)
+  userURL = getURL('/db/user')
+  webhookURL = getURL('/stripe/webhook')
+
+  it 'clears the db first', (done) ->
+    clearModels [User, Payment], (err) ->
+      throw err if err
+      done()
+
+  #- shared data between tests
+  joeData = null
+  firstSubscriptionID = null
+  
+  it 'does not work for non-admins', (done) ->
+    loginJoe (joe) ->
+      joeData = joe.toObject()
+      expect(joeData.stripe).toBeUndefined()
+      joeData.stripe = { couponID: '20pct' }
+      request.put {uri: userURL, json: joeData }, (err, res, body) ->
+        expect(res.statusCode).toBe(200) # fails silently
+        expect(res.body.stripe).toBeUndefined() # but still fails
+        done()
+        
+  it 'does not work with invalid coupons', (done) ->
+    loginAdmin (admin) ->
+      joeData.stripe = { couponID: 'DNE' }
+      request.put {uri: userURL, json: joeData }, (err, res, body) ->
+        expect(res.statusCode).toBe(404)
+        done()
+  
+  it 'sets the couponID on a user without an existing stripe object', (done) ->
+    joeData.stripe = { couponID: '20pct' }
+    request.put {uri: userURL, json: joeData }, (err, res, body) ->
+      joeData = body
+      expect(res.statusCode).toBe(200)
+      expect(body.stripe.couponID).toBe('20pct')
+      done()
+      
+  it 'just updates the couponID when it changes and there is no existing subscription', (done) ->
+    joeData.stripe.couponID = '500off'
+    request.put {uri: userURL, json: joeData }, (err, res, body) ->
+      expect(res.statusCode).toBe(200)
+      expect(body.stripe.couponID).toBe('500off')
+      done()
+
+  it 'removes the couponID from the user when the admin makes it so', (done) ->
+    delete joeData.stripe.couponID
+    request.put {uri: userURL, json: joeData }, (err, res, body) ->
+      joeData = body
+      expect(res.statusCode).toBe(200)
+      expect(body.stripe).toBeUndefined()
+      done()
+
+  it 'puts the coupon back', (done) ->
+    joeData.stripe = {couponID: '500off'}
+    request.put {uri: userURL, json: joeData }, (err, res, body) ->
+      expect(res.statusCode).toBe(200)
+      expect(body.stripe.couponID).toBe('500off')
+      done()
+
+  it 'applies a discount to the newly created customer when a plan is set', (done) ->
+    stripe.tokens.create {
+      card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
+    }, (err, token) ->
+      stripeTokenID = token.id
+      loginJoe (joe) ->
+        joeData.stripe.token = stripeTokenID
+        joeData.stripe.planID = 'basic'
+        request.put {uri: userURL, json: joeData }, (err, res, body) ->
+          joeData = body
+          expect(res.statusCode).toBe(200)
+          stripe.customers.retrieve joeData.stripe.customerID, (err, customer) ->
+            expect(customer.discount).toBeDefined()
+            expect(customer.discount.coupon.id).toBe('500off')
+            done()
+  
+          
+  it 'updates the discount on the customer when an admin changes the couponID', (done) ->
+    loginAdmin (admin) ->
+      joeData.stripe.couponID = '20pct'
+      request.put {uri: userURL, json: joeData }, (err, res, body) ->
+        expect(res.statusCode).toBe(200)
+        expect(body.stripe.couponID).toBe('20pct')
+        stripe.customers.retrieve joeData.stripe.customerID, (err, customer) ->
+          expect(customer.discount.coupon.id).toBe('20pct')
+          done()
+      
+  it 'removes discounts from the customer when an admin removes the couponID', (done) ->
+    delete joeData.stripe.couponID
+    request.put {uri: userURL, json: joeData }, (err, res, body) ->
+      expect(res.statusCode).toBe(200)
+      expect(body.stripe.couponID).toBeUndefined()
+      stripe.customers.retrieve joeData.stripe.customerID, (err, customer) ->
+        expect(customer.discount).toBe(null)
+        done()
+
+  it 'adds a discount to the customer when an admin adds the couponID', (done) ->
+    joeData.stripe.couponID = '20pct'
+    request.put {uri: userURL, json: joeData }, (err, res, body) ->
+      expect(res.statusCode).toBe(200)
+      expect(body.stripe.couponID).toBe('20pct')
+      stripe.customers.retrieve joeData.stripe.customerID, (err, customer) ->
+        expect(customer.discount.coupon.id).toBe('20pct')
+        done()
+        
diff --git a/test/server/functional/payment.spec.coffee b/test/server/functional/payment.spec.coffee
index 26cb4cb44..f8fb257cf 100644
--- a/test/server/functional/payment.spec.coffee
+++ b/test/server/functional/payment.spec.coffee
@@ -82,6 +82,7 @@ describe '/db/payment', ->
     joeID = null
     timestamp = new Date().getTime()
     stripeTokenID = null
+    joeData = null
 
     it 'clears the db first', (done) ->
       clearModels [User, Payment], (err) ->
@@ -131,6 +132,34 @@ describe '/db/payment', ->
             done()
           )
         )
+        
+    it 'allows a new charge on the existing customer', (done) ->
+      data = { productID: 'gems_5', stripe: { timestamp: new Date().getTime() } }
+      request.post {uri: paymentURL, json: data }, (err, res, body) ->
+        expect(res.statusCode).toBe 201
+        Payment.count {}, (err, count) ->
+          expect(count).toBe(2)
+          User.findById joeID, (err, user) ->
+            joeData = user.toObject()
+            expect(user.get('purchased').gems).toBe(10000)
+            done()
+            
+    it "updates the customer's card when you submit a new token", (done) ->
+      stripe.customers.retrieve joeData.stripe.customerID, (err, customer) ->
+        originalCustomerID = customer.id
+        originalCardID = customer.cards.data[0].id
+        stripe.tokens.create {
+            card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
+        }, (err, token) ->
+          data = { productID: 'gems_5', stripe: { timestamp: new Date().getTime(), token: token.id } }
+          request.post {uri: paymentURL, json: data }, (err, res, body) ->
+            expect(res.statusCode).toBe(201)
+            User.findById joeID, (err, user) ->
+              joeData = user.toObject()
+              expect(joeData.stripe.customerID).toBe(originalCustomerID)
+              stripe.customers.retrieve joeData.stripe.customerID, (err, customer) ->
+                expect(customer.cards.data[0].id).not.toBe(originalCardID)
+                done()
 
     it 'clears the db', (done) ->
       clearModels [User, Payment], (err) ->