diff --git a/app/application.coffee b/app/application.coffee index cc6acd63b..f44287599 100644 --- a/app/application.coffee +++ b/app/application.coffee @@ -5,10 +5,12 @@ locale = require 'locale/locale' Tracker = require 'lib/Tracker' CocoView = require 'views/kinds/CocoView' +# Prevent Ctrl/Cmd + [ / ], P, S +ctrlDefaultPrevented = [219, 221, 80, 83] preventBackspace = (event) -> if event.keyCode is 8 and not elementAcceptsKeystrokes(event.srcElement or event.target) event.preventDefault() - else if (key.ctrl or key.command) and not key.alt and event.keyCode in [219, 221] # prevent Ctrl/Cmd + [ / ] + else if (key.ctrl or key.command) and not key.alt and event.keyCode in ctrlDefaultPrevented event.preventDefault() elementAcceptsKeystrokes = (el) -> diff --git a/app/assets/index.html b/app/assets/main.html similarity index 99% rename from app/assets/index.html rename to app/assets/main.html index b558ff66f..96306649e 100644 --- a/app/assets/index.html +++ b/app/assets/main.html @@ -35,6 +35,11 @@ + + + diff --git a/app/initialize.coffee b/app/initialize.coffee index 7670088db..80c33c9b7 100644 --- a/app/initialize.coffee +++ b/app/initialize.coffee @@ -1,5 +1,4 @@ app = require 'application' -auth = require 'lib/auth' init = -> app.initialize() @@ -10,15 +9,8 @@ init = -> treemaExt.setup() filepicker.setKey('AvlkNoldcTOU4PvKi2Xm7z') -$ -> - # Make sure we're "logged in" first. - if auth.me.id - init() - else - Backbone.Mediator.subscribeOnce 'me:synced', init +$ -> init() -window.init = init - handleNormalUrls = -> # http://artsy.github.com/blog/2012/06/25/replacing-hashbang-routes-with-pushstate/ $(document).on "click", "a[href^='/']", (event) -> diff --git a/app/lib/FacebookHandler.coffee b/app/lib/FacebookHandler.coffee index ffd61b5a1..10a59c40c 100644 --- a/app/lib/FacebookHandler.coffee +++ b/app/lib/FacebookHandler.coffee @@ -1,5 +1,5 @@ CocoClass = require 'lib/CocoClass' -{me, CURRENT_USER_KEY} = require 'lib/auth' +{me} = require 'lib/auth' {backboneFailure} = require 'lib/errors' storage = require 'lib/storage' @@ -59,7 +59,6 @@ module.exports = FacebookHandler = class FacebookHandler extends CocoClass error: backboneFailure, url: "/db/user?facebookID=#{r.id}&facebookAccessToken=#{@authResponse.accessToken}" success: (model) -> - storage.save(CURRENT_USER_KEY, model.attributes) window.location.reload() if model.get('email') isnt oldEmail }) diff --git a/app/lib/GPlusHandler.coffee b/app/lib/GPlusHandler.coffee index 2ffd27805..8565a2075 100644 --- a/app/lib/GPlusHandler.coffee +++ b/app/lib/GPlusHandler.coffee @@ -1,5 +1,5 @@ CocoClass = require 'lib/CocoClass' -{me, CURRENT_USER_KEY} = require 'lib/auth' +{me} = require 'lib/auth' {backboneFailure} = require 'lib/errors' storage = require 'lib/storage' GPLUS_TOKEN_KEY = 'gplusToken' @@ -102,7 +102,6 @@ module.exports = GPlusHandler = class GPlusHandler extends CocoClass error: backboneFailure, url: "/db/user?gplusID=#{gplusID}&gplusAccessToken=#{@accessToken.access_token}" success: (model) -> - storage.save(CURRENT_USER_KEY, model.attributes) window.location.reload() if wasAnonymous and not model.get('anonymous') }) diff --git a/app/lib/Router.coffee b/app/lib/Router.coffee index 65915dd56..7c12e1cb8 100644 --- a/app/lib/Router.coffee +++ b/app/lib/Router.coffee @@ -1,5 +1,3 @@ -{me} = require 'lib/auth' - gplusClientID = "800329290710-j9sivplv2gpcdgkrsis9rff3o417mlfa.apps.googleusercontent.com" go = (path) -> -> @routeDirectly path, arguments diff --git a/app/lib/auth.coffee b/app/lib/auth.coffee index 78862d733..d46733089 100644 --- a/app/lib/auth.coffee +++ b/app/lib/auth.coffee @@ -1,20 +1,24 @@ {backboneFailure, genericFailure} = require 'lib/errors' User = require 'models/User' storage = require 'lib/storage' - -module.exports.CURRENT_USER_KEY = CURRENT_USER_KEY = 'whoami' BEEN_HERE_BEFORE_KEY = 'beenHereBefore' +init = -> + module.exports.me = window.me = new User(window.userObject) # inserted into main.html + trackFirstArrival() + if me and not me.get('testGroupNumber')? + # Assign testGroupNumber to returning visitors; new ones in server/routes/auth + me.set 'testGroupNumber', Math.floor(Math.random() * 256) + me.save() + + me.loadGravatarProfile() if me.get('email') + Backbone.listenTo(me, 'sync', Backbone.Mediator.publish('me:synced', {me:me})) + module.exports.createUser = (userObject, failure=backboneFailure, nextURL=null) -> user = new User(userObject) user.save({}, { - error: failure, - success: (model) -> - storage.save(CURRENT_USER_KEY, model) - if nextURL - window.location.href = nextURL - else - window.location.reload() + error: failure, + success: -> if nextURL then window.location.href = nextURL else window.location.reload() }) module.exports.loginUser = (userObject, failure=genericFailure) -> @@ -23,52 +27,15 @@ module.exports.loginUser = (userObject, failure=genericFailure) -> username:userObject.email, password:userObject.password }, - (model) -> - storage.save(CURRENT_USER_KEY, model) - window.location.reload() + (model) -> window.location.reload() ) jqxhr.fail(failure) module.exports.logoutUser = -> FB?.logout?() - res = $.post('/auth/logout', {}, -> - storage.save(CURRENT_USER_KEY, null) - window.location.reload() - ) + res = $.post('/auth/logout', {}, -> window.location.reload()) res.fail(genericFailure) -init = -> - # Load the user from local storage, and refresh it from the server. - # Also refresh and cache the gravatar info. - - storedUser = storage.load(CURRENT_USER_KEY) - firstTime = not storedUser - module.exports.me = window.me = new User(storedUser) - me.url = -> '/auth/whoami' - me.fetch() - - retry = -> me.fetch() # blindly try again - error = -> setTimeout(retry, 1000) # blindly try again - me.on 'error', error, @ - me.on 'sync', -> - me.off 'error', error, @ if firstTime - me.url = -> "/db/user/#{me.id}" - trackFirstArrival() if firstTime - if me and not me.get('testGroupNumber')? - # Assign testGroupNumber to returning visitors; new ones in server/handlers/user - me.set 'testGroupNumber', Math.floor(Math.random() * 256) - me.save() - storage.save(CURRENT_USER_KEY, me.attributes) - - me.loadGravatarProfile() if me.get('email') - Backbone.listenTo(me, 'sync', userSynced) - -userSynced = (user) -> - Backbone.Mediator.publish('me:synced', {me:user}) - storage.save(CURRENT_USER_KEY, user) - -init() - onSetVolume = (e) -> return if e.volume is me.get('volume') me.set('volume', e.volume) @@ -83,3 +50,6 @@ trackFirstArrival = -> return if beenHereBefore window.tracker?.trackEvent 'First Arrived' storage.save(BEEN_HERE_BEFORE_KEY, true) + +init() + diff --git a/app/locale/ar.coffee b/app/locale/ar.coffee index ae1634a04..d98e9c0e6 100644 --- a/app/locale/ar.coffee +++ b/app/locale/ar.coffee @@ -264,6 +264,8 @@ module.exports = nativeDescription: "العربية", englishDescription: "Arabi # tip_patience: "Patience you must have, young Padawan. - Yoda" # tip_documented_bug: "A documented bug is not a bug; it is a feature." # tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" +# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" +# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" diff --git a/app/locale/bg.coffee b/app/locale/bg.coffee index 02a48185f..5443c75a3 100644 --- a/app/locale/bg.coffee +++ b/app/locale/bg.coffee @@ -264,6 +264,8 @@ module.exports = nativeDescription: "български език", englishDescri # tip_patience: "Patience you must have, young Padawan. - Yoda" # tip_documented_bug: "A documented bug is not a bug; it is a feature." # tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" +# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" +# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" diff --git a/app/locale/ca.coffee b/app/locale/ca.coffee index b556bb751..305bd992e 100644 --- a/app/locale/ca.coffee +++ b/app/locale/ca.coffee @@ -264,6 +264,8 @@ module.exports = nativeDescription: "Català", englishDescription: "Catalan", tr # tip_patience: "Patience you must have, young Padawan. - Yoda" # tip_documented_bug: "A documented bug is not a bug; it is a feature." # tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" +# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" +# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" diff --git a/app/locale/cs.coffee b/app/locale/cs.coffee index d46a5ffc9..f60722bf1 100644 --- a/app/locale/cs.coffee +++ b/app/locale/cs.coffee @@ -264,6 +264,8 @@ module.exports = nativeDescription: "čeština", englishDescription: "Czech", tr # tip_patience: "Patience you must have, young Padawan. - Yoda" # tip_documented_bug: "A documented bug is not a bug; it is a feature." # tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" +# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" +# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" diff --git a/app/locale/da.coffee b/app/locale/da.coffee index e43633763..ce34dfa42 100644 --- a/app/locale/da.coffee +++ b/app/locale/da.coffee @@ -264,6 +264,8 @@ module.exports = nativeDescription: "dansk", englishDescription: "Danish", trans # tip_patience: "Patience you must have, young Padawan. - Yoda" # tip_documented_bug: "A documented bug is not a bug; it is a feature." # tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" +# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" +# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" diff --git a/app/locale/de.coffee b/app/locale/de.coffee index 7450a566d..d451d6528 100644 --- a/app/locale/de.coffee +++ b/app/locale/de.coffee @@ -264,6 +264,8 @@ module.exports = nativeDescription: "Deutsch", englishDescription: "German", tra tip_patience: "Geduld du musst haben, junger Padawan. - Yoda" tip_documented_bug: "Ein dokumentierter Fehler ist kein Fehler; er ist ein Merkmal." tip_impossible: "Es wirkt immer unmöglich bis es vollbracht ist. - Nelson Mandela" +# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" +# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" time_current: "Aktuell" time_total: "Total" time_goto: "Gehe zu" diff --git a/app/locale/el.coffee b/app/locale/el.coffee index db12d6a5c..a301dcb79 100644 --- a/app/locale/el.coffee +++ b/app/locale/el.coffee @@ -264,6 +264,8 @@ module.exports = nativeDescription: "ελληνικά", englishDescription: "Gre # tip_patience: "Patience you must have, young Padawan. - Yoda" # tip_documented_bug: "A documented bug is not a bug; it is a feature." # tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" +# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" +# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" diff --git a/app/locale/en-AU.coffee b/app/locale/en-AU.coffee index 1ef791725..98b872bce 100644 --- a/app/locale/en-AU.coffee +++ b/app/locale/en-AU.coffee @@ -264,6 +264,8 @@ module.exports = nativeDescription: "English (AU)", englishDescription: "English # tip_patience: "Patience you must have, young Padawan. - Yoda" # tip_documented_bug: "A documented bug is not a bug; it is a feature." # tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" +# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" +# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" diff --git a/app/locale/en-GB.coffee b/app/locale/en-GB.coffee index d815f11cc..d9f675858 100644 --- a/app/locale/en-GB.coffee +++ b/app/locale/en-GB.coffee @@ -264,6 +264,8 @@ module.exports = nativeDescription: "English (UK)", englishDescription: "English # tip_patience: "Patience you must have, young Padawan. - Yoda" # tip_documented_bug: "A documented bug is not a bug; it is a feature." # tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" +# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" +# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" diff --git a/app/locale/en-US.coffee b/app/locale/en-US.coffee index 3e0d493e0..78aa5661b 100644 --- a/app/locale/en-US.coffee +++ b/app/locale/en-US.coffee @@ -264,6 +264,8 @@ module.exports = nativeDescription: "English (US)", englishDescription: "English # tip_patience: "Patience you must have, young Padawan. - Yoda" # tip_documented_bug: "A documented bug is not a bug; it is a feature." # tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" +# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" +# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" diff --git a/app/locale/en.coffee b/app/locale/en.coffee index b52e049d6..6e3aebf3e 100644 --- a/app/locale/en.coffee +++ b/app/locale/en.coffee @@ -264,6 +264,8 @@ module.exports = nativeDescription: "English", englishDescription: "English", tr tip_patience: "Patience you must have, young Padawan. - Yoda" tip_documented_bug: "A documented bug is not a bug; it is a feature." tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" + tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" + tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" time_current: "Now:" time_total: "Max:" time_goto: "Go to:" diff --git a/app/locale/es-419.coffee b/app/locale/es-419.coffee index 62b503e40..a09319212 100644 --- a/app/locale/es-419.coffee +++ b/app/locale/es-419.coffee @@ -264,6 +264,8 @@ module.exports = nativeDescription: "español (América Latina)", englishDescrip # tip_patience: "Patience you must have, young Padawan. - Yoda" # tip_documented_bug: "A documented bug is not a bug; it is a feature." # tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" +# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" +# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" diff --git a/app/locale/es-ES.coffee b/app/locale/es-ES.coffee index bbbccea1b..fa6622d88 100644 --- a/app/locale/es-ES.coffee +++ b/app/locale/es-ES.coffee @@ -264,6 +264,8 @@ module.exports = nativeDescription: "español (ES)", englishDescription: "Spanis # tip_patience: "Patience you must have, young Padawan. - Yoda" # tip_documented_bug: "A documented bug is not a bug; it is a feature." # tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" +# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" +# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" diff --git a/app/locale/es.coffee b/app/locale/es.coffee index 7ff407ced..e94a4f211 100644 --- a/app/locale/es.coffee +++ b/app/locale/es.coffee @@ -264,6 +264,8 @@ module.exports = nativeDescription: "español", englishDescription: "Spanish", t # tip_patience: "Patience you must have, young Padawan. - Yoda" # tip_documented_bug: "A documented bug is not a bug; it is a feature." # tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" +# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" +# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" diff --git a/app/locale/fa.coffee b/app/locale/fa.coffee index 52b82c69e..424c6544d 100644 --- a/app/locale/fa.coffee +++ b/app/locale/fa.coffee @@ -264,6 +264,8 @@ module.exports = nativeDescription: "فارسی", englishDescription: "Persian", # tip_patience: "Patience you must have, young Padawan. - Yoda" # tip_documented_bug: "A documented bug is not a bug; it is a feature." # tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" +# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" +# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" diff --git a/app/locale/fi.coffee b/app/locale/fi.coffee index e6f05d307..ea46d4b27 100644 --- a/app/locale/fi.coffee +++ b/app/locale/fi.coffee @@ -264,6 +264,8 @@ module.exports = nativeDescription: "suomi", englishDescription: "Finnish", tran # tip_patience: "Patience you must have, young Padawan. - Yoda" # tip_documented_bug: "A documented bug is not a bug; it is a feature." # tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" +# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" +# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" diff --git a/app/locale/fr.coffee b/app/locale/fr.coffee index 5797e343e..8c77980bb 100644 --- a/app/locale/fr.coffee +++ b/app/locale/fr.coffee @@ -264,6 +264,8 @@ module.exports = nativeDescription: "français", englishDescription: "French", t # tip_patience: "Patience you must have, young Padawan. - Yoda" # tip_documented_bug: "A documented bug is not a bug; it is a feature." # tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" +# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" +# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" diff --git a/app/locale/he.coffee b/app/locale/he.coffee index 2281828a4..d61d6c68e 100644 --- a/app/locale/he.coffee +++ b/app/locale/he.coffee @@ -264,6 +264,8 @@ module.exports = nativeDescription: "עברית", englishDescription: "Hebrew", # tip_patience: "Patience you must have, young Padawan. - Yoda" # tip_documented_bug: "A documented bug is not a bug; it is a feature." # tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" +# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" +# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" diff --git a/app/locale/hi.coffee b/app/locale/hi.coffee index 5165f38e2..ffcdbc8c7 100644 --- a/app/locale/hi.coffee +++ b/app/locale/hi.coffee @@ -264,6 +264,8 @@ module.exports = nativeDescription: "मानक हिन्दी", englishDe # tip_patience: "Patience you must have, young Padawan. - Yoda" # tip_documented_bug: "A documented bug is not a bug; it is a feature." # tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" +# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" +# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" diff --git a/app/locale/hu.coffee b/app/locale/hu.coffee index 2c8a626b3..eaa9a8077 100644 --- a/app/locale/hu.coffee +++ b/app/locale/hu.coffee @@ -264,6 +264,8 @@ module.exports = nativeDescription: "magyar", englishDescription: "Hungarian", t # tip_patience: "Patience you must have, young Padawan. - Yoda" # tip_documented_bug: "A documented bug is not a bug; it is a feature." # tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" +# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" +# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" diff --git a/app/locale/id.coffee b/app/locale/id.coffee index f142263d0..bdafc21fc 100644 --- a/app/locale/id.coffee +++ b/app/locale/id.coffee @@ -264,6 +264,8 @@ module.exports = nativeDescription: "Bahasa Indonesia", englishDescription: "Ind # tip_patience: "Patience you must have, young Padawan. - Yoda" # tip_documented_bug: "A documented bug is not a bug; it is a feature." # tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" +# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" +# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" diff --git a/app/locale/it.coffee b/app/locale/it.coffee index f6ca3ad08..5acb59898 100644 --- a/app/locale/it.coffee +++ b/app/locale/it.coffee @@ -264,6 +264,8 @@ module.exports = nativeDescription: "Italiano", englishDescription: "Italian", t # tip_patience: "Patience you must have, young Padawan. - Yoda" # tip_documented_bug: "A documented bug is not a bug; it is a feature." # tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" +# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" +# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" diff --git a/app/locale/ja.coffee b/app/locale/ja.coffee index f27bfce8f..86a87bb66 100644 --- a/app/locale/ja.coffee +++ b/app/locale/ja.coffee @@ -264,6 +264,8 @@ module.exports = nativeDescription: "日本語", englishDescription: "Japanese", # tip_patience: "Patience you must have, young Padawan. - Yoda" # tip_documented_bug: "A documented bug is not a bug; it is a feature." # tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" +# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" +# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" diff --git a/app/locale/ko.coffee b/app/locale/ko.coffee index 1508eeb7a..c4f3f6ff6 100644 --- a/app/locale/ko.coffee +++ b/app/locale/ko.coffee @@ -264,6 +264,8 @@ module.exports = nativeDescription: "한국어", englishDescription: "Korean", t # tip_patience: "Patience you must have, young Padawan. - Yoda" # tip_documented_bug: "A documented bug is not a bug; it is a feature." # tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" +# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" +# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" diff --git a/app/locale/lt.coffee b/app/locale/lt.coffee index c411cccbc..fda003f0a 100644 --- a/app/locale/lt.coffee +++ b/app/locale/lt.coffee @@ -264,6 +264,8 @@ module.exports = nativeDescription: "lietuvių kalba", englishDescription: "Lith # tip_patience: "Patience you must have, young Padawan. - Yoda" # tip_documented_bug: "A documented bug is not a bug; it is a feature." # tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" +# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" +# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" diff --git a/app/locale/ms.coffee b/app/locale/ms.coffee index 45e1ee8a2..a678f4576 100644 --- a/app/locale/ms.coffee +++ b/app/locale/ms.coffee @@ -264,6 +264,8 @@ module.exports = nativeDescription: "Bahasa Melayu", englishDescription: "Bahasa # tip_patience: "Patience you must have, young Padawan. - Yoda" # tip_documented_bug: "A documented bug is not a bug; it is a feature." # tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" +# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" +# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" diff --git a/app/locale/nb.coffee b/app/locale/nb.coffee index b08126953..6035495d4 100644 --- a/app/locale/nb.coffee +++ b/app/locale/nb.coffee @@ -264,6 +264,8 @@ module.exports = nativeDescription: "Norsk Bokmål", englishDescription: "Norweg # tip_patience: "Patience you must have, young Padawan. - Yoda" # tip_documented_bug: "A documented bug is not a bug; it is a feature." # tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" +# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" +# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" diff --git a/app/locale/nl-BE.coffee b/app/locale/nl-BE.coffee index a4824a9eb..bcc6c0875 100644 --- a/app/locale/nl-BE.coffee +++ b/app/locale/nl-BE.coffee @@ -264,6 +264,8 @@ module.exports = nativeDescription: "Nederlands (België)", englishDescription: tip_patience: "Geduld moet je hebben, jonge Padawan. - Yoda" tip_documented_bug: "Een gedocumenteerde fout is geen fout; het is deel van het programma." tip_impossible: "Het lijkt altijd onmogelijk tot het gedaan wordt. - Nelson Mandela" +# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" +# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" time_current: "Nu:" time_total: "Maximum:" time_goto: "Ga naar:" diff --git a/app/locale/nl-NL.coffee b/app/locale/nl-NL.coffee index 3664ba69d..59783a502 100644 --- a/app/locale/nl-NL.coffee +++ b/app/locale/nl-NL.coffee @@ -264,6 +264,8 @@ module.exports = nativeDescription: "Nederlands (Nederland)", englishDescription tip_patience: "Geduld moet je hebben, jonge Padawan. - Yoda" tip_documented_bug: "Een gedocumenteerde fout is geen fout; het is deel van het programma." tip_impossible: "Het lijkt altijd onmogelijk tot het gedaan wordt. - Nelson Mandela" +# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" +# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" time_current: "Nu:" time_total: "Maximum:" time_goto: "Ga naar:" diff --git a/app/locale/nl.coffee b/app/locale/nl.coffee index e69fe027d..afcd5d37f 100644 --- a/app/locale/nl.coffee +++ b/app/locale/nl.coffee @@ -264,6 +264,8 @@ module.exports = nativeDescription: "Nederlands", englishDescription: "Dutch", t tip_patience: "Geduld moet je hebben, jonge Padawan. - Yoda" tip_documented_bug: "Een gedocumenteerde fout is geen fout; het is deel van het programma." tip_impossible: "Het lijkt altijd onmogelijk tot het gedaan wordt. - Nelson Mandela" +# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" +# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" time_current: "Nu:" time_total: "Maximum:" time_goto: "Ga naar:" diff --git a/app/locale/nn.coffee b/app/locale/nn.coffee index 4dc969190..88c9d7d35 100644 --- a/app/locale/nn.coffee +++ b/app/locale/nn.coffee @@ -264,6 +264,8 @@ module.exports = nativeDescription: "Norwegian Nynorsk", englishDescription: "No # tip_patience: "Patience you must have, young Padawan. - Yoda" # tip_documented_bug: "A documented bug is not a bug; it is a feature." # tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" +# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" +# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" diff --git a/app/locale/no.coffee b/app/locale/no.coffee index a64438ce8..aa3c48484 100644 --- a/app/locale/no.coffee +++ b/app/locale/no.coffee @@ -264,6 +264,8 @@ module.exports = nativeDescription: "Norsk", englishDescription: "Norwegian", tr # tip_patience: "Patience you must have, young Padawan. - Yoda" # tip_documented_bug: "A documented bug is not a bug; it is a feature." # tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" +# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" +# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" diff --git a/app/locale/pl.coffee b/app/locale/pl.coffee index 72db4f7ce..b858762ce 100644 --- a/app/locale/pl.coffee +++ b/app/locale/pl.coffee @@ -264,6 +264,8 @@ module.exports = nativeDescription: "język polski", englishDescription: "Polish # tip_patience: "Patience you must have, young Padawan. - Yoda" # tip_documented_bug: "A documented bug is not a bug; it is a feature." # tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" +# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" +# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" diff --git a/app/locale/pt-BR.coffee b/app/locale/pt-BR.coffee index d1bdfe010..09d9b2ac1 100644 --- a/app/locale/pt-BR.coffee +++ b/app/locale/pt-BR.coffee @@ -264,6 +264,8 @@ module.exports = nativeDescription: "português do Brasil", englishDescription: # tip_patience: "Patience you must have, young Padawan. - Yoda" # tip_documented_bug: "A documented bug is not a bug; it is a feature." # tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" +# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" +# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" diff --git a/app/locale/pt-PT.coffee b/app/locale/pt-PT.coffee index fa98c389f..5ad78369a 100644 --- a/app/locale/pt-PT.coffee +++ b/app/locale/pt-PT.coffee @@ -264,6 +264,8 @@ module.exports = nativeDescription: "Português europeu", englishDescription: "P # tip_patience: "Patience you must have, young Padawan. - Yoda" # tip_documented_bug: "A documented bug is not a bug; it is a feature." # tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" +# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" +# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" diff --git a/app/locale/pt.coffee b/app/locale/pt.coffee index eeb23e9d2..09d07b3db 100644 --- a/app/locale/pt.coffee +++ b/app/locale/pt.coffee @@ -264,6 +264,8 @@ module.exports = nativeDescription: "português", englishDescription: "Portugues # tip_patience: "Patience you must have, young Padawan. - Yoda" # tip_documented_bug: "A documented bug is not a bug; it is a feature." # tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" +# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" +# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" diff --git a/app/locale/ro.coffee b/app/locale/ro.coffee index 673eac87f..6fe1819ef 100644 --- a/app/locale/ro.coffee +++ b/app/locale/ro.coffee @@ -264,6 +264,8 @@ module.exports = nativeDescription: "limba română", englishDescription: "Roman # tip_patience: "Patience you must have, young Padawan. - Yoda" # tip_documented_bug: "A documented bug is not a bug; it is a feature." # tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" +# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" +# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" diff --git a/app/locale/ru.coffee b/app/locale/ru.coffee index 701d4c0a9..5f77ea288 100644 --- a/app/locale/ru.coffee +++ b/app/locale/ru.coffee @@ -264,6 +264,8 @@ module.exports = nativeDescription: "русский", englishDescription: "Russi tip_patience: "Терпением ты обладать должен, юный падаван. - Yoda" tip_documented_bug: "Документированный баг не является багом; это фича." tip_impossible: "Это всегда кажется невозможным, пока не сделано. - Nelson Mandela" +# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" +# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" time_current: "Текущее:" time_total: "Максимальное:" time_goto: "Перейти на:" diff --git a/app/locale/sk.coffee b/app/locale/sk.coffee index 7d712fcfd..70214b991 100644 --- a/app/locale/sk.coffee +++ b/app/locale/sk.coffee @@ -264,6 +264,8 @@ module.exports = nativeDescription: "slovenčina", englishDescription: "Slovak", # tip_patience: "Patience you must have, young Padawan. - Yoda" # tip_documented_bug: "A documented bug is not a bug; it is a feature." # tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" +# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" +# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" diff --git a/app/locale/sl.coffee b/app/locale/sl.coffee index 565ae2335..4815699e8 100644 --- a/app/locale/sl.coffee +++ b/app/locale/sl.coffee @@ -264,6 +264,8 @@ module.exports = nativeDescription: "slovenščina", englishDescription: "Sloven # tip_patience: "Patience you must have, young Padawan. - Yoda" # tip_documented_bug: "A documented bug is not a bug; it is a feature." # tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" +# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" +# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" diff --git a/app/locale/sr.coffee b/app/locale/sr.coffee index 9c49c79ee..ba3d37cf9 100644 --- a/app/locale/sr.coffee +++ b/app/locale/sr.coffee @@ -264,6 +264,8 @@ module.exports = nativeDescription: "српски", englishDescription: "Serbian # tip_patience: "Patience you must have, young Padawan. - Yoda" # tip_documented_bug: "A documented bug is not a bug; it is a feature." # tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" +# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" +# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" diff --git a/app/locale/sv.coffee b/app/locale/sv.coffee index 64556f8ba..9da2588d2 100644 --- a/app/locale/sv.coffee +++ b/app/locale/sv.coffee @@ -264,6 +264,8 @@ module.exports = nativeDescription: "Svenska", englishDescription: "Swedish", tr # tip_patience: "Patience you must have, young Padawan. - Yoda" # tip_documented_bug: "A documented bug is not a bug; it is a feature." # tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" +# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" +# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" diff --git a/app/locale/th.coffee b/app/locale/th.coffee index 9904dde0c..f5806b980 100644 --- a/app/locale/th.coffee +++ b/app/locale/th.coffee @@ -264,6 +264,8 @@ module.exports = nativeDescription: "ไทย", englishDescription: "Thai", tra # tip_patience: "Patience you must have, young Padawan. - Yoda" # tip_documented_bug: "A documented bug is not a bug; it is a feature." # tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" +# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" +# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" diff --git a/app/locale/tr.coffee b/app/locale/tr.coffee index b5c4b3d57..f72b6e2a0 100644 --- a/app/locale/tr.coffee +++ b/app/locale/tr.coffee @@ -264,6 +264,8 @@ module.exports = nativeDescription: "Türkçe", englishDescription: "Turkish", t # tip_patience: "Patience you must have, young Padawan. - Yoda" # tip_documented_bug: "A documented bug is not a bug; it is a feature." # tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" +# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" +# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" diff --git a/app/locale/uk.coffee b/app/locale/uk.coffee index 21c88cbf1..dd8967069 100644 --- a/app/locale/uk.coffee +++ b/app/locale/uk.coffee @@ -264,6 +264,8 @@ module.exports = nativeDescription: "українська мова", englishDesc # tip_patience: "Patience you must have, young Padawan. - Yoda" # tip_documented_bug: "A documented bug is not a bug; it is a feature." # tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" +# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" +# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" diff --git a/app/locale/ur.coffee b/app/locale/ur.coffee index ea9c2377e..3af879f81 100644 --- a/app/locale/ur.coffee +++ b/app/locale/ur.coffee @@ -264,6 +264,8 @@ module.exports = nativeDescription: "اُردُو", englishDescription: "Urdu", # tip_patience: "Patience you must have, young Padawan. - Yoda" # tip_documented_bug: "A documented bug is not a bug; it is a feature." # tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" +# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" +# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" diff --git a/app/locale/vi.coffee b/app/locale/vi.coffee index 6a04a79c4..b8a3dfbf5 100644 --- a/app/locale/vi.coffee +++ b/app/locale/vi.coffee @@ -264,6 +264,8 @@ module.exports = nativeDescription: "Tiếng Việt", englishDescription: "Vietn # tip_patience: "Patience you must have, young Padawan. - Yoda" # tip_documented_bug: "A documented bug is not a bug; it is a feature." # tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" +# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" +# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" diff --git a/app/locale/zh-HANS.coffee b/app/locale/zh-HANS.coffee index deede5373..36b055bd1 100644 --- a/app/locale/zh-HANS.coffee +++ b/app/locale/zh-HANS.coffee @@ -264,6 +264,8 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese # tip_patience: "Patience you must have, young Padawan. - Yoda" # tip_documented_bug: "A documented bug is not a bug; it is a feature." # tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" +# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" +# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" diff --git a/app/locale/zh-HANT.coffee b/app/locale/zh-HANT.coffee index 29f4d258a..82ee4eee3 100644 --- a/app/locale/zh-HANT.coffee +++ b/app/locale/zh-HANT.coffee @@ -264,6 +264,8 @@ module.exports = nativeDescription: "繁体中文", englishDescription: "Chinese # tip_patience: "Patience you must have, young Padawan. - Yoda" # tip_documented_bug: "A documented bug is not a bug; it is a feature." # tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" +# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" +# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" diff --git a/app/locale/zh.coffee b/app/locale/zh.coffee index d3ee927da..9aafa1d91 100644 --- a/app/locale/zh.coffee +++ b/app/locale/zh.coffee @@ -264,6 +264,8 @@ module.exports = nativeDescription: "中文", englishDescription: "Chinese", tra # tip_patience: "Patience you must have, young Padawan. - Yoda" # tip_documented_bug: "A documented bug is not a bug; it is a feature." # tip_impossible: "It always seems impossible until it's done. - Nelson Mandela" +# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds" +# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay" # time_current: "Now:" # time_total: "Max:" # time_goto: "Go to:" diff --git a/app/styles/play/ladder/my_matches_tab.sass b/app/styles/play/ladder/my_matches_tab.sass new file mode 100644 index 000000000..3483dcf38 --- /dev/null +++ b/app/styles/play/ladder/my_matches_tab.sass @@ -0,0 +1,13 @@ +#my-matches-tab-view + .axis path, .axis line + fill: none + stroke: #000 + shape-rendering: crispEdges + .x.axis.path + display: none + + .line + fill: none + stroke: steelblue + stroke-width: 1.5px + diff --git a/app/templates/play/ladder/my_matches_tab.jade b/app/templates/play/ladder/my_matches_tab.jade index 6b235148a..4975fa963 100644 --- a/app/templates/play/ladder/my_matches_tab.jade +++ b/app/templates/play/ladder/my_matches_tab.jade @@ -11,14 +11,14 @@ div#columns.row tr th(colspan=4, style="color: #{team.primaryColor}") - span(data-i18n="ladder.summary_your") Your + span(data-i18n="ladder.summary_your") Your |#{team.name} | - span(data-i18n="ladder.summary_matches") Matches - + span(data-i18n="ladder.summary_matches") Matches - |#{team.wins} - span(data-i18n="ladder.summary_wins") Wins, + span(data-i18n="ladder.summary_wins") Wins, |#{team.losses} - span(data-i18n="ladder.summary_losses") Losses + span(data-i18n="ladder.summary_losses") Losses if team.session tr @@ -34,7 +34,9 @@ div#columns.row if team.chartData tr th(colspan=4, style="color: #{team.primaryColor}") - img(src="https://chart.googleapis.com/chart?chs=450x125&cht=lxy&chco=#{team.chartColor}&chtt=Score%3A+#{team.currentScore}&chts=#{team.chartColor},16,r&chf=a,s,000000FF&chls=2&chm=o,#{team.chartColor},0,4&chd=t:#{team.chartData}&chxt=y&chxr=0,#{team.minScore},#{team.maxScore}") + div(class="score-chart-wrapper", data-team-name=team.name, id="score-chart-#{team.name}") + + tr th(data-i18n="general.result") Result diff --git a/app/templates/play/level/level_loading.jade b/app/templates/play/level/level_loading.jade index 66e42995b..cfd949909 100644 --- a/app/templates/play/level/level_loading.jade +++ b/app/templates/play/level/level_loading.jade @@ -35,6 +35,8 @@ strong.tip.rare(data-i18n='play_level.tip_no_try') Do. Or do not. There is no try. - Yoda strong.tip.rare(data-i18n='play_level.tip_patience') Patience you must have, young Padawan. - Yoda strong.tip.rare(data-i18n='play_level.tip_documented_bug') A documented bug is not a bug; it is a feature. + strong.tip.rare(data-i18n='play_level.tip_talk_is_cheap') Talk is cheap. Show me the code. - Linus Torvalds + strong.tip.rare(data-i18n='play_level.tip_first_language') The most disastrous thing that you can ever learn is your first programming language. - Alan Kay strong.tip.rare span(data-i18n='play_level.tip_harry') Yer a Wizard, span= me.get('name') || 'Anoner' diff --git a/app/views/editor/thang/colors_tab_view.coffee b/app/views/editor/thang/colors_tab_view.coffee index ed438fb46..a858f4385 100644 --- a/app/views/editor/thang/colors_tab_view.coffee +++ b/app/views/editor/thang/colors_tab_view.coffee @@ -21,6 +21,10 @@ module.exports = class ColorsTabView extends CocoView @interval = setInterval f, 1000 super options + destroy: -> + clearInterval @interval + super() + afterRender: -> super() @createShapeButtons() diff --git a/app/views/play/ladder/my_matches_tab.coffee b/app/views/play/ladder/my_matches_tab.coffee index ac8223442..94e4f4731 100644 --- a/app/views/play/ladder/my_matches_tab.coffee +++ b/app/views/play/ladder/my_matches_tab.coffee @@ -48,6 +48,8 @@ module.exports = class MyMatchesTabView extends CocoView @startsLoading = false @render() + + getRenderData: -> ctx = super() ctx.level = @level @@ -80,7 +82,9 @@ module.exports = class MyMatchesTabView extends CocoView team.losses = _.filter(team.matches, {state: 'loss'}).length scoreHistory = team.session?.get('scoreHistory') if scoreHistory?.length > 1 + team.scoreHistory = scoreHistory scoreHistory = _.last scoreHistory, 100 # Chart URL needs to be under 2048 characters for GET + team.currentScore = Math.round scoreHistory[scoreHistory.length - 1][1] * 100 team.chartColor = team.primaryColor.replace '#', '' #times = (s[0] for s in scoreHistory) @@ -109,7 +113,69 @@ module.exports = class MyMatchesTabView extends CocoView else if session.get 'isRanking' rankingState = 'ranking' @setRankingButtonText button, rankingState + + @$el.find('.score-chart-wrapper').each (i, el) => + scoreWrapper = $(el) + team = _.find @teams, name: scoreWrapper.data('team-name') + @generateScoreLineChart(scoreWrapper.attr('id'), team.scoreHistory) + + generateScoreLineChart: (wrapperID, scoreHistory) => + + + margin = + top: 20 + right: 20 + bottom: 30 + left: 50 + + width = 450 - margin.left - margin.right + height = 125 + x = d3.time.scale().range([0,width]) + y = d3.scale.linear().range([height,0]) + + xAxis = d3.svg.axis().scale(x).orient("bottom").ticks(4).outerTickSize(0) + yAxis = d3.svg.axis().scale(y).orient("left").ticks(4).outerTickSize(0) + + line = d3.svg.line().x(((d) -> x(d.date))).y((d) -> y(d.close)) + selector = "#" + wrapperID + + svg = d3.select(selector).append("svg") + .attr("width", width + margin.left + margin.right) + .attr("height", height + margin.top + margin.bottom) + .append("g") + .attr("transform","translate(#{margin.left},#{margin.top})") + time = 0 + data = scoreHistory.map (d) -> + time +=1 + return { + date: time + close: d[1] * 100 + } + + x.domain(d3.extent(data, (d) -> d.date)) + y.domain(d3.extent(data, (d) -> d.close)) + + + + svg.append("g") + .attr("class", "y axis") + .call(yAxis) + .append("text") + .attr("transform", "rotate(-90)") + .attr("y",4) + .attr("dy", ".75em") + .style("text-anchor","end") + .text("Score") + + svg.append("path") + .datum(data) + .attr("class","line") + .attr("d",line) + + + + readyToRank: (session) -> return false unless session?.get('levelID') # If it hasn't been denormalized, then it's not ready. return false unless c1 = session.get('code') diff --git a/app/views/play/level/playback_view.coffee b/app/views/play/level/playback_view.coffee index 43b744255..4a3e4d359 100644 --- a/app/views/play/level/playback_view.coffee +++ b/app/views/play/level/playback_view.coffee @@ -44,7 +44,6 @@ module.exports = class PlaybackView extends View '⌘+[, ctrl+[': 'onScrubBack' '⌘+], ctrl+]': 'onScrubForward' - # popover that shows at the current mouse position on the progressbar, using the bootstrap popover. # Could make this into a jQuery plugins itself theoretically. class HoverPopup extends $.fn.popover.Constructor diff --git a/bower.json b/bower.json index bd24eb94c..e73834bc5 100644 --- a/bower.json +++ b/bower.json @@ -35,7 +35,8 @@ "aether": "~0.1.18", "underscore.string": "~2.3.3", "firebase": "~1.0.2", - "catiline": "~2.9.3" + "catiline": "~2.9.3", + "d3": "~3.4.4" }, "overrides": { "backbone": { diff --git a/config.coffee b/config.coffee index f64a3d7ac..1a860cb76 100644 --- a/config.coffee +++ b/config.coffee @@ -65,6 +65,7 @@ exports.config = # Aether before box2d for some strange Object.defineProperty thing 'bower_components/aether/build/aether.js' + 'bower_components/d3/d3.min.js' ] stylesheets: defaultExtension: 'sass' diff --git a/server/commons/Handler.coffee b/server/commons/Handler.coffee index d026ea54f..f38885fd9 100644 --- a/server/commons/Handler.coffee +++ b/server/commons/Handler.coffee @@ -311,8 +311,9 @@ module.exports = class Handler for prop in @getEditableProperties req, document if (val = req.body[prop])? document.set prop, val - else if document.get(prop)? and req.method isnt 'PATCH' - document.set prop, 'undefined' + # Hold on, gotta think about that one + #else if document.get(prop)? and req.method isnt 'PATCH' + # document.set prop, 'undefined' obj = document.toObject() # Hack to get saving of Users to work. Probably should replace these props with strings diff --git a/server/queues/scoring.coffee b/server/queues/scoring.coffee index 327abf949..cd4670708 100644 --- a/server/queues/scoring.coffee +++ b/server/queues/scoring.coffee @@ -43,17 +43,17 @@ module.exports.addPairwiseTaskToQueueFromRequest = (req, res) -> addPairwiseTaskToQueue = (taskPair, cb) -> LevelSession.findOne(_id:taskPair[0]).lean().exec (err, firstSession) => - if err? then return cb err, false + if err? then return cb err LevelSession.find(_id:taskPair[1]).exec (err, secondSession) => - if err? then return cb err, false + if err? then return cb err try taskPairs = generateTaskPairs(secondSession, firstSession) catch e - if e then return cb e, false + if e then return cb e sendEachTaskPairToTheQueue taskPairs, (taskPairError) -> - if taskPairError? then return cb taskPairError,false - cb null, true + if taskPairError? then return cb taskPairError + cb null module.exports.resimulateAllSessions = (req, res) -> unless isUserAdmin req then return errors.unauthorized res, "Unauthorized. Even if you are authorized, you shouldn't do this" @@ -68,8 +68,8 @@ module.exports.resimulateAllSessions = (req, res) -> majorVersion: levelMajorVersion query = LevelSession - .find(findParameters) - .lean() + .find(findParameters) + .lean() query.exec (err, result) -> if err? then return errors.serverError res, err @@ -100,14 +100,12 @@ resimulateSession = (originalLevelID, levelMajorVersion, session, cb) => cb null - - module.exports.createNewTask = (req, res) -> requestSessionID = req.body.session originalLevelID = req.body.originalLevelID currentLevelID = req.body.levelID requestLevelMajorVersion = parseInt(req.body.levelMajorVersion) - + async.waterfall [ validatePermissions.bind(@,req,requestSessionID) fetchAndVerifyLevelType.bind(@,currentLevelID) @@ -115,12 +113,12 @@ module.exports.createNewTask = (req, res) -> updateSessionToSubmit fetchInitialSessionsToRankAgainst.bind(@, requestLevelMajorVersion, originalLevelID) generateAndSendTaskPairsToTheQueue - + ], (err, successMessageObject) -> if err? then return errors.serverError res, "There was an error submitting the game to the queue:#{err}" sendResponseObject req, res, successMessageObject - + validatePermissions = (req,sessionID, callback) -> if isUserAnonymous req then return callback "You are unauthorized to submit that game to the simulator" if isUserAdmin req then return callback null @@ -136,7 +134,7 @@ validatePermissions = (req,sessionID, callback) -> query.exec (err, retrievedSession) -> if err? then return callback err userHasPermissionToSubmitCode = retrievedSession.creator is req.user?.id and - not _.isEqual(retrievedSession.code, retrievedSession.submittedCode) + not _.isEqual(retrievedSession.code, retrievedSession.submittedCode) unless userHasPermissionToSubmitCode then return callback "You are unauthorized to submit that game to the simulator" callback null @@ -209,7 +207,7 @@ generateAndSendTaskPairsToTheQueue = (sessionToRankAgainst,submittedSession, cal sendEachTaskPairToTheQueue taskPairs, (taskPairError) -> if taskPairError? then return callback taskPairError callback null, {"message": "All task pairs were succesfully sent to the queue"} - + module.exports.dispatchTaskToConsumer = (req, res) -> async.waterfall [ @@ -221,7 +219,7 @@ module.exports.dispatchTaskToConsumer = (req, res) -> constructTaskLogObject.bind(@, getUserIDFromRequest(req)) processTaskObject ], (err, taskObjectToSend) -> - if err? + if err? if typeof err is "string" and err.indexOf "No more games in the queue" isnt -1 res.send(204, "No games to score.") return res.end() @@ -229,16 +227,16 @@ module.exports.dispatchTaskToConsumer = (req, res) -> return errors.serverError res, "There was an error dispatching the task: #{err}" sendResponseObject req, res, taskObjectToSend - - + + checkSimulationPermissions = (req, cb) -> - if isUserAnonymous req + if isUserAnonymous req cb "You need to be logged in to simulate games" else cb null - + receiveMessageFromSimulationQueue = (cb) -> - scoringTaskQueue.receiveMessage (err, message) -> + scoringTaskQueue.receiveMessage (err, message) -> if err? then return cb "No more games in the queue, error:#{err}" if messageIsInvalid(message) then return cb "Message received from queue is invalid" cb null, message @@ -292,90 +290,190 @@ processTaskObject = (taskObject,taskLogObject, message, cb) -> cb null, taskObject getSessionInformation = (sessionIDString, callback) -> - findParameters = + findParameters = _id: sessionIDString selectString = 'submitDate team submittedCode teamSpells levelID creator creatorName' query = LevelSession - .findOne(findParameters) - .select(selectString) - .lean() - + .findOne(findParameters) + .select(selectString) + .lean() + query.exec (err, session) -> if err? then return callback err, {"error":"There was an error retrieving the session."} callback null, session module.exports.processTaskResult = (req, res) -> - clientResponseObject = verifyClientResponse req.body, res + async.waterfall [ + verifyClientResponse.bind(@,req.body) + fetchTaskLog.bind(@) + checkTaskLog.bind(@) + deleteQueueMessage.bind(@) + fetchLevelSession.bind(@) + checkSubmissionDate.bind(@) + logTaskComputation.bind(@) + updateSessions.bind(@) + indexNewScoreArray.bind(@) + addMatchToSessions.bind(@) + updateUserSimulationCounts.bind(@, req.user._id) + determineIfSessionShouldContinueAndUpdateLog.bind(@) + findNearestBetterSessionID.bind(@) + addNewSessionsToQueue.bind(@) + ], (err, results) -> + if err is "shouldn't continue" + sendResponseObject req, res, {"message":"The scores were updated successfully, person lost so no more games are being inserted!"} + else if err is "no session was found" + sendResponseObject req, res, {"message":"There were no more games to rank (game is at top)!"} + else if err? + errors.serverError res, "There was an error:#{err}" + else + sendResponseObject req, res, {"message":"The scores were updated successfully and more games were sent to the queue!"} - return unless clientResponseObject? - TaskLog.findOne {_id: clientResponseObject.taskID}, (err, taskLog) -> - return errors.serverError res, "There was an error retrieiving the task log object" if err? +verifyClientResponse = (responseObject, callback) -> + #TODO: better verification + unless typeof responseObject is "object" + callback "The response to that query is required to be a JSON object." + else + @clientResponseObject = responseObject + log.info "Verified client response!" + callback null, responseObject - taskLogJSON = taskLog.toObject() +fetchTaskLog = (responseObject, callback) -> + findParameters = + _id: responseObject.taskID + query = TaskLog + .findOne(findParameters) + query.exec (err, taskLog) => + @taskLog = taskLog + log.info "Fetched task log!" + callback err, taskLog.toObject() - return errors.badInput res, "That computational task has already been performed" if taskLogJSON.calculationTimeMS - return handleTimedOutTask req, res, clientResponseObject if hasTaskTimedOut taskLogJSON.sentDate +checkTaskLog = (taskLog, callback) -> + if taskLog.calculationTimeMS then return callback "That computational task has already been performed" + if hasTaskTimedOut taskLog.sentDate then return callback "The task has timed out" + log.info "Checked task log" + callback null - scoringTaskQueue.deleteMessage clientResponseObject.receiptHandle, (err) -> - console.log "Deleted message." - if err? then return errors.badInput res, "The queue message is already back in the queue, rejecting results." +deleteQueueMessage = (callback) -> + scoringTaskQueue.deleteMessage @clientResponseObject.receiptHandle, (err) -> + log.info "Deleted queue message" + callback err - LevelSession.findOne(_id: clientResponseObject.originalSessionID).lean().exec (err, levelSession) -> - if err? then return errors.serverError res, "There was a problem finding the level session:#{err}" - - supposedSubmissionDate = new Date(clientResponseObject.sessions[0].submitDate) - - if Number(supposedSubmissionDate) isnt Number(levelSession.submitDate) - return sendResponseObject req, res, {"message":"The game has been resubmitted. Removing from queue..."} - - logTaskComputation clientResponseObject, taskLog, (logErr) -> - if logErr? then return errors.serverError res, "There as a problem logging the task computation: #{logErr}" - - updateSessions clientResponseObject, (updateError, newScoreArray) -> - if updateError? then return errors.serverError res, "There was an error updating the scores.#{updateError}" - - newScoresObject = _.indexBy newScoreArray, 'id' - - addMatchToSessions clientResponseObject, newScoresObject, (err, data) -> - if err? then return errors.serverError res, "There was an error updating the sessions with the match! #{JSON.stringify err}" - - incrementUserSimulationCount req.user._id, 'simulatedBy' - incrementUserSimulationCount levelSession.creator, 'simulatedFor' - - originalSessionID = clientResponseObject.originalSessionID - originalSessionTeam = clientResponseObject.originalSessionTeam - originalSessionRank = parseInt clientResponseObject.originalSessionRank - - determineIfSessionShouldContinueAndUpdateLog originalSessionID, originalSessionRank, (err, sessionShouldContinue) -> - if err? then return errors.serverError res, "There was an error determining if the session should continue, #{err}" - - if sessionShouldContinue - opposingTeam = calculateOpposingTeam(originalSessionTeam) - opponentID = _.pull(_.keys(newScoresObject), originalSessionID) - sessionNewScore = newScoresObject[originalSessionID].totalScore - opponentNewScore = newScoresObject[opponentID].totalScore - - levelOriginalID = levelSession.level.original - levelOriginalMajorVersion = levelSession.level.majorVersion - findNearestBetterSessionID levelOriginalID, levelOriginalMajorVersion, originalSessionID, sessionNewScore, opponentNewScore, opponentID, opposingTeam, (err, opponentSessionID) -> - if err? then return errors.serverError res, "There was an error finding the nearest sessionID!" - if opponentSessionID - addPairwiseTaskToQueue [originalSessionID, opponentSessionID], (err, success) -> - if err? then return errors.serverError res, "There was an error sending the pairwise tasks to the queue!" - sendResponseObject req, res, {"message":"The scores were updated successfully and more games were sent to the queue!"} - else - LevelSession.update {_id: originalSessionID}, {isRanking: false}, {multi: false}, (err, affected) -> - if err? then return errors.serverError res, "There was an error marking the victorious session as not being ranked." - return sendResponseObject req, res, {"message":"There were no more games to rank (game is at top)!"} - else - console.log "Player lost, achieved rank #{originalSessionRank}" - LevelSession.update {_id: originalSessionID}, {isRanking: false}, {multi: false}, (err, affected) -> - if err? then return errors.serverError res, "There was an error marking the completed session as not being ranked." - sendResponseObject req, res, {"message":"The scores were updated successfully, person lost so no more games are being inserted!"} +fetchLevelSession = (callback) -> + findParameters = + _id: @clientResponseObject.originalSessionID + query = LevelSession + .findOne(findParameters) + .lean() + query.exec (err, session) => + @levelSession = session + log.info "Fetched level session" + callback err -determineIfSessionShouldContinueAndUpdateLog = (sessionID, sessionRank, cb) -> +checkSubmissionDate = (callback) -> + supposedSubmissionDate = new Date(@clientResponseObject.sessions[0].submitDate) + if Number(supposedSubmissionDate) isnt Number(@levelSession.submitDate) + callback "The game has been resubmitted. Removing from queue..." + else + log.info "Checked submission date" + callback null + +logTaskComputation = (callback) -> + @taskLog.set('calculationTimeMS',@clientResponseObject.calculationTimeMS) + @taskLog.set('sessions') + @taskLog.calculationTimeMS = @clientResponseObject.calculationTimeMS + @taskLog.sessions = @clientResponseObject.sessions + @taskLog.save (err, saved) -> + log.info "Logged task computation" + callback err + +updateSessions = (callback) -> + sessionIDs = _.pluck @clientResponseObject.sessions, 'sessionID' + + async.map sessionIDs, retrieveOldSessionData, (err, oldScores) => + if err? then callback err, {"error": "There was an error retrieving the old scores"} + + oldScoreArray = _.toArray putRankingFromMetricsIntoScoreObject @clientResponseObject, oldScores + newScoreArray = bayes.updatePlayerSkills oldScoreArray + saveNewScoresToDatabase newScoreArray, callback + + +saveNewScoresToDatabase = (newScoreArray, callback) -> + async.eachSeries newScoreArray, updateScoreInSession, (err) -> + log.info "Saved new scores to database" + callback err,newScoreArray + + +updateScoreInSession = (scoreObject,callback) -> + LevelSession.findOne {"_id": scoreObject.id}, (err, session) -> + if err? then return callback err, null + + session = session.toObject() + newTotalScore = scoreObject.meanStrength - 1.8 * scoreObject.standardDeviation + scoreHistoryAddition = [Date.now(), newTotalScore] + updateObject = + meanStrength: scoreObject.meanStrength + standardDeviation: scoreObject.standardDeviation + totalScore: newTotalScore + $push: {scoreHistory: {$each: [scoreHistoryAddition], $slice: -1000}} + + LevelSession.update {"_id": scoreObject.id}, updateObject, callback + log.info "New total score for session #{scoreObject.id} is #{updateObject.totalScore}" + +indexNewScoreArray = (newScoreArray, callback) -> + newScoresObject = _.indexBy newScoreArray, 'id' + @newScoresObject = newScoresObject + callback null, newScoresObject + +addMatchToSessions = (newScoreObject, callback) -> + matchObject = {} + matchObject.date = new Date() + matchObject.opponents = {} + for session in @clientResponseObject.sessions + sessionID = session.sessionID + matchObject.opponents[sessionID] = {} + matchObject.opponents[sessionID].sessionID = sessionID + matchObject.opponents[sessionID].userID = session.creator + matchObject.opponents[sessionID].metrics = {} + matchObject.opponents[sessionID].metrics.rank = Number(newScoreObject[sessionID].gameRanking) + + log.info "Match object computed, result: #{matchObject}" + log.info "Writing match object to database..." + #use bind with async to do the writes + sessionIDs = _.pluck @clientResponseObject.sessions, 'sessionID' + async.each sessionIDs, updateMatchesInSession.bind(@,matchObject), (err) -> callback err + +updateMatchesInSession = (matchObject, sessionID, callback) -> + currentMatchObject = {} + currentMatchObject.date = matchObject.date + currentMatchObject.metrics = matchObject.opponents[sessionID].metrics + opponentsClone = _.cloneDeep matchObject.opponents + opponentsClone = _.omit opponentsClone, sessionID + opponentsArray = _.toArray opponentsClone + currentMatchObject.opponents = opponentsArray + + sessionUpdateObject = + $push: {matches: {$each: [currentMatchObject], $slice: -200}} + log.info "Updating session #{sessionID}" + LevelSession.update {"_id":sessionID}, sessionUpdateObject, callback + +updateUserSimulationCounts = (reqUserID,callback) -> + incrementUserSimulationCount reqUserID, 'simulatedBy', (err) => + if err? then return callback err + incrementUserSimulationCount @levelSession.creator, 'simulatedFor', callback + +incrementUserSimulationCount = (userID, type, callback) => + inc = {} + inc[type] = 1 + User.update {_id: userID}, {$inc: inc}, (err, affected) -> + log.error "Error incrementing #{type} for #{userID}: #{err}" if err + callback err + +determineIfSessionShouldContinueAndUpdateLog = (cb) -> + sessionID = @clientResponseObject.originalSessionID + sessionRank = parseInt @clientResponseObject.originalSessionRank + queryParameters = _id: sessionID @@ -394,18 +492,26 @@ determineIfSessionShouldContinueAndUpdateLog = (sessionID, sessionRank, cb) -> totalNumberOfGamesPlayed = updatedSession.numberOfWinsAndTies + updatedSession.numberOfLosses if totalNumberOfGamesPlayed < 10 console.log "Number of games played is less than 10, continuing..." - cb null, true + cb null else ratio = (updatedSession.numberOfLosses) / (totalNumberOfGamesPlayed) if ratio > 0.33 - cb null, false + cb "shouldn't continue" console.log "Ratio(#{ratio}) is bad, ending simulation" else console.log "Ratio(#{ratio}) is good, so continuing simulations" - cb null, true + cb null -findNearestBetterSessionID = (levelOriginalID, levelMajorVersion, sessionID, sessionTotalScore, opponentSessionTotalScore, opponentSessionID, opposingTeam, cb) -> +findNearestBetterSessionID = (cb) -> + levelOriginalID = @levelSession.level.original + levelMajorVersion = @levelSession.level.majorVersion + sessionID = @clientResponseObject.originalSessionID + sessionTotalScore = @newScoresObject[sessionID].totalScore + opponentSessionID = _.pull(_.keys(@newScoresObject), sessionID) + opponentSessionTotalScore = @newScoresObject[opponentSessionID].totalScore + opposingTeam = calculateOpposingTeam(@clientResponseObject.originalSessionTeam) + retrieveAllOpponentSessionIDs sessionID, (err, opponentSessionIDs) -> if err? then return cb err, null @@ -434,23 +540,23 @@ findNearestBetterSessionID = (levelOriginalID, levelMajorVersion, sessionID, ses selectString = '_id totalScore' query = LevelSession.findOne(queryParameters) - .sort(sortParameters) - .limit(limitNumber) - .select(selectString) - .lean() + .sort(sortParameters) + .limit(limitNumber) + .select(selectString) + .lean() console.log "Finding session with score near #{opponentSessionTotalScore}" query.exec (err, session) -> if err? then return cb err, session - unless session then return cb err, null + unless session then return cb "no session was found" console.log "Found session with score #{session.totalScore}" cb err, session._id retrieveAllOpponentSessionIDs = (sessionID, cb) -> query = LevelSession.findOne({"_id":sessionID}) - .select('matches.opponents.sessionID matches.date submitDate') - .lean() + .select('matches.opponents.sessionID matches.date submitDate') + .lean() query.exec (err, session) -> if err? then return cb err, null opponentSessionIDs = (match.opponents[0].sessionID for match in session.matches when match.date > session.submitDate) @@ -462,56 +568,15 @@ calculateOpposingTeam = (sessionTeam) -> opposingTeams = _.pull teams, sessionTeam return opposingTeams[0] -incrementUserSimulationCount = (userID, type) -> - inc = {} - inc[type] = 1 - User.update {_id: userID}, {$inc: inc}, (err, affected) -> - log.error "Error incrementing #{type} for #{userID}: #{err}" if err - - -addMatchToSessions = (clientResponseObject, newScoreObject, callback) -> - matchObject = {} - matchObject.date = new Date() - matchObject.opponents = {} - for session in clientResponseObject.sessions - sessionID = session.sessionID - matchObject.opponents[sessionID] = {} - matchObject.opponents[sessionID].sessionID = sessionID - matchObject.opponents[sessionID].userID = session.creator - matchObject.opponents[sessionID].metrics = {} - matchObject.opponents[sessionID].metrics.rank = Number(newScoreObject[sessionID].gameRanking) - - log.info "Match object computed, result: #{matchObject}" - log.info "Writing match object to database..." - #use bind with async to do the writes - sessionIDs = _.pluck clientResponseObject.sessions, 'sessionID' - async.each sessionIDs, updateMatchesInSession.bind(@,matchObject), (err) -> callback err, null - -updateMatchesInSession = (matchObject, sessionID, callback) -> - currentMatchObject = {} - currentMatchObject.date = matchObject.date - currentMatchObject.metrics = matchObject.opponents[sessionID].metrics - opponentsClone = _.cloneDeep matchObject.opponents - opponentsClone = _.omit opponentsClone, sessionID - opponentsArray = _.toArray opponentsClone - currentMatchObject.opponents = opponentsArray - - sessionUpdateObject = - $push: {matches: {$each: [currentMatchObject], $slice: -200}} - log.info "Updating session #{sessionID}" - LevelSession.update {"_id":sessionID}, sessionUpdateObject, callback - +addNewSessionsToQueue = (sessionID, callback) -> + sessions = [@clientResponseObject.originalSessionID, sessionID] + addPairwiseTaskToQueue sessions, callback messageIsInvalid = (message) -> (not message?) or message.isEmpty() sendEachTaskPairToTheQueue = (taskPairs, callback) -> async.each taskPairs, sendTaskPairToQueue, callback - - - - - generateTaskPairs = (submittedSessions, sessionToScore) -> taskPairs = [] for session in submittedSessions @@ -532,10 +597,6 @@ isUserAnonymous = (req) -> if req.user? then return req.user.get('anonymous') el isUserAdmin = (req) -> return Boolean(req.user?.isAdmin()) - - - - sendResponseObject = (req,res,object) -> res.setHeader('Content-Type', 'application/json') res.send(object) @@ -545,51 +606,6 @@ hasTaskTimedOut = (taskSentTimestamp) -> taskSentTimestamp + scoringTaskTimeoutI handleTimedOutTask = (req, res, taskBody) -> errors.clientTimeout res, "The results weren't provided within the timeout" -verifyClientResponse = (responseObject, res) -> - unless typeof responseObject is "object" - errors.badInput res, "The response to that query is required to be a JSON object." - null - else - responseObject - -logTaskComputation = (taskObject,taskLogObject, callback) -> - taskLogObject.calculationTimeMS = taskObject.calculationTimeMS - taskLogObject.sessions = taskObject.sessions - taskLogObject.save callback - - -updateSessions = (taskObject,callback) -> - sessionIDs = _.pluck taskObject.sessions, 'sessionID' - - async.map sessionIDs, retrieveOldSessionData, (err, oldScores) -> - if err? then callback err, {"error": "There was an error retrieving the old scores"} - - oldScoreArray = _.toArray putRankingFromMetricsIntoScoreObject taskObject, oldScores - newScoreArray = bayes.updatePlayerSkills oldScoreArray - saveNewScoresToDatabase newScoreArray, callback - - -saveNewScoresToDatabase = (newScoreArray, callback) -> - async.eachSeries newScoreArray, updateScoreInSession, (err) -> callback err,newScoreArray - - -updateScoreInSession = (scoreObject,callback) -> - LevelSession.findOne {"_id": scoreObject.id}, (err, session) -> - if err? then return callback err, null - - session = session.toObject() - newTotalScore = scoreObject.meanStrength - 1.8 * scoreObject.standardDeviation - scoreHistoryAddition = [Date.now(), newTotalScore] - updateObject = - meanStrength: scoreObject.meanStrength - standardDeviation: scoreObject.standardDeviation - totalScore: newTotalScore - $push: {scoreHistory: {$each: [scoreHistoryAddition], $slice: -1000}} - - LevelSession.update {"_id": scoreObject.id}, updateObject, callback - log.info "New total score for session #{scoreObject.id} is #{updateObject.totalScore}" - - putRankingFromMetricsIntoScoreObject = (taskObject,scoreObject) -> scoreObject = _.indexBy scoreObject, 'id' scoreObject[session.sessionID].gameRanking = session.metrics.rank for session in taskObject.sessions diff --git a/server/routes/auth.coffee b/server/routes/auth.coffee index dcb8ea12a..76612e2e0 100644 --- a/server/routes/auth.coffee +++ b/server/routes/auth.coffee @@ -71,9 +71,7 @@ module.exports.setup = (app) -> if req.user sendSelf(req, res) else - user = new User({anonymous:true}) - user.set 'testGroupNumber', Math.floor(Math.random() * 256) # also in app/lib/auth - user.set 'preferredLanguage', languages.languageCodeFromAcceptedLanguages req.acceptedLanguages + user = makeNewUser(req) makeNext = (req, res) -> -> sendSelf(req, res) next = makeNext(req, res) loginUser(req, res, user, false, next) @@ -84,21 +82,6 @@ module.exports.setup = (app) -> res.send(UserHandler.formatEntity(req, req.user)) res.end() - loginUser = (req, res, user, send=true, next=null) -> - user.save((err) -> - if err - return @sendDatabaseError(res, err) - - req.logIn(user, (err) -> - if err - return @sendDatabaseError(res, err) - - if send - return @sendSuccess(res, user) - next() if next - ) - ) - app.post('/auth/logout', (req, res) -> req.logout() res.end() @@ -155,6 +138,26 @@ module.exports.setup = (app) -> res.send "Unsubscribed #{req.query.email} from all CodeCombat emails. Sorry to see you go!

