From 95dd067c9c3b72e89e6c09bfb9b2c210a3ed42b2 Mon Sep 17 00:00:00 2001 From: Maka Date: Tue, 17 May 2016 23:04:46 -0400 Subject: [PATCH 01/24] Increased max thang-name-length to 60 characters --- app/schemas/models/level.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/schemas/models/level.coffee b/app/schemas/models/level.coffee index 4869e473a..6df2c44c1 100644 --- a/app/schemas/models/level.coffee +++ b/app/schemas/models/level.coffee @@ -57,7 +57,7 @@ SpecificArticleSchema.properties.i18n = {type: 'object', format: 'i18n', props: SpecificArticleSchema.displayProperty = 'name' side = {title: 'Side', description: 'A side.', type: 'string', 'enum': ['left', 'right', 'top', 'bottom']} -thang = {title: 'Thang', description: 'The name of a Thang.', type: 'string', maxLength: 30, format: 'thang'} +thang = {title: 'Thang', description: 'The name of a Thang.', type: 'string', maxLength: 60, format: 'thang'} eventPrereqValueTypes = ['boolean', 'integer', 'number', 'null', 'string'] # not 'object' or 'array' EventPrereqSchema = c.object {title: 'Event Prerequisite', format: 'event-prereq', description: 'Script requires that the value of some property on the event triggering it to meet some prerequisite.', required: ['eventProps']}, From 0436f18279058e4225ec4ca70f6d27409deb2998 Mon Sep 17 00:00:00 2001 From: Josh Callebaut Date: Mon, 4 Apr 2016 11:03:07 -0700 Subject: [PATCH 02/24] Migrates Artisan helpers to their own directory and begins implementation of level tasks view --- app/core/Router.coffee | 6 ++ app/styles/artisans/artisansView.sass | 6 ++ app/styles/artisans/levelAnalyticsView.sass | 1 + app/styles/artisans/levelTasksView.sass | 12 ++++ app/styles/artisans/thangTasksView.sass | 12 ++++ app/templates/artisans/artisansView.jade | 10 ++++ .../artisans/levelAnalyticsView.jade | 4 ++ app/templates/artisans/levelTasksView.jade | 34 +++++++++++ app/templates/artisans/thangTasksView.jade | 32 +++++++++++ app/views/artisans/ArtisansView.coffee | 8 +++ app/views/artisans/LevelAnalyticsView.coffee | 35 ++++++++++++ app/views/artisans/LevelTasksView.coffee | 57 +++++++++++++++++++ app/views/artisans/ThangTasksView.coffee | 48 ++++++++++++++++ 13 files changed, 265 insertions(+) create mode 100644 app/styles/artisans/artisansView.sass create mode 100644 app/styles/artisans/levelAnalyticsView.sass create mode 100644 app/styles/artisans/levelTasksView.sass create mode 100644 app/styles/artisans/thangTasksView.sass create mode 100644 app/templates/artisans/artisansView.jade create mode 100644 app/templates/artisans/levelAnalyticsView.jade create mode 100644 app/templates/artisans/levelTasksView.jade create mode 100644 app/templates/artisans/thangTasksView.jade create mode 100644 app/views/artisans/ArtisansView.coffee create mode 100644 app/views/artisans/LevelAnalyticsView.coffee create mode 100644 app/views/artisans/LevelTasksView.coffee create mode 100644 app/views/artisans/ThangTasksView.coffee diff --git a/app/core/Router.coffee b/app/core/Router.coffee index 17c5a1853..1ad136f59 100644 --- a/app/core/Router.coffee +++ b/app/core/Router.coffee @@ -43,6 +43,12 @@ module.exports = class CocoRouter extends Backbone.Router 'admin/pending-patches': go('admin/PendingPatchesView') 'admin/codelogs': go('admin/CodeLogsView') + 'artisans': go('artisans/ArtisansView') + + 'artisans/level-analytics': go('artisans/LevelAnalyticsView') + 'artisans/level-tasks': go('artisans/LevelTasksView') + 'artisans/thang-tasks': go('artisans/ThangTasksView') + 'beta': go('HomeView') 'careers': => window.location.href = 'https://jobs.lever.co/codecombat' diff --git a/app/styles/artisans/artisansView.sass b/app/styles/artisans/artisansView.sass new file mode 100644 index 000000000..1a56401f8 --- /dev/null +++ b/app/styles/artisans/artisansView.sass @@ -0,0 +1,6 @@ +#artisans-view + text-align: center + a + font-size: xx-large + img + border-radius: 8px \ No newline at end of file diff --git a/app/styles/artisans/levelAnalyticsView.sass b/app/styles/artisans/levelAnalyticsView.sass new file mode 100644 index 000000000..a1327ed63 --- /dev/null +++ b/app/styles/artisans/levelAnalyticsView.sass @@ -0,0 +1 @@ +#level-analytics-view \ No newline at end of file diff --git a/app/styles/artisans/levelTasksView.sass b/app/styles/artisans/levelTasksView.sass new file mode 100644 index 000000000..a5585bb76 --- /dev/null +++ b/app/styles/artisans/levelTasksView.sass @@ -0,0 +1,12 @@ +#level-tasks-view + #levelTable + width: 100% + + .tasksTable + width: 100% + + .tasks + width: 87.5% + + .taskOwner + width: 12.5% \ No newline at end of file diff --git a/app/styles/artisans/thangTasksView.sass b/app/styles/artisans/thangTasksView.sass new file mode 100644 index 000000000..599a6a6ab --- /dev/null +++ b/app/styles/artisans/thangTasksView.sass @@ -0,0 +1,12 @@ +#thang-tasks-view + #thangTable + width: 100% + + .tasksTable + width: 100% + + .tasks + width: 87.5% + + .taskOwner + width: 12.5% \ No newline at end of file diff --git a/app/templates/artisans/artisansView.jade b/app/templates/artisans/artisansView.jade new file mode 100644 index 000000000..0cf81943f --- /dev/null +++ b/app/templates/artisans/artisansView.jade @@ -0,0 +1,10 @@ +extends /templates/base + +block content + img(src='/images/pages/user/artisan.png') + div + a(href='artisans/thang-tasks') + |Thang Tasks + div + a(href="artisans/level-tasks") + |Level Tasks \ No newline at end of file diff --git a/app/templates/artisans/levelAnalyticsView.jade b/app/templates/artisans/levelAnalyticsView.jade new file mode 100644 index 000000000..d733d9169 --- /dev/null +++ b/app/templates/artisans/levelAnalyticsView.jade @@ -0,0 +1,4 @@ +extends /templates/base + +block content + table#levelTable \ No newline at end of file diff --git a/app/templates/artisans/levelTasksView.jade b/app/templates/artisans/levelTasksView.jade new file mode 100644 index 000000000..e44ae7dbd --- /dev/null +++ b/app/templates/artisans/levelTasksView.jade @@ -0,0 +1,34 @@ +extends /templates/base + +block content + #level-tasks-view + div + a(href='./') + | < Artisans Home + input#nameSearch(placeholder='Filter: Level Name') + br + input#descSearch(placeholder='Filter: Task Description') + hr + if view.processedLevels + table.table.table-striped#levelTable + tr + th Level Name + th Task List + for level in view.processedLevels + if view.hasIncompleteTasks(level) + +levelRow(level) + else + div ole? + + + +mixin levelRow(level) + tr + td.taskOwner + a(href= 'level/' + level.slug)= level.name + td.tasks + table.table-striped.table-hover.tasksTable + for task in (level.tasks2 || []) + if !task.complete + tr + td= task.name diff --git a/app/templates/artisans/thangTasksView.jade b/app/templates/artisans/thangTasksView.jade new file mode 100644 index 000000000..dc9c30c08 --- /dev/null +++ b/app/templates/artisans/thangTasksView.jade @@ -0,0 +1,32 @@ +extends /templates/base + +block content + #thang-tasks-view + div + a(href='./') + | < Artisans Home + input#nameSearch(placeholder='Filter: Thang Name') + br + input#descSearch(placeholder='Filter: Task Description') + hr + if view.processedThangs + table.table.table-striped#thangTable + tr + th Thang Name + th Task List + for thang in view.processedThangs + if view.hasIncompleteTasks(thang) + +thangRow(thang) + else + span No view.processedThangs + +mixin thangRow(thang) + tr + td.taskOwner + a(href= 'thang/' + thang.get('slug'))= thang.get('name') + td.tasks + table.table-striped.table-hover.tasksTable + for task in (thang.tasks || []) + if !task.complete + tr + td= task.name diff --git a/app/views/artisans/ArtisansView.coffee b/app/views/artisans/ArtisansView.coffee new file mode 100644 index 000000000..76b4110e9 --- /dev/null +++ b/app/views/artisans/ArtisansView.coffee @@ -0,0 +1,8 @@ +RootView = require 'views/core/RootView' +template = require 'templates/artisans/artisansView' + +module.exports = class ArtisansView extends RootView + template: template + id: 'artisans-view' + constructor: (options) -> + super options \ No newline at end of file diff --git a/app/views/artisans/LevelAnalyticsView.coffee b/app/views/artisans/LevelAnalyticsView.coffee new file mode 100644 index 000000000..4a35daf7f --- /dev/null +++ b/app/views/artisans/LevelAnalyticsView.coffee @@ -0,0 +1,35 @@ +RootView = require 'views/core/RootView' +template = require 'templates/artisans/levelAnalyticsView' +Level = require 'models/Level' +Campaign = require 'models/Campaign' +CocoCollection = require 'collections/CocoCollection' + +module.exports = class LevelAnalyticsView extends RootView + template: template + id: 'level-analytics-view' + constructor: (options) -> + super options + @campaigns = new CocoCollection([], + url: '/db/campaign?project=name,slug,tasks' + model: Campaign + ) + @campaigns.fetch() + @listenTo(@campaigns, 'sync', @onCampaignsLoaded) + @supermodel.loadCollection(@campaigns, 'campaigns') + onCampaignsLoaded: -> + @levels = [] + for campaign in @campaigns.models + continue unless campaign.get('slug') is 'dungeon' + levels = campaign.get('levels') + for key, level of levels + @levels.push level.slug + @stats = new CocoCollection([], + url: '/db/analytics_perday/-/level_completions?slug=dungeons-of-kithgard&startDay=20151022&endDay=20151104' + model: {} + ) + @stats.fetch() + @listenTo(@stats, 'sync', @onStatsLoaded) + @supermodel.loadCollection(@stats, 'stats') + @renderSelectors '#levelTable' + onStatsLoaded: -> + console.log @stats \ No newline at end of file diff --git a/app/views/artisans/LevelTasksView.coffee b/app/views/artisans/LevelTasksView.coffee new file mode 100644 index 000000000..a898e52d4 --- /dev/null +++ b/app/views/artisans/LevelTasksView.coffee @@ -0,0 +1,57 @@ +RootView = require 'views/core/RootView' +template = require 'templates/artisans/levelTasksView' +#ThangType = require 'models/ThangType' +Level = require 'models/Level' +Campaign = require 'models/Campaign' +CocoCollection = require 'collections/CocoCollection' + +module.exports = class LevelTasksView extends RootView + template: template + id: 'level-tasks-view' + events: + 'input input': 'searchUpdate' + 'change input': 'searchUpdate' + excludedCampaigns = [ + "picoctf" + "auditions" + ] + constructor: (options) -> + super options + @campaigns = new CocoCollection([], + url: '/db/campaign?project=name,slug,tasks' + model: Campaign + ) + @campaigns.fetch() + @listenTo(@campaigns, 'sync', @onCampaignsLoaded) + @supermodel.loadCollection(@campaigns, 'campaigns') + + onCampaignsLoaded: -> + @levels = {} + sum = 0 + for campaign in @campaigns.models + continue unless excludedCampaigns.indexOf(campaign.get 'slug') is -1 + levels = campaign.get('levels') + sum += Object.keys(levels).length + for key, level of levels + continue unless ///#{$('#nameSearch')[0].value}///i.test level.name + levelSlug = level.slug + @levels[levelSlug] = level + @processedLevels = @levels + for key, level of @processedLevels + level.tasks2 = _.filter level.tasks, (_elem) -> + return ///#{$('#descSearch')[0].value}///i.test _elem.name + @renderSelectors '#levelTable' + + searchUpdate: -> + if not @lastLoad? or (new Date()).getTime() - @lastLoad > 60 * 1000 * 1 # Update only after a minute from last update. + @campaigns.fetch() + @listenTo(@campaigns, 'sync', @onCampaignsLoaded) + @supermodel.loadCollection(@campaigns, 'campaigns') + @lastLoad = (new Date()).getTime() + else + @onCampaignsLoaded() + + + # Jade helper + hasIncompleteTasks: (level) -> + return level.tasks2 and level.tasks2.filter((_elem) -> return not _elem.complete).length > 0 \ No newline at end of file diff --git a/app/views/artisans/ThangTasksView.coffee b/app/views/artisans/ThangTasksView.coffee new file mode 100644 index 000000000..d17bef021 --- /dev/null +++ b/app/views/artisans/ThangTasksView.coffee @@ -0,0 +1,48 @@ +RootView = require 'views/core/RootView' +template = require 'templates/artisans/thangTasksView' +ThangType = require 'models/ThangType' +CocoCollection = require 'collections/CocoCollection' + +module.exports = class ThangTasksView extends RootView + template: template + id: 'thang-tasks-view' + events: + 'input input': 'searchUpdate' + 'change input': 'searchUpdate' + + constructor: (options) -> + super options + @thangs = new CocoCollection([], + url: '/db/thang.type?project=name,tasks,slug' + model: ThangType + comparator: @sortThangs + ) + @lastLoad = (new Date()).getTime() + @listenTo(@thangs, 'sync', @onThangsLoaded) + @supermodel.loadCollection(@thangs, 'thangs') + + searchUpdate: -> + if not @lastLoad? or (new Date()).getTime() - @lastLoad > 60 * 1000 * 1 # Update only after a minute from last update. + @thangs.fetch() + @listenTo(@thangs, 'sync', @onThangsLoaded) + @supermodel.loadCollection(@thangs, 'thangs') + @lastLoad = (new Date()).getTime() + else + @onThangsLoaded() + + onThangsLoaded: -> + @processedThangs = @thangs.filter (_elem) -> + # Case-insensitive search of input vs name. + return ///#{$('#nameSearch')[0].value}///i.test _elem.get('name') + for thang in @processedThangs + thang.tasks = _.filter thang.attributes.tasks, (_elem) -> + # Similar case-insensitive search of input vs description (name). + return ///#{$('#descSearch')[0].value}///i.test _elem.name + @renderSelectors '#thangTable' + + sortThangs: (a, b) -> + a.get('name').localeCompare(b.get('name')) + + # Jade helper + hasIncompleteTasks: (thang) -> + return thang.tasks and thang.tasks.filter((_elem) -> return not _elem.complete).length > 0 \ No newline at end of file From 62a027e76ed1cbcec45612ecb31c63b2d75063eb Mon Sep 17 00:00:00 2001 From: Josh Callebaut Date: Thu, 7 Apr 2016 14:48:40 -0700 Subject: [PATCH 03/24] Initial stages of an analytics view --- app/views/artisans/LevelAnalyticsView.coffee | 46 +++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/app/views/artisans/LevelAnalyticsView.coffee b/app/views/artisans/LevelAnalyticsView.coffee index 4a35daf7f..82dcbb9e8 100644 --- a/app/views/artisans/LevelAnalyticsView.coffee +++ b/app/views/artisans/LevelAnalyticsView.coffee @@ -2,21 +2,64 @@ RootView = require 'views/core/RootView' template = require 'templates/artisans/levelAnalyticsView' Level = require 'models/Level' Campaign = require 'models/Campaign' +Level = require 'models/Level' CocoCollection = require 'collections/CocoCollection' module.exports = class LevelAnalyticsView extends RootView template: template id: 'level-analytics-view' + excludedCampaigns = [ + "picoctf" + "auditions" + ] constructor: (options) -> super options @campaigns = new CocoCollection([], url: '/db/campaign?project=name,slug,tasks' model: Campaign ) + @levels = new CocoCollection([], + url: '/db/level?project=slug,thangs&limit=100' + model: Level + ) @campaigns.fetch() @listenTo(@campaigns, 'sync', @onCampaignsLoaded) @supermodel.loadCollection(@campaigns, 'campaigns') + + @levels.fetch() + @listenTo(@levels, 'sync', @onLevelsLoaded) + @supermodel.loadCollection(@levels, 'levels') + onCampaignsLoaded: -> + @levelSlugs = [] + for campaign in @campaigns.models + continue unless excludedCampaigns.indexOf(campaign.get 'slug') is -1 + levels = campaign.get('levels') + for key, level of levels + @levelSlugs.push level.slug + if @levels.models.length isnt 0 + @readyUp() + onLevelsLoaded: -> + console.log @levels + if @campaigns.models.length isnt 0 + @readyUp() + readyUp: -> + for levelSlug in @levelSlugs + level = @levels.findWhere({slug:levelSlug}) + unless level? + continue + console.warn('Warning: ' + levelSlug) unless level? + console.log levelSlug + + thangs = level.get('thangs') + for thang in thangs + for component in thang.components + if component.config?.programmableMethods? + console.log "HI!" + break + console.log thang + break + ### @levels = [] for campaign in @campaigns.models continue unless campaign.get('slug') is 'dungeon' @@ -32,4 +75,5 @@ module.exports = class LevelAnalyticsView extends RootView @supermodel.loadCollection(@stats, 'stats') @renderSelectors '#levelTable' onStatsLoaded: -> - console.log @stats \ No newline at end of file + console.log @stats + ### \ No newline at end of file From 8df6a182e8b0658cb75bf444e026dddeddf7948a Mon Sep 17 00:00:00 2001 From: Josh Callebaut Date: Fri, 8 Apr 2016 15:50:04 -0700 Subject: [PATCH 04/24] Further changes on the Analytics view --- app/styles/artisans/levelAnalyticsView.sass | 6 +- .../artisans/levelAnalyticsView.jade | 11 +++- app/views/artisans/LevelAnalyticsView.coffee | 59 +++++++++++++++---- 3 files changed, 63 insertions(+), 13 deletions(-) diff --git a/app/styles/artisans/levelAnalyticsView.sass b/app/styles/artisans/levelAnalyticsView.sass index a1327ed63..c9bb5b938 100644 --- a/app/styles/artisans/levelAnalyticsView.sass +++ b/app/styles/artisans/levelAnalyticsView.sass @@ -1 +1,5 @@ -#level-analytics-view \ No newline at end of file +#level-analytics-view + .problemType + width: 50% + .problemValue + width: 50% \ No newline at end of file diff --git a/app/templates/artisans/levelAnalyticsView.jade b/app/templates/artisans/levelAnalyticsView.jade index d733d9169..52c121408 100644 --- a/app/templates/artisans/levelAnalyticsView.jade +++ b/app/templates/artisans/levelAnalyticsView.jade @@ -1,4 +1,13 @@ extends /templates/base block content - table#levelTable \ No newline at end of file + table.table.table-striped#levelTable + for level in (view.parsedLevels || []) + tr + td(style="width:10%")= level.level.get('slug') + td + table.table-striped + for problem in (level.problems || []) + tr(style="width:100%") + td.problemType= problem.type + td.problemValue= problem.value \ No newline at end of file diff --git a/app/views/artisans/LevelAnalyticsView.coffee b/app/views/artisans/LevelAnalyticsView.coffee index 82dcbb9e8..e7bbe194f 100644 --- a/app/views/artisans/LevelAnalyticsView.coffee +++ b/app/views/artisans/LevelAnalyticsView.coffee @@ -36,29 +36,66 @@ module.exports = class LevelAnalyticsView extends RootView continue unless excludedCampaigns.indexOf(campaign.get 'slug') is -1 levels = campaign.get('levels') for key, level of levels - @levelSlugs.push level.slug + if @levelSlugs.indexOf(level.slug) is -1 + @levelSlugs.push level.slug if @levels.models.length isnt 0 @readyUp() + console.log @levelSlugs.length + onLevelsLoaded: -> - console.log @levels + #console.log @levels if @campaigns.models.length isnt 0 @readyUp() + readyUp: -> + @parsedLevels = [] for levelSlug in @levelSlugs level = @levels.findWhere({slug:levelSlug}) unless level? + #console.log("Level missing from @levels: " + levelSlug) continue - console.warn('Warning: ' + levelSlug) unless level? - console.log levelSlug thangs = level.get('thangs') - for thang in thangs - for component in thang.components - if component.config?.programmableMethods? - console.log "HI!" - break - console.log thang - break + component = null + thang = _.findWhere(thangs, (elem) -> + return _.findWhere(elem.components, (elem2) -> + if elem2.config?.programmableMethods?.plan? + component = elem2 + return true + ) + ) + + unless thang? and component? + console.log("Cannot find programmableMethods component in: " + levelSlug) + continue + unless component?.config?.programmableMethods?.plan? + console.log("Cannot find plannable method inside component: " + levelSlug) + continue + solutions = component.config.programmableMethods.plan.solutions + + problems = [] + for lang in ["python", "javascript", "lua"] + unless _.findWhere(solutions, (elem) -> return elem.language is lang) + problems.push { + "type":"Missing Solution Language", + "value":lang + } + for solutionIndex of solutions + solution = solutions[solutionIndex] + for req in ["seed", "succeeds", "heroConfig"] + unless solution[req]? + problems.push { + "type":"Solution is not simulatable", + "value":solution.language + } + break + + @parsedLevels.push { + level: level + problems: problems + } + console.log @parsedLevels.length + @renderSelectors '#levelTable' ### @levels = [] for campaign in @campaigns.models From bd322b3899c7f6c1af087fa39de29caeb3f5fe0b Mon Sep 17 00:00:00 2001 From: Josh Callebaut Date: Wed, 20 Apr 2016 11:15:26 -0700 Subject: [PATCH 05/24] Improvements on solution tracking --- app/views/artisans/LevelAnalyticsView.coffee | 128 +++++++++++++------ 1 file changed, 87 insertions(+), 41 deletions(-) diff --git a/app/views/artisans/LevelAnalyticsView.coffee b/app/views/artisans/LevelAnalyticsView.coffee index e7bbe194f..c4253d743 100644 --- a/app/views/artisans/LevelAnalyticsView.coffee +++ b/app/views/artisans/LevelAnalyticsView.coffee @@ -11,21 +11,39 @@ module.exports = class LevelAnalyticsView extends RootView excludedCampaigns = [ "picoctf" "auditions" + + "dungeon" + "forest" + "desert" + "mountain" + "glacier" + + "dungeon-branching-test" + "forest-branching-test" + "desert-branching-test" + + "course-6" ] + excludedSimulationLevels = [ + "wakka-maul" + "cross-bones" + ] + levelOffset: 0 + isReady: 0 constructor: (options) -> super options @campaigns = new CocoCollection([], url: '/db/campaign?project=name,slug,tasks' model: Campaign ) - @levels = new CocoCollection([], - url: '/db/level?project=slug,thangs&limit=100' - model: Level - ) @campaigns.fetch() @listenTo(@campaigns, 'sync', @onCampaignsLoaded) @supermodel.loadCollection(@campaigns, 'campaigns') + @levels = new CocoCollection([], + url: '/db/level?project=slug,thangs&limit=100&skip=' + @levelOffset + model: Level + ) @levels.fetch() @listenTo(@levels, 'sync', @onLevelsLoaded) @supermodel.loadCollection(@levels, 'levels') @@ -34,83 +52,111 @@ module.exports = class LevelAnalyticsView extends RootView @levelSlugs = [] for campaign in @campaigns.models continue unless excludedCampaigns.indexOf(campaign.get 'slug') is -1 + console.log(campaign.get 'slug') levels = campaign.get('levels') for key, level of levels if @levelSlugs.indexOf(level.slug) is -1 @levelSlugs.push level.slug - if @levels.models.length isnt 0 + console.log "???" + @isReady += 1 + if @isReady is 2 @readyUp() + console.log @levelSlugs.length onLevelsLoaded: -> - #console.log @levels - if @campaigns.models.length isnt 0 - @readyUp() + @loadedLevels ?= [] + @loadedLevels = @loadedLevels.concat(@levels.models) + if(@levels.length is 100) + console.log("Not done yet...") + @levelOffset += 100 + @levels = new CocoCollection([], + url: '/db/level?project=slug,thangs&limit=100&skip=' + @levelOffset + model: Level + ) + @levels.fetch() + @listenTo(@levels, 'sync', @onLevelsLoaded) + @supermodel.loadCollection(@levels, 'levels') + else + @isReady += 1 + if @isReady is 2 + @readyUp() readyUp: -> + console.log("All done!") + console.log(@loadedLevels.length) @parsedLevels = [] + console.log @loadedLevels for levelSlug in @levelSlugs - level = @levels.findWhere({slug:levelSlug}) + level = @loadedLevels.find((elem) -> + return elem.get('slug') is levelSlug + ) unless level? - #console.log("Level missing from @levels: " + levelSlug) continue - thangs = level.get('thangs') component = null thang = _.findWhere(thangs, (elem) -> - return _.findWhere(elem.components, (elem2) -> + return elem.id is "Hero Placeholder" and _.findWhere(elem.components, (elem2) -> if elem2.config?.programmableMethods?.plan? component = elem2 return true ) ) - - unless thang? and component? + unless thang? and component console.log("Cannot find programmableMethods component in: " + levelSlug) continue unless component?.config?.programmableMethods?.plan? console.log("Cannot find plannable method inside component: " + levelSlug) continue - solutions = component.config.programmableMethods.plan.solutions + plan = component.config.programmableMethods.plan + solutions = plan.solutions + problems = [] - for lang in ["python", "javascript", "lua"] + + for lang in ["python", "javascript"] unless _.findWhere(solutions, (elem) -> return elem.language is lang) problems.push { "type":"Missing Solution Language", "value":lang } + for solutionIndex of solutions solution = solutions[solutionIndex] - for req in ["seed", "succeeds", "heroConfig"] - unless solution[req]? + if excludedSimulationLevels.indexOf(levelSlug) is -1 + for req in ["seed", "succeeds", "heroConfig", 'lastHash', 'frameCount', 'goals'] + unless solution[req]? + problems.push { + "type":"Solution is not simulatable", + "value":solution.language + } + break + if solution.source.indexOf("<%=") is -1 + problems.push { + "type":"Solution is not i18n'd", + "value":solution.language + } + if solution.source.indexOf("pass") isnt -1 + problems.push { + "type":"Solution contains pass", + "value":solution.language + } + if solution.language is 'javascript' + if solution.source is plan.source problems.push { - "type":"Solution is not simulatable", + "type":"Solution is identical to source", + "value":solution.language + } + else + console.log solution.source + console.log plan.languages[solution.language] + if solution.source is plan.languages[solution.language] + problems.push { + "type":"Solution is identical to source", "value":solution.language } - break - @parsedLevels.push { level: level problems: problems } - console.log @parsedLevels.length - @renderSelectors '#levelTable' - ### - @levels = [] - for campaign in @campaigns.models - continue unless campaign.get('slug') is 'dungeon' - levels = campaign.get('levels') - for key, level of levels - @levels.push level.slug - @stats = new CocoCollection([], - url: '/db/analytics_perday/-/level_completions?slug=dungeons-of-kithgard&startDay=20151022&endDay=20151104' - model: {} - ) - @stats.fetch() - @listenTo(@stats, 'sync', @onStatsLoaded) - @supermodel.loadCollection(@stats, 'stats') - @renderSelectors '#levelTable' - onStatsLoaded: -> - console.log @stats - ### \ No newline at end of file + @renderSelectors '#levelTable' \ No newline at end of file From 443bbae5db65c688faddde4cd8fb05c57de4266b Mon Sep 17 00:00:00 2001 From: Josh Callebaut Date: Thu, 21 Apr 2016 09:17:54 -0700 Subject: [PATCH 06/24] Improves level/campaign fetching for the solution problems view, and switches the names of the files --- app/core/Router.coffee | 2 +- ...icsView.sass => solutionProblemsView.sass} | 2 +- .../artisans/levelAnalyticsView.jade | 13 --- .../artisans/solutionProblemsView.jade | 15 ++++ ...iew.coffee => SolutionProblemsView.coffee} | 89 +++++++++---------- 5 files changed, 60 insertions(+), 61 deletions(-) rename app/styles/artisans/{levelAnalyticsView.sass => solutionProblemsView.sass} (71%) delete mode 100644 app/templates/artisans/levelAnalyticsView.jade create mode 100644 app/templates/artisans/solutionProblemsView.jade rename app/views/artisans/{LevelAnalyticsView.coffee => SolutionProblemsView.coffee} (71%) diff --git a/app/core/Router.coffee b/app/core/Router.coffee index 1ad136f59..830aa5f9e 100644 --- a/app/core/Router.coffee +++ b/app/core/Router.coffee @@ -45,7 +45,7 @@ module.exports = class CocoRouter extends Backbone.Router 'artisans': go('artisans/ArtisansView') - 'artisans/level-analytics': go('artisans/LevelAnalyticsView') + 'artisans/solution-problems': go('artisans/SolutionProblemsView') 'artisans/level-tasks': go('artisans/LevelTasksView') 'artisans/thang-tasks': go('artisans/ThangTasksView') diff --git a/app/styles/artisans/levelAnalyticsView.sass b/app/styles/artisans/solutionProblemsView.sass similarity index 71% rename from app/styles/artisans/levelAnalyticsView.sass rename to app/styles/artisans/solutionProblemsView.sass index c9bb5b938..d54f137dd 100644 --- a/app/styles/artisans/levelAnalyticsView.sass +++ b/app/styles/artisans/solutionProblemsView.sass @@ -1,4 +1,4 @@ -#level-analytics-view +#solution-problems-view .problemType width: 50% .problemValue diff --git a/app/templates/artisans/levelAnalyticsView.jade b/app/templates/artisans/levelAnalyticsView.jade deleted file mode 100644 index 52c121408..000000000 --- a/app/templates/artisans/levelAnalyticsView.jade +++ /dev/null @@ -1,13 +0,0 @@ -extends /templates/base - -block content - table.table.table-striped#levelTable - for level in (view.parsedLevels || []) - tr - td(style="width:10%")= level.level.get('slug') - td - table.table-striped - for problem in (level.problems || []) - tr(style="width:100%") - td.problemType= problem.type - td.problemValue= problem.value \ No newline at end of file diff --git a/app/templates/artisans/solutionProblemsView.jade b/app/templates/artisans/solutionProblemsView.jade new file mode 100644 index 000000000..1f806e2a2 --- /dev/null +++ b/app/templates/artisans/solutionProblemsView.jade @@ -0,0 +1,15 @@ +extends /templates/base + +block content + div Total number of problems: #{view.problemCount} + table.table.table-striped#levelTable + for level in (view.parsedLevels || []) + if (level.problems || []).length != 0 + tr + td(style="width:10%")= level.level.get('slug') + td + table.table-striped + for problem in (level.problems || []) + tr(style="width:100%") + td.problemType= problem.type + td.problemValue= problem.value \ No newline at end of file diff --git a/app/views/artisans/LevelAnalyticsView.coffee b/app/views/artisans/SolutionProblemsView.coffee similarity index 71% rename from app/views/artisans/LevelAnalyticsView.coffee rename to app/views/artisans/SolutionProblemsView.coffee index c4253d743..4ec2030db 100644 --- a/app/views/artisans/LevelAnalyticsView.coffee +++ b/app/views/artisans/SolutionProblemsView.coffee @@ -1,27 +1,32 @@ RootView = require 'views/core/RootView' -template = require 'templates/artisans/levelAnalyticsView' +template = require 'templates/artisans/solutionProblemsView' Level = require 'models/Level' Campaign = require 'models/Campaign' Level = require 'models/Level' CocoCollection = require 'collections/CocoCollection' -module.exports = class LevelAnalyticsView extends RootView +module.exports = class SolutionProblemsView extends RootView template: template - id: 'level-analytics-view' + id: 'solution-problems-view' excludedCampaigns = [ "picoctf" "auditions" - "dungeon" - "forest" - "desert" - "mountain" - "glacier" + # "dungeon" + # "forest" + # "desert" + # "mountain" + # "glacier" "dungeon-branching-test" "forest-branching-test" "desert-branching-test" + "intro" + "course-2" + "course-3" + "course-4" + "course-5" "course-6" ] excludedSimulationLevels = [ @@ -33,13 +38,13 @@ module.exports = class LevelAnalyticsView extends RootView constructor: (options) -> super options @campaigns = new CocoCollection([], - url: '/db/campaign?project=name,slug,tasks' + url: '/db/campaign?project=slug' model: Campaign ) @campaigns.fetch() @listenTo(@campaigns, 'sync', @onCampaignsLoaded) @supermodel.loadCollection(@campaigns, 'campaigns') - + ### @levels = new CocoCollection([], url: '/db/level?project=slug,thangs&limit=100&skip=' + @levelOffset model: Level @@ -47,50 +52,37 @@ module.exports = class LevelAnalyticsView extends RootView @levels.fetch() @listenTo(@levels, 'sync', @onLevelsLoaded) @supermodel.loadCollection(@levels, 'levels') + ### onCampaignsLoaded: -> @levelSlugs = [] + @test = {} + @loadedLevels = {} + count = 0 for campaign in @campaigns.models continue unless excludedCampaigns.indexOf(campaign.get 'slug') is -1 - console.log(campaign.get 'slug') - levels = campaign.get('levels') - for key, level of levels - if @levelSlugs.indexOf(level.slug) is -1 - @levelSlugs.push level.slug - console.log "???" - @isReady += 1 - if @isReady is 2 - @readyUp() - - console.log @levelSlugs.length - - onLevelsLoaded: -> - @loadedLevels ?= [] - @loadedLevels = @loadedLevels.concat(@levels.models) - if(@levels.length is 100) - console.log("Not done yet...") - @levelOffset += 100 - @levels = new CocoCollection([], - url: '/db/level?project=slug,thangs&limit=100&skip=' + @levelOffset + count++ + @test[campaign.get('slug')] = new CocoCollection([], + url: '/db/campaign/' + campaign.get('slug') + '/levels?project=thangs,slug' model: Level ) - @levels.fetch() - @listenTo(@levels, 'sync', @onLevelsLoaded) - @supermodel.loadCollection(@levels, 'levels') - else - @isReady += 1 - if @isReady is 2 - @readyUp() + @test[campaign.get('slug')].fetch() + @listenTo(@test[campaign.get('slug')], 'sync', (e) -> + #@loadedLevels = _uniq(_.union(@loadedLevels, e.models)) + for level in e.models + @loadedLevels[level.get('slug')] = level + count-- + if count is 0 + @readyUp() + ) + @supermodel.loadCollection(@test[campaign.get('slug')], 'levels') readyUp: -> - console.log("All done!") - console.log(@loadedLevels.length) + console.log("Count of levels: " + _.size(@loadedLevels)) @parsedLevels = [] - console.log @loadedLevels - for levelSlug in @levelSlugs - level = @loadedLevels.find((elem) -> - return elem.get('slug') is levelSlug - ) + + @problemCount = 0 + for levelSlug, level of @loadedLevels unless level? continue thangs = level.get('thangs') @@ -130,31 +122,36 @@ module.exports = class LevelAnalyticsView extends RootView "type":"Solution is not simulatable", "value":solution.language } + @problemCount++ break if solution.source.indexOf("<%=") is -1 problems.push { "type":"Solution is not i18n'd", "value":solution.language } + @problemCount++ if solution.source.indexOf("pass") isnt -1 problems.push { "type":"Solution contains pass", "value":solution.language } + @problemCount++ if solution.language is 'javascript' if solution.source is plan.source problems.push { "type":"Solution is identical to source", "value":solution.language } + @problemCount++ else - console.log solution.source - console.log plan.languages[solution.language] + #console.log solution.source + #console.log plan.languages[solution.language] if solution.source is plan.languages[solution.language] problems.push { "type":"Solution is identical to source", "value":solution.language } + @problemCount++ @parsedLevels.push { level: level problems: problems From 30c879ddc0d40570d2358baf57b17607d2cbe169 Mon Sep 17 00:00:00 2001 From: Josh Callebaut Date: Fri, 29 Apr 2016 15:58:30 -0700 Subject: [PATCH 07/24] Fix bug with Solution Problem View's problem count; add start of Course Gear View --- app/core/Router.coffee | 1 + app/styles/artisans/courseGearView.sass | 0 app/templates/artisans/artisansView.jade | 8 +- app/templates/artisans/courseGearView.jade | 3 + app/views/artisans/CourseGearView.coffee | 16 ++++ .../artisans/SolutionProblemsView.coffee | 86 +++++++++++++------ 6 files changed, 87 insertions(+), 27 deletions(-) create mode 100644 app/styles/artisans/courseGearView.sass create mode 100644 app/templates/artisans/courseGearView.jade create mode 100644 app/views/artisans/CourseGearView.coffee diff --git a/app/core/Router.coffee b/app/core/Router.coffee index 830aa5f9e..64ba4535e 100644 --- a/app/core/Router.coffee +++ b/app/core/Router.coffee @@ -46,6 +46,7 @@ module.exports = class CocoRouter extends Backbone.Router 'artisans': go('artisans/ArtisansView') 'artisans/solution-problems': go('artisans/SolutionProblemsView') + 'artisans/course-gear': go('artisans/CourseGearView') 'artisans/level-tasks': go('artisans/LevelTasksView') 'artisans/thang-tasks': go('artisans/ThangTasksView') diff --git a/app/styles/artisans/courseGearView.sass b/app/styles/artisans/courseGearView.sass new file mode 100644 index 000000000..e69de29bb diff --git a/app/templates/artisans/artisansView.jade b/app/templates/artisans/artisansView.jade index 0cf81943f..7d5becb36 100644 --- a/app/templates/artisans/artisansView.jade +++ b/app/templates/artisans/artisansView.jade @@ -7,4 +7,10 @@ block content |Thang Tasks div a(href="artisans/level-tasks") - |Level Tasks \ No newline at end of file + |Level Tasks + div + a(href="artisans/solution-problems") + |Solution Problems + div + a(href="artisans/course-gear") + |Course Gear Progression \ No newline at end of file diff --git a/app/templates/artisans/courseGearView.jade b/app/templates/artisans/courseGearView.jade new file mode 100644 index 000000000..5b40f96a0 --- /dev/null +++ b/app/templates/artisans/courseGearView.jade @@ -0,0 +1,3 @@ +extends /templates/base + +block content \ No newline at end of file diff --git a/app/views/artisans/CourseGearView.coffee b/app/views/artisans/CourseGearView.coffee new file mode 100644 index 000000000..838b33d9b --- /dev/null +++ b/app/views/artisans/CourseGearView.coffee @@ -0,0 +1,16 @@ +RootView = require 'views/core/RootView' +template = require 'templates/artisans/courseGearView' +Level = require 'models/Level' +Campaign = require 'models/Campaign' +Level = require 'models/Level' +CocoCollection = require 'collections/CocoCollection' + +module.exports = class CourseGearView extends RootView + template: template + id: 'course-gear-view' + initialize: -> + @campaigns = new CocoCollection([], + url: '/db/campaign?project=slug' + model: Campaign + ) + @supermodel.trackRequest(@campaigns.fetch()) \ No newline at end of file diff --git a/app/views/artisans/SolutionProblemsView.coffee b/app/views/artisans/SolutionProblemsView.coffee index 4ec2030db..cdd76bb30 100644 --- a/app/views/artisans/SolutionProblemsView.coffee +++ b/app/views/artisans/SolutionProblemsView.coffee @@ -12,29 +12,46 @@ module.exports = class SolutionProblemsView extends RootView "picoctf" "auditions" - # "dungeon" - # "forest" - # "desert" - # "mountain" - # "glacier" + #"dungeon" + #"forest" + #"desert" + #"mountain" + #"glacier" "dungeon-branching-test" "forest-branching-test" "desert-branching-test" - "intro" - "course-2" - "course-3" - "course-4" - "course-5" - "course-6" + #"intro" + #"course-2" + #"course-3" + #"course-4" + #"course-5" + #"course-6" ] excludedSimulationLevels = [ + # Course Arenas "wakka-maul" "cross-bones" ] + excludedSolutionLevels = [ + # Multiplayer Levels + "cavern-survival" + + "dueling-grounds" + "multiplayer-treasure-grove" + + "harrowland" + + "zero-sum" + + "ace-of-coders" + "capture-their-flag" + ] levelOffset: 0 isReady: 0 + requiresSubs: 0 + rob: [] constructor: (options) -> super options @campaigns = new CocoCollection([], @@ -63,13 +80,15 @@ module.exports = class SolutionProblemsView extends RootView continue unless excludedCampaigns.indexOf(campaign.get 'slug') is -1 count++ @test[campaign.get('slug')] = new CocoCollection([], - url: '/db/campaign/' + campaign.get('slug') + '/levels?project=thangs,slug' + url: '/db/campaign/' + campaign.get('slug') + '/levels?project=thangs,slug,requiresSubscription' model: Level ) @test[campaign.get('slug')].fetch() @listenTo(@test[campaign.get('slug')], 'sync', (e) -> #@loadedLevels = _uniq(_.union(@loadedLevels, e.models)) for level in e.models + if not @loadedLevels[level.get('slug')]? and level.get('requiresSubscription') + @requiresSubs++ @loadedLevels[level.get('slug')] = level count-- if count is 0 @@ -79,6 +98,7 @@ module.exports = class SolutionProblemsView extends RootView readyUp: -> console.log("Count of levels: " + _.size(@loadedLevels)) + console.log("Count requires sub: " + @requiresSubs) @parsedLevels = [] @problemCount = 0 @@ -94,6 +114,14 @@ module.exports = class SolutionProblemsView extends RootView return true ) ) + thangs = _.filter(thangs, (elem) -> + return _.findWhere(elem.components, (elem2) -> + if elem2.config?.programmableMethods? + return true + ) + ) + if thangs.length > 1 + console.log levelSlug + ":" + thangs.length + " " + thangs.map((elem) -> return elem.id) unless thang? and component console.log("Cannot find programmableMethods component in: " + levelSlug) continue @@ -105,37 +133,43 @@ module.exports = class SolutionProblemsView extends RootView problems = [] + if excludedSolutionLevels.indexOf(levelSlug) is -1 + for lang in ["python", "javascript", "lua", "java"] + if _.findWhere(solutions, (elem) -> return elem.language is lang) + @rob.push language: lang, level: levelSlug + else if lang not in ["lua", "java"] + problems.push { + "type":"Missing Solution Language", + "value":lang + } + @problemCount++ + else + # monitor lua/java when we care about it here - for lang in ["python", "javascript"] - unless _.findWhere(solutions, (elem) -> return elem.language is lang) - problems.push { - "type":"Missing Solution Language", - "value":lang - } - for solutionIndex of solutions solution = solutions[solutionIndex] if excludedSimulationLevels.indexOf(levelSlug) is -1 - for req in ["seed", "succeeds", "heroConfig", 'lastHash', 'frameCount', 'goals'] + for req in ["seed", "succeeds", "heroConfig", 'frameCount', 'goals'] # Implement a fix for lastHash unless solution[req]? + console.log levelSlug, req problems.push { "type":"Solution is not simulatable", "value":solution.language } @problemCount++ break - if solution.source.indexOf("<%=") is -1 - problems.push { - "type":"Solution is not i18n'd", - "value":solution.language - } - @problemCount++ if solution.source.indexOf("pass") isnt -1 problems.push { "type":"Solution contains pass", "value":solution.language } @problemCount++ + if solution.source.indexOf("<%=") is -1 + problems.push { + "type":"Solution is not i18n'd", + "value":solution.language + } + @problemCount++ if solution.language is 'javascript' if solution.source is plan.source problems.push { From 19e1c808d8a801ec55ab0b57294ebec93fa646fb Mon Sep 17 00:00:00 2001 From: Josh Callebaut Date: Tue, 10 May 2016 14:34:17 -0700 Subject: [PATCH 08/24] Fix filename convention, improve solution checker, remove old files --- .../{artisansView.sass => artisans-view.sass} | 0 ...rseGearView.sass => course-gear-view.sass} | 0 ...elTasksView.sass => level-tasks-view.sass} | 0 ...sView.sass => solution-problems-view.sass} | 0 ...ngTasksView.sass => thang-tasks-view.sass} | 0 app/styles/editor/thangTasksView.sass | 12 ---- .../{artisansView.jade => artisans-view.jade} | 0 ...rseGearView.jade => course-gear-view.jade} | 0 ...elTasksView.jade => level-tasks-view.jade} | 2 +- ...sView.jade => solution-problems-view.jade} | 2 +- ...ngTasksView.jade => thang-tasks-view.jade} | 0 app/templates/editor/thangTasksView.jade | 29 --------- app/views/artisans/ArtisansView.coffee | 4 +- app/views/artisans/CourseGearView.coffee | 4 +- app/views/artisans/LevelTasksView.coffee | 2 +- .../artisans/SolutionProblemsView.coffee | 59 +++++++++++-------- app/views/artisans/ThangTasksView.coffee | 2 +- app/views/editor/ThangTasksView.coffee | 48 --------------- 18 files changed, 43 insertions(+), 121 deletions(-) rename app/styles/artisans/{artisansView.sass => artisans-view.sass} (100%) rename app/styles/artisans/{courseGearView.sass => course-gear-view.sass} (100%) rename app/styles/artisans/{levelTasksView.sass => level-tasks-view.sass} (100%) rename app/styles/artisans/{solutionProblemsView.sass => solution-problems-view.sass} (100%) rename app/styles/artisans/{thangTasksView.sass => thang-tasks-view.sass} (100%) delete mode 100644 app/styles/editor/thangTasksView.sass rename app/templates/artisans/{artisansView.jade => artisans-view.jade} (100%) rename app/templates/artisans/{courseGearView.jade => course-gear-view.jade} (100%) rename app/templates/artisans/{levelTasksView.jade => level-tasks-view.jade} (91%) rename app/templates/artisans/{solutionProblemsView.jade => solution-problems-view.jade} (88%) rename app/templates/artisans/{thangTasksView.jade => thang-tasks-view.jade} (100%) delete mode 100644 app/templates/editor/thangTasksView.jade delete mode 100644 app/views/editor/ThangTasksView.coffee diff --git a/app/styles/artisans/artisansView.sass b/app/styles/artisans/artisans-view.sass similarity index 100% rename from app/styles/artisans/artisansView.sass rename to app/styles/artisans/artisans-view.sass diff --git a/app/styles/artisans/courseGearView.sass b/app/styles/artisans/course-gear-view.sass similarity index 100% rename from app/styles/artisans/courseGearView.sass rename to app/styles/artisans/course-gear-view.sass diff --git a/app/styles/artisans/levelTasksView.sass b/app/styles/artisans/level-tasks-view.sass similarity index 100% rename from app/styles/artisans/levelTasksView.sass rename to app/styles/artisans/level-tasks-view.sass diff --git a/app/styles/artisans/solutionProblemsView.sass b/app/styles/artisans/solution-problems-view.sass similarity index 100% rename from app/styles/artisans/solutionProblemsView.sass rename to app/styles/artisans/solution-problems-view.sass diff --git a/app/styles/artisans/thangTasksView.sass b/app/styles/artisans/thang-tasks-view.sass similarity index 100% rename from app/styles/artisans/thangTasksView.sass rename to app/styles/artisans/thang-tasks-view.sass diff --git a/app/styles/editor/thangTasksView.sass b/app/styles/editor/thangTasksView.sass deleted file mode 100644 index 599a6a6ab..000000000 --- a/app/styles/editor/thangTasksView.sass +++ /dev/null @@ -1,12 +0,0 @@ -#thang-tasks-view - #thangTable - width: 100% - - .tasksTable - width: 100% - - .tasks - width: 87.5% - - .taskOwner - width: 12.5% \ No newline at end of file diff --git a/app/templates/artisans/artisansView.jade b/app/templates/artisans/artisans-view.jade similarity index 100% rename from app/templates/artisans/artisansView.jade rename to app/templates/artisans/artisans-view.jade diff --git a/app/templates/artisans/courseGearView.jade b/app/templates/artisans/course-gear-view.jade similarity index 100% rename from app/templates/artisans/courseGearView.jade rename to app/templates/artisans/course-gear-view.jade diff --git a/app/templates/artisans/levelTasksView.jade b/app/templates/artisans/level-tasks-view.jade similarity index 91% rename from app/templates/artisans/levelTasksView.jade rename to app/templates/artisans/level-tasks-view.jade index e44ae7dbd..127861cab 100644 --- a/app/templates/artisans/levelTasksView.jade +++ b/app/templates/artisans/level-tasks-view.jade @@ -27,7 +27,7 @@ mixin levelRow(level) td.taskOwner a(href= 'level/' + level.slug)= level.name td.tasks - table.table-striped.table-hover.tasksTable + table.table-condensed.table-striped.table-hover.tasksTable for task in (level.tasks2 || []) if !task.complete tr diff --git a/app/templates/artisans/solutionProblemsView.jade b/app/templates/artisans/solution-problems-view.jade similarity index 88% rename from app/templates/artisans/solutionProblemsView.jade rename to app/templates/artisans/solution-problems-view.jade index 1f806e2a2..2a44adcf3 100644 --- a/app/templates/artisans/solutionProblemsView.jade +++ b/app/templates/artisans/solution-problems-view.jade @@ -8,7 +8,7 @@ block content tr td(style="width:10%")= level.level.get('slug') td - table.table-striped + table.table-condensed.table-striped.table-hover for problem in (level.problems || []) tr(style="width:100%") td.problemType= problem.type diff --git a/app/templates/artisans/thangTasksView.jade b/app/templates/artisans/thang-tasks-view.jade similarity index 100% rename from app/templates/artisans/thangTasksView.jade rename to app/templates/artisans/thang-tasks-view.jade diff --git a/app/templates/editor/thangTasksView.jade b/app/templates/editor/thangTasksView.jade deleted file mode 100644 index 48a216782..000000000 --- a/app/templates/editor/thangTasksView.jade +++ /dev/null @@ -1,29 +0,0 @@ -extends /templates/base - -block content - #thang-tasks-view - input#nameSearch(placeholder='Filter: Thang Name') - br - input#descSearch(placeholder='Filter: Task Description') - hr - if view.processedThangs - table.table.table-striped#thangTable - tr - th Thang Name - th Task List - for thang in view.processedThangs - if view.hasIncompleteTasks(thang) - +thangRow(thang) - else - span No view.processedThangs - -mixin thangRow(thang) - tr - td.taskOwner - a(href= 'thang/' + thang.get('slug'))= thang.get('name') - td.tasks - table.table-striped.table-hover.tasksTable - for task in (thang.tasks || []) - if !task.complete - tr - td= task.name diff --git a/app/views/artisans/ArtisansView.coffee b/app/views/artisans/ArtisansView.coffee index 76b4110e9..60cc6c526 100644 --- a/app/views/artisans/ArtisansView.coffee +++ b/app/views/artisans/ArtisansView.coffee @@ -1,8 +1,6 @@ RootView = require 'views/core/RootView' -template = require 'templates/artisans/artisansView' +template = require 'templates/artisans/artisans-view' module.exports = class ArtisansView extends RootView template: template id: 'artisans-view' - constructor: (options) -> - super options \ No newline at end of file diff --git a/app/views/artisans/CourseGearView.coffee b/app/views/artisans/CourseGearView.coffee index 838b33d9b..9a9181f4a 100644 --- a/app/views/artisans/CourseGearView.coffee +++ b/app/views/artisans/CourseGearView.coffee @@ -1,5 +1,5 @@ RootView = require 'views/core/RootView' -template = require 'templates/artisans/courseGearView' +template = require 'templates/artisans/course-gear-view' Level = require 'models/Level' Campaign = require 'models/Campaign' Level = require 'models/Level' @@ -13,4 +13,4 @@ module.exports = class CourseGearView extends RootView url: '/db/campaign?project=slug' model: Campaign ) - @supermodel.trackRequest(@campaigns.fetch()) \ No newline at end of file + @supermodel.trackRequest(@campaigns.fetch(), @do ) \ No newline at end of file diff --git a/app/views/artisans/LevelTasksView.coffee b/app/views/artisans/LevelTasksView.coffee index a898e52d4..f7225fa29 100644 --- a/app/views/artisans/LevelTasksView.coffee +++ b/app/views/artisans/LevelTasksView.coffee @@ -1,5 +1,5 @@ RootView = require 'views/core/RootView' -template = require 'templates/artisans/levelTasksView' +template = require 'templates/artisans/level-tasks-view' #ThangType = require 'models/ThangType' Level = require 'models/Level' Campaign = require 'models/Campaign' diff --git a/app/views/artisans/SolutionProblemsView.coffee b/app/views/artisans/SolutionProblemsView.coffee index cdd76bb30..09164ee72 100644 --- a/app/views/artisans/SolutionProblemsView.coffee +++ b/app/views/artisans/SolutionProblemsView.coffee @@ -1,5 +1,5 @@ RootView = require 'views/core/RootView' -template = require 'templates/artisans/solutionProblemsView' +template = require 'templates/artisans/solution-problems-view' Level = require 'models/Level' Campaign = require 'models/Campaign' Level = require 'models/Level' @@ -12,22 +12,22 @@ module.exports = class SolutionProblemsView extends RootView "picoctf" "auditions" - #"dungeon" - #"forest" - #"desert" + "dungeon" + "forest" + "desert" #"mountain" - #"glacier" + "glacier" "dungeon-branching-test" "forest-branching-test" "desert-branching-test" - #"intro" - #"course-2" - #"course-3" - #"course-4" - #"course-5" - #"course-6" + "intro" + "course-2" + "course-3" + "course-4" + "course-5" + "course-6" ] excludedSimulationLevels = [ # Course Arenas @@ -52,6 +52,7 @@ module.exports = class SolutionProblemsView extends RootView isReady: 0 requiresSubs: 0 rob: [] + test2: [] constructor: (options) -> super options @campaigns = new CocoCollection([], @@ -77,15 +78,16 @@ module.exports = class SolutionProblemsView extends RootView @loadedLevels = {} count = 0 for campaign in @campaigns.models - continue unless excludedCampaigns.indexOf(campaign.get 'slug') is -1 + campaignSlug = campaign.get('slug') + continue unless excludedCampaigns.indexOf(campaignSlug) is -1 count++ - @test[campaign.get('slug')] = new CocoCollection([], - url: '/db/campaign/' + campaign.get('slug') + '/levels?project=thangs,slug,requiresSubscription' + @test[campaignSlug] = new CocoCollection([], + url: '/db/campaign/' + campaignSlug + '/levels?project=thangs,slug,requiresSubscription,campaign' model: Level ) - @test[campaign.get('slug')].fetch() - @listenTo(@test[campaign.get('slug')], 'sync', (e) -> - #@loadedLevels = _uniq(_.union(@loadedLevels, e.models)) + @test[campaignSlug].fetch() + @listenTo(@test[campaignSlug], 'sync', (e) -> + e.models.reverse() for level in e.models if not @loadedLevels[level.get('slug')]? and level.get('requiresSubscription') @requiresSubs++ @@ -94,7 +96,7 @@ module.exports = class SolutionProblemsView extends RootView if count is 0 @readyUp() ) - @supermodel.loadCollection(@test[campaign.get('slug')], 'levels') + @supermodel.loadCollection(@test[campaignSlug], 'levels') readyUp: -> console.log("Count of levels: " + _.size(@loadedLevels)) @@ -134,14 +136,17 @@ module.exports = class SolutionProblemsView extends RootView problems = [] if excludedSolutionLevels.indexOf(levelSlug) is -1 - for lang in ["python", "javascript", "lua", "java"] + for lang in ["python", "javascript", "lua", "java", "coffeescript"] if _.findWhere(solutions, (elem) -> return elem.language is lang) - @rob.push language: lang, level: levelSlug - else if lang not in ["lua", "java"] + #@rob.push language: lang, level: levelSlug + + else if lang not in ["lua", "java", "coffeescript"] problems.push { "type":"Missing Solution Language", "value":lang } + @test2.push(levelSlug) + #break @problemCount++ else # monitor lua/java when we care about it here @@ -149,6 +154,7 @@ module.exports = class SolutionProblemsView extends RootView for solutionIndex of solutions solution = solutions[solutionIndex] if excludedSimulationLevels.indexOf(levelSlug) is -1 + isSimul = true for req in ["seed", "succeeds", "heroConfig", 'frameCount', 'goals'] # Implement a fix for lastHash unless solution[req]? console.log levelSlug, req @@ -157,14 +163,20 @@ module.exports = class SolutionProblemsView extends RootView "value":solution.language } @problemCount++ + isSimul = false break - if solution.source.indexOf("pass") isnt -1 + if isSimul + console.log level.get('campaign') + if @rob.indexOf(levelSlug) is -1 + @rob.push(levelSlug) + + if solution.source.search(/pass\n/i) isnt -1 problems.push { "type":"Solution contains pass", "value":solution.language } @problemCount++ - if solution.source.indexOf("<%=") is -1 + if solution.source.indexOf('<%=') is -1 problems.push { "type":"Solution is not i18n'd", "value":solution.language @@ -186,6 +198,7 @@ module.exports = class SolutionProblemsView extends RootView "value":solution.language } @problemCount++ + @parsedLevels.push { level: level problems: problems diff --git a/app/views/artisans/ThangTasksView.coffee b/app/views/artisans/ThangTasksView.coffee index d17bef021..e70bf0dea 100644 --- a/app/views/artisans/ThangTasksView.coffee +++ b/app/views/artisans/ThangTasksView.coffee @@ -1,5 +1,5 @@ RootView = require 'views/core/RootView' -template = require 'templates/artisans/thangTasksView' +template = require 'templates/artisans/thang-tasks-view' ThangType = require 'models/ThangType' CocoCollection = require 'collections/CocoCollection' diff --git a/app/views/editor/ThangTasksView.coffee b/app/views/editor/ThangTasksView.coffee deleted file mode 100644 index ecc9500a0..000000000 --- a/app/views/editor/ThangTasksView.coffee +++ /dev/null @@ -1,48 +0,0 @@ -RootView = require 'views/core/RootView' -template = require 'templates/editor/thangTasksView' -ThangType = require 'models/ThangType' -CocoCollection = require 'collections/CocoCollection' - -module.exports = class ThangTasksView extends RootView - template: template - id: 'thang-tasks-view' - events: - 'input input': 'searchUpdate' - 'change input': 'searchUpdate' - - constructor: (options) -> - super options - @thangs = new CocoCollection([], - url: '/db/thang.type?project=name,tasks,slug' - model: ThangType - comparator: @sortThangs - ) - @lastLoad = (new Date()).getTime() - @listenTo(@thangs, 'sync', @onThangsLoaded) - @supermodel.loadCollection(@thangs, 'thangs') - - searchUpdate: -> - if not @lastLoad? or (new Date()).getTime() - @lastLoad > 60 * 1000 * 1 # Update only after a minute from last update. - @thangs.fetch() - @listenTo(@thangs, 'sync', @onThangsLoaded) - @supermodel.loadCollection(@thangs, 'thangs') - @lastLoad = (new Date()).getTime() - else - @onThangsLoaded() - - onThangsLoaded: -> - @processedThangs = @thangs.filter (_elem) -> - # Case-insensitive search of input vs name. - return ///#{$('#nameSearch')[0].value}///i.test _elem.get('name') - for thang in @processedThangs - thang.tasks = _.filter thang.attributes.tasks, (_elem) -> - # Similar case-insensitive search of input vs description (name). - return ///#{$('#descSearch')[0].value}///i.test _elem.name - @renderSelectors '#thangTable' - - sortThangs: (a, b) -> - a.get('name').localeCompare(b.get('name')) - - # Jade helper - hasIncompleteTasks: (thang) -> - return thang.tasks and thang.tasks.filter((_elem) -> return not _elem.complete).length > 0 \ No newline at end of file From 38e97ab404af247809920d21a45c2a0206dbf433 Mon Sep 17 00:00:00 2001 From: Josh Callebaut Date: Fri, 13 May 2016 15:32:59 -0700 Subject: [PATCH 09/24] Refactor all server-side fetching calls, refactor solutionProblemView, minor changes to rest --- app/collections/Levels.coffee | 9 +- app/styles/artisans/level-tasks-view.sass | 2 +- .../artisans/solution-problems-view.sass | 8 +- app/styles/artisans/thang-tasks-view.sass | 2 +- app/templates/artisans/artisans-view.jade | 8 +- app/templates/artisans/level-tasks-view.jade | 9 +- .../artisans/solution-problems-view.jade | 33 +- app/templates/artisans/thang-tasks-view.jade | 3 +- app/views/artisans/LevelTasksView.coffee | 68 +++-- .../artisans/SolutionProblemsView.coffee | 287 ++++++++---------- app/views/artisans/ThangTasksView.coffee | 21 +- 11 files changed, 216 insertions(+), 234 deletions(-) diff --git a/app/collections/Levels.coffee b/app/collections/Levels.coffee index 0d87816ad..f6da979aa 100644 --- a/app/collections/Levels.coffee +++ b/app/collections/Levels.coffee @@ -6,10 +6,13 @@ module.exports = class LevelCollection extends CocoCollection model: Level fetchForClassroom: (classroomID, options={}) -> - options.url = "/db/classroom/#{classroomID}/levels" + options.url = '/db/classroom/#{classroomID}/levels' @fetch(options) fetchForClassroomAndCourse: (classroomID, courseID, options={}) -> - options.url = "/db/classroom/#{classroomID}/courses/#{courseID}/levels" + options.url = '/db/classroom/#{classroomID}/courses/#{courseID}/levels' + @fetch(options) + + fetchForCampaign: (campaignSlug, options={}) -> + options.url = '/db/campaign/' + campaignSlug + '/levels' @fetch(options) - \ No newline at end of file diff --git a/app/styles/artisans/level-tasks-view.sass b/app/styles/artisans/level-tasks-view.sass index a5585bb76..53a171d82 100644 --- a/app/styles/artisans/level-tasks-view.sass +++ b/app/styles/artisans/level-tasks-view.sass @@ -9,4 +9,4 @@ width: 87.5% .taskOwner - width: 12.5% \ No newline at end of file + width: 12.5% diff --git a/app/styles/artisans/solution-problems-view.sass b/app/styles/artisans/solution-problems-view.sass index d54f137dd..949d57341 100644 --- a/app/styles/artisans/solution-problems-view.sass +++ b/app/styles/artisans/solution-problems-view.sass @@ -1,5 +1,9 @@ #solution-problems-view .problemType - width: 50% + width: 87.5% + .problemValue - width: 50% \ No newline at end of file + width: 12.5% + + .problemsTable + width: 100% diff --git a/app/styles/artisans/thang-tasks-view.sass b/app/styles/artisans/thang-tasks-view.sass index 599a6a6ab..d989428e2 100644 --- a/app/styles/artisans/thang-tasks-view.sass +++ b/app/styles/artisans/thang-tasks-view.sass @@ -9,4 +9,4 @@ width: 87.5% .taskOwner - width: 12.5% \ No newline at end of file + width: 12.5% diff --git a/app/templates/artisans/artisans-view.jade b/app/templates/artisans/artisans-view.jade index 7d5becb36..9eebf08d4 100644 --- a/app/templates/artisans/artisans-view.jade +++ b/app/templates/artisans/artisans-view.jade @@ -3,14 +3,14 @@ extends /templates/base block content img(src='/images/pages/user/artisan.png') div - a(href='artisans/thang-tasks') + a(href='/artisans/thang-tasks') |Thang Tasks div - a(href="artisans/level-tasks") + a(href="/artisans/level-tasks") |Level Tasks div - a(href="artisans/solution-problems") + a(href="/artisans/solution-problems") |Solution Problems div - a(href="artisans/course-gear") + a(href="/artisans/course-gear") |Course Gear Progression \ No newline at end of file diff --git a/app/templates/artisans/level-tasks-view.jade b/app/templates/artisans/level-tasks-view.jade index 127861cab..cead6003a 100644 --- a/app/templates/artisans/level-tasks-view.jade +++ b/app/templates/artisans/level-tasks-view.jade @@ -3,8 +3,9 @@ extends /templates/base block content #level-tasks-view div - a(href='./') + a(href='/artisans') | < Artisans Home + br input#nameSearch(placeholder='Filter: Level Name') br input#descSearch(placeholder='Filter: Task Description') @@ -20,15 +21,13 @@ block content else div ole? - - mixin levelRow(level) tr td.taskOwner a(href= 'level/' + level.slug)= level.name td.tasks - table.table-condensed.table-striped.table-hover.tasksTable - for task in (level.tasks2 || []) + table.table-striped.table-hover.tasksTable + for task in (level.tasks || []) if !task.complete tr td= task.name diff --git a/app/templates/artisans/solution-problems-view.jade b/app/templates/artisans/solution-problems-view.jade index 2a44adcf3..ab9cfefba 100644 --- a/app/templates/artisans/solution-problems-view.jade +++ b/app/templates/artisans/solution-problems-view.jade @@ -1,15 +1,24 @@ extends /templates/base block content - div Total number of problems: #{view.problemCount} - table.table.table-striped#levelTable - for level in (view.parsedLevels || []) - if (level.problems || []).length != 0 - tr - td(style="width:10%")= level.level.get('slug') - td - table.table-condensed.table-striped.table-hover - for problem in (level.problems || []) - tr(style="width:100%") - td.problemType= problem.type - td.problemValue= problem.value \ No newline at end of file + #solution-problems-view + div + a(href='/artisans') + | < Artisans Home + br + div Total number of problems: #{view.problemCount} + hr + table.table.table-striped#levelTable + tr + th Level Name + th Solution Problems + for level in (view.parsedLevels || []) + if (level.problems || []).length != 0 + tr + td(style="width:10%")= level.level.get('name') + td + table.table-striped.table-hover.problemsTable + for problem in (level.problems || []) + tr(style="width:100%") + td.problemValue= problem.value + td.problemType= problem.type diff --git a/app/templates/artisans/thang-tasks-view.jade b/app/templates/artisans/thang-tasks-view.jade index dc9c30c08..1e08cea18 100644 --- a/app/templates/artisans/thang-tasks-view.jade +++ b/app/templates/artisans/thang-tasks-view.jade @@ -3,8 +3,9 @@ extends /templates/base block content #thang-tasks-view div - a(href='./') + a(href='/artisans') | < Artisans Home + br input#nameSearch(placeholder='Filter: Thang Name') br input#descSearch(placeholder='Filter: Task Description') diff --git a/app/views/artisans/LevelTasksView.coffee b/app/views/artisans/LevelTasksView.coffee index f7225fa29..174b5b4de 100644 --- a/app/views/artisans/LevelTasksView.coffee +++ b/app/views/artisans/LevelTasksView.coffee @@ -1,57 +1,67 @@ RootView = require 'views/core/RootView' template = require 'templates/artisans/level-tasks-view' -#ThangType = require 'models/ThangType' -Level = require 'models/Level' + +Campaigns = require 'collections/Campaigns' + Campaign = require 'models/Campaign' -CocoCollection = require 'collections/CocoCollection' module.exports = class LevelTasksView extends RootView template: template id: 'level-tasks-view' events: - 'input input': 'searchUpdate' - 'change input': 'searchUpdate' + 'input .searchInput': 'searchUpdate' + 'change .searchInput': 'searchUpdate' excludedCampaigns = [ - "picoctf" - "auditions" + 'picoctf', 'auditions' ] - constructor: (options) -> - super options - @campaigns = new CocoCollection([], - url: '/db/campaign?project=name,slug,tasks' - model: Campaign - ) - @campaigns.fetch() + levels: {} + initialize: () -> + @searchUpdate = _.debounce(@searchUpdate, 250) + + @campaigns = new Campaigns() @listenTo(@campaigns, 'sync', @onCampaignsLoaded) - @supermodel.loadCollection(@campaigns, 'campaigns') + @supermodel.trackRequest(@campaigns.fetch( + data: + project: 'name,slug,levels,tasks' + )) - onCampaignsLoaded: -> + onCampaignsLoaded: (campCollection) -> @levels = {} - sum = 0 - for campaign in @campaigns.models - continue unless excludedCampaigns.indexOf(campaign.get 'slug') is -1 - levels = campaign.get('levels') - sum += Object.keys(levels).length + for campaign in campCollection.models + campaignSlug = campaign.get 'slug' + continue if campaignSlug in excludedCampaigns + levels = campaign.get 'levels' for key, level of levels continue unless ///#{$('#nameSearch')[0].value}///i.test level.name levelSlug = level.slug @levels[levelSlug] = level - @processedLevels = @levels - for key, level of @processedLevels - level.tasks2 = _.filter level.tasks, (_elem) -> - return ///#{$('#descSearch')[0].value}///i.test _elem.name + @processedLevels = {} + for key, level of @levels + filteredTasks = level.tasks.filter (elem) -> + return ///#{$('#descSearch')[0].value}///i.test elem.name + @processedLevels[key] = { + tasks: filteredTasks + name: level.name + } @renderSelectors '#levelTable' searchUpdate: -> + @onCampaignsLoaded(@campaigns) + ### if not @lastLoad? or (new Date()).getTime() - @lastLoad > 60 * 1000 * 1 # Update only after a minute from last update. - @campaigns.fetch() + #@campaigns.fetch() @listenTo(@campaigns, 'sync', @onCampaignsLoaded) - @supermodel.loadCollection(@campaigns, 'campaigns') + @superModel.trackRequest() + #@supermodel.loadCollection(@campaigns, 'campaigns') @lastLoad = (new Date()).getTime() else @onCampaignsLoaded() - + ### + + destroy: -> + @searchUpdate.cancel() + super() # Jade helper hasIncompleteTasks: (level) -> - return level.tasks2 and level.tasks2.filter((_elem) -> return not _elem.complete).length > 0 \ No newline at end of file + return level.tasks and level.tasks.filter((_elem) -> return not _elem.complete).length > 0 \ No newline at end of file diff --git a/app/views/artisans/SolutionProblemsView.coffee b/app/views/artisans/SolutionProblemsView.coffee index 09164ee72..c672f3fea 100644 --- a/app/views/artisans/SolutionProblemsView.coffee +++ b/app/views/artisans/SolutionProblemsView.coffee @@ -1,206 +1,165 @@ RootView = require 'views/core/RootView' template = require 'templates/artisans/solution-problems-view' + Level = require 'models/Level' Campaign = require 'models/Campaign' -Level = require 'models/Level' + CocoCollection = require 'collections/CocoCollection' +Campaigns = require 'collections/Campaigns' +Levels = require 'collections/Levels' module.exports = class SolutionProblemsView extends RootView template: template id: 'solution-problems-view' excludedCampaigns = [ - "picoctf" - "auditions" + # Misc. campaigns + 'picoctf', 'auditions' - "dungeon" - "forest" - "desert" - #"mountain" - "glacier" + # Campaign-version campaigns + #'dungeon', 'forest', 'desert', 'mountain', 'glacier' - "dungeon-branching-test" - "forest-branching-test" - "desert-branching-test" + # Test campaigns + 'dungeon-branching-test', 'forest-branching-test', 'desert-branching-test' - "intro" - "course-2" - "course-3" - "course-4" - "course-5" - "course-6" + # Course-version campaigns + #'intro', 'course-2', 'course-3', 'course-4', 'course-5', 'course-6' ] excludedSimulationLevels = [ # Course Arenas - "wakka-maul" - "cross-bones" + 'wakka-maul', 'cross-bones' ] excludedSolutionLevels = [ # Multiplayer Levels - "cavern-survival" - - "dueling-grounds" - "multiplayer-treasure-grove" - - "harrowland" - - "zero-sum" - - "ace-of-coders" - "capture-their-flag" + 'cavern-survival' + 'dueling-grounds', 'multiplayer-treasure-grove' + 'harrowland' + 'zero-sum' + 'ace-of-coders', 'capture-their-flag' ] - levelOffset: 0 - isReady: 0 - requiresSubs: 0 + simulationRequirements = [ + 'seed' + 'succeeds' + 'heroConfig' + 'frameCount' + 'goals' + ] + includedLanguages = [ + 'python', 'javascript', 'java', 'lua', 'coffeescript' + ] + # TODO: Phase the following out: + excludedLanguages = [ + #'java', 'lua', 'coffeescript' + ] + rob: [] test2: [] - constructor: (options) -> - super options - @campaigns = new CocoCollection([], - url: '/db/campaign?project=slug' - model: Campaign - ) - @campaigns.fetch() + unloadedCampaigns: 0 + campaignLevels: {} + loadedLevels: {} + parsedLevels: [] + problemCount: 0 + + initialize: -> + @campaigns = new Campaigns([]) @listenTo(@campaigns, 'sync', @onCampaignsLoaded) - @supermodel.loadCollection(@campaigns, 'campaigns') - ### - @levels = new CocoCollection([], - url: '/db/level?project=slug,thangs&limit=100&skip=' + @levelOffset - model: Level - ) - @levels.fetch() - @listenTo(@levels, 'sync', @onLevelsLoaded) - @supermodel.loadCollection(@levels, 'levels') - ### + @supermodel.trackRequest(@campaigns.fetch( + data: + project:'slug' + )) - onCampaignsLoaded: -> - @levelSlugs = [] - @test = {} - @loadedLevels = {} - count = 0 - for campaign in @campaigns.models + onCampaignsLoaded: (campCollection) -> + for campaign in campCollection.models campaignSlug = campaign.get('slug') - continue unless excludedCampaigns.indexOf(campaignSlug) is -1 - count++ - @test[campaignSlug] = new CocoCollection([], - url: '/db/campaign/' + campaignSlug + '/levels?project=thangs,slug,requiresSubscription,campaign' - model: Level - ) - @test[campaignSlug].fetch() - @listenTo(@test[campaignSlug], 'sync', (e) -> - e.models.reverse() - for level in e.models - if not @loadedLevels[level.get('slug')]? and level.get('requiresSubscription') - @requiresSubs++ - @loadedLevels[level.get('slug')] = level - count-- - if count is 0 - @readyUp() - ) - @supermodel.loadCollection(@test[campaignSlug], 'levels') + continue if campaignSlug in excludedCampaigns + @unloadedCampaigns++ - readyUp: -> - console.log("Count of levels: " + _.size(@loadedLevels)) - console.log("Count requires sub: " + @requiresSubs) - @parsedLevels = [] + @campaignLevels[campaignSlug] = new Levels() + @listenTo(@campaignLevels[campaignSlug], 'sync', @onLevelsLoaded) + @supermodel.trackRequest(@campaignLevels[campaignSlug].fetchForCampaign(campaignSlug, + data: + project: 'thangs,name,slug,campaign' + )) - @problemCount = 0 + onLevelsLoaded: (lvlCollection) -> + for level in lvlCollection.models + @loadedLevels[level.get('slug')] = level + if --@unloadedCampaigns is 0 + @onAllLevelsLoaded() + + onAllLevelsLoaded: -> for levelSlug, level of @loadedLevels unless level? + console.error 'Level Slug doesn\'t have associated Level', levelSlug continue - thangs = level.get('thangs') + continue if levelSlug in excludedSolutionLevels + thangs = level.get 'thangs' component = null - thang = _.findWhere(thangs, (elem) -> - return elem.id is "Hero Placeholder" and _.findWhere(elem.components, (elem2) -> - if elem2.config?.programmableMethods?.plan? + thangs = _.filter(thangs, (elem) -> + return _.findWhere(elem.components, (elem2) -> + if elem2.config?.programmableMethods? component = elem2 return true ) ) - thangs = _.filter(thangs, (elem) -> - return _.findWhere(elem.components, (elem2) -> - if elem2.config?.programmableMethods? - return true - ) - ) + if thangs.length > 1 - console.log levelSlug + ":" + thangs.length + " " + thangs.map((elem) -> return elem.id) - unless thang? and component - console.log("Cannot find programmableMethods component in: " + levelSlug) + unless levelSlug in excludedSimulationLevels + console.warn 'Level has more than 1 programmableMethod Thangs', levelSlug continue - unless component?.config?.programmableMethods?.plan? - console.log("Cannot find plannable method inside component: " + levelSlug) + unless component? + console.error 'Level doesn\'t have programmableMethod Thang', levelSlug continue + plan = component.config.programmableMethods.plan - solutions = plan.solutions - - + solutions = plan.solutions or [] problems = [] - if excludedSolutionLevels.indexOf(levelSlug) is -1 - for lang in ["python", "javascript", "lua", "java", "coffeescript"] - if _.findWhere(solutions, (elem) -> return elem.language is lang) - #@rob.push language: lang, level: levelSlug - - else if lang not in ["lua", "java", "coffeescript"] - problems.push { - "type":"Missing Solution Language", - "value":lang - } - @test2.push(levelSlug) - #break - @problemCount++ - else - # monitor lua/java when we care about it here - - for solutionIndex of solutions - solution = solutions[solutionIndex] - if excludedSimulationLevels.indexOf(levelSlug) is -1 - isSimul = true - for req in ["seed", "succeeds", "heroConfig", 'frameCount', 'goals'] # Implement a fix for lastHash - unless solution[req]? - console.log levelSlug, req - problems.push { - "type":"Solution is not simulatable", - "value":solution.language - } - @problemCount++ - isSimul = false - break - if isSimul - console.log level.get('campaign') - if @rob.indexOf(levelSlug) is -1 - @rob.push(levelSlug) - - if solution.source.search(/pass\n/i) isnt -1 - problems.push { - "type":"Solution contains pass", - "value":solution.language - } - @problemCount++ - if solution.source.indexOf('<%=') is -1 - problems.push { - "type":"Solution is not i18n'd", - "value":solution.language - } - @problemCount++ - if solution.language is 'javascript' - if solution.source is plan.source - problems.push { - "type":"Solution is identical to source", - "value":solution.language - } - @problemCount++ - else - #console.log solution.source - #console.log plan.languages[solution.language] - if solution.source is plan.languages[solution.language] - problems.push { - "type":"Solution is identical to source", - "value":solution.language - } - @problemCount++ - - @parsedLevels.push { + problems = problems.concat(@findMissingSolutions solutions) + unless levelSlug in excludedSimulationLevels + for solution in solutions + problems = problems.concat(@findSimulationProblems solution) + problems = problems.concat(@findPass solution) + problems = problems.concat(@findIdenticalToSource solution, plan) + @problemCount += problems.length + @parsedLevels.push level: level problems: problems - } - @renderSelectors '#levelTable' \ No newline at end of file + + @renderSelectors '#levelTable' + + findMissingSolutions: (solutions) -> + problems = [] + for lang in includedLanguages + if _.findWhere(solutions, (elem) -> return elem.language is lang) + # TODO: Phase the following out: + else if lang not in excludedLanguages + problems.push + type: 'Missing solution language' + value: lang + problems + + findSimulationProblems: (solution) -> + problems = [] + for req in simulationRequirements + unless solution[req]? + problems.push + type: 'Solution is not simulatable' + value: solution.language + break + problems + + findPass: (solution) -> + problems = [] + if solution.source.search(/pass\n/) isnt -1 + problems.push + type: 'Solution contains pass' + value: solution.language + problems + + findIdenticalToSource: (solution, plan) -> + problems = [] + source = if solution.lang is 'javascript' then plan.source else plan.languages[solution.language] + if solution.source is source + problems.push + type: 'Solution matches sample code' + value: solution.language + problems diff --git a/app/views/artisans/ThangTasksView.coffee b/app/views/artisans/ThangTasksView.coffee index e70bf0dea..65d170493 100644 --- a/app/views/artisans/ThangTasksView.coffee +++ b/app/views/artisans/ThangTasksView.coffee @@ -1,7 +1,9 @@ RootView = require 'views/core/RootView' template = require 'templates/artisans/thang-tasks-view' + ThangType = require 'models/ThangType' -CocoCollection = require 'collections/CocoCollection' + +ThangTypes = require 'collections/ThangTypes' module.exports = class ThangTasksView extends RootView template: template @@ -9,18 +11,13 @@ module.exports = class ThangTasksView extends RootView events: 'input input': 'searchUpdate' 'change input': 'searchUpdate' - - constructor: (options) -> - super options - @thangs = new CocoCollection([], - url: '/db/thang.type?project=name,tasks,slug' - model: ThangType - comparator: @sortThangs - ) - @lastLoad = (new Date()).getTime() + initialize: () -> + @thangs = new ThangTypes() @listenTo(@thangs, 'sync', @onThangsLoaded) - @supermodel.loadCollection(@thangs, 'thangs') - + @supermodel.trackRequest(@thangs.fetch( + data: + project: 'name,tasks,slug' + )) searchUpdate: -> if not @lastLoad? or (new Date()).getTime() - @lastLoad > 60 * 1000 * 1 # Update only after a minute from last update. @thangs.fetch() From a5cad6f98660bb973d37e5ef31d3988786c81181 Mon Sep 17 00:00:00 2001 From: Josh Callebaut Date: Mon, 16 May 2016 11:45:06 -0700 Subject: [PATCH 10/24] Utilize debounce, clean up event logic, remove unused CourseGearView --- app/core/Router.coffee | 3 +- app/styles/artisans/course-gear-view.sass | 0 app/templates/artisans/artisans-view.jade | 5 +-- app/templates/artisans/course-gear-view.jade | 3 -- app/templates/artisans/level-tasks-view.jade | 29 ++++++++------- .../artisans/solution-problems-view.jade | 4 +- app/templates/artisans/thang-tasks-view.jade | 30 ++++++++------- app/views/artisans/CourseGearView.coffee | 16 -------- app/views/artisans/LevelTasksView.coffee | 37 +++++++------------ .../artisans/SolutionProblemsView.coffee | 17 ++++++--- app/views/artisans/ThangTasksView.coffee | 25 +++++++------ 11 files changed, 76 insertions(+), 93 deletions(-) delete mode 100644 app/styles/artisans/course-gear-view.sass delete mode 100644 app/templates/artisans/course-gear-view.jade delete mode 100644 app/views/artisans/CourseGearView.coffee diff --git a/app/core/Router.coffee b/app/core/Router.coffee index 64ba4535e..44bc54c6a 100644 --- a/app/core/Router.coffee +++ b/app/core/Router.coffee @@ -45,9 +45,8 @@ module.exports = class CocoRouter extends Backbone.Router 'artisans': go('artisans/ArtisansView') - 'artisans/solution-problems': go('artisans/SolutionProblemsView') - 'artisans/course-gear': go('artisans/CourseGearView') 'artisans/level-tasks': go('artisans/LevelTasksView') + 'artisans/solution-problems': go('artisans/SolutionProblemsView') 'artisans/thang-tasks': go('artisans/ThangTasksView') 'beta': go('HomeView') diff --git a/app/styles/artisans/course-gear-view.sass b/app/styles/artisans/course-gear-view.sass deleted file mode 100644 index e69de29bb..000000000 diff --git a/app/templates/artisans/artisans-view.jade b/app/templates/artisans/artisans-view.jade index 9eebf08d4..c2b5b3215 100644 --- a/app/templates/artisans/artisans-view.jade +++ b/app/templates/artisans/artisans-view.jade @@ -10,7 +10,4 @@ block content |Level Tasks div a(href="/artisans/solution-problems") - |Solution Problems - div - a(href="/artisans/course-gear") - |Course Gear Progression \ No newline at end of file + |Solution Problems \ No newline at end of file diff --git a/app/templates/artisans/course-gear-view.jade b/app/templates/artisans/course-gear-view.jade deleted file mode 100644 index 5b40f96a0..000000000 --- a/app/templates/artisans/course-gear-view.jade +++ /dev/null @@ -1,3 +0,0 @@ -extends /templates/base - -block content \ No newline at end of file diff --git a/app/templates/artisans/level-tasks-view.jade b/app/templates/artisans/level-tasks-view.jade index cead6003a..f905d61ac 100644 --- a/app/templates/artisans/level-tasks-view.jade +++ b/app/templates/artisans/level-tasks-view.jade @@ -1,25 +1,28 @@ +# DNT extends /templates/base block content #level-tasks-view div a(href='/artisans') - | < Artisans Home + span.glyphicon.glyphicon-chevron-left + span Artisans Home br - input#nameSearch(placeholder='Filter: Level Name') + input.searchInput#nameSearch(placeholder='Filter: Level Name') br - input#descSearch(placeholder='Filter: Task Description') + input.searchInput#descSearch(placeholder='Filter: Task Description') hr - if view.processedLevels - table.table.table-striped#levelTable - tr - th Level Name - th Task List - for level in view.processedLevels - if view.hasIncompleteTasks(level) - +levelRow(level) - else - div ole? + div#levelTable + if view.processedLevels + table.table.table-striped + tr + th Level Name + th Task List + for level in view.processedLevels + if view.hasIncompleteTasks(level) + +levelRow(level) + else + div No view.processedLevels mixin levelRow(level) tr diff --git a/app/templates/artisans/solution-problems-view.jade b/app/templates/artisans/solution-problems-view.jade index ab9cfefba..6b44bf71b 100644 --- a/app/templates/artisans/solution-problems-view.jade +++ b/app/templates/artisans/solution-problems-view.jade @@ -1,10 +1,12 @@ +# DNT extends /templates/base block content #solution-problems-view div a(href='/artisans') - | < Artisans Home + span.glyphicon.glyphicon-chevron-left + span Artisans Home br div Total number of problems: #{view.problemCount} hr diff --git a/app/templates/artisans/thang-tasks-view.jade b/app/templates/artisans/thang-tasks-view.jade index 1e08cea18..01275b99c 100644 --- a/app/templates/artisans/thang-tasks-view.jade +++ b/app/templates/artisans/thang-tasks-view.jade @@ -1,25 +1,27 @@ +# DNT extends /templates/base block content #thang-tasks-view div a(href='/artisans') - | < Artisans Home + span.glyphicon.glyphicon-chevron-left + span Artisans Home + input.inputSearch#nameSearch(placeholder='Filter: Thang Name') br - input#nameSearch(placeholder='Filter: Thang Name') - br - input#descSearch(placeholder='Filter: Task Description') + input.inputSearch#descSearch(placeholder='Filter: Task Description') hr - if view.processedThangs - table.table.table-striped#thangTable - tr - th Thang Name - th Task List - for thang in view.processedThangs - if view.hasIncompleteTasks(thang) - +thangRow(thang) - else - span No view.processedThangs + div#thangTable + if view.processedThangs + table.table.table-striped#thangTable + tr + th Thang Name + th Task List + for thang in view.processedThangs + if view.hasIncompleteTasks(thang) + +thangRow(thang) + else + span No view.processedThangs mixin thangRow(thang) tr diff --git a/app/views/artisans/CourseGearView.coffee b/app/views/artisans/CourseGearView.coffee deleted file mode 100644 index 9a9181f4a..000000000 --- a/app/views/artisans/CourseGearView.coffee +++ /dev/null @@ -1,16 +0,0 @@ -RootView = require 'views/core/RootView' -template = require 'templates/artisans/course-gear-view' -Level = require 'models/Level' -Campaign = require 'models/Campaign' -Level = require 'models/Level' -CocoCollection = require 'collections/CocoCollection' - -module.exports = class CourseGearView extends RootView - template: template - id: 'course-gear-view' - initialize: -> - @campaigns = new CocoCollection([], - url: '/db/campaign?project=slug' - model: Campaign - ) - @supermodel.trackRequest(@campaigns.fetch(), @do ) \ No newline at end of file diff --git a/app/views/artisans/LevelTasksView.coffee b/app/views/artisans/LevelTasksView.coffee index 174b5b4de..51269886f 100644 --- a/app/views/artisans/LevelTasksView.coffee +++ b/app/views/artisans/LevelTasksView.coffee @@ -9,14 +9,18 @@ module.exports = class LevelTasksView extends RootView template: template id: 'level-tasks-view' events: - 'input .searchInput': 'searchUpdate' - 'change .searchInput': 'searchUpdate' + 'input .searchInput': 'processLevels' + 'change .searchInput': 'processLevels' + excludedCampaigns = [ 'picoctf', 'auditions' ] + levels: {} + processedLevels: {} + initialize: () -> - @searchUpdate = _.debounce(@searchUpdate, 250) + @processLevels = _.debounce(@processLevels, 250) @campaigns = new Campaigns() @listenTo(@campaigns, 'sync', @onCampaignsLoaded) @@ -32,12 +36,16 @@ module.exports = class LevelTasksView extends RootView continue if campaignSlug in excludedCampaigns levels = campaign.get 'levels' for key, level of levels - continue unless ///#{$('#nameSearch')[0].value}///i.test level.name levelSlug = level.slug @levels[levelSlug] = level + @processLevels() + + processLevels: () -> @processedLevels = {} for key, level of @levels - filteredTasks = level.tasks.filter (elem) -> + continue unless ///#{$('#nameSearch')[0].value}///i.test level.name + filteredTasks = level.tasks.filter (elem) -> + # Similar case-insensitive search of input vs description (name). return ///#{$('#descSearch')[0].value}///i.test elem.name @processedLevels[key] = { tasks: filteredTasks @@ -45,23 +53,6 @@ module.exports = class LevelTasksView extends RootView } @renderSelectors '#levelTable' - searchUpdate: -> - @onCampaignsLoaded(@campaigns) - ### - if not @lastLoad? or (new Date()).getTime() - @lastLoad > 60 * 1000 * 1 # Update only after a minute from last update. - #@campaigns.fetch() - @listenTo(@campaigns, 'sync', @onCampaignsLoaded) - @superModel.trackRequest() - #@supermodel.loadCollection(@campaigns, 'campaigns') - @lastLoad = (new Date()).getTime() - else - @onCampaignsLoaded() - ### - - destroy: -> - @searchUpdate.cancel() - super() - # Jade helper hasIncompleteTasks: (level) -> - return level.tasks and level.tasks.filter((_elem) -> return not _elem.complete).length > 0 \ No newline at end of file + return level.tasks and level.tasks.filter((_elem) -> return not _elem.complete).length > 0 diff --git a/app/views/artisans/SolutionProblemsView.coffee b/app/views/artisans/SolutionProblemsView.coffee index c672f3fea..bec950ba2 100644 --- a/app/views/artisans/SolutionProblemsView.coffee +++ b/app/views/artisans/SolutionProblemsView.coffee @@ -16,7 +16,8 @@ module.exports = class SolutionProblemsView extends RootView 'picoctf', 'auditions' # Campaign-version campaigns - #'dungeon', 'forest', 'desert', 'mountain', 'glacier' + 'dungeon', 'forest', 'desert',# 'mountain', + 'glacier' # Test campaigns 'dungeon-branching-test', 'forest-branching-test', 'desert-branching-test' @@ -48,11 +49,12 @@ module.exports = class SolutionProblemsView extends RootView ] # TODO: Phase the following out: excludedLanguages = [ - #'java', 'lua', 'coffeescript' + 'java', 'lua', 'coffeescript' ] - - rob: [] - test2: [] + excludedLevelSnippets = [ + 'treasure', 'brawl', 'siege' + ] + unloadedCampaigns: 0 campaignLevels: {} loadedLevels: {} @@ -92,6 +94,11 @@ module.exports = class SolutionProblemsView extends RootView console.error 'Level Slug doesn\'t have associated Level', levelSlug continue continue if levelSlug in excludedSolutionLevels + isBad = false + for word in excludedLevelSnippets + if levelSlug.indexOf(word) isnt -1 + isBad = true + continue if isBad thangs = level.get 'thangs' component = null thangs = _.filter(thangs, (elem) -> diff --git a/app/views/artisans/ThangTasksView.coffee b/app/views/artisans/ThangTasksView.coffee index 65d170493..5e226f806 100644 --- a/app/views/artisans/ThangTasksView.coffee +++ b/app/views/artisans/ThangTasksView.coffee @@ -9,25 +9,26 @@ module.exports = class ThangTasksView extends RootView template: template id: 'thang-tasks-view' events: - 'input input': 'searchUpdate' - 'change input': 'searchUpdate' + 'input input': 'processThangs' + 'change input': 'processThangs' + + thangs: {} + processedThangs: {} + initialize: () -> + @processThangs = _.debounce(@processThangs, 250) + @thangs = new ThangTypes() @listenTo(@thangs, 'sync', @onThangsLoaded) @supermodel.trackRequest(@thangs.fetch( data: project: 'name,tasks,slug' )) - searchUpdate: -> - if not @lastLoad? or (new Date()).getTime() - @lastLoad > 60 * 1000 * 1 # Update only after a minute from last update. - @thangs.fetch() - @listenTo(@thangs, 'sync', @onThangsLoaded) - @supermodel.loadCollection(@thangs, 'thangs') - @lastLoad = (new Date()).getTime() - else - @onThangsLoaded() - onThangsLoaded: -> + onThangsLoaded: (thangCollection) -> + @processThangs() + + processThangs: -> @processedThangs = @thangs.filter (_elem) -> # Case-insensitive search of input vs name. return ///#{$('#nameSearch')[0].value}///i.test _elem.get('name') @@ -42,4 +43,4 @@ module.exports = class ThangTasksView extends RootView # Jade helper hasIncompleteTasks: (thang) -> - return thang.tasks and thang.tasks.filter((_elem) -> return not _elem.complete).length > 0 \ No newline at end of file + return thang.tasks and thang.tasks.filter((_elem) -> return not _elem.complete).length > 0 From cca19f200811c1a1e7924625f826e19af0c90194 Mon Sep 17 00:00:00 2001 From: Josh Callebaut Date: Wed, 18 May 2016 13:25:00 -0700 Subject: [PATCH 11/24] Fix string interpolation, fix jx jade DNT comments --- app/collections/Levels.coffee | 6 +++--- app/templates/artisans/level-tasks-view.jade | 2 +- app/templates/artisans/solution-problems-view.jade | 2 +- app/templates/artisans/thang-tasks-view.jade | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/collections/Levels.coffee b/app/collections/Levels.coffee index f6da979aa..89be79fcf 100644 --- a/app/collections/Levels.coffee +++ b/app/collections/Levels.coffee @@ -6,13 +6,13 @@ module.exports = class LevelCollection extends CocoCollection model: Level fetchForClassroom: (classroomID, options={}) -> - options.url = '/db/classroom/#{classroomID}/levels' + options.url = "/db/classroom/#{classroomID}/levels" @fetch(options) fetchForClassroomAndCourse: (classroomID, courseID, options={}) -> - options.url = '/db/classroom/#{classroomID}/courses/#{courseID}/levels' + options.url = "/db/classroom/#{classroomID}/courses/#{courseID}/levels" @fetch(options) fetchForCampaign: (campaignSlug, options={}) -> - options.url = '/db/campaign/' + campaignSlug + '/levels' + options.url = "/db/campaign/#{campaignSlug}/levels" @fetch(options) diff --git a/app/templates/artisans/level-tasks-view.jade b/app/templates/artisans/level-tasks-view.jade index f905d61ac..bbf554216 100644 --- a/app/templates/artisans/level-tasks-view.jade +++ b/app/templates/artisans/level-tasks-view.jade @@ -1,4 +1,4 @@ -# DNT +// DNT extends /templates/base block content diff --git a/app/templates/artisans/solution-problems-view.jade b/app/templates/artisans/solution-problems-view.jade index 6b44bf71b..788ebafac 100644 --- a/app/templates/artisans/solution-problems-view.jade +++ b/app/templates/artisans/solution-problems-view.jade @@ -1,4 +1,4 @@ -# DNT +// DNT extends /templates/base block content diff --git a/app/templates/artisans/thang-tasks-view.jade b/app/templates/artisans/thang-tasks-view.jade index 01275b99c..15f99456b 100644 --- a/app/templates/artisans/thang-tasks-view.jade +++ b/app/templates/artisans/thang-tasks-view.jade @@ -1,4 +1,4 @@ -# DNT +// DNT extends /templates/base block content From a190acb108828de3530960b3cf002555ab6326dc Mon Sep 17 00:00:00 2001 From: Josh Callebaut Date: Wed, 18 May 2016 13:33:02 -0700 Subject: [PATCH 12/24] Kebab-cases html ids --- app/templates/artisans/level-tasks-view.jade | 6 +++--- app/templates/artisans/solution-problems-view.jade | 2 +- app/templates/artisans/thang-tasks-view.jade | 8 ++++---- app/views/artisans/LevelTasksView.coffee | 6 +++--- app/views/artisans/SolutionProblemsView.coffee | 2 +- app/views/artisans/ThangTasksView.coffee | 6 +++--- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/app/templates/artisans/level-tasks-view.jade b/app/templates/artisans/level-tasks-view.jade index bbf554216..29e7f22d5 100644 --- a/app/templates/artisans/level-tasks-view.jade +++ b/app/templates/artisans/level-tasks-view.jade @@ -8,11 +8,11 @@ block content span.glyphicon.glyphicon-chevron-left span Artisans Home br - input.searchInput#nameSearch(placeholder='Filter: Level Name') + input.searchInput#name-search(placeholder='Filter: Level Name') br - input.searchInput#descSearch(placeholder='Filter: Task Description') + input.searchInput#desc-search(placeholder='Filter: Task Description') hr - div#levelTable + div#level-table if view.processedLevels table.table.table-striped tr diff --git a/app/templates/artisans/solution-problems-view.jade b/app/templates/artisans/solution-problems-view.jade index 788ebafac..6d9e7615d 100644 --- a/app/templates/artisans/solution-problems-view.jade +++ b/app/templates/artisans/solution-problems-view.jade @@ -10,7 +10,7 @@ block content br div Total number of problems: #{view.problemCount} hr - table.table.table-striped#levelTable + table.table.table-striped#level-table tr th Level Name th Solution Problems diff --git a/app/templates/artisans/thang-tasks-view.jade b/app/templates/artisans/thang-tasks-view.jade index 15f99456b..af688af55 100644 --- a/app/templates/artisans/thang-tasks-view.jade +++ b/app/templates/artisans/thang-tasks-view.jade @@ -7,13 +7,13 @@ block content a(href='/artisans') span.glyphicon.glyphicon-chevron-left span Artisans Home - input.inputSearch#nameSearch(placeholder='Filter: Thang Name') + input.inputSearch#name-search(placeholder='Filter: Thang Name') br - input.inputSearch#descSearch(placeholder='Filter: Task Description') + input.inputSearch#desc-search(placeholder='Filter: Task Description') hr - div#thangTable + div#thang-table if view.processedThangs - table.table.table-striped#thangTable + table.table.table-striped tr th Thang Name th Task List diff --git a/app/views/artisans/LevelTasksView.coffee b/app/views/artisans/LevelTasksView.coffee index 51269886f..4195f3df3 100644 --- a/app/views/artisans/LevelTasksView.coffee +++ b/app/views/artisans/LevelTasksView.coffee @@ -43,15 +43,15 @@ module.exports = class LevelTasksView extends RootView processLevels: () -> @processedLevels = {} for key, level of @levels - continue unless ///#{$('#nameSearch')[0].value}///i.test level.name + continue unless ///#{$('#name-search')[0].value}///i.test level.name filteredTasks = level.tasks.filter (elem) -> # Similar case-insensitive search of input vs description (name). - return ///#{$('#descSearch')[0].value}///i.test elem.name + return ///#{$('#desc-search')[0].value}///i.test elem.name @processedLevels[key] = { tasks: filteredTasks name: level.name } - @renderSelectors '#levelTable' + @renderSelectors '#level-table' # Jade helper hasIncompleteTasks: (level) -> diff --git a/app/views/artisans/SolutionProblemsView.coffee b/app/views/artisans/SolutionProblemsView.coffee index bec950ba2..630f8de45 100644 --- a/app/views/artisans/SolutionProblemsView.coffee +++ b/app/views/artisans/SolutionProblemsView.coffee @@ -131,7 +131,7 @@ module.exports = class SolutionProblemsView extends RootView level: level problems: problems - @renderSelectors '#levelTable' + @renderSelectors '#level-table' findMissingSolutions: (solutions) -> problems = [] diff --git a/app/views/artisans/ThangTasksView.coffee b/app/views/artisans/ThangTasksView.coffee index 5e226f806..896a826e3 100644 --- a/app/views/artisans/ThangTasksView.coffee +++ b/app/views/artisans/ThangTasksView.coffee @@ -31,12 +31,12 @@ module.exports = class ThangTasksView extends RootView processThangs: -> @processedThangs = @thangs.filter (_elem) -> # Case-insensitive search of input vs name. - return ///#{$('#nameSearch')[0].value}///i.test _elem.get('name') + return ///#{$('#name-search')[0].value}///i.test _elem.get('name') for thang in @processedThangs thang.tasks = _.filter thang.attributes.tasks, (_elem) -> # Similar case-insensitive search of input vs description (name). - return ///#{$('#descSearch')[0].value}///i.test _elem.name - @renderSelectors '#thangTable' + return ///#{$('#desc-search')[0].value}///i.test _elem.name + @renderSelectors '#thang-table' sortThangs: (a, b) -> a.get('name').localeCompare(b.get('name')) From bc036edfb9da6cefb594494557c914912befbcf1 Mon Sep 17 00:00:00 2001 From: Ana Date: Wed, 18 May 2016 23:31:33 +0200 Subject: [PATCH 13/24] Update sr.coffee (#3659) * Update sr.coffee adjusted the translation for the newest locale file * Update sr.coffee --- app/locale/sr.coffee | 448 +++++++++++++++++++++---------------------- 1 file changed, 224 insertions(+), 224 deletions(-) diff --git a/app/locale/sr.coffee b/app/locale/sr.coffee index 1017f0f3e..529522b78 100644 --- a/app/locale/sr.coffee +++ b/app/locale/sr.coffee @@ -112,7 +112,7 @@ module.exports = nativeDescription: "српски", englishDescription: "Serbian about: "О нама" contact: "Контакт" twitter_follow: "Прати" -# students: "Students" + students: "Ученици" teachers: "Учитељи" careers: "Каријере" facebook: "Фејсбук" @@ -262,7 +262,7 @@ module.exports = nativeDescription: "српски", englishDescription: "Serbian login_switch: "Већ имаш налог?" school_name: "Име школе и града" optional: "опционо" -# school_name_placeholder: "Example High School, Springfield, IL" + school_name_placeholder: "Средња школа, Место, Држава" or_sign_up_with: "или се пријави преко" connected_gplus_header: "Успешно си се повезао са Гугл+!" connected_gplus_p: "Заврши пријаву да би могао да се улогујеш са својим Гугл+ налогом." @@ -271,7 +271,7 @@ module.exports = nativeDescription: "српски", englishDescription: "Serbian connected_facebook_p: "Заврши пријаву да би могао да се улогујеш са својим Фејсбук налогом." facebook_exists: "Већ имаш налог који је повезан са Фејсбуком!" hey_students: "Ученици, упишите код за разред од вашег учитеља." -# birthday: "Birthday" + birthday: "Датум рођења" recover: recover_account_title: "Поврати налог" @@ -298,7 +298,7 @@ module.exports = nativeDescription: "српски", englishDescription: "Serbian publish: "Објави" create: "Направи" # fork: "Fork" - play: "Нивои" # When used as an action verb, like "Play next level" + play: "Играј" # When used as an action verb, like "Play next level" retry: "Покушај поново" actions: "Радње" info: "Инфо" @@ -425,13 +425,13 @@ module.exports = nativeDescription: "српски", englishDescription: "Serbian victory_new_item: "Новa ствар" # victory_viking_code_school: "Holy smokes, that was a hard level you just beat! If you aren't already a software developer, you should be. You just got fast-tracked for acceptance with Viking Code School, where you can take your skills to the next level and become a professional web developer in 14 weeks." victory_become_a_viking: "Постани Викинг" -# victory_no_progress_for_teachers: "Progress is not saved for teachers. But, you can add a student account to your classroom for yourself." + victory_no_progress_for_teachers: "Напредак се не чува за учитеље, али можеш додати ученички профил за себе у свој разред." guide_title: "Водич" tome_cast_button_run: "Покрени" tome_cast_button_running: "Покреће се" tome_cast_button_ran: "Покренуто" tome_submit_button: "Потврди" -# tome_reload_method: "Reload original code for this method" # Title text for individual method reload button. + tome_reload_method: "Поново учитај оригинални код за овај метод" # Title text for individual method reload button. tome_select_method: "Изабери метод" tome_see_all_methods: "Види све методе које можеш да измениш" # Title text for method list selector (shown when there are multiple programmable methods). tome_select_a_thang: "Изабери неког за " @@ -449,8 +449,8 @@ module.exports = nativeDescription: "српски", englishDescription: "Serbian time_goto: "Иди на:" non_user_code_problem_title: "Није могуће учитати ниво" infinite_loop_title: "Бесконачна петља откривена" -# infinite_loop_description: "The initial code to build the world never finished running. It's probably either really slow or has an infinite loop. Or there might be a bug. You can either try running this code again or reset the code to the default state. If that doesn't fix it, please let us know." -# check_dev_console: "You can also open the developer console to see what might be going wrong." + infinite_loop_description: "Иницијални код за грађење света се није никад завршио. Вероватно је јако спор или има бесконачну петљу. Или можда постоји грешка. Можеш да покушаш да покренеш овај код поново или да ресетујеш код на уобичајено стање. Дај нам до знања ако га то не поправи." + check_dev_console: "Можеш такође да отвориш конзолу за девелопере да видиш шта не ваља." check_dev_console_link: "(инструкције)" infinite_loop_try_again: "Покушај поново" infinite_loop_reset_level: "Ресетуј ниво" @@ -563,92 +563,92 @@ module.exports = nativeDescription: "српски", englishDescription: "Serbian equip: "Опреми" unequip: "Скини" -# buy_gems: -# few_gems: "A few gems" -# pile_gems: "Pile of gems" -# chest_gems: "Chest of gems" -# purchasing: "Purchasing..." -# declined: "Your card was declined" -# retrying: "Server error, retrying." -# prompt_title: "Not Enough Gems" -# prompt_body: "Do you want to get more?" -# prompt_button: "Enter Shop" -# recovered: "Previous gems purchase recovered. Please refresh the page." -# price: "x{{gems}} / mo" + buy_gems: + few_gems: "Неколико драгуља" + pile_gems: "Гомила драгуља" + chest_gems: "Ковчег драгуља" + purchasing: "Куповина је у току..." + declined: "Ваша картица је одбијена" + retrying: "Грешка на серверу, поновни покушај." + prompt_title: "Недовољно драгуља" + prompt_body: "Да ли желиш да узмеш још?" + prompt_button: "Уђи у продавницу" + recovered: "Претходна куповина драгуља је надокнађена. Освежите страницу." + #price: "x{{gems}} месечно" -# subscribe: -# comparison_blurb: "Sharpen your skills with a CodeCombat subscription!" -# feature1: "__levelsCount__+ basic levels across __worldsCount__ worlds" -# feature2: "__heroesCount__ powerful new heroes with unique skills!" -# feature3: "__bonusLevelsCount__+ bonus levels" -# feature4: "{{gems}} bonus gems every month!" -# feature5: "Video tutorials" -# feature6: "Premium email support" -# feature7: "Private Clans" -# feature8: "No ads!" -# free: "Free" -# month: "month" -# must_be_logged: "You must be logged in first. Please create an account or log in from the menu above." -# subscribe_title: "Subscribe" -# unsubscribe: "Unsubscribe" -# confirm_unsubscribe: "Confirm Unsubscribe" -# never_mind: "Never Mind, I Still Love You" -# thank_you_months_prefix: "Thank you for supporting us these last" -# thank_you_months_suffix: "months." -# thank_you: "Thank you for supporting CodeCombat." -# sorry_to_see_you_go: "Sorry to see you go! Please let us know what we could have done better." -# unsubscribe_feedback_placeholder: "O, what have we done?" -# parent_button: "Ask your parent" -# parent_email_description: "We'll email them so they can buy you a CodeCombat subscription." -# parent_email_input_invalid: "Email address invalid." -# parent_email_input_label: "Parent email address" -# parent_email_input_placeholder: "Enter parent email" -# parent_email_send: "Send Email" -# parent_email_sent: "Email sent!" -# parent_email_title: "What's your parent's email?" -# parents: "For Parents" -# parents_title: "Dear Parent: Your child is learning to code. Will you help them continue?" -# parents_blurb1: "Your child has played __nLevels__ levels and learned programming basics. Help cultivate their interest and buy them a subscription so they can keep playing." -# parents_blurb1a: "Computer programming is an essential skill that your child will undoubtedly use as an adult. By 2020, basic software skills will be needed by 77% of jobs, and software engineers are in high demand across the world. Did you know that Computer Science is the highest-paid university degree?" -# parents_blurb2: "For ${{price}} USD/mo, your child will get new challenges every week and personal email support from professional programmers." -# parents_blurb3: "No Risk: 100% money back guarantee, easy 1-click unsubscribe." -# payment_methods: "Payment Methods" -# payment_methods_title: "Accepted Payment Methods" -# payment_methods_blurb1: "We currently accept credit cards and Alipay. You can also PayPal {{three_month_price}} USD to nick@codecombat.com with your account email in the memo to purchase three months' subscription and gems, or ${{year_price}} for a year." -# payment_methods_blurb2: "If you require an alternate form of payment, please contact" -# sale_button: "Sale!" -# sale_button_title: "Save $21 when you purchase a 1 year subscription" -# stripe_description: "Monthly Subscription" -# stripe_description_year_sale: "1 Year Subscription (${{discount}} discount)" -# subscription_required_to_play: "You'll need a subscription to play this level." -# unlock_help_videos: "Subscribe to unlock all video tutorials." -# personal_sub: "Personal Subscription" # Accounts Subscription View below -# loading_info: "Loading subscription information..." -# managed_by: "Managed by" -# will_be_cancelled: "Will be cancelled on" -# currently_free: "You currently have a free subscription" -# currently_free_until: "You currently have a subscription until" -# was_free_until: "You had a free subscription until" -# managed_subs: "Managed Subscriptions" -# subscribing: "Subscribing..." -# current_recipients: "Current Recipients" -# unsubscribing: "Unsubscribing" -# subscribe_prepaid: "Click Subscribe to use prepaid code" -# using_prepaid: "Using prepaid code for monthly subscription" + subscribe: + comparison_blurb: "Унапреди своје вештине са CodeCombat претплатом!" + feature1: "__levelsCount__+ основних нивоа кроз __worldsCount__ светова" + feature2: "__heroesCount__ моћних нових хероја са јединственим вештинама!" + feature3: "__bonusLevelsCount__+ бонус нивоа" + feature4: "{{gems}} бонус драгуља сваког месеца!" + feature5: "Видео туторијали" + feature6: "Премијум имејл подршка" + feature7: "Приватни Кланови" + feature8: "Без реклама!" + free: "Бесплатан" + month: "месец" + must_be_logged: "Мораш прво бити пријављен. Направи налог или се пријави у менију изнад." + subscribe_title: "Претплати се" + unsubscribe: "Одјави претплату" + confirm_unsubscribe: "Потврди одјаву претплате" + never_mind: "Није важно, и даље те волим" + thank_you_months_prefix: "Хвала што нас подржаваш ових последњих" + thank_you_months_suffix: "месеци." + thank_you: "Хвала што подржаваш CodeCombat." + sorry_to_see_you_go: "Жао нам је што идеш! Дај нам до знања шта можемо боље да урадимо." + unsubscribe_feedback_placeholder: "O, шта смо урадили?" + parent_button: "Питај свог родитеља" + parent_email_description: "Послаћемо им мејл како би могли да ти купе CodeCombat претплату." + parent_email_input_invalid: "Имејл адреса је неисправна." + parent_email_input_label: "Имејл адреса родитеља" + parent_email_input_placeholder: "Укуцај имејл родитеља" + parent_email_send: "Пошаљи мејл" + parent_email_sent: "Мејл послат!" + parent_email_title: "Који је имејл твог родитеља?" + parents: "За родитеље" + parents_title: "Драги родитељу: Ваше дете учи да кодира. Да ли ћете му помоћи да настави?" + parents_blurb1: "Ваше дете је одиграло __nLevels__ нивоа и научило основе програмирања. Помозите му да негује своју заинтересованост и купите му претплату како би могло да настави да игра." + parents_blurb1a: "Компјутерско програмирање је есенцијална вештина коју ће Ваше дете без сумње користити кад одрасте. До 2020, основне софтверске вештине ће бити потребне за 77% послова, и софтверски инжењери су веома тражени широм света. Да ли сте знали да су Компјутерске науке најплаћенија факултетска диплома?" + parents_blurb2: "За ${{price}} америчких долара месечно, Ваше дете ће добити нове изазове сваке недеље и личну имејл подршку од професионалних програмера." + parents_blurb3: "Без ризика: 100% гаранција повраћаја новца, једноставна одјава претплате једним кликом." + payment_methods: "Методе плаћања" + payment_methods_title: "Прихваћене методе плаћања" + payment_methods_blurb1: "Тренутно прихватамо кредитне картице и Alipay. Можете такође користити PayPal да платите {{three_month_price}} америчких долара на nick@codecombat.com са вашим имејлом од налога у допису да бисте купили претплату на три месеца и драгуље, или ${{year_price}} за годину дана." + payment_methods_blurb2: "Ако Вам је потребан алтернативни начин плаћања, контактирајте нас" + sale_button: "Распродаја!" + sale_button_title: "Уштедите $21 када купите претплату за годину дана" + stripe_description: "Месечна претплата" + stripe_description_year_sale: "Годишња претплата (${{discount}} попуста)" + subscription_required_to_play: "Треба ти претплата да би играо овај ниво." + unlock_help_videos: "Претплати се да откључаш све видео туторијале." + personal_sub: "Лична претплата" # Accounts Subscription View below + loading_info: "Учитавање информација о претплати..." + managed_by: "Управља" + will_be_cancelled: "Биће поништено" + currently_free: "Тренутно имате бесплатну претплату" + currently_free_until: "Тренутно имате претплату до" + was_free_until: "Имали сте бесплатну претплату до" + # managed_subs: "Managed Subscriptions" + subscribing: "Претплата је у току..." + current_recipients: "Тренутни примаоци" + unsubscribing: "Одјава претплате" + subscribe_prepaid: "Кликните на Претплата да искористите припејд код" + using_prepaid: "Коришћење припејд кода за месечну претплату" choose_hero: choose_hero: "Изабери свог хероја" programming_language: "Програмски језик" programming_language_description: "Који програмски језик желиш да користиш у игри?" -# default: "Default" + default: "Подразумевани" experimental: "Експериментални" -# python_blurb: "Simple yet powerful, great for beginners and experts." -# javascript_blurb: "The language of the web. (Not the same as Java.)" -# coffeescript_blurb: "Nicer JavaScript syntax." -# clojure_blurb: "A modern Lisp." -# lua_blurb: "Game scripting language." -# io_blurb: "Simple but obscure." -# java_blurb: "(Subscriber Only) Android and enterprise." + python_blurb: "Једноставан, а моћан, одличан за почетнике и експерте." + javascript_blurb: "Језик интернета. (Није исто што и Java.)" + coffeescript_blurb: "Лепша JavaScript синтакса." + clojure_blurb: "Модерни Lisp." + lua_blurb: "Скриптни језик за игре." + io_blurb: "Једноставан, али непознат." + # java_blurb: "(Subscriber Only) Android and enterprise." status: "Статус" hero_type: "Врста" weapons: "Оружја" @@ -656,7 +656,7 @@ module.exports = nativeDescription: "српски", englishDescription: "Serbian weapons_ranger: "Самострели, пушке - Велики домет, без магије" weapons_wizard: "Штапићи, штапови - Велики домет, магија" attack: "Напад" # Can also translate as "Attack" -# health: "Health" + health: "Здравље" speed: "Брзина" regeneration: "Регенерација" range: "Домет" # As in "attack or visual range" @@ -664,11 +664,11 @@ module.exports = nativeDescription: "српски", englishDescription: "Serbian # backstab: "Backstab" # As in "this dagger does this much backstab damage" skills: "Вештине" attack_1: "Наноси" -# attack_2: "of listed" -# attack_3: "weapon damage." -# health_1: "Gains" -# health_2: "of listed" -# health_3: "armor health." + attack_2: "од наведене" + attack_3: "штете оружја." + health_1: "Добија" + health_2: "од наведеног" + health_3: "здравља оклопа." speed_1: "Помера се" speed_2: "метара у секунди." available_for_purchase: "Доступно за куповину" # Shows up when you have unlocked, but not purchased, a hero in the hero store @@ -702,111 +702,111 @@ module.exports = nativeDescription: "српски", englishDescription: "Serbian # returns: "Returns" # granted_by: "Granted by" -# save_load: -# granularity_saved_games: "Saved" -# granularity_change_history: "History" + save_load: + granularity_saved_games: "Сачувано" + granularity_change_history: "Историја" -# options: -# general_options: "General Options" # Check out the Options tab in the Game Menu while playing a level -# volume_label: "Volume" -# music_label: "Music" -# music_description: "Turn background music on/off." -# editor_config_title: "Editor Configuration" -# editor_config_keybindings_label: "Key Bindings" -# editor_config_keybindings_default: "Default (Ace)" -# editor_config_keybindings_description: "Adds additional shortcuts known from the common editors." -# editor_config_livecompletion_label: "Live Autocompletion" -# editor_config_livecompletion_description: "Displays autocomplete suggestions while typing." -# editor_config_invisibles_label: "Show Invisibles" -# editor_config_invisibles_description: "Displays invisibles such as spaces or tabs." -# editor_config_indentguides_label: "Show Indent Guides" -# editor_config_indentguides_description: "Displays vertical lines to see indentation better." -# editor_config_behaviors_label: "Smart Behaviors" -# editor_config_behaviors_description: "Autocompletes brackets, braces, and quotes." + options: + general_options: "Општа подешавања" # Check out the Options tab in the Game Menu while playing a level + volume_label: "Јачина звука" + music_label: "Музика" + music_description: "Укључи/искључи позадинску музику." + editor_config_title: "Едитор конфигурација" + editor_config_keybindings_label: "Функције тастера" + editor_config_keybindings_default: "Подразумевано (Ace)" + editor_config_keybindings_description: "Додаје додатне пречице познате из заједничких едитора." + editor_config_livecompletion_label: "Аутоматско довршавање у реалном времену" + editor_config_livecompletion_description: "Приказује сугестију за аутоматску допуну док куцаш." + editor_config_invisibles_label: "Прикажи невидљиве" + editor_config_invisibles_description: "Приказује невидљиве као што су размаци или табови." + editor_config_indentguides_label: "Прикажи водиче за индентацију" + editor_config_indentguides_description: "Приказује вертикалне линије да би се индентације боље виделе." + editor_config_behaviors_label: "Паметна понашања" + editor_config_behaviors_description: "Аутоматски довршава угласте и витичасте заграде и наводнике." -# about: -# main_title: "If you want to learn to program, you need to write (a lot of) code." -# main_description: "At CodeCombat, our job is to make sure you're doing that with a smile on your face." -# mission_link: "Mission" -# team_link: "Team" -# story_link: "Story" -# press_link: "Press" -# mission_title: "Our mission: make programming accessible to every student on Earth." -# mission_description_1: "Programming is magic. It's the ability to create things from pure imagination. We started CodeCombat to give learners the feeling of wizardly power at their fingertips by using typed code." -# mission_description_2: "As it turns out, that enables them to learn faster too. WAY faster. It's like having a conversation instead of reading a manual. We want to bring that conversation to every school and to every student, because everyone should have the chance to learn the magic of programming." -# team_title: "Meet the CodeCombat team" -# team_values: "We value open and respectful dialog, where the best idea wins. Our decisions are grounded in customer research and our process is focused on delivering tangible results for them. Everyone is hands-on, from our CEO to our Github contributors, because we value growth and learning in our team." -# nick_title: "Cofounder, CEO" -# nick_blurb: "Motivation Guru" -# matt_title: "Cofounder, CTO" -# cat_title: "Game Designer" -# cat_blurb: "Airbender" -# scott_title: "Cofounder, Software Engineer" -# scott_blurb: "Reasonable One" -# maka_title: "Customer Advocate" -# maka_blurb: "Storyteller" -# rob_title: "Software Engineer" -# rob_blurb: "Codes things and stuff" -# josh_c_title: "Game Designer" -# josh_c_blurb: "Designs games" -# robin_title: "UX Design & Research" -# robin_blurb: "Scaffolding" -# josh_title: "Game Designer" -# josh_blurb: "Floor Is Lava" -# phoenix_title: "Software Engineer" -# nolan_title: "Territory Manager" -# elliot_title: "Partnership Manager" -# retrostyle_title: "Illustration" -# retrostyle_blurb: "RetroStyle Games" -# jose_title: "Music" -# jose_blurb: "Taking Off" -# community_title: "...and our open-source community" -# community_subtitle: "Over 450 contributors have helped build CodeCombat, with more joining every week!" -# community_description_1: "CodeCombat is a community project, with hundreds of players volunteering to create levels, contribute to our code to add features, fix bugs, playtest, and even translate the game into 50 languages so far. Employees, contributors and the site gain by sharing ideas and pooling effort, as does the open source community in general. The site is built on numerous open source projects, and we are open sourced to give back to the community and provide code-curious players a familiar project to explore and experiment with. Anyone can join the CodeCombat community! Check out our" -# community_description_link: "contribute page" -# community_description_2: "for more info." -# number_contributors: "Over 450 contributors have lent their support and time to this project." -# story_title: "Our story so far" -# story_subtitle: "Since 2013, CodeCombat has grown from a mere set of sketches to a living, thriving game." -# story_statistic_1a: "5,000,000+" -# story_statistic_1b: "total players" -# story_statistic_1c: "have started their programming journey through CodeCombat" -# story_statistic_2a: "We’ve been translated into over 50 languages — our players hail from" -# story_statistic_2b: "200+ countries" -# story_statistic_3a: "Together, they have written" -# story_statistic_3b: "1 billion lines of code and counting" -# story_statistic_3c: "across many different programming languages" -# story_long_way_1: "Though we've come a long way..." -# story_sketch_caption: "Nick's very first sketch depicting a programming game in action." -# story_long_way_2: "we still have much to do before we complete our quest, so..." -# jobs_title: "Come work with us and help write CodeCombat history!" -# jobs_subtitle: "Don't see a good fit but interested in keeping in touch? See our \"Create Your Own\" listing." -# jobs_benefits: "Employee Benefits" -# jobs_benefit_4: "Unlimited vacation" -# jobs_benefit_5: "Professional development and continuing education support – free books and games!" -# jobs_benefit_6: "Medical (gold), dental, vision" -# jobs_benefit_7: "Sit-stand desks for all" + about: + main_title: "Ако желиш да научиш да програмираш, мораш (доста) да кодираш." + main_description: "У CodeCombat-у, наш посао је да будемо сигурни да да то радиш с осмехом на лицу." + mission_link: "Мисија" + team_link: "Тим" + story_link: "Прича" + press_link: "Прес" + mission_title: "Наша мисија: да учинимо програмирање доступним сваком ученику на планети." + mission_description_1: "Програмирање је магично. То је могућност да створиш ствари из чисте имагинације. Ми смо покренули CodeCombat да бисмо дали ученицима осећај чаробњачке моћи на дохват руке користећикуцани код." + mission_description_2: "Како се испоставља, то им омогућава да такође уче брже. МНОГО брже. То је као конверзација уместо коришћења упутства. Желимо да донесему ту конверзацију у сваку школу и сваком ученику, јер би свако требало да добије шансу да научи магију програмирања." + team_title: "Упознај CodeCombat тим" + team_values: "Ми ценимо отворен дијалог пун поштовања, где најбоља идеја побеђује. Наше одлуке су засноване на истраживању потрошача и наш процес је фокусиран на достављање опипљивих резултата за њих. Свако је практичан, од нашег генералног директора до наших Github сарадника, јер ми ценимо раст и учење у нашем тиму." + nick_title: "Кооснивач, генерални директор" + nick_blurb: "Мотивациони гуру" + matt_title: "Кооснивач, технички директор" + cat_title: "Дизајнер игара" + cat_blurb: "Владар ветрова" + scott_title: "Кооснивач, софтверски инжењер" + scott_blurb: "Разуман део тима" + maka_title: "Заступник корисника" + maka_blurb: "Приповедач" + rob_title: "Софтверски инжењер" + rob_blurb: "Кодира свашта нешто" + josh_c_title: "Дизајнер игара" + josh_c_blurb: "Дизајнира игре" + robin_title: "Дизајн и истраживање корисничког искуства" + robin_blurb: "Подупире скеле" + josh_title: "Дизајнер игара" + josh_blurb: "Под је лава" + phoenix_title: "Софтверски инжењер" + nolan_title: "Руководилац подручја" + elliot_title: "Руководилац партнерства" + retrostyle_title: "Илустрација" + retrostyle_blurb: "RetroStyle Games" + jose_title: "Музика" + jose_blurb: "Узлеће" + community_title: "...и наша заједница отвореног кода" + community_subtitle: "Преко 450 сарадника је помогло да се изгради CodeCombat, и још њих се придружује сваке недеље!" + community_description_1: "CodeCombat је пројекат заједнице, са стотинама играча који волонтирају да праве нивое, доприносе нашем коду да додају функције, исправљају грешке, тестирају игру, и чак и преводе игру на (до сад) 50 језика. Запослени, сарадници и сајт добијају путем дељења идеја и удруживањем напора, као и заједница отвореног кода у глобалу. Сајт је изграђен на бројним пројектима отвореног кода, и ми смо отвореног кода како бисмо вратили заједници и пружили радозналим-за-код играчима познати пројекат за истраживање и експериментисање.Свако може да се прикључи CodeCombat заједници! Погледај нашу" + community_description_link: "страницу за допринос" + community_description_2: "за више информација." + number_contributors: "Преко 450 сарадника је дало своју подршку и време овом пројекту." + story_title: "Наша прича до сад" + story_subtitle: "Од 2013, CodeCombat је израстао из обичних скупова скица у праву успешну игру." + story_statistic_1a: "Више од 5 000 000" + story_statistic_1b: "играча укупно" + story_statistic_1c: "је започело њихово програмерско путовање кроз CodeCombat" + story_statistic_2a: "Преведени смо на преко 50 језика — наши играчи долазе из" + story_statistic_2b: "преко 200 земаља" + story_statistic_3a: "Заједно, они су написали" + story_statistic_3b: "једну милијарду линија кода" + story_statistic_3c: "преко више различитих програмских језика" + story_long_way_1: "Иако смо прешли велики пут..." + story_sketch_caption: "Nick-ове прве скице које приказују програмску игру на делу." + story_long_way_2: "и даље имамо доста да урадимо пре него што завршимо нашу потрагу, тако да..." + jobs_title: "Дођи да радиш са нама и помози нам да напишему CodeCombat историју!" + jobs_subtitle: "Не уклапа ти се ништа, али си заинтересован за остајање у контакту? Погледај наш \"Направи свој\" списак." + jobs_benefits: "Бенефиције за запослене" + jobs_benefit_4: "Неограничен одмор" + jobs_benefit_5: "Професионални развој и континуирана подршка образовања - бесплатне књиге и игре!" +# jobs_benefit_6: "Медицинско (gold), зубно, очно" + jobs_benefit_7: "Sit-stand радни столови за свакога" # jobs_benefit_9: "10-year option exercise window" -# jobs_benefit_10: "Maternity leave: 10 weeks paid, next 6 @ 55% salary" -# jobs_benefit_11: "Paternity leave: 10 weeks paid" -# learn_more: "Learn More" -# jobs_custom_title: "Create Your Own" -# jobs_custom_description: "Are you passionate about CodeCombat but don't see a job listed that matches your qualifications? Write us and show how you think you can contribute to our team. We'd love to hear from you!" -# jobs_custom_contact_1: "Send us a note at" -# jobs_custom_contact_2: "introducing yourself and we might get in touch in the future!" -# contact_title: "Press & Contact" -# contact_subtitle: "Need more information? Get in touch with us at" -# screenshots_title: "Game Screenshots" -# screenshots_hint: "(click to view full size)" -# downloads_title: "Download Assets & Information" -# about_codecombat: "About CodeCombat" -# logo: "Logo" -# screenshots: "Screenshots" -# character_art: "Character Art" -# download_all: "Download All" -# previous: "Previous" -# next: "Next" -# location_title: "We're located in downtown SF:" + jobs_benefit_10: "Породиљско одсуство: 10 плаћених недеља, наредних 6 недеља 55% плате" + jobs_benefit_11: "Очинско одсуство: 10 плаћених недеља" + learn_more: "Сазнај више" + jobs_custom_title: "Направи свој" + jobs_custom_description: "Да ли си заинтересован за CodeCombat али не видиш од наведених послова ниједан који одговара твојим квалификацијама? Пиши нам и покажи нам како мислиш да можеш да допринесеш нашем тиму. Волели бисмо да нам се јавиш!" + jobs_custom_contact_1: "Пошаљи нам поруку на" + jobs_custom_contact_2: "и представи се, и можда ступимо у контакт у будућности!" + contact_title: "Прес и контакт" + contact_subtitle: "Треба ти још информација? Ступи у контакт с нама на" + screenshots_title: "Снимци екрана игре" + screenshots_hint: "(кликни да видиш пуну величину)" + downloads_title: "Преузми средства и информације" + about_codecombat: "О CodeCombat-у" + logo: "Лого" + screenshots: "Снимци екрана" + character_art: "Илустрације ликова" + download_all: "Преузми све" + previous: "Претходно" + next: "Следеће" + location_title: "Налазимо се у центру Сан Франциска:" # teachers: # who_for_title: "Who is CodeCombat for?" @@ -1661,19 +1661,19 @@ module.exports = nativeDescription: "српски", englishDescription: "Serbian payments: "Уплате" prepaid_codes: "Припејд кодови" purchased: "Купљено" - subscription: "Pretplata" - invoices: "Fakture" -# service_apple: "Apple" -# service_web: "Web" -# paid_on: "Paid On" -# service: "Service" + subscription: "Претплата" + invoices: "Фактуре" + service_apple: "Apple" + service_web: "Web" + paid_on: "Плаћено" + service: "Услуга" price: "Цена" gems: "Драгуљи" -# active: "Active" + active: "Активно" subscribed: "Претплаћени" unsubscribed: "Нисте претплаћени" active_until: "Важи до" -# cost: "Cost" + cost: "Цена" next_payment: "Следећа уплата" card: "Картица" status_unsubscribed_active: "Нисте претплаћени и неће Вам бити наплаћено, али Ваш налог је и даље активан за сада." @@ -1738,13 +1738,13 @@ module.exports = nativeDescription: "српски", englishDescription: "Serbian resources: level: "Ниво" -# patch: "Patch" -# patches: "Patches" + patch: "Измена" + patches: "Измене" system: "Систем" systems: "Системи" -# component: "Component" -# components: "Components" -# hero: "Hero" + component: "Компонента" + components: "Компоненте" + hero: "Херој" campaigns: "Кампање" # concepts: @@ -1869,19 +1869,19 @@ module.exports = nativeDescription: "српски", englishDescription: "Serbian # license: "license" # oreilly: "ebook of your choice" -# calendar: -# year: "Year" -# day: "Day" -# month: "Month" -# january: "January" -# february: "February" -# march: "March" -# april: "April" -# may: "May" -# june: "June" -# july: "July" -# august: "August" -# september: "September" -# october: "October" -# november: "November" -# december: "December" + calendar: + year: "Година" + day: "Дан" + month: "Месец" + january: "Јануар" + february: "Фебруар" + march: "Март" + april: "Април" + may: "Мај" + june: "Јун" + july: "Јул" + august: "Август" + september: "Септембар" + october: "Октобар" + november: "Новембар" + december: "Децембар" From d4a557ef70770fb1622b58e35f74d9cc26f92860 Mon Sep 17 00:00:00 2001 From: Josh Callebaut Date: Wed, 18 May 2016 14:53:34 -0700 Subject: [PATCH 14/24] Fix uncommented campaigns --- app/views/artisans/SolutionProblemsView.coffee | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/views/artisans/SolutionProblemsView.coffee b/app/views/artisans/SolutionProblemsView.coffee index 630f8de45..a7130cce1 100644 --- a/app/views/artisans/SolutionProblemsView.coffee +++ b/app/views/artisans/SolutionProblemsView.coffee @@ -16,8 +16,7 @@ module.exports = class SolutionProblemsView extends RootView 'picoctf', 'auditions' # Campaign-version campaigns - 'dungeon', 'forest', 'desert',# 'mountain', - 'glacier' + #'dungeon', 'forest', 'desert', 'mountain', 'glacier' # Test campaigns 'dungeon-branching-test', 'forest-branching-test', 'desert-branching-test' From a89782b9c632974d57b87136d7864803f6ba7137 Mon Sep 17 00:00:00 2001 From: Scott Erickson Date: Wed, 18 May 2016 16:49:57 -0700 Subject: [PATCH 15/24] Fix /auth/unsubscribe for emails with + in them --- server/middleware/auth.coffee | 11 ++++++++++- spec/server/functional/auth.spec.coffee | 8 ++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/server/middleware/auth.coffee b/server/middleware/auth.coffee index aa9188643..904c094b2 100644 --- a/server/middleware/auth.coffee +++ b/server/middleware/auth.coffee @@ -147,7 +147,16 @@ module.exports = res.end() unsubscribe: wrap (req, res) -> - email = req.query.email + # need to grab email directly from url, in case it has "+" in it + queryString = req.url.split('?')[1] or '' + queryParts = queryString.split('&') + email = null + for part in queryParts + [name, value] = part.split('=') + if name is 'email' + email = value + break + unless email throw new errors.UnprocessableEntity 'No email provided to unsubscribe.' email = decodeURIComponent(email) diff --git a/spec/server/functional/auth.spec.coffee b/spec/server/functional/auth.spec.coffee index b97227676..ffb173131 100644 --- a/spec/server/functional/auth.spec.coffee +++ b/spec/server/functional/auth.spec.coffee @@ -165,6 +165,14 @@ describe 'GET /auth/unsubscribe', -> expect(res.statusCode).toBe(404) done() + it 'returns 200 even if the email has a + in it', utils.wrap (done) -> + @user.set('email', 'some+email@address.com') + yield @user.save() + url = getURL('/auth/unsubscribe?recruitNotes=1&email='+@user.get('email')) + [res, body] = yield request.getAsync(url, {json: true}) + expect(res.statusCode).toBe(200) + done() + describe '?recruitNotes=1', -> it 'unsubscribes the user from recruitment emails', utils.wrap (done) -> From 184be0bf65800b1d77557cbf67d11ffbd0594123 Mon Sep 17 00:00:00 2001 From: Scott Erickson Date: Wed, 18 May 2016 17:03:49 -0700 Subject: [PATCH 16/24] CourseDetailsView does not link to next course if the student is not assigned to that course --- app/templates/courses/course-details.jade | 2 +- app/views/courses/CourseDetailsView.coffee | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/templates/courses/course-details.jade b/app/templates/courses/course-details.jade index 2bb9c549d..333e0fc12 100644 --- a/app/templates/courses/course-details.jade +++ b/app/templates/courses/course-details.jade @@ -65,7 +65,7 @@ block content span= view.course.get('name') span . .col-md-6 - if view.nextCourseInstance + if view.nextCourseInstance && _.contains(view.nextCourseInstance.get('members'), me.id) a.btn.btn-lg.btn-success(href="/courses/#{view.nextCourse.id}/#{view.nextCourseInstance.id}") h1= view.nextCourse.get('name') p= view.nextCourse.get('description') diff --git a/app/views/courses/CourseDetailsView.coffee b/app/views/courses/CourseDetailsView.coffee index 12ba1d63f..abb619d2b 100644 --- a/app/views/courses/CourseDetailsView.coffee +++ b/app/views/courses/CourseDetailsView.coffee @@ -62,6 +62,8 @@ module.exports = class CourseDetailsView extends RootView # need to figure out the next course instance @courseComplete = true @courseInstances.comparator = 'courseID' + # TODO: make this logic use locked course content to figure out the next course, then fetch the + # course instance for that @supermodel.trackRequest(@courseInstances.fetchForClassroom(classroomID).then(=> @nextCourseInstance = _.find @courseInstances.models, (ci) => ci.get('courseID') > @courseID if @nextCourseInstance From 75c7d140d16d73243d10ebf6c9e0c19f31d8af2c Mon Sep 17 00:00:00 2001 From: duybkict Date: Wed, 18 May 2016 09:55:22 +0700 Subject: [PATCH 17/24] refactor UnsubcribeView #3138 #3488 --- app/templates/account/unsubscribe-view.jade | 2 +- app/views/account/UnsubscribeView.coffee | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/app/templates/account/unsubscribe-view.jade b/app/templates/account/unsubscribe-view.jade index 5eeee57cc..e7fcdfe67 100644 --- a/app/templates/account/unsubscribe-view.jade +++ b/app/templates/account/unsubscribe-view.jade @@ -5,7 +5,7 @@ block content p span(data-i18n="account.unsubscribe") Unsubscribing for span - strong= email + strong= view.email button.btn.btn-warning#unsubscribe-button(data-i18n="account.unsubscribe_button") Do it diff --git a/app/views/account/UnsubscribeView.coffee b/app/views/account/UnsubscribeView.coffee index b098a9a38..4bf25bdad 100644 --- a/app/views/account/UnsubscribeView.coffee +++ b/app/views/account/UnsubscribeView.coffee @@ -6,14 +6,12 @@ module.exports = class UnsubscribeView extends RootView id: 'unsubscribe-view' template: template + initialize: -> + @email = @getQueryVariable 'email' + events: 'click #unsubscribe-button': 'onUnsubscribeButtonClicked' - getRenderData: -> - context = super() - context.email = @getQueryVariable 'email' - context - onUnsubscribeButtonClicked: -> @$el.find('#unsubscribe-button').hide() @$el.find('.progress').show() From c461a0055db08b53f77e6a0241417bfbfd9d7de5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Duy=20Tr=E1=BA=A7n?= Date: Fri, 20 May 2016 01:57:29 +0700 Subject: [PATCH 18/24] Vi translation (#3661) * Translate into Vietnamese * Translate and edit some Vietnamese strings * update Vietnamese translate * try to fix some error * fix bugs with tab character * update vi.coffee: play_level * Update vi.coffee * update vi.coffee * update text on Home page * Vietnamese: update legal * vi.coffee: edit community page * vi.coffee: update user's page * vi.coffee: about page * update vi.coffee * update vi.coffee * vi.coffee: invoices * vi.coffee: account_prepaid * update vi.coffee * vi.coffee: error strings * Update vi.coffee * update vi.coffee * vi.coffee: update contact form * vi.coffee: minor update * vi.coffee: update about page, modify some strings * update vi.coffee * vi.coffee: minor update * no message * Update vi strings, fix minor bug in page /community * vi.coffee: update Adventure and Artisan * vi.coffee: update Adventurer * vi.coffee: reverse changes * vi.coffee: reverse changes * vi.coffee: update some strings * vi.cofffe: update Diplomat * vi.coffee: update Diplomat * vi.coffee: update descriptions of classes * vi.coffee: update Ambassador * remove .cleafix div, will fix in another branch * refactor ClansView #3138 #3488 * use initialize() in ClansView #3138 #3488 * update vi.coffee * update vi.coffee * exclude changes on ClansView * vi.coffee: update play screen * vi.coffee: update some strings * vi.coffee: update createClass form --- app/locale/vi.coffee | 302 +++++++++++++++++++++---------------------- 1 file changed, 151 insertions(+), 151 deletions(-) diff --git a/app/locale/vi.coffee b/app/locale/vi.coffee index 3653b92b7..fb407b1b3 100644 --- a/app/locale/vi.coffee +++ b/app/locale/vi.coffee @@ -136,14 +136,14 @@ module.exports = nativeDescription: "Tiếng Việt", englishDescription: "Vietn okay: "OK" not_found: - page_not_found: "không tìm thấy trang" + page_not_found: "Không tìm thấy trang" diplomat_suggestion: title: "Hãy giúp chúng tôi phiên dịch CodeCombat!" # This shows up when a player switches to a non-English language using the language selector. sub_heading: "Chúng tôi cần kỹ năng ngoại ngữ của bạn." pitch_body: "Chúng tôi xây dựng Codecombat bằng Tiếng Anh, tuy nhiên có rất nhiều bạn trẻ trên toàn thế giới đều muốn tham gia. Các bạn trẻ Việt Nam cũng muốn chơi với nội dung Tiếng Việt, nếu như bạn có thể đọc và viết thành thạo cả 2 ngôn ngữ xin hãy đăng kí làm dịch thuật cho chúng tôi." missing_translations: "Bạn sẽ tiếp tục thấy Tiếng Anh cho đến khi chúng tôi dịch tất cả nội dung qua Tiếng Việt." - learn_more: "Tìm hiểu thêm để tham gia làm Phiên Dịch Viên" + learn_more: "Tìm hiểu thêm để tham gia trở thành Phiên Dịch Viên" subscribe_as_diplomat: "Trở thành Phiên Dịch Viên" play: @@ -152,22 +152,22 @@ module.exports = nativeDescription: "Tiếng Việt", englishDescription: "Vietn spectate: "Quan sát" # Ladder page players: "người chơi" # Hover over a level on /play hours_played: "Thời gian chơi" # Hover over a level on /play - items: "Trang bị" # Tooltip on item shop button from /play + items: "Trang Bị" # Tooltip on item shop button from /play unlock: "Mua" # For purchasing items and heroes confirm: "Xác nhận" owned: "Đã có" # For items you own locked: "Bị khóa" purchasable: "Có thể mua" # For a hero you unlocked but haven't purchased available: "Khả dụng" - skills_granted: "Đã nhận được Kĩ Năng" # Property documentation details - heroes: "Các Tướng" # Tooltip on hero shop button from /play - achievements: "Thành tích" # Tooltip on achievement list button from /play + skills_granted: "Kỹ năng nhận được" # Property documentation details + heroes: "Tướng" # Tooltip on hero shop button from /play + achievements: "Thành Tích" # Tooltip on achievement list button from /play account: "Tài khoản" # Tooltip on account button from /play settings: "Tùy Chỉnh" # Tooltip on settings button from /play poll: "Bỏ phiếu" # Tooltip on poll button from /play next: "Tiếp" # Go from choose hero to choose inventory before playing a level change_hero: "Đổi Tướng" # Go back from choose inventory to choose hero - buy_gems: "Mua ngọc" + buy_gems: "Mua Ngọc" subscription_required: "Cần đăng kí" anonymous: "Người chơi ẩn danh" level_difficulty: "Độ khó: " @@ -251,7 +251,7 @@ module.exports = nativeDescription: "Tiếng Việt", englishDescription: "Vietn finishing: "Sắp hoàn tất" sign_in_with_facebook: "Đăng nhập với Facebook" sign_in_with_gplus: "Đăng nhập với G+" - signup_switch: "Bạn có muốn tạo tài khoản mới?" + signup_switch: "Bạn muốn tạo tài khoản mới?" signup: email_announcements: "Nhận thông báo bằng email" @@ -289,9 +289,9 @@ module.exports = nativeDescription: "Tiếng Việt", englishDescription: "Vietn common: back: "Trở lại" # When used as an action verb, like "Navigate backward" continue: "Tiếp tục" # When used as an action verb, like "Continue forward" - loading: "Đang tải..." - saving: "Đang lưu..." - sending: "Đang gửi..." + loading: "Đang Tải..." + saving: "Đang Lưu..." + sending: "Đang Gửi..." send: "Gửi" cancel: "Hủy" save: "Lưu" @@ -345,7 +345,7 @@ module.exports = nativeDescription: "Tiếng Việt", englishDescription: "Vietn message: "Tin nhắn" code: "Code" ladder: "Thang điểm" - when: "Khi nào" + when: "Thời gian" opponent: "Đối thủ" rank: "Hạng" score: "Điểm" @@ -358,7 +358,7 @@ module.exports = nativeDescription: "Tiếng Việt", englishDescription: "Vietn player: "Người chơi" player_level: "Cấp độ" # Like player level 5, not like level: Dungeons of Kithgard warrior: "Chiến binh" - ranger: "Cung thủ" + ranger: "Xạ thủ" wizard: "Phù thủy" first_name: "Tên" last_name: "Họ" @@ -420,8 +420,8 @@ module.exports = nativeDescription: "Tiếng Việt", englishDescription: "Vietn victory_review_placeholder: "Màn chơi vừa rồi như thế nào?" victory_hour_of_code_done: "Bạn xong chưa?" victory_hour_of_code_done_yes: "Đúng vậy, tôi đã hoàn tất thời gian lập trình!" - victory_experience_gained: "Đã tăng XP" - victory_gems_gained: "Nhận được Ngọc" + victory_experience_gained: "XP nhận được" + victory_gems_gained: "Ngọc nhận được" victory_new_item: "Vật phẩm mới" victory_viking_code_school: "Thật tuyệt vời, bạn vừa vượt qua một màn chơi khó khủng khiếp! Không lâu nữa bạn sẽ trở thành một lập trình viên thôi. Bạn vừa được nhận thẳng vào trường Viking Code School, nơi bạn có thể nâng tầm kĩ năng của mình và trở thành lập trình viên web chuyên nghiệp trong 14 tuần." victory_become_a_viking: "Trở thành Viking" @@ -442,7 +442,7 @@ module.exports = nativeDescription: "Tiếng Việt", englishDescription: "Vietn skip_tutorial: "Bỏ qua (esc)" keyboard_shortcuts: "Các phím tắt" loading_ready: "Sẵn sàng!" - loading_start: "Bắt đầu màn này" + loading_start: "Bắt đầu màn chơi" problem_alert_title: "Hãy sửa lại Code của bạn" time_current: "Bây giờ:" time_total: "Tối đa:" @@ -542,12 +542,12 @@ module.exports = nativeDescription: "Tiếng Việt", englishDescription: "Vietn view_other_solutions: "Xem xếp hạng" # {change} scores: "Điểm" top_players: "Người chơi dẫn đầu xếp theo" - day: "Hôm nay" - week: "Tuần này" - all: "Tất cả" - time: "Thời gian" + day: "Hôm Nay" + week: "Tuần Này" + all: "Tất Cả" + time: "Thời Gian" damage_taken: "Sát thương nhận vào" - damage_dealt: "Sát thương gây ra" + damage_dealt: "Mức Sát Thương" difficulty: "Độ khó" gold_collected: "Vàng đã thu thập" @@ -560,7 +560,7 @@ module.exports = nativeDescription: "Tiếng Việt", englishDescription: "Vietn equipped: "(đã trang bị)" locked: "(khóa)" restricted: "(bị giới hạn ở màn này)" - equip: "Mặc trang bị" + equip: "Mặc" unequip: "Cởi ra" buy_gems: @@ -577,7 +577,7 @@ module.exports = nativeDescription: "Tiếng Việt", englishDescription: "Vietn price: "x{{gems}} / tháng" subscribe: - comparison_blurb: "Tăng cường kĩ năng bằng việc đăng kí theo dõi CodeCombat!" + comparison_blurb: "Tăng cường kĩ năng bằng cách mua gói dịch vụ nâng cao của CodeCombat!" feature1: "__levelsCount__+ màn chơi cơ bản trên __worldsCount__ bản đồ thế giới" feature2: "__heroesCount__ tướng mới mạnh mẽ với những kĩ năng đặc biệt!" feature3: "__bonusLevelsCount__+ màn chơi thêm" @@ -589,7 +589,7 @@ module.exports = nativeDescription: "Tiếng Việt", englishDescription: "Vietn free: "Miễn phí" month: "tháng" must_be_logged: "Trước tiên bạn phải đăng nhập. Hãy tạo một tài khoản mới hoặc đăng nhập ở menu phía trên." - subscribe_title: "Đăng kí theo dõi" + subscribe_title: "Mua gói nâng cao" unsubscribe: "Ngừng theo dõi" confirm_unsubscribe: "Xác nhận ngừng theo dõi" never_mind: "Đừng bận tâm, tôi vẫn yêu bạn" @@ -598,8 +598,8 @@ module.exports = nativeDescription: "Tiếng Việt", englishDescription: "Vietn thank_you: "Cảm ơn bạn đã ủng hộ CodeCombat." sorry_to_see_you_go: "Thật đáng tiếc khi phải chia tay bạn! Hãy góp ý để chúng tôi có thể cái thiện tốt hơn." unsubscribe_feedback_placeholder: "Ồ, chúng tôi đã làm gì sai ư?" - parent_button: "Hãy hỏi phụ huynh bạn" - parent_email_description: "Chúng tôi sẽ email cho họ để họ có thể mua cho bạn một gói dịch vụ của CodeCombat." + parent_button: "Hỏi phụ huynh bạn" + parent_email_description: "Chúng tôi sẽ email cho họ để họ có thể mua cho bạn một gói dịch vụ nâng cao của CodeCombat." parent_email_input_invalid: "Địa chỉ email không hợp lệ." parent_email_input_label: "Địa chỉ email của phụ huynh" parent_email_input_placeholder: "Hãy nhập địa chi email của phụ huynh bạn" @@ -608,13 +608,13 @@ module.exports = nativeDescription: "Tiếng Việt", englishDescription: "Vietn parent_email_title: "Địa chỉ email của phụ huynh bạn là gì?" parents: "Dành cho Phụ huynh" parents_title: "Xin chào: Con của bạn muốn học lập trình. Bạn đồng ý chứ?" # {change} - parents_blurb1: "Con của bạn đã hoàn thiện __nLevels__ cấp độ lập trình đầu tiên với CodeCombat. Hãy giúp con bạn theo đuổi giấc mơ lập trình bằng cách đăng kí thêm khóa học." - parents_blurb1a: "Lập trình là một kỹ năng cần thiết mà con bạn chắc chắn sẽ cần khi trưởng thành. Tới 2020, kỹ năng phần mếm cơ bản sẽ được dùng trong 77% các ngành nghề, và khắp nơi trên thế giới hiện nay đều đang có nhu cầu cao tìm kiếm những kĩ sư phần mềm. Bạn có biết Công Nghệ Thông Tin đang là bằng cấp đại học đem lại mức lương cao nhất?" + parents_blurb1: "Con của bạn đã hoàn thiện __nLevels__ cấp độ lập trình cơ bản với CodeCombat. Hãy giúp con bạn theo đuổi giấc mơ lập trình bằng cách đăng kí thêm khóa học." + parents_blurb1a: "Lập trình là một kỹ năng cần thiết mà con bạn chắc chắn sẽ cần khi trưởng thành. Tính đến 2020, kỹ năng phần mếm cơ bản sẽ được dùng trong 77% các ngành nghề, và khắp mọi nơi trên thế giới hiện nay đều đang có nhu cầu cao tìm kiếm kĩ sư phần mềm. Bạn có biết Công Nghệ Thông Tin đang là bằng cấp đại học đem lại mức lương cao nhất?" parents_blurb2: "Chỉ với ${{price}} USD/tháng, con bạn sẽ nhận được những thử thách mới mỗi tháng và sẽ nhận được sự hỗ trợ đặc biệt từ các lập trình viên chuyên nghiệp." # {change} - parents_blurb3: "Không hề có rủi ro: Nếu bạn không hài lòng bạn có thể nhận lại 100% số tiền mình bỏ ra chỉ với 1 cú nhấp chuốt." + parents_blurb3: "Không hề có rủi ro: Nếu bạn không hài lòng bạn có thể nhận lại 100% số tiền mình bỏ ra chỉ với 1 cú click chuốt." payment_methods: "Phương thức thanh toán" payment_methods_title: "Những phương thức thanh toán được chấp nhận." - payment_methods_blurb1: "Hiện tại chúng tôi chấp nhận thẻ tín dụng và Alipay. Bạn cũng có thể sử dụng PayPal để chuyển {{three_month_price}} USD tới nick@codecombat.com và ghi rõ email tài khoản để mua dịch vụ trong 3 tháng, hoặc ${{year_price}} để mua dịch vụ trong 1 năm." + payment_methods_blurb1: "Hiện tại chúng tôi chấp nhận thẻ tín dụng và Alipay. Bạn cũng có thể sử dụng PayPal để chuyển ${{three_month_price}} tới nick@codecombat.com và ghi rõ email tài khoản để mua dịch vụ trong 3 tháng, hoặc ${{year_price}} để mua dịch vụ trong 1 năm." payment_methods_blurb2: "Nếu bạn cần một phương thức thanh toán khác, hãy liên hệ" sale_button: "Ưu đãi!" sale_button_title: "Tiết kiệm $21 khi mua gói dịch vụ 1 năm" @@ -644,7 +644,7 @@ module.exports = nativeDescription: "Tiếng Việt", englishDescription: "Vietn experimental: "Thử" python_blurb: "Đơn giản nhưng mạnh mẽ, tốt cho cả những người mới bắt đầu và chuyên gia." javascript_blurb: "Ngôn ngữ của thế giới web. (Không giống với Java đâu nhé.)" - coffeescript_blurb: "Là JavaScript viết bằng cú pháp tốt hơn." + coffeescript_blurb: "JavaScript với cú pháp tốt hơn." clojure_blurb: "Lisp thời đại mới." lua_blurb: "Ngôn ngữ được ưa chuông để làm game." io_blurb: "Đơn giản nhưng ít người biết đến." @@ -659,7 +659,7 @@ module.exports = nativeDescription: "Tiếng Việt", englishDescription: "Vietn health: "Sinh lực" speed: "Tốc độ" regeneration: "Hồi sinh lực" - range: "Tầm đánh/Tầm nhìn" # As in "attack or visual range" + range: "Tầm xa" # As in "attack or visual range" blocks: "Đỡ" # As in "this shield blocks this much damage" # backstab: "Backstab" # As in "this dagger does this much backstab damage" skills: "Kĩ năng" @@ -707,14 +707,14 @@ module.exports = nativeDescription: "Tiếng Việt", englishDescription: "Vietn granularity_change_history: "Lịch sử" options: - general_options: "Tùy chỉnh chung" # Check out the Options tab in the Game Menu while playing a level - volume_label: "Âm lượng" - music_label: "Âm nhạc" + general_options: "Tùy Chỉnh Chung" # Check out the Options tab in the Game Menu while playing a level + volume_label: "Âm Lượng" + music_label: "Âm Nhạc" music_description: "Bật/tắt nhạc nền." - editor_config_title: "Cấu hình Editor" -# editor_config_keybindings_label: "Key Bindings" + editor_config_title: "Cấu Hình Editor" + editor_config_keybindings_label: "Các phím tắt" editor_config_keybindings_default: "Mặc định (Ace)" - editor_config_keybindings_description: "Thêm shortcuts chung cho các công cụ editor." + editor_config_keybindings_description: "Hệ thống phím tắt chung cho các công cụ editor." editor_config_livecompletion_label: "Gợi ý tự động" editor_config_livecompletion_description: "Hiển thị gợi ý tự động trong khi gõ phím." editor_config_invisibles_label: "Hiện kí tự ẩn" @@ -899,14 +899,14 @@ module.exports = nativeDescription: "Tiếng Việt", englishDescription: "Vietn not_logged_in: "Đăng nhập hoặc tạo tài khoản để thay đổi cài đặt." autosave: "Tự động lưu thay đổi" me_tab: "Tôi" - picture_tab: "Ảnh đại diện" - delete_account_tab: "Xóa tài khoản" + picture_tab: "Ảnh Đại Diện" + delete_account_tab: "Xóa Tài Khoản" wrong_email: "Email không đúng" wrong_password: "Mật khẩu không đúng" upload_picture: "Tải ảnh lên" delete_this_account: "Xóa tài khoản này vĩnh viễn" -# reset_progress_tab: "Reset All Progress" -# reset_your_progress: "Clear all your progress and start over" + reset_progress_tab: "Xóa Mọi Tiến Trình" + reset_your_progress: "Xóa mọi tiến trình của bạn và bắt đầu lại từ đầu" # god_mode: "God Mode" password_tab: "Mật khẩu" emails_tab: "Email" @@ -914,9 +914,9 @@ module.exports = nativeDescription: "Tiếng Việt", englishDescription: "Vietn manage_subscription: "Nhấn vào đây để chỉnh sửa gói đăng ký." new_password: "Mật khẩu mới" new_password_verify: "Xác nhận" -# type_in_email: "Type in your email to confirm account deletion." -# type_in_email_progress: "Type in your email to confirm deleting your progress." -# type_in_password: "Also, type in your password." + type_in_email: "Nhập email của bạn để xác nhận xóa tài khoản." + type_in_email_progress: "Nhập email của bạn để xác nhận xóa tiến trình." + type_in_password: "Nhập lại mật khẩu của bạn." email_subscriptions: "Thuê bao Email" # email_subscriptions_none: "No Email Subscriptions." email_announcements: "Thông báo" @@ -928,8 +928,8 @@ module.exports = nativeDescription: "Tiếng Việt", englishDescription: "Vietn # email_news: "News" email_recruit_notes: "Cơ hội việc làm" email_recruit_notes_description: "Nếu bạn chơi trò này rất giỏi, chúng tôi có thể sẽ liên lạc với bạn về cơ hội nghề nghiệp." -# contributor_emails: "Contributor Class Emails" - contribute_prefix: "Chúng tôi đang tìm thêm người vào nhóm của chúng tôi! Hãy kiểm " + contributor_emails: "Email tham gia đóng góp" + contribute_prefix: "Chúng tôi đang tìm thêm người để cùng tham gia với chúng tôi! Hãy vào " contribute_page: "trang đóng góp" contribute_suffix: " để tìm hiểu thêm." # email_toggle: "Toggle All" @@ -980,78 +980,78 @@ module.exports = nativeDescription: "Tiếng Việt", englishDescription: "Vietn clans: clan: "Clan" -# clans: "Clans" - new_name: "Tên mới cho bè đảng" - new_description: "Miêu tả cho bè đảng mới này" - make_private: "Tạo bè đảng kín" -# subs_only: "subscribers only" + clans: "Các Clan" + new_name: "Tên Clan mới" + new_description: "Mô tả Clan mới" + make_private: "Make clan private" + subs_only: "chỉ dành cho các subscriber" create_clan: "Tạo một clan mới" -# private_preview: "Preview" -# private_clans: "Private Clans" -# public_clans: "Public Clans" -# my_clans: "My Clans" -# clan_name: "Clan Name" + private_preview: "Xem trước" + private_clans: "Các Clan kín" + public_clans: "Các Clan mở" + my_clans: "Các Clan của tôi" + clan_name: "Tên Clan" name: "Tên" -# chieftain: "Chieftain" -# type: "Type" -# edit_clan_name: "Edit Clan Name" -# edit_clan_description: "Edit Clan Description" -# edit_name: "edit name" -# edit_description: "edit description" -# private: "(private)" -# summary: "Summary" -# average_level: "Average Level" + chieftain: "Thủ lĩnh" + type: "Loại" + edit_clan_name: "Sửa tên Clan" + edit_clan_description: "Sửa mô tả Clan" + edit_name: "sửa tên" + edit_description: "sửa mô tả" + private: "(kín)" + summary: "Tóm tắt" + average_level: "Cấp độ trng bình" # average_achievements: "Average Achievements" -# delete_clan: "Delete Clan" -# leave_clan: "Leave Clan" -# join_clan: "Join Clan" -# invite_1: "Invite:" -# invite_2: "*Invite players to this Clan by sending them this link." - members: "Những thành viên" -# progress: "Progress" -# not_started_1: "not started" -# started_1: "started" -# complete_1: "complete" + delete_clan: "Xóa Clan" + leave_clan: "Rời Clan" + join_clan: "Tham gia Clan" + invite_1: "Mời:" + invite_2: "*Mời người chơi khác tham dự Clan này bằng cách gửi họ đường link này." + members: "Thành viên" + progress: "Tiến trình" + not_started_1: "chưa băt đầu" + started_1: "đã bắt đầu" + complete_1: "hoàn thành" # exp_levels: "Expand levels" # rem_hero: "Remove Hero" # status: "Status" -# complete_2: "Complete" -# started_2: "Started" -# not_started_2: "Not Started" -# view_solution: "Click to view solution." + complete_2: "Hoàn thành" + started_2: "Đã bắt đầu" + not_started_2: "Chưa bắt đầu" + view_solution: "Click để xem lời giải." # view_attempt: "Click to view attempt." # latest_achievement: "Latest Achievement" -# playtime: "Playtime" -# last_played: "Last played" + playtime: "Thời gian chơi" + last_played: "Lần chơi cuối" # leagues_explanation: "Play in a league against other clan members in these multiplayer arena instances." # track_concepts1: "Track concepts" # track_concepts2a: "learned by each student" # track_concepts2b: "learned by each member" # track_concepts3a: "Track levels completed for each student" # track_concepts3b: "Track levels completed for each member" -# track_concepts4a: "See your students'" -# track_concepts4b: "See your members'" -# track_concepts5: "solutions" -# track_concepts6a: "Sort students by name or progress" -# track_concepts6b: "Sort members by name or progress" + track_concepts4a: "Xem các học viên của bạn'" + track_concepts4b: "Xem các thành viên của bạn'" + track_concepts5: "lời giải" + track_concepts6a: "Sắp xếp học viên theo tên hoặc tiến trình" + track_concepts6b: "Sắp xếp thành viên theo tên hoặc tiến trình" # track_concepts7: "Requires invitation" # track_concepts8: "to join" -# private_require_sub: "Private clans require a subscription to create or join." + private_require_sub: "Các Clan kín cần mua subscription để tạo hoặc tham gia." courses: course: "Khóa học" courses: "Những khóa học" - create_new_class: "Tạo khóa học mới" + create_new_class: "Tạo Lớp Học Mới" not_enrolled: "Bạn không đăng kí vào khóa học này" -# visit_pref: "Please visit the" -# visit_suf: "page to enroll." -# select_class: "Select one of your classes" -# unnamed: "*unnamed*" + visit_pref: "Hãy ghé thăm trang" + visit_suf: "để tham gia." + select_class: "Chọn một trong các lớp học của bạn" + unnamed: "*unnamed*" # select: "Select" -# unnamed_class: "Unnamed Class" -# edit_settings: "edit class settings" -# edit_settings1: "Edit Class Settings" - progress: "Tiến trình của khóa học" + unnamed_class: "Lớp học chưa đặt tên" + edit_settings: "thay đổi tùy chỉnh lớp học" + edit_settings1: "Thay đổi tùy chỉnh lớp học" + progress: "Tiến trình của lớp học" add_students: "Thêm học sinh" stats: "Thống kê" total_students: "Tổng số học sinh:" @@ -1073,9 +1073,9 @@ module.exports = nativeDescription: "Tiếng Việt", englishDescription: "Vietn # invite_link_p_2: "Or have us email them directly:" # capacity_used: "Course slots used:" # enter_emails: "Enter student emails to invite, one per line" -# send_invites: "Send Invites" -# creating_class: "Creating class..." -# purchasing_course: "Purchasing course..." + send_invites: "Gửi lời mời" + creating_class: "Đang tạo lớp..." + purchasing_course: "Đang mua khóa học..." buy_course: "Mua khóa học" buy_course1: "Mua khóa học này" select_all_courses: "Lựa chọn 'Tất cả khóa học' để nhận giảm giá 50%!" @@ -1083,7 +1083,7 @@ module.exports = nativeDescription: "Tiếng Việt", englishDescription: "Vietn number_programming_students: "Số Lượng Học Viên" number_total_students: "Tổng Số Học Viên tại Trường/Quận" enter_number_students: "Hãy nhập vào số lượng học sinh bạn cần cho lớp học này." -# name_class: "Name your class" + name_class: "Đặt tên lớp của bạn" # displayed_course_page: "This will be displayed on the course page for you and your students. It can be changed later." buy: "Mua" # purchasing_for: "You are purchasing a license for" @@ -1273,25 +1273,25 @@ module.exports = nativeDescription: "Tiếng Việt", englishDescription: "Vietn # last_updated: "Last updated:" # grants_lifetime_access: "Grants access to all Courses." # enrollment_credits_available: "Enrollment Credits Available:" - description: "Miêu tả" # ClassroomSettingsModal + description: "Mô tả" # ClassroomSettingsModal language_select: "Lựa chọn một ngôn ngữ" language_cannot_change: "Không thể đổi ngôn ngữ sau khi học viên đã gia nhập lớp học." learn_p: "Học Python" learn_j: "Học JavaScript" -# avg_student_exp_label: "Average Student Programming Experience" -# avg_student_exp_desc: "This will help us understand how to pace courses better." -# avg_student_exp_select: "Select the best option" -# avg_student_exp_none: "No Experience - little to no experience" -# avg_student_exp_beginner: "Beginner - some exposure or block-based" -# avg_student_exp_intermediate: "Intermediate - some experience with typed code" -# avg_student_exp_advanced: "Advanced - extensive experience with typed code" -# avg_student_exp_varied: "Varied Levels of Experience" -# student_age_range_label: "Student Age Range" -# student_age_range_younger: "Younger than 6" -# student_age_range_older: "Older than 18" -# student_age_range_to: "to" -# create_class: "Create Class" -# class_name: "Class Name" + avg_student_exp_label: "Kinh nghiệm lập trình trung bình của học viên" + avg_student_exp_desc: "Điều này sẽ giúp chúng tôi điều chỉnh tốc độ các khóa học tốt hơn." + avg_student_exp_select: "Chọn lựa chọn đúng nhất" + avg_student_exp_none: "Không Kinh Nghiệm - ít hoặc không có kinh nghiệm" + avg_student_exp_beginner: "Mới Bắt Đầu - đã tiếp cận hoặc đã được giới thiệu" + avg_student_exp_intermediate: "Khá - có chút kinh nghiệm viết code" + avg_student_exp_advanced: "Nâng Cao - có nhiều kình nghiệm viết code" + avg_student_exp_varied: "Nhiều Trình Độ" + student_age_range_label: "Lứa tuổi học viên" + student_age_range_younger: "Nhỏ hơn 6 tuổi" + student_age_range_older: "Lớn hơn 18 tuổi" + student_age_range_to: "tới" + create_class: "Tạo Lớp" + class_name: "Tên lớp" # teacher_account_restricted: "Your account is a teacher account, and so cannot access student content." teacher: @@ -1318,7 +1318,7 @@ module.exports = nativeDescription: "Tiếng Việt", englishDescription: "Vietn # unarchive_class: "unarchive class" # no_students_yet: "This class has no students yet." add_students: "Thêm Học Viên" -# create_new_class: "Create a New Class" + create_new_class: "Tạo Lớp học mới" # class_overview: "Class Overview" # View Class page # avg_playtime: "Average level playtime" # total_playtime: "Total play time" @@ -1530,13 +1530,13 @@ module.exports = nativeDescription: "Tiếng Việt", englishDescription: "Vietn adventurer_forum_url: "diễn đàn" adventurer_join_suf: "vì vậy nếu bạn muốn liên lạc thông qua những kênh trên, hãy đăng ký ở đó!" adventurer_subscribe_desc: "Nhận email khi có màn chơi mới cần kiểm thử." -# scribe_introduction_pref: "CodeCombat isn't just going to be a bunch of levels. It will also include a resource for knowledge, a wiki of programming concepts that levels can hook into. That way rather than each Artisan having to describe in detail what a comparison operator is, they can simply link their level to the Article describing them that is already written for the player's edification. Something along the lines of what the " -# scribe_introduction_url_mozilla: "Mozilla Developer Network" -# scribe_introduction_suf: " has built. If your idea of fun is articulating the concepts of programming in Markdown form, then this class might be for you." -# scribe_attribute_1: "Skill in words is pretty much all you need. Not only grammar and spelling, but able to convey complicated ideas to others." + scribe_introduction_pref: "CodeCombat không chỉ là một đống các màn chơi. Nó cũng sẽ là một nguồn tài nguyên tri thức, một cuốn thư viện về các khái niệm lập trình, chính những thứ mà được sử dụng để xây dựng các màn chơi. Như vậy các Thợ Thủ Công không phải bỏ công giải thích đi giải thích lại những khái niệm cơ bản như toán tử là gì, họ có thể một cách đơn giản dẫn link từ các màn chơi của họ sang các bài viết dành cho người chơi. Việc này tương tự như những thứ mà " + scribe_introduction_url_mozilla: "Cộng Đồng Lập Trình Mozilla" + scribe_introduction_suf: " đã xây dựng. Nếu bạn có thể truyền tải được các tư tưởng lập trình dưới dạng Markdown, thì lớp nhân vật này có thể phù hợp với bạn." + scribe_attribute_1: "Khả năng hành văn gần như là thứ duy nhất bạn cần. Không chỉ cần ngữ pháp và đánh vần thành thạo, mà bạn còn cần khả năng truyền tải những thông điệp phức tạp tới người khác." contact_us_url: "Liên hệ với chúng tôi" -# scribe_join_description: "tell us a little about yourself, your experience with programming and what sort of things you'd like to write about. We'll go from there!" -# scribe_subscribe_desc: "Get emails about article writing announcements." + scribe_join_description: "kể cho chung tôi một chút về bạn, kinh nghiệm lập trình của bạn và bạn hứng thú viết về điều gì. Chúng ta sẽ cùng bắt đầu từ đó!" + scribe_subscribe_desc: "Nhận email về những thông tin viết bài." diplomat_introduction_pref: "Nếu như bạn hỏi chúng tôi đã nhận được gì kể từ khi " diplomat_launch_url: "bắt đầu vào tháng Mười" diplomat_introduction_suf: "thì đó chính là niềm quan tâm rất lớn với CodeCombat đến từ nhiều quốc gia trên thế giới! Chúng tôi đang xây dựng một đội ngũ phiên dịch viên đầy nhiệt huyết để đưa CodeCombat đến với mọi nơi trên thế giới. Nếu bạn muốn cập nhật những nội dung mới nhất đồng thời muốn truyền tải chúng tới quốc gia của bạn, thì lớp nhân vật này có thể sẽ phù hợp với bạn." @@ -1548,7 +1548,7 @@ module.exports = nativeDescription: "Tiếng Việt", englishDescription: "Vietn diplomat_github_url: "ở trên GitHub" diplomat_join_suf_github: ", chỉnh sửa online, và submit một pull request. Đồng thời, đánh dấu vào ô phía dưới để theo dõi những thông tin cập nhật về việc phát triển đa ngôn ngữ!" diplomat_subscribe_desc: "Nhận email về việc phát triển đa ngôn ngữ và màn chơi mới cần dịch thuật." -# ambassador_introduction: "This is a community we're building, and you are the connections. We've got forums, emails, and social networks with lots of people to talk with and help get acquainted with the game and learn from. If you want to help people get involved and have fun, and get a good feel of the pulse of CodeCombat and where we're going, then this class might be for you." + ambassador_introduction: "Đây là cộng đồng mà chúng tôi đang gây dựng, và bạn là những người kết nối. Chúng tôi có các diễn đàn, email, và các mạng xã hội với rất nhiêu người để nói chuyện và giúp đỡ làm quen và học từ game. Nếu bạn muốn giúp đỡ người khác tham gia chơi, và cùng tham gia CodeCombat trên con đường chúng tôi đang hướng đến, thì lớp nhân vật này có thể phù hợp với bạn." ambassador_attribute_1: "Kỹ năng giao tiếp. Có thể nhận định được vấn đề của người chơi đang gặp phải và giúp họ giải quyết. Đồng thời, thông báo cho chúng tôi biết ý kiến của người chơi, những gì họ thích và không thích và những điều họ mong muốn!" ambassador_join_desc: "kể cho chúng tôi một chút về bạn, bạn đã làm gì và bạn hứng thú làm gì. Chúng ta sẽ cùng bắt đầu từ đó!" ambassador_join_note_strong: "Chú thích" @@ -1564,7 +1564,7 @@ module.exports = nativeDescription: "Tiếng Việt", englishDescription: "Vietn helpful_ambassadors: "Những Sứ Giả đầy hữu ích của chúng tôi:" ladder: -# please_login: "Please log in first before playing a ladder game." + please_login: "Hãy đăng nhập để tham gia thi đấu." my_matches: "Những trận đấu của tôi" # simulate: "Simulate" # simulation_explanation: "By simulating games you can get your game ranked faster!" @@ -1574,7 +1574,7 @@ module.exports = nativeDescription: "Tiếng Việt", englishDescription: "Vietn # games_simulated_for: "Games simulated for you:" # games_in_queue: "Games currently in the queue:" # games_simulated: "Games simulated" -# games_played: "Games played" + games_played: "Các game đã chơi" ratio: "Tỷ lệ" leaderboard: "Bạng xếp hạng" # battle_as: "Battle as " @@ -1593,40 +1593,40 @@ module.exports = nativeDescription: "Tiếng Việt", englishDescription: "Vietn # code_being_simulated: "Your new code is being simulated by other players for ranking. This will refresh as new matches come in." # no_ranked_matches_pre: "No ranked matches for the " # no_ranked_matches_post: " team! Play against some competitors and then come back here to get your game ranked." -# choose_opponent: "Choose an Opponent" -# select_your_language: "Select your language!" -# tutorial_play: "Play Tutorial" + choose_opponent: "Chọn một đối thủ" + select_your_language: "Lựa chọn ngôn ngữ của bạn!" + tutorial_play: "Chạy hướng dẫn" # tutorial_recommended: "Recommended if you've never played before" # tutorial_skip: "Skip Tutorial" # tutorial_not_sure: "Not sure what's going on?" # tutorial_play_first: "Play the Tutorial first." # simple_ai: "Simple CPU" -# warmup: "Warmup" + warmup: "Khởi động" # friends_playing: "Friends Playing" -# log_in_for_friends: "Log in to play with your friends!" -# social_connect_blurb: "Connect and play against your friends!" -# invite_friends_to_battle: "Invite your friends to join you in battle!" -# fight: "Fight!" + log_in_for_friends: "Đăng nhập để chơi với bàn bè!" + social_connect_blurb: "Kết nối và chơi với bạn bè!" + invite_friends_to_battle: "Mời bạn bè tham gia thi đấu tranh tài!" + fight: "Chiến!" # watch_victory: "Watch your victory" # defeat_the: "Defeat the" -# watch_battle: "Watch the battle" + watch_battle: "Xem trận đấu" # tournament_started: ", started" -# tournament_ends: "Tournament ends" -# tournament_ended: "Tournament ended" -# tournament_rules: "Tournament Rules" + tournament_ends: "Giải đấu kết thúc" + tournament_ended: "Giải đấu đã kết thúc" + tournament_rules: "Luật lệ giải đấu" # tournament_blurb: "Write code, collect gold, build armies, crush foes, win prizes, and upgrade your career in our $40,000 Greed tournament! Check out the details" # tournament_blurb_criss_cross: "Win bids, construct paths, outwit opponents, grab gems, and upgrade your career in our Criss-Cross tournament! Check out the details" # tournament_blurb_zero_sum: "Unleash your coding creativity in both gold gathering and battle tactics in this alpine mirror match between red sorcerer and blue sorcerer. The tournament began on Friday, March 27 and will run until Monday, April 6 at 5PM PDT. Compete for fun and glory! Check out the details" # tournament_blurb_ace_of_coders: "Battle it out in the frozen glacier in this domination-style mirror match! The tournament began on Wednesday, September 16 and will run until Wednesday, October 14 at 5PM PDT. Check out the details" # tournament_blurb_blog: "on our blog" rules: "Những điều lệ" -# winners: "Winners" + winners: "Những người thắng cuộc" # league: "League" -# red_ai: "Red CPU" # "Red AI Wins", at end of multiplayer match playback -# blue_ai: "Blue CPU" -# wins: "Wins" # At end of multiplayer match playback -# humans: "Red" # Ladder page display team name -# ogres: "Blue" + red_ai: "CPU Đỏ" # "Red AI Wins", at end of multiplayer match playback + blue_ai: "CPU Xanh" + wins: "Những chiến thắng" # At end of multiplayer match playback + humans: "Đỏ" # Ladder page display team name + ogres: "Xanh" user: stats: "Chỉ số" @@ -1660,7 +1660,7 @@ module.exports = nativeDescription: "Tiếng Việt", englishDescription: "Vietn payments: "Thanh Toán" prepaid_codes: "Mã Trả Trước" purchased: "Đã Thanh Toán" - subscription: "Subscription" + subscription: "Dịch vụ nâng cao" invoices: "Hóa Đơn" service_apple: "Apple" service_web: "Web" @@ -1722,16 +1722,16 @@ module.exports = nativeDescription: "Tiếng Việt", englishDescription: "Vietn login_required: "Yêu cầu đăng nhập" login_required_desc: "Bạn cần đăng nhập để truy cập trang này." unauthorized: "Bạn cần đăng nhập. Bạn có vô hiệu hóa cookie không?" -# forbidden: "Forbidden" + forbidden: "Cấm" forbidden_desc: "Ôi không, không có gì ở đây cả! Hãy đảm bảo rằng bạn đăng nhập đúng tài khoản, hoặc truy cập trong số những đường link phía dưới để quay lại tiếp tục lập trình!" not_found: "Không tìm thấy" not_found_desc: "Hm, chả có gì ở đây cả. Truy cập một trong số những đường link phía dưới để quay lại tiếp tục lập trình!" -# not_allowed: "Method not allowed." -# timeout: "Server Timeout" + not_allowed: "Phương thức không được phép." + timeout: "Máy chủ timeout" conflict: "Xung đột tài nguyên." bad_input: "Lỗi đầu vào." server_error: "Lỗi server." -# unknown: "Unknown Error" + unknown: "Lỗi không xác định" error: "LỖI" general_desc: "Có lỗi xảy ra, và có thể là lỗi do chúng tôi. Hãy cố đợi một lát và tải lại trang, hoặc truy cập một trong số những đường link phía dưới để quay lại tiếp tục lập trình!" @@ -1753,7 +1753,7 @@ module.exports = nativeDescription: "Tiếng Việt", englishDescription: "Vietn arithmetic: "Toán tử" arrays: "Mảng" basic_syntax: "Cú pháp cơ bản" -# boolean_logic: "Boolean Logic" + boolean_logic: "Luận lý Boolean" break_statements: "Câu lệnh Break" classes: "Lớp" continue_statements: "Câu lệnh Continue" @@ -1766,7 +1766,7 @@ module.exports = nativeDescription: "Tiếng Việt", englishDescription: "Vietn # object_literals: "Object Literals" parameters: "Tham số" strings: "Chuỗi" - variables: "Biến" + variables: "Biến số" vectors: "Các Vector" while_loops: "Vòng lặp While" recursion: "Đệ quy" From bf537aa3a02b4ec66d858d64d5a49ee57a7da677 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dong=E6=AE=BA=E5=B8=83=E6=B2=99?= Date: Fri, 20 May 2016 02:58:45 +0800 Subject: [PATCH 19/24] Zh hant (#3664) * Update zh-HANT.coffee * Update zh-HANT.coffee * Update zh-HANT.coffee * Update zh-HANT.coffee * Update zh-HANT.coffee * Update zh-HANT.coffee --- app/locale/zh-HANT.coffee | 134 +++++++++++++++++++------------------- 1 file changed, 67 insertions(+), 67 deletions(-) diff --git a/app/locale/zh-HANT.coffee b/app/locale/zh-HANT.coffee index 66b67eb85..62d408037 100644 --- a/app/locale/zh-HANT.coffee +++ b/app/locale/zh-HANT.coffee @@ -25,7 +25,7 @@ module.exports = nativeDescription: "繁體中文", englishDescription: "Chinese im_a_student: "我是學生"#"I'm a Student" learn_more: "了解更多"#"Learn more" classroom_in_a_box: "在一個盒子中的電腦科學教室。"#"A classroom in-a-box for teaching computer science." - codecombat_is: "CodeCombat是一個給學生透過進行遊戲來學習電腦科學的平台。" #"CodeCombat is a platform for students to learn computer science while playing through a real game." + codecombat_is: "CodeCombat是一個讓學生透過進行遊戲來學習電腦科學的平台。" #"CodeCombat is a platform for students to learn computer science while playing through a real game." our_courses: "我們的課程經過特別的遊戲測試來超越教室教學,甚至是超越一些先前沒有編程經驗的老師。" #"Our courses have been specifically playtested to excel in the classroom, even by teachers with little to no prior programming experience." top_screenshots_hint: "學生們寫程式碼並且隨時觀看他們的更新。" #"Students write code and see their changes update in real-time" designed_with: "在心中與老師們一起設計"#"Designed with teachers in mind" @@ -37,31 +37,31 @@ module.exports = nativeDescription: "繁體中文", englishDescription: "Chinese teaching_computer_science: "教電腦科學不需要一個昂貴的學位,因為我們提供了工具來支援各種背景的教學者。" #"Teaching computer science does not require a costly degree, because we provide tools to support educators of all backgrounds." accessible_to: "提供給" everyone: "每一個人" - democratizing: "使學習寫程式碼的過程民主化是我們的核心理念,每個人都應該有機會學習寫程式。" #"Democratizing the process of learning coding is at the core of our philosophy. Everyone should be able to learn to code." + democratizing: "使學習寫程式碼的過程普及化是我們的核心理念,每個人都應該有機會學習寫程式。" #"Democratizing the process of learning coding is at the core of our philosophy. Everyone should be able to learn to code." forgot_learning: "我認為他們甚至忘記了他們正在學東西。" #"I think they actually forgot that they were actually learning something." wanted_to_do: "寫程式一直是我想要做的事情,而我從不認為我會在學校裡學到它們。" #" Coding is something I've always wanted to do, and I never thought I would be able to learn it in school." why_games: "為何從遊戲中學習是很重要的呢?" #"Why is learning through games important?" games_reward: "遊戲鼓勵我們良性競爭。"#"Games reward the productive struggle." - encourage: "遊戲是一個促進互動、發現及嘗試錯誤的媒介,一款好的遊戲可以試煉玩家並隨著時間精進技巧,這個過程與學生在學習中的經歷是同等重要的。" #"Gaming is a medium that encourages interaction, discovery, and trial-and-error. A good game challenges the player to master skills over time, which is the same critical process students go through as they learn." + encourage: "遊戲是一個促進互動、發現及嘗試錯誤的媒介,一款好的遊戲可以試煉玩家並隨著時間精進技巧,這個過程與學生在學校學習中所經歷到的一樣重要。" #"Gaming is a medium that encourages interaction, discovery, and trial-and-error. A good game challenges the player to master skills over time, which is the same critical process students go through as they learn." excel: "遊戲在獎勵方面勝出" #"Games excel at rewarding" struggle: "良性競爭"#"productive struggle" - kind_of_struggle: "那種競爭使學習是引人入勝的,並且"#"the kind of struggle that results in learning that’s engaging and" + kind_of_struggle: "那種競爭使學習引人入勝,並且"#"the kind of struggle that results in learning that’s engaging and" motivating: "有動力"#"motivating" - not_tedious: "不乏味"#"not tedious." + not_tedious: "不乏味。"#"not tedious." gaming_is_good: "研究指出玩遊戲對小孩的大腦是有幫助的。(這是真的!)"#"Studies suggest gaming is good for children’s brains. (it’s true!)" game_based: "在基於遊戲的學習系統中這是"#"When game-based learning systems are" - compared: "相符的" - conventional: "相較於傳統評定方式的差異很明顯,「遊戲在保存知識和保持專注上是有幫助的」。" #"against conventional assessment methods, the difference is clear: games are better at helping students retain knowledge, concentrate and" - perform_at_higher_level: "表現更高的成就水平"#"perform at a higher level of achievement" + compared: "相符的。" + conventional: "與傳統評定方式比較有很明顯的不同,「遊戲在保存知識和保持專注上是有幫助的」。" #"against conventional assessment methods, the difference is clear: games are better at helping students retain knowledge, concentrate and" + perform_at_higher_level: "展現更高的成就水平"#"perform at a higher level of achievement" feedback: "遊戲中也提供了及時回饋,讓學生去調整他們的解決途徑,並且更完整的了解學習內容,而不是被解答的正確或是不正確限制住。" #"Games also provide real-time feedback that allows students to adjust their solution path and understand concepts more holistically, instead of being limited to just “correct” or “incorrect” answers." real_game: "這是一個真正的遊戲,利用真正寫入程式碼來遊玩。"#"A real game, played with real coding." - great_game: "一個很棒的遊戲不只有徽章和成就--它更是玩家的旅程、設計優良的關卡,以及藉由幫助和信心完成挑戰的能力。" # "A great game is more than just badges and achievements - it’s about a player’s journey, well-designed puzzles, and the ability to tackle challenges with agency and confidence." + great_game: "一個很棒的遊戲不只有徽章和成就--它更是玩家的旅程、設計優良的關卡,以及藉由信心和幫助完成挑戰的能力。" # "A great game is more than just badges and achievements - it’s about a player’s journey, well-designed puzzles, and the ability to tackle challenges with agency and confidence." agency: "CodeCombat是一個能給予玩家協助以及信心的遊戲,藉由我們強大的程式碼鍵入引擎,可以幫助新手或是進階的學生寫出正確的、有效的程式碼。" #"CodeCombat is a game that gives players that agency and confidence with our robust typed code engine, which helps beginner and advanced students alike write proper, valid code." request_demo_title: "讓您的學生從今天開始遊玩吧!"#"Get your students started today!" - request_demo_subtitle: "要求一個demo示範版本,並且讓您的學生在一個小時之內就能上手。"#"Request a demo and get your students started in less than an hour." + request_demo_subtitle: "申請一個demo示範版本,並且讓您的學生在一個小時之內就能上手。"#"Request a demo and get your students started in less than an hour." get_started_title: "現在就設立您的班級。"#"Set up your class today" get_started_subtitle: "設立一個班級、加入您的學生,並在他們學習電腦科學的過程中掌握他們的進度。"#"Set up a class, add your students, and monitor their progress as they learn computer science." - request_demo: "要求一個demo示範版本"#"Request a Demo" + request_demo: "申請一個demo示範版本"#"Request a Demo" setup_a_class: "設立一個班級"#"Set Up a Class" have_an_account: "您是否擁有一個帳號?"#"Have an account?" logged_in_as: "您現在登入的身分為"#"You are currently logged in as" @@ -69,7 +69,7 @@ module.exports = nativeDescription: "繁體中文", englishDescription: "Chinese computer_science: "全年齡向的電腦科學課程"#"Computer science courses for all ages" show_me_lesson_time: "顯示課程預估時間:"#"Show me lesson time estimates for:" curriculum: "課程總共時數:"#"Total curriculum hours:" - ffa: "對所有學生都是免費的"#"Free for all students" + ffa: "學生免費"#"Free for all students" lesson_time: "課程時間:"#"Lesson time:" coming_soon: "敬請期待!"#"Coming soon!" courses_available_in: "包含JavaScript, Python,和Java的課程(敬請期待!)"#"Courses are available in JavaScript, Python, and Java (coming soon!)" @@ -107,7 +107,7 @@ module.exports = nativeDescription: "繁體中文", englishDescription: "Chinese stats: "記錄" code: "程式碼" home: "首頁" - contribute: "貢獻" + contribute: "幫助我們" legal: "版權聲明" about: "關於" contact: "聯繫我們" @@ -124,9 +124,9 @@ module.exports = nativeDescription: "繁體中文", englishDescription: "Chinese jobs: "工作" schools: "學校" educator_wiki: "教育者 Wiki" - get_involved: "參與其中" + get_involved: "親身參與" open_source: "開源 (GitHub)" - support: "支援" + support: "取得幫助" faqs: "FAQs常見問題" help_pref: "需要協助嗎? 寫封Email給我們" help_suff: "然後我們會與您接觸!" @@ -139,7 +139,7 @@ module.exports = nativeDescription: "繁體中文", englishDescription: "Chinese page_not_found: "找不到網頁" diplomat_suggestion: - title: "幫我們翻譯CodeCombat" # This shows up when a player switches to a non-English language using the language selector. + title: "幫助我們翻譯CodeCombat" # This shows up when a player switches to a non-English language using the language selector. sub_heading: "我們需要您的語言技能" pitch_body: "我們開發了CodeCombat的英文版,但是現在我們的玩家遍佈全球。很多人想玩中文版的,卻不會說英文,所以如果您中英文都會,請考慮一下參加我們的翻譯工作,幫忙把 CodeCombat 網站還有所有的關卡翻譯成中文(繁體)。" missing_translations: "直至所有正體中文的翻譯完畢,當無法提供正體中文時還會以英文顯示。" @@ -168,7 +168,7 @@ module.exports = nativeDescription: "繁體中文", englishDescription: "Chinese next: "下一步" # Go from choose hero to choose inventory before playing a level change_hero: "更換英雄" # Go back from choose inventory to choose hero buy_gems: "購買寶石" - subscription_required: "需要訂購" + subscription_required: "訂閱限定" anonymous: "匿名玩家" level_difficulty: "難度" play_classroom_version: "遊玩教室版本" # Choose a level in campaign version that you also can play in one of your courses @@ -179,7 +179,7 @@ module.exports = nativeDescription: "繁體中文", englishDescription: "Chinese adjust_volume: "調整音量" campaign_multiplayer: "多人競技場" campaign_multiplayer_description: "…在這裡您可以和其他玩家進行對戰。" - campaign_old_multiplayer: "(過時的)舊多人競技場" + campaign_old_multiplayer: "(過時的)舊的多人競技場" campaign_old_multiplayer_description: "多個文明時代的遺跡。已沒有模擬運行這些陳舊、英雄蕪絕的多人競技場。" code: @@ -387,7 +387,7 @@ module.exports = nativeDescription: "繁體中文", englishDescription: "Chinese done: "完成" next_level: "下一個關卡:" next_game: "下一個遊戲" - show_menu: "顯示遊戲菜單" + show_menu: "顯示遊戲選單" home: "首頁" # Not used any more, will be removed soon. level: "關卡" # Like "Level: Dungeons of Kithgard" skip: "跳過" @@ -425,11 +425,11 @@ module.exports = nativeDescription: "繁體中文", englishDescription: "Chinese victory_new_item: "新的物品" victory_viking_code_school: "太厲害了,您剛完成了非常困難的關卡!如果您想成為一個軟體開發人員,您就應該去試一下Viking Code School。在這裡您可以把您的知識增長到另一個台階。只需要14個星期您就能成為一個專業的網頁開發人員。" victory_become_a_viking: "成為一個維京人。" - victory_no_progress_for_teachers: "老師不能保存進度,但是您可以將自己的帳號加入班級作為學生來保存進度。" #"Progress is not saved for teachers. But, you can add a student account to your classroom for yourself." + victory_no_progress_for_teachers: "老師們不能保存進度,但是您可以將自己的帳號加入班級作為學生來保存進度。" #"Progress is not saved for teachers. But, you can add a student account to your classroom for yourself." guide_title: "指南" - tome_cast_button_run: "運作" - tome_cast_button_running: "運作中" - tome_cast_button_ran: "已運作" + tome_cast_button_run: "運行" + tome_cast_button_running: "運行中" + tome_cast_button_ran: "已運行" tome_submit_button: "送出" tome_reload_method: "重新載入該方法的原程式碼" # Title text for individual method reload button. tome_select_method: "選擇一個方法" @@ -522,7 +522,7 @@ module.exports = nativeDescription: "繁體中文", englishDescription: "Chinese tip_mulan: "相信你可以做到,然後你就會做到。 - Mulan"#"Believe you can, then you will. - Mulan" game_menu: - inventory_tab: "倉庫" + inventory_tab: "道具欄" save_load_tab: "保存/載入" options_tab: "選項" guide_tab: "導引" @@ -546,16 +546,16 @@ module.exports = nativeDescription: "繁體中文", englishDescription: "Chinese week: "這週" all: "長期以來" time: "時間" - damage_taken: "遭受的攻擊" - damage_dealt: "造成的攻擊" + damage_taken: "遭受的傷害" + damage_dealt: "造成的傷害" difficulty: "困難度" gold_collected: "收集的黃金" inventory: equipped_item: "已裝備" - required_purchase_title: "需要" - available_item: "可使用" - restricted_title: "被限制" + required_purchase_title: "必要的" + available_item: "可使用的" + restricted_title: "被限制的" should_equip: "連點物品兩下可裝備" equipped: "(已裝備)" locked: "(需解鎖)" @@ -578,12 +578,12 @@ module.exports = nativeDescription: "繁體中文", englishDescription: "Chinese subscribe: comparison_blurb: "訂閱 CodeCombat 來磨練您的技巧!" - feature1: "__levelsCount__ 個以上的基本關卡分散在__worldsCount__張地圖中" # {change} + feature1: "__levelsCount__ 個以上的基本關卡分佈在__worldsCount__張地圖中" # {change} feature2: "__heroesCount__ 個強力的新英雄並且每位都有不同技能!" # {change} feature3: "__bonusLevelsCount__ 個以上的額外關卡" # {change} feature4: "每個月{{gems}}顆額外寶石!" feature5: "影片教學" - feature6: "頂級信箱支援" + feature6: "高級郵件幫助" feature7: "私密部落" feature8: "沒有廣告!" free: "免費" @@ -744,7 +744,7 @@ module.exports = nativeDescription: "繁體中文", englishDescription: "Chinese scott_title: "共同創辦人" # {change} scott_blurb: "理性至上" # maka_title: "Customer Advocate" -# maka_blurb: "Storyteller" + maka_blurb: "說書人" rob_title: "編譯工程師" # {change} rob_blurb: "編寫一些的程式碼" josh_c_title: "遊戲設計師" @@ -1184,9 +1184,9 @@ module.exports = nativeDescription: "繁體中文", englishDescription: "Chinese # last_level: "Last Level" # welcome_to_hoc: "Adventurers, welcome to our Hour of Code!" # logged_in_as: "Logged in as:" -# not_you: "Not you?" + not_you: "不是您嗎?"#"Not you?" # welcome_back: "Hi adventurer, welcome back!" -# continue_playing: "Continue Playing" + continue_playing: "繼續進行遊戲"#"Continue Playing" # more_options: "More options:" # option1_header: "Option 1: Invite students via email" # option1_body: "Students will automatically be sent an invitation to join this class, and will need to create an account with a username and password." @@ -1223,7 +1223,7 @@ module.exports = nativeDescription: "繁體中文", englishDescription: "Chinese # class_code: "Class Code" # optional_ask: "optional - ask your teacher to give you one!" # optional_school: "optional - what school do you go to?" -# start_playing: "Start Playing" + start_playing: "開始遊戲"#"Start Playing" # skip_this: "Skip this, I'll create an account later!" # welcome: "Welcome" # getting_started: "Getting Started with Courses" @@ -1398,7 +1398,7 @@ module.exports = nativeDescription: "繁體中文", englishDescription: "Chinese ambassador_title: "使節" ambassador_title_description: "(Support)" ambassador_summary: "安撫我們論壇的用戶並且提供發問者適當的方向。我們的使節代表CodeCombat面對全世界。" -# teacher_title: "Teacher" + teacher_title: "教師"#"Teacher" editor: main_title: "CodeCombat編輯器" @@ -1407,7 +1407,7 @@ module.exports = nativeDescription: "繁體中文", englishDescription: "Chinese level_title: "關卡編輯器" achievement_title: "目標編輯器" poll_title: "投票編輯器" - back: "後退" + back: "返回" revert: "還原" revert_models: "還原模式" pick_a_terrain: "選擇地形" @@ -1511,7 +1511,7 @@ module.exports = nativeDescription: "繁體中文", englishDescription: "Chinese join_desc_3: ",或者找到我們在" join_desc_4: "讓我們從這開始!" join_url_email: "發信給我們" -# join_url_slack: "public Slack channel" + join_url_slack: "公共休閒頻道"#"public Slack channel" archmage_subscribe_desc: "取得郵件關於新的編程機會和公告。" artisan_introduction_pref: "我們必須建造更多的關卡!大家為了更多的內容在高聲吶喊,但只靠我們只能建造這麼多。現在您的工作場所就是一關;我們的關卡編輯器是勉強可用的,所以請小心。只要您有新的靈感,不論從簡單的 for-loops 到" artisan_introduction_suf: ",那個這職業會適合您。" @@ -1555,7 +1555,7 @@ module.exports = nativeDescription: "繁體中文", englishDescription: "Chinese ambassador_join_note_strong: "注意" ambassador_join_note_desc: "其中一件我們優先要做的事情是建立多人連線,玩家將面臨難以獨自解決的關卡而且可以招喚更高等級的法師來幫助。這將對於使節是一個很棒的方式來完成自己的責任。我們會及時地向大家公佈!" ambassador_subscribe_desc: "取得更新和多人連線開發的郵件。" -# teacher_subscribe_desc: "Get emails on updates and announcements for teachers." + teacher_subscribe_desc: "取得給教師的更新以及消息。"#"Get emails on updates and announcements for teachers." changes_auto_save: "當您勾選後,改變將自動儲存。" diligent_scribes: "我們勤奮的文書:" powerful_archmages: "我們強勁的大法師:" @@ -1565,11 +1565,11 @@ module.exports = nativeDescription: "繁體中文", englishDescription: "Chinese helpful_ambassadors: "我們善於幫助的使節:" ladder: - please_login: "在參與對弈前請先登入。" + please_login: "在參與對戰前請先登入。" my_matches: "我的對手" simulate: "模擬" simulation_explanation: "通過模擬遊戲,您可以使您的遊戲更快得到評分!" - simulation_explanation_leagues: "你會主要給在你的部落或者課程的同伴幫忙模擬遊戲。" + simulation_explanation_leagues: "你主要會為你的部落或者課程的同伴幫忙模擬遊戲。" simulate_games: "模擬遊戲!" games_simulated_by: "您模擬過的次數:" games_simulated_for: "替您模擬的次數:" @@ -1590,14 +1590,14 @@ module.exports = nativeDescription: "繁體中文", englishDescription: "Chinese rank_failed: "評分失敗" rank_being_ranked: "已評分" rank_last_submitted: "已上傳 " - help_simulate: "模擬遊戲需要幫助?" + help_simulate: "幫我們模擬遊戲?" code_being_simulated: "您的新程式碼正在被其他人模擬評分中。分數將隨每次新的配對而更新。" no_ranked_matches_pre: "對這個隊伍尚未有評分過的配對!" - no_ranked_matches_post: " 在別人的戰場上扮演競爭者並且回到這使您的程式碼接受評分。" + no_ranked_matches_post: " 在別人的戰場上扮演對手並且回到這使您的程式碼接受評分。" choose_opponent: "選擇對手" select_your_language: "選擇您的語言!" tutorial_play: "教學" - tutorial_recommended: "如果您尚未玩過,推薦先嘗試教學" + tutorial_recommended: "如果您尚未玩過,建議先嘗試教學" tutorial_skip: "略過教學" tutorial_not_sure: "不確定發生啥事?" tutorial_play_first: "先嘗試教學" @@ -1650,11 +1650,11 @@ module.exports = nativeDescription: "繁體中文", englishDescription: "Chinese amount_achieved: "數量" achievement: "成就" current_xp_prefix: "當前總共" - current_xp_postfix: "經驗" + current_xp_postfix: "經驗值" new_xp_prefix: "獲得" - new_xp_postfix: "經驗" + new_xp_postfix: "經驗值" left_xp_prefix: "還需要" - left_xp_infix: "經驗" + left_xp_infix: "經驗值" left_xp_postfix: "到下一個等級" account: @@ -1694,13 +1694,13 @@ module.exports = nativeDescription: "繁體中文", englishDescription: "Chinese # purchase_code1: "Subscription Codes can be redeemed to add premium subscription time to one or more CodeCombat accounts." # purchase_code2: "Each CodeCombat account can only redeem a particular Subscription Code once." # purchase_code3: "Subscription Code months will be added to the end of any existing subscription on the account." -# users: "Users" -# months: "Months" + users: "使用者"#"Users" + months: "月數"#"Months" purchase_total: "總共" purchase_button: "提交購買" your_codes: "你的訂閱碼:" # {change} redeem_codes: "兌換訂閱碼" -# prepaid_code: "Prepaid Code" + prepaid_code: "預付代碼"#"Prepaid Code" # lookup_code: "Lookup prepaid code" # apply_account: "Apply to your account" # copy_link: "You can copy the code's link and send it to someone." @@ -1847,7 +1847,7 @@ module.exports = nativeDescription: "繁體中文", englishDescription: "Chinese nutshell_description: "我們在關卡編輯器裡公開的任何資源,您都可以在製作關卡時隨意使用,但我們保留在 codecombat.com 之上創建的關卡本身傳播的權利,因為我們往後可能決定以它們收費。" canonical: "我們宣告這篇說明的英文版本是權威版本。如果各個翻譯版本之間有任何衝突,以英文版為準。" third_party_title: "第三方服務" -# third_party_description: "CodeCombat uses the following third party services (among others):" + third_party_description: "CodeCombat使用下列的第三方服務"#"CodeCombat uses the following third party services (among others):" ladder_prizes: title: "錦標賽獎項" # This section was for an old tournament and doesn't need new translations now. @@ -1869,19 +1869,19 @@ module.exports = nativeDescription: "繁體中文", englishDescription: "Chinese license: "許可證" oreilly: "您選擇的電子書" -# calendar: -# year: "Year" -# day: "Day" -# month: "Month" -# january: "January" -# february: "February" -# march: "March" -# april: "April" -# may: "May" -# june: "June" -# july: "July" -# august: "August" -# september: "September" -# october: "October" -# november: "November" -# december: "December" + calendar: + year: "年"#"Year" + day: "日"#"Day" + month: "月"#"Month" + january: "一月"#"January" + february: "二月"#"February" + march: "三月"#"March" + april: "四月"#"April" + may: "五月"#"May" + june: "六月"#"June" + july: "七月"#"July" + august: "八月"#"August" + september: "九月"#"September" + october: "十月"#"October" + november: "十一月"#"November" + december: "十二月"#"December" From 1ae2537591e5eb58d7a9468db4ec81cb238844d7 Mon Sep 17 00:00:00 2001 From: Matt Lott Date: Thu, 19 May 2016 14:07:58 -0700 Subject: [PATCH 20/24] Update inbound lead importing Send international emails to international leads Update lead assignment breakdown --- package.json | 1 + scripts/followupCloseIoLeads.js | 13 ++--- scripts/updateCloseIoLeads.js | 85 ++++++++++++++++++++++++--------- 3 files changed, 67 insertions(+), 32 deletions(-) diff --git a/package.json b/package.json index 82f4419b6..79a4fb3ab 100644 --- a/package.json +++ b/package.json @@ -100,6 +100,7 @@ "coffeelint-brunch": "^1.7.1", "commonjs-require-definition": "0.2.0", "compressible": "~1.0.1", + "country-list": "0.0.3", "css-brunch": "^1.7.0", "fs-extra": "^0.26.2", "http-proxy": "^1.13.2", diff --git a/scripts/followupCloseIoLeads.js b/scripts/followupCloseIoLeads.js index b6abbebe8..bc8096dc0 100644 --- a/scripts/followupCloseIoLeads.js +++ b/scripts/followupCloseIoLeads.js @@ -1,8 +1,8 @@ // Follow up on Close.io leads 'use strict'; -if (process.argv.length !== 6) { - log("Usage: node