Merge branch 'master' of https://github.com/codecombat/codecombat
Conflicts: server/queues/scoring.coffee
BIN
app/assets/images/pages/play/ladder/prize_aws.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
app/assets/images/pages/play/ladder/prize_cash1.png
Normal file
After Width: | Height: | Size: 3.9 KiB |
BIN
app/assets/images/pages/play/ladder/prize_cash2.png
Normal file
After Width: | Height: | Size: 3.7 KiB |
BIN
app/assets/images/pages/play/ladder/prize_cash3.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
app/assets/images/pages/play/ladder/prize_custom_avatar.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
app/assets/images/pages/play/ladder/prize_custom_wizard.png
Normal file
After Width: | Height: | Size: 4.9 KiB |
BIN
app/assets/images/pages/play/ladder/prize_digital_ocean.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
app/assets/images/pages/play/ladder/prize_firebase.png
Normal file
After Width: | Height: | Size: 4 KiB |
BIN
app/assets/images/pages/play/ladder/prize_heap.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
app/assets/images/pages/play/ladder/prize_one_month.png
Normal file
After Width: | Height: | Size: 3.7 KiB |
BIN
app/assets/images/pages/play/ladder/prize_oreilly.png
Normal file
After Width: | Height: | Size: 3.1 KiB |
BIN
app/assets/images/pages/play/ladder/prize_webstorm.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
|
@ -135,6 +135,7 @@ module.exports = class LevelLoader extends CocoClass
|
|||
onWorldNecessitiesLoaded: =>
|
||||
@initWorld()
|
||||
@supermodel.clearMaxProgress()
|
||||
@trigger 'world-necessities-loaded'
|
||||
return if @headless and not @editorMode
|
||||
thangsToLoad = _.uniq( (t.spriteName for t in @world.thangs when t.exists) )
|
||||
nameModelTuples = ([thangType.get('name'), thangType] for thangType in @thangNames.models)
|
||||
|
|
|
@ -37,12 +37,16 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
|
|||
possessed: false
|
||||
flipped: false
|
||||
flippedCount: 0
|
||||
originalScaleX: null
|
||||
originalScaleY: null
|
||||
actionQueue: null
|
||||
actions: null
|
||||
rotation: 0
|
||||
|
||||
# Scale numbers
|
||||
baseScaleX: 1 # scale + flip (for current action) / resolutionFactor.
|
||||
baseScaleY: 1 # These numbers rarely change, so keep them around.
|
||||
scaleFactor: 1 # Current scale adjustment. This can change rapidly.
|
||||
targetScaleFactor: 1 # What the scaleFactor is going toward during a tween.
|
||||
|
||||
# ACTION STATE
|
||||
# Actions have relations. If you say 'move', 'move_side' may play because of a direction
|
||||
# relationship, and if you say 'cast', 'cast_begin' may happen first, or 'cast_end' after.
|
||||
|
@ -71,7 +75,6 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
|
|||
@ranges = []
|
||||
@handledDisplayEvents = {}
|
||||
@age = 0
|
||||
@scaleFactor = @targetScaleFactor = 1
|
||||
if @thangType.isFullyLoaded()
|
||||
@setupSprite()
|
||||
else
|
||||
|
@ -94,6 +97,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
|
|||
|
||||
finishSetup: ->
|
||||
return unless @thang
|
||||
@updateBaseScale()
|
||||
@update true # Reflect initial scale and other state
|
||||
|
||||
setUpRasterImage: ->
|
||||
|
@ -102,8 +106,6 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
|
|||
@setImageObject image
|
||||
$(image.image).one 'load', => @updateScale?()
|
||||
@configureMouse()
|
||||
@originalScaleX = image.scaleX
|
||||
@originalScaleY = image.scaleY
|
||||
@imageObject.sprite = @
|
||||
@imageObject.layerPriority = @thangType.get 'layerPriority'
|
||||
@imageObject.name = @thang?.spriteName or @thangType.get 'name'
|
||||
|
@ -112,14 +114,6 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
|
|||
@imageObject.regY = -reg.y
|
||||
@finishSetup()
|
||||
|
||||
destroy: ->
|
||||
mark.destroy() for name, mark of @marks
|
||||
label.destroy() for name, label of @labels
|
||||
p.removeChild @healthBar if p = @healthBar?.parent
|
||||
@imageObject?.off 'animationend', @playNextAction
|
||||
clearInterval @effectInterval if @effectInterval
|
||||
super()
|
||||
|
||||
toString: -> "<CocoSprite: #{@thang?.id}>"
|
||||
|
||||
buildSpriteSheet: ->
|
||||
|
@ -139,17 +133,11 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
|
|||
sprite = new createjs.Sprite(spriteSheet)
|
||||
else
|
||||
sprite = new createjs.Shape()
|
||||
sprite.scaleX = sprite.scaleY = 1 / @options.resolutionFactor
|
||||
# temp, until these are re-exported with perspective
|
||||
if @options.camera and @thangType.get('name') in ['Dungeon Floor', 'Indoor Floor', 'Grass', 'Goal Trigger', 'Obstacle']
|
||||
sprite.scaleY *= @options.camera.y2x
|
||||
|
||||
@setImageObject sprite
|
||||
@addHealthBar()
|
||||
@configureMouse()
|
||||
# TODO: generalize this later?
|
||||
@originalScaleX = sprite.scaleX
|
||||
@originalScaleY = sprite.scaleY
|
||||
@imageObject.sprite = @
|
||||
@imageObject.layerPriority = @thangType.get 'layerPriority'
|
||||
@imageObject.name = @thang?.spriteName or @thangType.get 'name'
|
||||
|
@ -183,6 +171,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
|
|||
@currentAction = action
|
||||
return @hide() unless action.animation or action.container or action.relatedActions
|
||||
@show()
|
||||
@updateBaseScale()
|
||||
return @updateActionDirection() unless action.animation or action.container
|
||||
m = if action.container then "gotoAndStop" else "gotoAndPlay"
|
||||
@imageObject.framerate = action.framerate or 20
|
||||
|
@ -307,6 +296,18 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
|
|||
[@imageObject.x, @imageObject.y] = [sup.x, sup.y]
|
||||
@lastPos = p1.copy?() or _.clone(p1)
|
||||
@hasMoved = true
|
||||
|
||||
updateBaseScale: ->
|
||||
scale = 1
|
||||
scale = @thangType.get('scale') or 1 if @isRaster
|
||||
scale /= @options.resolutionFactor unless @isRaster
|
||||
@baseScaleX = @baseScaleY = scale
|
||||
@baseScaleX *= -1 if @getActionProp 'flipX'
|
||||
@baseScaleY *= -1 if @getActionProp 'flipY'
|
||||
# temp, until these are re-exported with perspective
|
||||
floors = ['Dungeon Floor', 'Indoor Floor', 'Grass', 'Goal Trigger', 'Obstacle']
|
||||
if @options.camera and @thangType.get('name') in floors
|
||||
@baseScaleY *= @options.camera.y2x
|
||||
|
||||
updateScale: ->
|
||||
return unless @imageObject
|
||||
|
@ -326,8 +327,9 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
|
|||
@imageObject.scaleY *= @thangType.get('scale') ? 1
|
||||
[@lastThangWidth, @lastThangHeight] = [@thang.width, @thang.height]
|
||||
return
|
||||
scaleX = if @getActionProp 'flipX' then -1 else 1
|
||||
scaleY = if @getActionProp 'flipY' then -1 else 1
|
||||
|
||||
scaleX = scaleY = 1
|
||||
|
||||
if @thangType.get('name') in ['Arrow', 'Spear']
|
||||
# Scales the arrow so it appears longer when flying parallel to horizon.
|
||||
# To do that, we convert angle to [0, 90] (mirroring half-planes twice), then make linear function out of it:
|
||||
|
@ -342,18 +344,12 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
|
|||
angle = 180 - angle if angle > 90
|
||||
scaleX = 0.5 + 0.5 * (90 - angle) / 90
|
||||
|
||||
if @isRaster # scale is worked into building the sprite sheet for animations
|
||||
scale = @thangType.get('scale') or 1
|
||||
scaleX *= scale
|
||||
scaleY *= scale
|
||||
# console.error "No thang for", @ unless @thang
|
||||
# TODO: support using scaleFactorX/Y from the thang object
|
||||
@imageObject.scaleX = @baseScaleX * @scaleFactor * scaleX
|
||||
@imageObject.scaleY = @baseScaleY * @scaleFactor * scaleY
|
||||
|
||||
console.error "No thang for", @ unless @thang
|
||||
scaleFactorX = @thang.scaleFactorX ? @scaleFactor
|
||||
scaleFactorY = @thang.scaleFactorY ? @scaleFactor
|
||||
@imageObject.scaleX = @originalScaleX * scaleX * scaleFactorX
|
||||
@imageObject.scaleY = @originalScaleY * scaleY * scaleFactorY
|
||||
|
||||
if (@thang.scaleFactor or 1) isnt @targetScaleFactor
|
||||
if @thang and (@thang.scaleFactor or 1) isnt @targetScaleFactor
|
||||
createjs.Tween.removeTweens(@)
|
||||
createjs.Tween.get(@).to({scaleFactor:@thang.scaleFactor or 1}, 2000, createjs.Ease.elasticOut)
|
||||
@targetScaleFactor = @thang.scaleFactor or 1
|
||||
|
@ -783,3 +779,11 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
|
|||
return unless @healthBar
|
||||
@healthBar.x = @imageObject.x
|
||||
@healthBar.y = @imageObject.y
|
||||
|
||||
destroy: ->
|
||||
mark.destroy() for name, mark of @marks
|
||||
label.destroy() for name, label of @labels
|
||||
p.removeChild @healthBar if p = @healthBar?.parent
|
||||
@imageObject?.off 'animationend', @playNextAction
|
||||
clearInterval @effectInterval if @effectInterval
|
||||
super()
|
|
@ -201,7 +201,8 @@ module.exports = class Mark extends CocoClass
|
|||
Backbone.Mediator.publish 'sprite:loaded'
|
||||
|
||||
update: (pos=null) ->
|
||||
return false unless @on and @mark and @sprite?.thangType.isFullyLoaded()
|
||||
return false unless @on and @mark
|
||||
return false if @sprite? and not @sprite.thangType.isFullyLoaded()
|
||||
@mark.visible = not @hidden
|
||||
@updatePosition pos
|
||||
@updateRotation()
|
||||
|
@ -250,10 +251,12 @@ module.exports = class Mark extends CocoClass
|
|||
scale = size / {selection: 128, target: 128, repair: 320, highlight: 160}[@name]
|
||||
if @sprite?.thang.spriteName.search(/(dungeon|indoor).wall/i) isnt -1
|
||||
scale *= 2
|
||||
@mark.scaleX = @mark.scaleY = Math.min 1, scale
|
||||
|
||||
if @markSprite?
|
||||
@mark.scaleX *= @markSprite.originalScaleX
|
||||
@mark.scaleY *= @markSprite.originalScaleY
|
||||
@markSprite.scaleFactor = scale
|
||||
@markSprite.updateScale()
|
||||
else
|
||||
@mark.scaleX = @mark.scaleY = Math.min 1, scale
|
||||
if @name in ['selection', 'target', 'repair']
|
||||
@mark.scaleY *= @camera.y2x # code applies perspective
|
||||
|
||||
|
|
|
@ -104,7 +104,11 @@ module.exports = class GoalManager extends CocoClass
|
|||
|
||||
notifyGoalChanges: ->
|
||||
overallStatus = @checkOverallStatus()
|
||||
event = {goalStates: @goalStates, goals: @goals, overallStatus: overallStatus}
|
||||
event =
|
||||
goalStates: @goalStates
|
||||
goals: @goals
|
||||
overallStatus: overallStatus
|
||||
timedOut: @world.totalFrames is @world.maxTotalFrames
|
||||
Backbone.Mediator.publish('goal-manager:new-goal-states', event)
|
||||
|
||||
checkOverallStatus: (ignoreIncomplete=false) ->
|
||||
|
|
|
@ -222,6 +222,10 @@
|
|||
multiplayer: "Multiplayer"
|
||||
restart: "Restart"
|
||||
goals: "Goals"
|
||||
success: "Success!"
|
||||
incomplete: "Incomplete"
|
||||
timed_out: "Ran out of time"
|
||||
failing: "Failing"
|
||||
action_timeline: "Action Timeline"
|
||||
click_to_select: "Click on a unit to select it."
|
||||
reload_title: "Reload All Code?"
|
||||
|
@ -656,6 +660,7 @@
|
|||
rank_submitted: "Submitted for Ranking"
|
||||
rank_failed: "Failed to Rank"
|
||||
rank_being_ranked: "Game Being Ranked"
|
||||
help_simulate: "Help simulate games?"
|
||||
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."
|
||||
|
@ -676,6 +681,27 @@
|
|||
watch_victory: "Watch your victory"
|
||||
defeat_the: "Defeat the"
|
||||
|
||||
ladder_prizes:
|
||||
title: "Tournament Prizes"
|
||||
blurb_1: "These prizes will be awarded according to"
|
||||
blurb_2: "the tournament rules"
|
||||
blurb_3: "to the top human and ogre players."
|
||||
blurb_4: "Two teams means double the prizes!"
|
||||
blurb_5: "(There will be two first place winners, two second-place winners, etc.)"
|
||||
rank: "Rank"
|
||||
prizes: "Prizes"
|
||||
total_value: "Total Value"
|
||||
in_cash: "in cash"
|
||||
custom_wizard: "Custom CodeCombat Wizard"
|
||||
custom_avatar: "Custom CodeCombat avatar"
|
||||
heap: "span for six months of \"Startup\" access"
|
||||
credits: "credits"
|
||||
one_month_coupon: "coupon: choose either Rails or HTML"
|
||||
one_month_discount: "discount, 30% off: choose either Rails or HTML"
|
||||
license: "license"
|
||||
oreilly: "ebook of your choice"
|
||||
|
||||
|
||||
multiplayer_launch:
|
||||
introducing_dungeon_arena: "Introducing Dungeon Arena"
|
||||
new_way: "The new way to compete with code."
|
||||
|
|
|
@ -30,7 +30,7 @@ module.exports = class ThangType extends CocoModel
|
|||
isFullyLoaded: ->
|
||||
# TODO: Come up with a better way to identify when the model doesn't have everything needed to build the sprite. ie when it's a projection without all the required data.
|
||||
return @get('actions') or @get('raster') # needs one of these two things
|
||||
|
||||
|
||||
getActions: ->
|
||||
return {} unless @isFullyLoaded()
|
||||
return @actions or @buildActions()
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
.ladder-submission-view
|
||||
h3
|
||||
text-decoration: underline
|
||||
.help-simulate
|
||||
font-weight: normal
|
||||
float: right
|
||||
|
|
|
@ -74,7 +74,35 @@
|
|||
#must-log-in button
|
||||
margin-right: 10px
|
||||
|
||||
#prize_table
|
||||
width: 960px
|
||||
font-weight: bold
|
||||
|
||||
thead
|
||||
font-size: 24px
|
||||
|
||||
tbody
|
||||
tr:not(:first-child)
|
||||
border-top: 10px solid #ddd
|
||||
|
||||
td
|
||||
vertical-align: middle
|
||||
|
||||
&:nth-child(1), &:nth-child(3)
|
||||
text-align: center
|
||||
font-size: 24px
|
||||
|
||||
li
|
||||
list-style: none
|
||||
|
||||
&:not(:last-child)
|
||||
margin-bottom: 10px
|
||||
border-bottom: 1px solid #ddd
|
||||
|
||||
img
|
||||
margin-right: 10px
|
||||
|
||||
@media only screen and (max-width: 800px)
|
||||
#ladder-view
|
||||
#level-column img
|
||||
width: 100%
|
||||
width: 100%
|
||||
|
|
|
@ -5,24 +5,26 @@
|
|||
left: 10px
|
||||
top: -100px
|
||||
@include transition(top 0.5s ease-in-out)
|
||||
background-color: rgba(200,200,200,0.8)
|
||||
|
||||
&.brighter
|
||||
background-color: rgba(200,200,200,1.0)
|
||||
background-color: rgba(200,200,200,1.0)
|
||||
|
||||
border: black
|
||||
padding: 15px 7px 5px 5px
|
||||
padding: 15px 7px 2px 5px
|
||||
box-sizing: border-box
|
||||
border: 1px solid #333
|
||||
border-radius: 5px
|
||||
|
||||
h3
|
||||
.goals-status
|
||||
font-size: 14px
|
||||
margin: 0
|
||||
color: black
|
||||
|
||||
i
|
||||
margin-right: 5px
|
||||
.success
|
||||
color: darkgreen
|
||||
.timed-out
|
||||
color: darkslategray
|
||||
.failure
|
||||
color: darkred
|
||||
.incomplete
|
||||
color: darkgoldenrod
|
||||
|
||||
ul
|
||||
padding-left: 0
|
||||
|
|
|
@ -38,7 +38,7 @@ block content
|
|||
input#email.form-control(name="email", type="text", value="#{me.get('email')}")
|
||||
if !isProduction
|
||||
.form-group.checkbox
|
||||
label(for="email", data-i18n="account_settings.admin") Admin
|
||||
label(for="admin", data-i18n="account_settings.admin") Admin
|
||||
input#admin(name="admin", type="checkbox", checked=me.get('permissions').indexOf('admin') != -1)
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
button.btn.btn-success.rank-button
|
||||
span(data-i18n="ladder.rank_no_code").unavailable.hidden No New Code to Rank
|
||||
span(data-i18n="ladder.rank_my_game").rank.hidden Rank My Game!
|
||||
span(data-i18n="ladder.rank_submitting").submitting.hidden Submitting...
|
||||
span(data-i18n="ladder.rank_submitted").submitted.hidden Submitted for Ranking
|
||||
span(data-i18n="ladder.rank_failed").failed.hidden Failed to Rank
|
||||
span(data-i18n="ladder.rank_being_ranked").ranking.hidden Game Being Ranked
|
||||
span(data-i18n="ladder.rank_no_code").unavailable.secret No New Code to Rank
|
||||
span(data-i18n="ladder.rank_my_game").rank.secret Rank My Game!
|
||||
span(data-i18n="ladder.rank_submitting").submitting.secret Submitting...
|
||||
span(data-i18n="ladder.rank_submitted").submitted.secret Submitted for Ranking
|
||||
span(data-i18n="ladder.rank_failed").failed.secret Failed to Rank
|
||||
span(data-i18n="ladder.rank_being_ranked").ranking.secret Game Being Ranked
|
||||
|
||||
a(href=simulateURL, data-i18n="ladder.help_simulate").help-simulate.secret Help simulate games?
|
|
@ -45,8 +45,612 @@ block content
|
|||
.tab-pane.well#simulate
|
||||
#simulate-tab-view
|
||||
.tab-pane.well#prizes
|
||||
h1(data-i18n="ladder.prizes_remember_to_add_i18n_tags") Tournament Prizes
|
||||
p(data-i18n="ladder.prizes_but_this_is_just_placeholder") Fill in the Greed prizes list here.
|
||||
h1(data-i18n="ladder_prizes.title") Tournament Prizes
|
||||
p
|
||||
span(data-i18n="ladder_prizes.blurb_1") These prizes will be awarded according to
|
||||
|
|
||||
a(href="#rules", data-i18n="ladder_prizes.blurb_2") the tournament rules
|
||||
|
|
||||
span(data-i18n="ladder_prizes.blurb_3") to the top human and ogre players.
|
||||
|
|
||||
strong(data-i18n="ladder_prizes.blurb_4") Two teams means double the prizes!
|
||||
|
|
||||
span(data-i18n="ladder_prizes.blurb_5") (There will be two first place winners, two second-place winners, etc.)
|
||||
- var base = "/images/pages/play/ladder/prize_";
|
||||
|
||||
table#prize_table.table
|
||||
thead
|
||||
tr
|
||||
td(data-i18n="ladder_prizes.rank") Rank
|
||||
td(data-i18n="ladder_prizes.prizes") Prizes
|
||||
td(data-i18n="ladder_prizes.total_value") Total Value
|
||||
tbody
|
||||
tr
|
||||
td 1st
|
||||
td
|
||||
ul.list-unstyled
|
||||
li
|
||||
img(src=base + "cash1.png")
|
||||
span $512
|
||||
span(data-i18n="ladder_prizes.in_cash") in cash
|
||||
li
|
||||
img(src=base + "custom_wizard.png")
|
||||
span(data-i18n="ladder_prizes.custom_wizard") Custom CodeCombat Wizard
|
||||
li
|
||||
img(src=base + "custom_avatar.png")
|
||||
span(data-i18n="ladder_prizes.custom_avatar") Custom CodeCombat avatar
|
||||
li
|
||||
img(src=base + "heap.png")
|
||||
span
|
||||
a(href="https://heapanalytics.com/") Heap Analytics
|
||||
|
|
||||
span(data-i18n="ladder_prizes.heap") span for six months of "Startup" access
|
||||
| - $354
|
||||
li
|
||||
img(src=base + "firebase.png")
|
||||
span
|
||||
a(href="https://www.firebase.com/") Firebase
|
||||
|
|
||||
span(data-i18n="ladder_prizes.credits") credits
|
||||
| - $300
|
||||
li
|
||||
img(src=base + "one_month.png")
|
||||
span
|
||||
a(href="https://onemonthrails.com/") One Month Rails
|
||||
|
|
||||
span(data-i18n="ladder_prizes.one_month_coupon") coupon: choose either Rails or HTML
|
||||
| - $99
|
||||
li
|
||||
img(src=base + "webstorm.png")
|
||||
span
|
||||
a(href="http://www.jetbrains.com/webstorm/") Webstorm
|
||||
|
|
||||
span(data-i18n="ladder_prizes.license") license
|
||||
| - $49
|
||||
li
|
||||
img(src=base + "oreilly.png")
|
||||
span
|
||||
a(href="http://shop.oreilly.com/category/ebooks.do") O'Reilly
|
||||
|
|
||||
span(data-i18n="ladder_prizes.oreilly") ebook of your choice
|
||||
| - $40
|
||||
li
|
||||
img(src=base + "aws.png")
|
||||
span
|
||||
a(href="http://aws.amazon.com/") Amazon Web Services
|
||||
|
|
||||
span(data-i18n="ladder_prizes.credits") credits
|
||||
| - $50
|
||||
td $2054
|
||||
tr
|
||||
td 2nd
|
||||
td
|
||||
ul.list-unstyled
|
||||
li
|
||||
img(src=base + "cash2.png")
|
||||
span $256
|
||||
span(data-i18n="ladder_prizes.in_cash") in cash
|
||||
li
|
||||
img(src=base + "custom_avatar.png")
|
||||
span(data-i18n="ladder_prizes.custom_avatar") Custom CodeCombat avatar
|
||||
li
|
||||
img(src=base + "heap.png")
|
||||
span
|
||||
a(href="https://heapanalytics.com/") Heap Analytics
|
||||
|
|
||||
span(data-i18n="ladder_prizes.heap") span for six months of "Startup" access
|
||||
| - $354
|
||||
li
|
||||
img(src=base + "firebase.png")
|
||||
span
|
||||
a(href="https://www.firebase.com/") Firebase
|
||||
|
|
||||
span(data-i18n="ladder_prizes.credits") credits
|
||||
| - $300
|
||||
li
|
||||
img(src=base + "one_month.png")
|
||||
span
|
||||
a(href="https://onemonthrails.com/") One Month Rails
|
||||
|
|
||||
span(data-i18n="ladder_prizes.one_month_discount") discount, 30% off: choose either Rails or HTML
|
||||
| - $30
|
||||
li
|
||||
img(src=base + "webstorm.png")
|
||||
span
|
||||
a(href="http://www.jetbrains.com/webstorm/") Webstorm
|
||||
|
|
||||
span(data-i18n="ladder_prizes.license") license
|
||||
| - $49
|
||||
li
|
||||
img(src=base + "oreilly.png")
|
||||
span
|
||||
a(href="http://shop.oreilly.com/category/ebooks.do") O'Reilly
|
||||
|
|
||||
span(data-i18n="ladder_prizes.oreilly") ebook of your choice
|
||||
| - $40
|
||||
li
|
||||
img(src=base + "aws.png")
|
||||
span
|
||||
a(href="http://aws.amazon.com/") Amazon Web Services
|
||||
|
|
||||
span(data-i18n="ladder_prizes.credits") credits
|
||||
| - $50
|
||||
td $1229
|
||||
tr
|
||||
td 3rd
|
||||
td
|
||||
ul.list-unstyled
|
||||
li
|
||||
img(src=base + "cash2.png")
|
||||
span $128
|
||||
span(data-i18n="ladder_prizes.in_cash") in cash
|
||||
li
|
||||
img(src=base + "custom_avatar.png")
|
||||
span(data-i18n="ladder_prizes.custom_avatar") Custom CodeCombat avatar
|
||||
li
|
||||
img(src=base + "heap.png")
|
||||
span
|
||||
a(href="https://heapanalytics.com/") Heap Analytics
|
||||
|
|
||||
span(data-i18n="ladder_prizes.heap") span for six months of "Startup" access
|
||||
| - $354
|
||||
li
|
||||
img(src=base + "firebase.png")
|
||||
span
|
||||
a(href="https://www.firebase.com/") Firebase
|
||||
|
|
||||
span(data-i18n="ladder_prizes.credits") credits
|
||||
| - $300
|
||||
li
|
||||
img(src=base + "one_month.png")
|
||||
span
|
||||
a(href="https://onemonthrails.com/") One Month Rails
|
||||
|
|
||||
span(data-i18n="ladder_prizes.one_month_discount") discount, 30% off: choose either Rails or HTML
|
||||
| - $30
|
||||
li
|
||||
img(src=base + "webstorm.png")
|
||||
span
|
||||
a(href="http://www.jetbrains.com/webstorm/") Webstorm
|
||||
|
|
||||
span(data-i18n="ladder_prizes.license") license
|
||||
| - $49
|
||||
li
|
||||
img(src=base + "oreilly.png")
|
||||
span
|
||||
a(href="http://shop.oreilly.com/category/ebooks.do") O'Reilly
|
||||
|
|
||||
span(data-i18n="ladder_prizes.oreilly") ebook of your choice
|
||||
| - $40
|
||||
li
|
||||
img(src=base + "aws.png")
|
||||
span
|
||||
a(href="http://aws.amazon.com/") Amazon Web Services
|
||||
|
|
||||
span(data-i18n="ladder_prizes.credits") credits
|
||||
| - $50
|
||||
td $1101
|
||||
tr
|
||||
td 4th
|
||||
td
|
||||
ul.list-unstyled
|
||||
li
|
||||
img(src=base + "cash3.png")
|
||||
span $64
|
||||
span(data-i18n="ladder_prizes.in_cash") in cash
|
||||
li
|
||||
img(src=base + "heap.png")
|
||||
span
|
||||
a(href="https://heapanalytics.com/") Heap Analytics
|
||||
|
|
||||
span(data-i18n="ladder_prizes.heap") span for six months of "Startup" access
|
||||
| - $354
|
||||
li
|
||||
img(src=base + "firebase.png")
|
||||
span
|
||||
a(href="https://www.firebase.com/") Firebase
|
||||
|
|
||||
span(data-i18n="ladder_prizes.credits") credits
|
||||
| - $300
|
||||
li
|
||||
img(src=base + "one_month.png")
|
||||
span
|
||||
a(href="https://onemonthrails.com/") One Month Rails
|
||||
|
|
||||
span(data-i18n="ladder_prizes.one_month_discount") discount, 30% off: choose either Rails or HTML
|
||||
| - $30
|
||||
li
|
||||
img(src=base + "webstorm.png")
|
||||
span
|
||||
a(href="http://www.jetbrains.com/webstorm/") Webstorm
|
||||
|
|
||||
span(data-i18n="ladder_prizes.license") license
|
||||
| - $49
|
||||
li
|
||||
img(src=base + "oreilly.png")
|
||||
span
|
||||
a(href="http://shop.oreilly.com/category/ebooks.do") O'Reilly
|
||||
|
|
||||
span(data-i18n="ladder_prizes.oreilly") ebook of your choice
|
||||
| - $40
|
||||
li
|
||||
img(src=base + "aws.png")
|
||||
span
|
||||
a(href="http://aws.amazon.com/") Amazon Web Services
|
||||
|
|
||||
span(data-i18n="ladder_prizes.credits") credits
|
||||
| - $50
|
||||
td $887
|
||||
tr
|
||||
td 5th
|
||||
td
|
||||
ul.list-unstyled
|
||||
li
|
||||
img(src=base + "cash3.png")
|
||||
span $32
|
||||
span(data-i18n="ladder_prizes.in_cash") in cash
|
||||
li
|
||||
img(src=base + "heap.png")
|
||||
span
|
||||
a(href="https://heapanalytics.com/") Heap Analytics
|
||||
|
|
||||
span(data-i18n="ladder_prizes.heap") span for six months of "Startup" access
|
||||
| - $354
|
||||
li
|
||||
img(src=base + "firebase.png")
|
||||
span
|
||||
a(href="https://www.firebase.com/") Firebase
|
||||
|
|
||||
span(data-i18n="ladder_prizes.credits") credits
|
||||
| - $300
|
||||
li
|
||||
img(src=base + "one_month.png")
|
||||
span
|
||||
a(href="https://onemonthrails.com/") One Month Rails
|
||||
|
|
||||
span(data-i18n="ladder_prizes.one_month_discount") discount, 30% off: choose either Rails or HTML
|
||||
| - $30
|
||||
li
|
||||
img(src=base + "webstorm.png")
|
||||
span
|
||||
a(href="http://www.jetbrains.com/webstorm/") Webstorm
|
||||
|
|
||||
span(data-i18n="ladder_prizes.license") license
|
||||
| - $49
|
||||
li
|
||||
img(src=base + "oreilly.png")
|
||||
span
|
||||
a(href="http://shop.oreilly.com/category/ebooks.do") O'Reilly
|
||||
|
|
||||
span(data-i18n="ladder_prizes.oreilly") ebook of your choice
|
||||
| - $40
|
||||
li
|
||||
img(src=base + "aws.png")
|
||||
span
|
||||
a(href="http://aws.amazon.com/") Amazon Web Services
|
||||
|
|
||||
span(data-i18n="ladder_prizes.credits") credits
|
||||
| - $50
|
||||
td $855
|
||||
tr
|
||||
td 6th
|
||||
td
|
||||
ul.list-unstyled
|
||||
li
|
||||
img(src=base + "cash3.png")
|
||||
span $16
|
||||
span(data-i18n="ladder_prizes.in_cash") in cash
|
||||
li
|
||||
img(src=base + "firebase.png")
|
||||
span
|
||||
a(href="https://www.firebase.com/") Firebase
|
||||
|
|
||||
span(data-i18n="ladder_prizes.credits") credits
|
||||
| - $300
|
||||
li
|
||||
img(src=base + "one_month.png")
|
||||
span
|
||||
a(href="https://onemonthrails.com/") One Month Rails
|
||||
|
|
||||
span(data-i18n="ladder_prizes.one_month_discount") discount, 30% off: choose either Rails or HTML
|
||||
| - $30
|
||||
li
|
||||
img(src=base + "webstorm.png")
|
||||
span
|
||||
a(href="http://www.jetbrains.com/webstorm/") Webstorm
|
||||
|
|
||||
span(data-i18n="ladder_prizes.license") license
|
||||
| - $49
|
||||
li
|
||||
img(src=base + "oreilly.png")
|
||||
span
|
||||
a(href="http://shop.oreilly.com/category/ebooks.do") O'Reilly
|
||||
|
|
||||
span(data-i18n="ladder_prizes.oreilly") ebook of your choice
|
||||
| - $40
|
||||
li
|
||||
img(src=base + "aws.png")
|
||||
span
|
||||
a(href="http://aws.amazon.com/") Amazon Web Services
|
||||
|
|
||||
span(data-i18n="ladder_prizes.credits") credits
|
||||
| - $50
|
||||
td $485
|
||||
tr
|
||||
td 7th
|
||||
td
|
||||
ul.list-unstyled
|
||||
li
|
||||
img(src=base + "cash3.png")
|
||||
span $8
|
||||
span(data-i18n="ladder_prizes.in_cash") in cash
|
||||
li
|
||||
img(src=base + "firebase.png")
|
||||
span
|
||||
a(href="https://www.firebase.com/") Firebase
|
||||
|
|
||||
span(data-i18n="ladder_prizes.credits") credits
|
||||
| - $300
|
||||
li
|
||||
img(src=base + "one_month.png")
|
||||
span
|
||||
a(href="https://onemonthrails.com/") One Month Rails
|
||||
|
|
||||
span(data-i18n="ladder_prizes.one_month_discount") discount, 30% off: choose either Rails or HTML
|
||||
| - $30
|
||||
li
|
||||
img(src=base + "webstorm.png")
|
||||
span
|
||||
a(href="http://www.jetbrains.com/webstorm/") Webstorm
|
||||
|
|
||||
span(data-i18n="ladder_prizes.license") license
|
||||
| - $49
|
||||
li
|
||||
img(src=base + "oreilly.png")
|
||||
span
|
||||
a(href="http://shop.oreilly.com/category/ebooks.do") O'Reilly
|
||||
|
|
||||
span(data-i18n="ladder_prizes.oreilly") ebook of your choice
|
||||
| - $40
|
||||
li
|
||||
img(src=base + "aws.png")
|
||||
span
|
||||
a(href="http://aws.amazon.com/") Amazon Web Services
|
||||
|
|
||||
span(data-i18n="ladder_prizes.credits") credits
|
||||
| - $50
|
||||
td $477
|
||||
tr
|
||||
td 8th
|
||||
td
|
||||
ul.list-unstyled
|
||||
li
|
||||
img(src=base + "cash3.png")
|
||||
span $4
|
||||
span(data-i18n="ladder_prizes.in_cash") in cash
|
||||
li
|
||||
img(src=base + "firebase.png")
|
||||
span
|
||||
a(href="https://www.firebase.com/") Firebase
|
||||
|
|
||||
span(data-i18n="ladder_prizes.credits") credits
|
||||
| - $300
|
||||
li
|
||||
img(src=base + "one_month.png")
|
||||
span
|
||||
a(href="https://onemonthrails.com/") One Month Rails
|
||||
|
|
||||
span(data-i18n="ladder_prizes.one_month_discount") discount, 30% off: choose either Rails or HTML
|
||||
| - $30
|
||||
li
|
||||
img(src=base + "webstorm.png")
|
||||
span
|
||||
a(href="http://www.jetbrains.com/webstorm/") Webstorm
|
||||
|
|
||||
span(data-i18n="ladder_prizes.license") license
|
||||
| - $49
|
||||
li
|
||||
img(src=base + "oreilly.png")
|
||||
span
|
||||
a(href="http://shop.oreilly.com/category/ebooks.do") O'Reilly
|
||||
|
|
||||
span(data-i18n="ladder_prizes.oreilly") ebook of your choice
|
||||
| - $40
|
||||
li
|
||||
img(src=base + "aws.png")
|
||||
span
|
||||
a(href="http://aws.amazon.com/") Amazon Web Services
|
||||
|
|
||||
span(data-i18n="ladder_prizes.credits") credits
|
||||
| - $50
|
||||
td $473
|
||||
tr
|
||||
td 9th
|
||||
td
|
||||
ul.list-unstyled
|
||||
li
|
||||
img(src=base + "cash3.png")
|
||||
span $2
|
||||
span(data-i18n="ladder_prizes.in_cash") in cash
|
||||
li
|
||||
img(src=base + "firebase.png")
|
||||
span
|
||||
a(href="https://www.firebase.com/") Firebase
|
||||
|
|
||||
span(data-i18n="ladder_prizes.credits") credits
|
||||
| - $300
|
||||
li
|
||||
img(src=base + "one_month.png")
|
||||
span
|
||||
a(href="https://onemonthrails.com/") One Month Rails
|
||||
|
|
||||
span(data-i18n="ladder_prizes.one_month_discount") discount, 30% off: choose either Rails or HTML
|
||||
| - $30
|
||||
li
|
||||
img(src=base + "webstorm.png")
|
||||
span
|
||||
a(href="http://www.jetbrains.com/webstorm/") Webstorm
|
||||
|
|
||||
span(data-i18n="ladder_prizes.license") license
|
||||
| - $49
|
||||
li
|
||||
img(src=base + "oreilly.png")
|
||||
span
|
||||
a(href="http://shop.oreilly.com/category/ebooks.do") O'Reilly
|
||||
|
|
||||
span(data-i18n="ladder_prizes.oreilly") ebook of your choice
|
||||
| - $40
|
||||
li
|
||||
img(src=base + "aws.png")
|
||||
span
|
||||
a(href="http://aws.amazon.com/") Amazon Web Services
|
||||
|
|
||||
span(data-i18n="ladder_prizes.credits") credits
|
||||
| - $50
|
||||
td $471
|
||||
tr
|
||||
td 10th
|
||||
td
|
||||
ul.list-unstyled
|
||||
li
|
||||
img(src=base + "cash3.png")
|
||||
span $1
|
||||
span(data-i18n="ladder_prizes.in_cash") in cash
|
||||
li
|
||||
img(src=base + "firebase.png")
|
||||
span
|
||||
a(href="https://www.firebase.com/") Firebase
|
||||
|
|
||||
span(data-i18n="ladder_prizes.credits") credits
|
||||
| - $300
|
||||
li
|
||||
img(src=base + "one_month.png")
|
||||
span
|
||||
a(href="https://onemonthrails.com/") One Month Rails
|
||||
|
|
||||
span(data-i18n="ladder_prizes.one_month_discount") discount, 30% off: choose either Rails or HTML
|
||||
| - $30
|
||||
li
|
||||
img(src=base + "webstorm.png")
|
||||
span
|
||||
a(href="http://www.jetbrains.com/webstorm/") Webstorm
|
||||
|
|
||||
span(data-i18n="ladder_prizes.license") license
|
||||
| - $49
|
||||
li
|
||||
img(src=base + "oreilly.png")
|
||||
span
|
||||
a(href="http://shop.oreilly.com/category/ebooks.do") O'Reilly
|
||||
|
|
||||
span(data-i18n="ladder_prizes.oreilly") ebook of your choice
|
||||
| - $40
|
||||
li
|
||||
img(src=base + "aws.png")
|
||||
span
|
||||
a(href="http://aws.amazon.com/") Amazon Web Services
|
||||
|
|
||||
span(data-i18n="ladder_prizes.credits") credits
|
||||
| - $50
|
||||
td $470
|
||||
tr
|
||||
td 11 - 40
|
||||
td
|
||||
ul.list-unstyled
|
||||
li
|
||||
img(src=base + "webstorm.png")
|
||||
span
|
||||
a(href="http://www.jetbrains.com/webstorm/") Webstorm
|
||||
|
|
||||
span(data-i18n="ladder_prizes.license") license
|
||||
| - $49
|
||||
li
|
||||
img(src=base + "oreilly.png")
|
||||
span
|
||||
a(href="http://shop.oreilly.com/category/ebooks.do") O'Reilly
|
||||
|
|
||||
span(data-i18n="ladder_prizes.oreilly") ebook of your choice
|
||||
| - $40
|
||||
li
|
||||
img(src=base + "aws.png")
|
||||
span
|
||||
a(href="http://aws.amazon.com/") Amazon Web Services
|
||||
|
|
||||
span(data-i18n="ladder_prizes.credits") credits
|
||||
| - $50
|
||||
td $139
|
||||
tr
|
||||
td 41 - 100
|
||||
td
|
||||
ul.list-unstyled
|
||||
li
|
||||
img(src=base + "oreilly.png")
|
||||
span
|
||||
a(href="http://shop.oreilly.com/category/ebooks.do") O'Reilly
|
||||
|
|
||||
span(data-i18n="ladder_prizes.oreilly") ebook of your choice
|
||||
| - $40
|
||||
li
|
||||
img(src=base + "aws.png")
|
||||
span
|
||||
a(href="http://aws.amazon.com/") Amazon Web Services
|
||||
|
|
||||
span(data-i18n="ladder_prizes.credits") credits
|
||||
| - $50
|
||||
td $90
|
||||
tr
|
||||
td 101+
|
||||
td
|
||||
ul.list-unstyled
|
||||
li
|
||||
img(src=base + "aws.png")
|
||||
span
|
||||
a(href="http://aws.amazon.com/") Amazon Web Services
|
||||
|
|
||||
span(data-i18n="ladder_prizes.credits") credits
|
||||
| - $50
|
||||
td $50
|
||||
|
||||
.tab-pane.well#rules
|
||||
h1(data-i18n="ladder.rules_remember_to_add_i18n_tags") Tournament Rules
|
||||
p(data-i18n="ladder.rules_but_this_is_just_placeholder") We probably don't have to translate legal documents from English, but we should translate any conversational summary.
|
||||
h2 General
|
||||
p You don't have to buy anything to participate in the tournament, and trying to pay us won't increase your odds of winning.
|
||||
|
||||
h2 Dates and Times
|
||||
p The tournament starts on Tuesday 5/20 at 8:30AM and ends on Tuesday 6/10 at 5:30PM PDT. After the tournament finishes, we will check the games manually to prevent duplicate entries and cheating. We will email all the winners within 2 weeks of the end date.
|
||||
|
||||
h2 Eligilibity
|
||||
p The tournament is open to anyone over the age of 13. Players are allowed to form teams to compete, but we will only be rewarding submissions, so if a team of 10 wins, they will need to split the prize.
|
||||
p The tournament is NOT open to people who live in countries or states that prohibit participating or receiving a prize in a challenge (these include, but are not limited to Brazil, Quebec, Italy, Cuba, Sudan, Iran, North Korea, and Syria). Organizations involved in putting the tournament together (namely CodeCombat and all of our employees) are excluded from participating/winning prizes.
|
||||
|
||||
h2 Submission Requirements
|
||||
p To be eligible to win prizes, players must submit their code to the Greed ladder for ranking AND defeat our default AI. Every player that submits their code to the ladder and beats our default AI will receive $50 in AWS credits as described on the
|
||||
a(href="#prizes", data-toggle="tab", data-i18n="ladder.prizes") prizes page.
|
||||
|
||||
p There are some restrictions regarding who can use the AWS credits, please see the additional rules of use on
|
||||
a(href="https://aws.amazon.com/awscredits") Amazon's AWS credits page.
|
||||
|
||||
h2 Submission Rights
|
||||
p We reserve the right to use your submission and site identity (including username, avatar, and any information you mark as public) to promote the tournament. This is in keeping with our overall site terms of service.
|
||||
|
||||
h2 Judging Criteria
|
||||
p We will award prizes according to player's rank on the leaderboards. We will not be evaluating code in any manual way for common traits like adequate documentation, cleanliness, etc. Although we will run a final check of all submissions to rule out duplicates and cheating, the leaderboards are a good proxy for your final rank. Your rank will change as players submit more solutions.
|
||||
|
||||
h2 Prizes
|
||||
p Prizes will be awarded to everyone that achieves a rank covered on the
|
||||
a(href="#prizes", data-toggle="tab", data-i18n="ladder.prizes") prizes page.
|
||||
|
||||
p Please remember that the player ranks listed on the prize page refer to ranks WITHIN a leaderboard. So if you are #2 on the Ogre leaderboard, you will get the #2 prize. Similarly, if you are #3 on the Human leaderboard, you will receive the #3 prize. As mentioned above, if you had a submission in the top 10 for both boards, we will only count your highest submission for the purposes of distributing prizes.
|
||||
|
||||
h2 Verifying Potential Winners
|
||||
p We may ask players to identify themselves so that we can detect duplicate entries. This may be done in the form of a Facebook, Google+, or LinkedIn profile, but we may need more information. All players eligible for prizes agree that refusing to provide us with identifying information may lead to removal from the tournament.
|
||||
|
||||
p On a related note, if we have reason to believe that a player has intentionally submitted duplicate entries for the purpose of receiving more prizes or manipulating the leaderboards in any way, we will remove that player and all submissions we believe to be associated with them. We want this to be fair for everyone.
|
||||
|
||||
h2 Prize Distribution
|
||||
p Different sponsors require different ways of claiming their prizes, and we will work with winners to ensure they are able to redeem their prizes in a timely fashion. For cash prizes, we will deliver the money via Paypal. We will not ship checks, money orders, or cash through the mail. We will assume reasonable international money transfer costs to deliver cash prizes through Paypal.
|
||||
|
||||
p Winners are responsible for any taxes associated with claiming their prizes. CodeCombat is not responsible for filing paperwork on behalf of winners for tax claims.
|
||||
|
||||
h2 Contact
|
||||
p If you have any questions or would like to get in touch with us for any other reason, we can be reached at team@codecombat.com. You can also post to our public
|
||||
a(href="http://discourse.codecombat.com/") Discourse forum.
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
ul#primary-goals-list
|
||||
h3
|
||||
span(data-i18n="play_level.goals") Goals
|
||||
div.goals-status
|
||||
strong(data-i18n="play_level.goals") Goals
|
||||
span.spl.spr :
|
||||
span(data-i18n="play_level.success").secret.goal-status.success Success!
|
||||
span(data-i18n="play_level.incomplete").secret.goal-status.incomplete Incomplete
|
||||
span(data-i18n="play_level.timed_out").secret.goal-status.timed-out Ran out of time
|
||||
span(data-i18n="play_level.failing").secret.goal-status.failure Failing
|
||||
|
|
|
@ -284,7 +284,11 @@ module.exports = class ThangTypeEditView extends View
|
|||
fixed = scaleValue.toFixed(1)
|
||||
@scale = scaleValue
|
||||
@$el.find('.scale-label').text " #{fixed}x "
|
||||
@currentObject.scaleX = @currentObject.scaleY = scaleValue / resValue if @currentObject?
|
||||
if @currentSprite
|
||||
@currentSprite.scaleFactor = scaleValue
|
||||
@currentSprite.updateScale()
|
||||
else if @currentObject?
|
||||
@currentObject.scaleX = @currentObject.scaleY = scaleValue / resValue
|
||||
@updateGrid()
|
||||
@updateDots()
|
||||
|
||||
|
|
|
@ -2,11 +2,12 @@ CocoView = require 'views/kinds/CocoView'
|
|||
template = require 'templates/play/common/ladder_submission'
|
||||
|
||||
module.exports = class LadderSubmissionView extends CocoView
|
||||
class: "ladder-submission-view"
|
||||
className: "ladder-submission-view"
|
||||
template: template
|
||||
|
||||
events:
|
||||
'click .rank-button': 'rankSession'
|
||||
'click .help-simulate': 'onHelpSimulate'
|
||||
|
||||
constructor: (options) ->
|
||||
super options
|
||||
|
@ -16,9 +17,10 @@ module.exports = class LadderSubmissionView extends CocoView
|
|||
getRenderData: ->
|
||||
ctx = super()
|
||||
ctx.readyToRank = @session?.readyToRank()
|
||||
ctx.isRanking = @ession?.get('isRanking')
|
||||
ctx.isRanking = @session?.get('isRanking')
|
||||
ctx.simulateURL = "/play/ladder/#{@level.get('slug')}#simulate"
|
||||
ctx
|
||||
|
||||
|
||||
afterRender: ->
|
||||
super()
|
||||
return unless @supermodel.finished()
|
||||
|
@ -34,9 +36,11 @@ module.exports = class LadderSubmissionView extends CocoView
|
|||
@setRankingButtonText rankingState
|
||||
|
||||
setRankingButtonText: (spanClass) ->
|
||||
@rankButton.find('span').addClass('hidden')
|
||||
@rankButton.find(".#{spanClass}").removeClass('hidden')
|
||||
@rankButton.find('span').hide()
|
||||
@rankButton.find(".#{spanClass}").show()
|
||||
@rankButton.toggleClass 'disabled', spanClass isnt 'rank'
|
||||
helpSimulate = spanClass in ['submitted', 'ranking']
|
||||
@$el.find('.help-simulate').toggle(helpSimulate, 'slow')
|
||||
|
||||
rankSession: (e) ->
|
||||
return unless @session.readyToRank()
|
||||
|
@ -86,3 +90,5 @@ module.exports = class LadderSubmissionView extends CocoView
|
|||
transpiledCode[thang][spellID] = aether.transpile spell
|
||||
transpiledCode
|
||||
|
||||
onHelpSimulate: ->
|
||||
$('a[href="#simulate"]').tab('show')
|
||||
|
|
|
@ -100,6 +100,8 @@ module.exports = class LadderView extends RootView
|
|||
e.stopPropagation()
|
||||
e.preventDefault()
|
||||
@showApologeticSignupModal()
|
||||
if link and /#rules$/.test link
|
||||
@$el.find('a[href="#rules"]').tab('show')
|
||||
|
||||
destroy: ->
|
||||
clearInterval @refreshInterval
|
||||
|
|
|
@ -91,7 +91,7 @@ module.exports = class MyMatchesTabView extends CocoView
|
|||
session = _.find @sessions.models, {id: sessionID}
|
||||
ladderSubmissionView = new LadderSubmissionView session: session, level: @level
|
||||
@insertSubView ladderSubmissionView, placeholder
|
||||
ladderSubmissionView.$el.find('.rank-button').addClass 'btn-block'
|
||||
ladderSubmissionView.$el.find('.rank-button').addClass 'btn-block btn-lg'
|
||||
|
||||
@$el.find('.score-chart-wrapper').each (i, el) =>
|
||||
scoreWrapper = $(el)
|
||||
|
|
|
@ -19,13 +19,26 @@ module.exports = class GoalsView extends View
|
|||
'surface:playback-ended': 'onSurfacePlaybackEnded'
|
||||
|
||||
events:
|
||||
'mouseenter': -> @$el.css('top', -10)
|
||||
'mouseleave': -> @updateTop()
|
||||
'mouseenter': ->
|
||||
@mouseEntered = true
|
||||
@updatePlacement()
|
||||
|
||||
'mouseleave': ->
|
||||
@mouseEntered = false
|
||||
@updatePlacement()
|
||||
|
||||
toggleCollapse: (e) ->
|
||||
@$el.toggleClass('expanded').toggleClass('collapsed')
|
||||
|
||||
onNewGoalStates: (e) ->
|
||||
@$el.find('.goal-status').addClass 'secret'
|
||||
classToShow = null
|
||||
classToShow = 'success' if e.overallStatus is 'success'
|
||||
classToShow = 'failure' if e.overallStatus is 'failure'
|
||||
classToShow ?= 'timed-out' if e.timedOut
|
||||
classToShow ?= 'incomplete'
|
||||
@$el.find('.goal-status.'+classToShow).removeClass 'secret'
|
||||
|
||||
list = $('#primary-goals-list', @$el)
|
||||
list.empty()
|
||||
goals = []
|
||||
|
@ -53,10 +66,14 @@ module.exports = class GoalsView extends View
|
|||
@$el.removeClass('secret') if goals.length > 0
|
||||
|
||||
onSurfacePlaybackRestarted: ->
|
||||
@playbackEnded = false
|
||||
@$el.removeClass 'brighter'
|
||||
@updatePlacement()
|
||||
|
||||
onSurfacePlaybackEnded: ->
|
||||
@playbackEnded = true
|
||||
@$el.addClass 'brighter'
|
||||
@updatePlacement()
|
||||
|
||||
render: ->
|
||||
super()
|
||||
|
@ -64,11 +81,16 @@ module.exports = class GoalsView extends View
|
|||
|
||||
afterRender: ->
|
||||
super()
|
||||
@updateTop()
|
||||
@updatePlacement()
|
||||
|
||||
updateTop: ->
|
||||
@$el.css('top', 26 - @$el.outerHeight())
|
||||
updatePlacement: ->
|
||||
if @playbackEnded or @mouseEntered
|
||||
# expand
|
||||
@$el.css('top', -10)
|
||||
else
|
||||
# collapse
|
||||
@$el.css('top', 26 - @$el.outerHeight())
|
||||
|
||||
onSetLetterbox: (e) ->
|
||||
@$el.toggle not e.on
|
||||
@updateTop()
|
||||
@updatePlacement()
|
||||
|
|
|
@ -68,15 +68,14 @@ module.exports = class PlayLevelView extends View
|
|||
|
||||
shortcuts:
|
||||
'ctrl+s': 'onCtrlS'
|
||||
|
||||
# Initial Setup #############################################################
|
||||
|
||||
constructor: (options, @levelID) ->
|
||||
console.profile?() if PROFILE_ME
|
||||
super options
|
||||
if not me.get('hourOfCode') and @getQueryVariable "hour_of_code"
|
||||
me.set 'hourOfCode', true
|
||||
me.save()
|
||||
$('body').append($("<img src='http://code.org/api/hour/begin_codecombat.png' style='visibility: hidden;'>"))
|
||||
application.tracker?.trackEvent 'Hour of Code Begin', {}
|
||||
@setUpHourOfCode()
|
||||
|
||||
@isEditorPreview = @getQueryVariable 'dev'
|
||||
@sessionID = @getQueryVariable 'session'
|
||||
|
@ -91,10 +90,12 @@ module.exports = class PlayLevelView extends View
|
|||
else
|
||||
@load()
|
||||
application.tracker?.trackEvent 'Started Level Load', level: @levelID, label: @levelID
|
||||
|
||||
onLevelLoadError: (e) ->
|
||||
# TODO NOW: remove this in favor of the supermodel handling it
|
||||
application.router.navigate "/play?not_found=#{@levelID}", {trigger: true}
|
||||
|
||||
setUpHourOfCode: ->
|
||||
me.set 'hourOfCode', true
|
||||
me.save()
|
||||
$('body').append($("<img src='http://code.org/api/hour/begin_codecombat.png' style='visibility: hidden;'>"))
|
||||
application.tracker?.trackEvent 'Hour of Code Begin', {}
|
||||
|
||||
setLevel: (@level, givenSupermodel) ->
|
||||
@supermodel.models = givenSupermodel.models
|
||||
|
@ -112,6 +113,30 @@ module.exports = class PlayLevelView extends View
|
|||
@loadStartTime = new Date()
|
||||
@god = new God debugWorker: true
|
||||
@levelLoader = new LevelLoader supermodel: @supermodel, levelID: @levelID, sessionID: @sessionID, opponentSessionID: @getQueryVariable('opponent'), team: @getQueryVariable("team")
|
||||
@listenToOnce @levelLoader, 'world-necessities-loaded', @onWorldNecessitiesLoaded
|
||||
|
||||
# CocoView overridden methods ###############################################
|
||||
|
||||
updateProgress: (progress) ->
|
||||
super(progress)
|
||||
return if @seenDocs
|
||||
return unless @levelLoader.session.loaded and @levelLoader.level.loaded
|
||||
return unless showFrequency = @levelLoader.level.get('showsGuide')
|
||||
session = @levelLoader.session
|
||||
diff = new Date().getTime() - new Date(session.get('created')).getTime()
|
||||
return if showFrequency is 'first-time' and diff > (5 * 60 * 1000)
|
||||
articles = @levelLoader.supermodel.getModels Article
|
||||
for article in articles
|
||||
return unless article.loaded
|
||||
@showGuide()
|
||||
|
||||
showGuide: ->
|
||||
@seenDocs = true
|
||||
DocsModal = require './level/modal/docs_modal'
|
||||
options = {docs: @levelLoader.level.get('documentation'), supermodel: @supermodel}
|
||||
@openModalView(new DocsModal(options), true)
|
||||
Backbone.Mediator.subscribeOnce 'modal-closed', @onLevelLoaded, @
|
||||
return true
|
||||
|
||||
getRenderData: ->
|
||||
c = super()
|
||||
|
@ -129,62 +154,26 @@ module.exports = class PlayLevelView extends View
|
|||
@$el.find('#level-done-button').hide()
|
||||
$('body').addClass('is-playing')
|
||||
|
||||
updateProgress: (progress) ->
|
||||
super(progress)
|
||||
if not @worldInitialized and @levelLoader.session.loaded and @levelLoader.level.loaded and @levelLoader.world and (not @levelLoader.opponentSession or @levelLoader.opponentSession.loaded)
|
||||
@grabLevelLoaderData()
|
||||
@onWorldInitialized()
|
||||
return if @seenDocs
|
||||
return unless @levelLoader.session.loaded and @levelLoader.level.loaded
|
||||
return unless showFrequency = @levelLoader.level.get('showsGuide')
|
||||
session = @levelLoader.session
|
||||
diff = new Date().getTime() - new Date(session.get('created')).getTime()
|
||||
return if showFrequency is 'first-time' and diff > (5 * 60 * 1000)
|
||||
articles = @levelLoader.supermodel.getModels Article
|
||||
for article in articles
|
||||
return unless article.loaded
|
||||
@showGuide()
|
||||
afterInsert: ->
|
||||
super()
|
||||
@showWizardSettingsModal() if not me.get('name')
|
||||
|
||||
onWorldInitialized: ->
|
||||
@worldInitialized = true
|
||||
# Partially Loaded Setup ####################################################
|
||||
|
||||
onWorldNecessitiesLoaded: ->
|
||||
# Called when we have enough to build the world, but not everything is loaded
|
||||
@grabLevelLoaderData()
|
||||
team = @getQueryVariable("team") ? @world.teamForPlayer(0)
|
||||
@loadOpponentTeam(team)
|
||||
@god.setLevel @level.serialize @supermodel
|
||||
@god.setLevelSessionIDs if @otherSession then [@session.id, @otherSession.id] else [@session.id]
|
||||
@god.setWorldClassMap @world.classMap
|
||||
@setupGod()
|
||||
@setTeam team
|
||||
@initGoalManager()
|
||||
@insertSubviews ladderGame: (@level.get('type') is "ladder")
|
||||
@insertSubviews()
|
||||
@initVolume()
|
||||
@listenTo(@session, 'change:multiplayer', @onMultiplayerChanged)
|
||||
@originalSessionState = $.extend(true, {}, @session.get('state'))
|
||||
@register()
|
||||
@controlBar.setBus(@bus)
|
||||
|
||||
showGuide: ->
|
||||
@seenDocs = true
|
||||
DocsModal = require './level/modal/docs_modal'
|
||||
options = {docs: @levelLoader.level.get('documentation'), supermodel: @supermodel}
|
||||
@openModalView(new DocsModal(options), true)
|
||||
Backbone.Mediator.subscribeOnce 'modal-closed', @onLevelLoaded, @
|
||||
return true
|
||||
|
||||
onLoaded: ->
|
||||
_.defer => @onLevelLoaded()
|
||||
|
||||
onLevelLoaded: ->
|
||||
return unless @levelLoader.progress() is 1 # double check, since closing the guide may trigger this early
|
||||
@loadingView.showReady()
|
||||
if window.currentModal and not window.currentModal.destroyed
|
||||
return Backbone.Mediator.subscribeOnce 'modal-closed', @onLevelLoaded, @
|
||||
|
||||
# Save latest level played in local storage
|
||||
if not (@levelLoader.level.get('type') in ['ladder', 'ladder-tutorial'])
|
||||
me.set('lastLevel', @levelID)
|
||||
me.save()
|
||||
@levelLoader.destroy()
|
||||
@levelLoader = null
|
||||
@initSurface()
|
||||
@initScriptManager()
|
||||
|
||||
grabLevelLoaderData: ->
|
||||
|
@ -212,7 +201,78 @@ module.exports = class PlayLevelView extends View
|
|||
# For now, ladderGame will disallow multiplayer, because session code combining doesn't play nice yet.
|
||||
@session.set 'multiplayer', false
|
||||
|
||||
onLevelStarted: (e) ->
|
||||
setupGod: ->
|
||||
@god.setLevel @level.serialize @supermodel
|
||||
@god.setLevelSessionIDs if @otherSession then [@session.id, @otherSession.id] else [@session.id]
|
||||
@god.setWorldClassMap @world.classMap
|
||||
|
||||
setTeam: (team) ->
|
||||
team = team?.team unless _.isString team
|
||||
team ?= 'humans'
|
||||
me.team = team
|
||||
Backbone.Mediator.publish 'level:team-set', team: team
|
||||
|
||||
initGoalManager: ->
|
||||
@goalManager = new GoalManager(@world, @level.get('goals'))
|
||||
@god.setGoalManager @goalManager
|
||||
|
||||
insertSubviews: ->
|
||||
@insertSubView @tome = new TomeView levelID: @levelID, session: @session, thangs: @world.thangs, supermodel: @supermodel
|
||||
@insertSubView new PlaybackView session: @session
|
||||
@insertSubView new GoalsView {}
|
||||
@insertSubView new GoldView {}
|
||||
@insertSubView new HUDView {}
|
||||
@insertSubView new ChatView levelID: @levelID, sessionID: @session.id, session: @session
|
||||
worldName = utils.i18n @level.attributes, 'name'
|
||||
@controlBar = @insertSubView new ControlBarView {worldName: worldName, session: @session, level: @level, supermodel: @supermodel, playableTeams: @world.playableTeams}
|
||||
#Backbone.Mediator.publish('level-set-debug', debug: true) if me.displayName() is 'Nick!'
|
||||
|
||||
initVolume: ->
|
||||
volume = me.get('volume')
|
||||
volume = 1.0 unless volume?
|
||||
Backbone.Mediator.publish 'level-set-volume', volume: volume
|
||||
|
||||
initScriptManager: ->
|
||||
@scriptManager = new ScriptManager({scripts: @world.scripts or [], view:@, session: @session})
|
||||
@scriptManager.loadFromSession()
|
||||
|
||||
register: ->
|
||||
@bus = LevelBus.get(@levelID, @session.id)
|
||||
@bus.setSession(@session)
|
||||
@bus.setSpells @tome.spells
|
||||
@bus.connect() if @session.get('multiplayer')
|
||||
|
||||
# Load Completed Setup ######################################################
|
||||
|
||||
onLoaded: ->
|
||||
_.defer => @onLevelLoaded()
|
||||
|
||||
onLevelLoaded: ->
|
||||
# Everything is now loaded
|
||||
return unless @levelLoader.progress() is 1 # double check, since closing the guide may trigger this early
|
||||
@loadingView.showReady()
|
||||
if window.currentModal and not window.currentModal.destroyed
|
||||
return Backbone.Mediator.subscribeOnce 'modal-closed', @onLevelLoaded, @
|
||||
|
||||
# Save latest level played in local storage
|
||||
if not (@levelLoader.level.get('type') in ['ladder', 'ladder-tutorial'])
|
||||
me.set('lastLevel', @levelID)
|
||||
me.save()
|
||||
@levelLoader.destroy()
|
||||
@levelLoader = null
|
||||
@initSurface()
|
||||
|
||||
initSurface: ->
|
||||
surfaceCanvas = $('canvas#surface', @$el)
|
||||
@surface = new Surface(@world, surfaceCanvas, thangTypes: @supermodel.getModels(ThangType), playJingle: not @isEditorPreview)
|
||||
worldBounds = @world.getBounds()
|
||||
bounds = [{x:worldBounds.left, y:worldBounds.top}, {x:worldBounds.right, y:worldBounds.bottom}]
|
||||
@surface.camera.setBounds(bounds)
|
||||
@surface.camera.zoomTo({x:0, y:0}, 0.1, 0)
|
||||
|
||||
# Once Surface is Loaded ####################################################
|
||||
|
||||
onLevelStarted: ->
|
||||
@surface.showLevel()
|
||||
if @otherSession
|
||||
# TODO: colorize name and cloud by team, colorize wizard by user's color config
|
||||
|
@ -229,34 +289,17 @@ module.exports = class PlayLevelView extends View
|
|||
application.tracker?.trackEvent 'Finished Level Load', level: @levelID, label: @levelID, loadDuration: loadDuration
|
||||
application.tracker?.trackTiming loadDuration, 'Level Load Time', @levelID, @levelID
|
||||
|
||||
onSupermodelLoadedOne: =>
|
||||
@modelsLoaded ?= 0
|
||||
@modelsLoaded += 1
|
||||
@updateInitString()
|
||||
|
||||
updateInitString: ->
|
||||
return if @surface
|
||||
@modelsLoaded ?= 0
|
||||
canvas = @$el.find('#surface')[0]
|
||||
ctx = canvas.getContext('2d')
|
||||
ctx.font="20px Georgia"
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height)
|
||||
ctx.fillText("Loaded #{@modelsLoaded} thingies",50,50)
|
||||
|
||||
insertSubviews: ->
|
||||
@insertSubView @tome = new TomeView levelID: @levelID, session: @session, thangs: @world.thangs, supermodel: @supermodel
|
||||
@insertSubView new PlaybackView session: @session
|
||||
@insertSubView new GoalsView {}
|
||||
@insertSubView new GoldView {}
|
||||
@insertSubView new HUDView {}
|
||||
@insertSubView new ChatView levelID: @levelID, sessionID: @session.id, session: @session
|
||||
worldName = utils.i18n @level.attributes, 'name'
|
||||
@controlBar = @insertSubView new ControlBarView {worldName: worldName, session: @session, level: @level, supermodel: @supermodel, playableTeams: @world.playableTeams}
|
||||
#Backbone.Mediator.publish('level-set-debug', debug: true) if me.displayName() is 'Nick!'
|
||||
|
||||
afterInsert: ->
|
||||
super()
|
||||
@showWizardSettingsModal() if not me.get('name')
|
||||
onSurfaceSetUpNewWorld: ->
|
||||
return if @alreadyLoadedState
|
||||
@alreadyLoadedState = true
|
||||
state = @originalSessionState
|
||||
if state.frame and @level.get('type') isnt 'ladder' # https://github.com/codecombat/codecombat/issues/714
|
||||
Backbone.Mediator.publish 'level-set-time', { time: 0, frameOffset: state.frame }
|
||||
if state.selected
|
||||
# TODO: Should also restore selected spell here by saving spellName
|
||||
Backbone.Mediator.publish 'level-select-sprite', { thangID: state.selected, spellName: null }
|
||||
if state.playing?
|
||||
Backbone.Mediator.publish 'level-set-playing', { playing: state.playing }
|
||||
|
||||
# callbacks
|
||||
|
||||
|
@ -412,46 +455,11 @@ module.exports = class PlayLevelView extends View
|
|||
@bus.removeFirebaseData =>
|
||||
@bus.disconnect()
|
||||
|
||||
# initialization
|
||||
|
||||
addPointer: ->
|
||||
p = $('#pointer')
|
||||
return if p.length
|
||||
@$el.append($('<img src="/images/level/pointer.png" id="pointer">'))
|
||||
|
||||
initSurface: ->
|
||||
surfaceCanvas = $('canvas#surface', @$el)
|
||||
@surface = new Surface(@world, surfaceCanvas, thangTypes: @supermodel.getModels(ThangType), playJingle: not @isEditorPreview)
|
||||
worldBounds = @world.getBounds()
|
||||
bounds = [{x:worldBounds.left, y:worldBounds.top}, {x:worldBounds.right, y:worldBounds.bottom}]
|
||||
@surface.camera.setBounds(bounds)
|
||||
@surface.camera.zoomTo({x:0, y:0}, 0.1, 0)
|
||||
|
||||
initGoalManager: ->
|
||||
@goalManager = new GoalManager(@world, @level.get('goals'))
|
||||
@god.setGoalManager @goalManager
|
||||
|
||||
initScriptManager: ->
|
||||
@scriptManager = new ScriptManager({scripts: @world.scripts or [], view:@, session: @session})
|
||||
@scriptManager.loadFromSession()
|
||||
|
||||
initVolume: ->
|
||||
volume = me.get('volume')
|
||||
volume = 1.0 unless volume?
|
||||
Backbone.Mediator.publish 'level-set-volume', volume: volume
|
||||
|
||||
onSurfaceSetUpNewWorld: ->
|
||||
return if @alreadyLoadedState
|
||||
@alreadyLoadedState = true
|
||||
state = @originalSessionState
|
||||
if state.frame and @level.get('type') isnt 'ladder' # https://github.com/codecombat/codecombat/issues/714
|
||||
Backbone.Mediator.publish 'level-set-time', { time: 0, frameOffset: state.frame }
|
||||
if state.selected
|
||||
# TODO: Should also restore selected spell here by saving spellName
|
||||
Backbone.Mediator.publish 'level-select-sprite', { thangID: state.selected, spellName: null }
|
||||
if state.playing?
|
||||
Backbone.Mediator.publish 'level-set-playing', { playing: state.playing }
|
||||
|
||||
preloadNextLevel: =>
|
||||
# TODO: Loading models in the middle of gameplay causes stuttering. Most of the improvement in loading time is simply from passing the supermodel from this level to the next, but if we can find a way to populate the level early without it being noticeable, that would be even better.
|
||||
# return if @destroyed
|
||||
|
@ -460,12 +468,6 @@ module.exports = class PlayLevelView extends View
|
|||
# @supermodel.populateModel nextLevel
|
||||
# @preloaded = true
|
||||
|
||||
register: ->
|
||||
@bus = LevelBus.get(@levelID, @session.id)
|
||||
@bus.setSession(@session)
|
||||
@bus.setSpells @tome.spells
|
||||
@bus.connect() if @session.get('multiplayer')
|
||||
|
||||
onSessionWillSave: (e) ->
|
||||
# Something interesting has happened, so (at a lower frequency), we'll save a screenshot.
|
||||
#@saveScreenshot e.session
|
||||
|
@ -475,12 +477,6 @@ module.exports = class PlayLevelView extends View
|
|||
return unless screenshot = @surface?.screenshot()
|
||||
session.save {screenshot: screenshot}, {patch: true}
|
||||
|
||||
setTeam: (team) ->
|
||||
team = team?.team unless _.isString team
|
||||
team ?= 'humans'
|
||||
me.team = team
|
||||
Backbone.Mediator.publish 'level:team-set', team: team
|
||||
|
||||
# Dynamic sound loading
|
||||
|
||||
onNewWorld: (e) ->
|
||||
|
|
|
@ -121,7 +121,7 @@ module.exports = class Handler
|
|||
@modelClass.findOne(criteria, project).sort(sort).exec (err, document) ->
|
||||
return done(err) if err
|
||||
callback(null, document?.toObject() or null)
|
||||
|
||||
|
||||
funcs = {}
|
||||
for id in ids
|
||||
return errors.badInput(res, "Given an invalid id: #{id}") unless Handler.isID(id)
|
||||
|
|
|
@ -103,7 +103,7 @@ module.exports.getTwoGames = (req, res) ->
|
|||
#if userIsAnonymous req then return errors.unauthorized(res, "You need to be logged in to get games.")
|
||||
humansGameID = req.body.humansGameID
|
||||
ogresGameID = req.body.ogresGameID
|
||||
|
||||
|
||||
unless ogresGameID and humansGameID
|
||||
#fetch random games here
|
||||
queryParams =
|
||||
|
@ -185,6 +185,7 @@ module.exports.recordTwoGames = (req, res) ->
|
|||
sendResponseObject req, res, {"message":"The single game was submitted successfully!"}
|
||||
|
||||
|
||||
|
||||
module.exports.createNewTask = (req, res) ->
|
||||
requestSessionID = req.body.session
|
||||
originalLevelID = req.body.originalLevelID
|
||||
|
@ -274,7 +275,7 @@ fetchInitialSessionsToRankAgainst = (levelMajorVersion, levelID, submittedSessio
|
|||
submittedCode:
|
||||
$exists: true
|
||||
team: opposingTeam
|
||||
|
||||
|
||||
sortParameters =
|
||||
totalScore: 1
|
||||
|
||||
|
@ -723,9 +724,7 @@ retrieveOldSessionData = (sessionID, callback) ->
|
|||
"totalScore":session.totalScore ? (25 - 1.8*(25/3))
|
||||
"id": sessionID
|
||||
callback err, oldScoreObject
|
||||
|
||||
markSessionAsDoneRanking = (sessionID, cb) ->
|
||||
|
||||
markSessionAsDoneRanking = (sessionID, cb) ->
|
||||
#console.log "Marking session as done ranking..."
|
||||
LevelSession.update {"_id":sessionID}, {"isRanking":false}, cb
|
||||
|
||||
|
||||
|
|
|
@ -91,8 +91,8 @@ setupFallbackRouteToIndex = (app) ->
|
|||
sendMain = (req, res) ->
|
||||
fs.readFile path.join(__dirname, 'public', 'main.html'), 'utf8', (err, data) ->
|
||||
log.error "Error modifying main.html: #{err}" if err
|
||||
# insert the user object directly into the html so the application can have it immediately
|
||||
data = data.replace('"userObjectTag"', JSON.stringify(UserHandler.formatEntity(req, req.user)))
|
||||
# insert the user object directly into the html so the application can have it immediately. Sanitize </script>
|
||||
data = data.replace('"userObjectTag"', JSON.stringify(UserHandler.formatEntity(req, req.user)).replace('/', '\\/'))
|
||||
res.send data
|
||||
|
||||
setupFacebookCrossDomainCommunicationRoute = (app) ->
|
||||
|
|