Account settings

" res.end() +module.exports.loginUser = loginUser = (req, res, user, send=true, next=null) -> + user.save((err) -> + if err + return @sendDatabaseError(res, err) + + req.logIn(user, (err) -> + if err + return @sendDatabaseError(res, err) + + if send + return @sendSuccess(res, user) + next() if next + ) + ) + +module.exports.makeNewUser = makeNewUser = (req) -> + user = new User({anonymous:true}) + user.set 'testGroupNumber', Math.floor(Math.random() * 256) # also in app/lib/auth + user.set 'preferredLanguage', languages.languageCodeFromAcceptedLanguages req.acceptedLanguages + createMailOptions = (receiver, password) -> # TODO: use email templates here options = @@ -163,4 +166,4 @@ createMailOptions = (receiver, password) -> replyTo: config.mail.username subject: "[CodeCombat] Password Reset" text: "You can log into your account with: #{password}" -# + diff --git a/server_setup.coffee b/server_setup.coffee index e0a72f4dc..c06482a85 100644 --- a/server_setup.coffee +++ b/server_setup.coffee @@ -9,6 +9,8 @@ baseRoute = require './server/routes/base' user = require './server/users/user_handler' logging = require './server/commons/logging' config = require './server_config' +auth = require './server/routes/auth' +UserHandler = require('./server/users/user_handler') ###Middleware setup functions implementation### # 2014-03-03: Try not using this and see if it's still a problem @@ -85,7 +87,19 @@ exports.setupMiddleware = (app) -> setupFallbackRouteToIndex = (app) -> app.all '*', (req, res) -> - res.sendfile path.join(__dirname, 'public', 'index.html') + if req.user + sendMain(req, res) + else + user = auth.makeNewUser(req) + makeNext = (req, res) -> -> sendMain(req, res) + next = makeNext(req, res) + auth.loginUser(req, res, user, false, next) + +sendMain = (req, res) -> + fs.readFile path.join(__dirname, 'public', 'main.html'), 'utf8', (err,data) -> + # insert the user object directly into the html so the application can have it immediately + data = data.replace('"userObjectTag"', JSON.stringify(UserHandler.formatEntity(req, req.user))) + res.send data setupFacebookCrossDomainCommunicationRoute = (app) -> app.get '/channel.html', (req, res) ->