diff --git a/README.md b/README.md index d6e11e265..0e451ff48 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,7 @@ so we can accept your pull requests. It is easy. ![Josh Callebaut](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Josh%20Callebaut/josh_callebaut_100.png "Josh Callebaut") ![Michael Schmatz](http://codecombat.com/images/pages/about/michael_small.png "Michael Schmatz") ![Josh Lee](http://codecombat.com/images/pages/about/josh_small.png "Josh Lee") +![Dan TDM](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Dan_TDM/dan_tdm_100.png "Dan TDM") ![Alex Cotsarelis](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Alex%20Cotsarelis/alex_100.png "Alex Cotsarelis") ![Alex Crooks](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Alex%20Crooks/alex_100.png "Alex Crooks") ![Alexandru Caciulescu](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/avatars/Alexandru%20Caciulescu/alexandru_100.png "Alexandru Caciulescu") diff --git a/app/collections/LevelSessions.coffee b/app/collections/LevelSessions.coffee index dbbc343a5..20de80e42 100644 --- a/app/collections/LevelSessions.coffee +++ b/app/collections/LevelSessions.coffee @@ -5,12 +5,6 @@ module.exports = class LevelSessionCollection extends CocoCollection url: '/db/level.session' model: LevelSession - fetchMineForCourseInstance: (courseInstanceID, options) -> - options = _.extend({ - url: "/db/course_instance/#{courseInstanceID}/my-course-level-sessions" - }, options) - @fetch(options) - fetchForCourseInstance: (courseInstanceID, options) -> options = _.extend({ url: "/db/course_instance/#{courseInstanceID}/my-course-level-sessions" diff --git a/app/lib/LevelLoader.coffee b/app/lib/LevelLoader.coffee index 3a1bb39c3..24feca40f 100644 --- a/app/lib/LevelLoader.coffee +++ b/app/lib/LevelLoader.coffee @@ -478,7 +478,7 @@ module.exports = class LevelLoader extends CocoClass @world.difficulty = @session?.get('state')?.difficulty ? 0 if @observing @world.difficulty = Math.max 0, @world.difficulty - 1 # Show the difficulty they won, not the next one. - serializedLevel = @level.serialize(@supermodel, @session, @opponentSession) + serializedLevel = @level.serialize {@supermodel, @session, @opponentSession, @headless, @sessionless} @world.loadFromLevel serializedLevel, false console.log 'World has been initialized from level loader.' if LOG diff --git a/app/lib/simulator/Simulator.coffee b/app/lib/simulator/Simulator.coffee index 473ea06af..16e48dd6a 100644 --- a/app/lib/simulator/Simulator.coffee +++ b/app/lib/simulator/Simulator.coffee @@ -226,7 +226,7 @@ module.exports = class Simulator extends CocoClass @levelLoader = null setupGod: -> - @god.setLevel @level.serialize(@supermodel, @session, @otherSession) + @god.setLevel @level.serialize {@supermodel, @session, @otherSession, headless: true, sessionless: false} @god.setLevelSessionIDs (session.sessionID for session in @task.getSessions()) @god.setWorldClassMap @world.classMap @god.setGoalManager new GoalManager @world, @level.get('goals'), null, {headless: true} diff --git a/app/models/Level.coffee b/app/models/Level.coffee index 8df696750..77c4ff84c 100644 --- a/app/models/Level.coffee +++ b/app/models/Level.coffee @@ -12,7 +12,8 @@ module.exports = class Level extends CocoModel urlRoot: '/db/level' editableByArtisans: true - serialize: (supermodel, session, otherSession, cached=false) -> + serialize: (options) -> + {supermodel, session, otherSession, @headless, @sessionless, cached=false} = options o = @denormalize supermodel, session, otherSession # hot spot to optimize # Figure out Components @@ -146,7 +147,7 @@ module.exports = class Level extends CocoModel levelThang.components.push placeholderComponent # Load the user's chosen hero AFTER getting stats from default char - if /Hero Placeholder/.test(levelThang.id) and @get('type', true) in ['course'] + if /Hero Placeholder/.test(levelThang.id) and @get('type', true) in ['course'] and not @headless and not @sessionless heroThangType = me.get('heroConfig')?.thangType or ThangType.heroes.captain levelThang.thangType = heroThangType if heroThangType diff --git a/app/schemas/models/level_session.coffee b/app/schemas/models/level_session.coffee index 339d1f491..95be39816 100644 --- a/app/schemas/models/level_session.coffee +++ b/app/schemas/models/level_session.coffee @@ -54,7 +54,7 @@ _.extend LevelSessionSchema.properties, changed: c.date title: 'Changed' readOnly: true - + dateFirstCompleted: {} # c.stringDate # title: 'Completed' # readOnly: true @@ -62,9 +62,6 @@ _.extend LevelSessionSchema.properties, team: c.shortString() level: LevelSessionLevelSchema - screenshot: - type: 'string' - heroConfig: c.HeroConfigSchema state: c.object {}, @@ -208,14 +205,6 @@ _.extend LevelSessionSchema.properties, submittedCodeLanguage: type: 'string' - transpiledCode: - type: 'object' - additionalProperties: - type: 'object' - additionalProperties: - type: 'string' - format: 'code' - isRanking: type: 'boolean' description: 'Whether this session is still in the first ranking chain after being submitted.' diff --git a/app/styles/admin/level_sessions.sass b/app/styles/admin/level_sessions.sass deleted file mode 100644 index b84a7813e..000000000 --- a/app/styles/admin/level_sessions.sass +++ /dev/null @@ -1,14 +0,0 @@ -#admin-level-sessions-view - .session_tile - display: inline-block - position: relative - margin: 8px - - .session_info - position: absolute - top: 0 - left: 0 - right: 0 - text-align: center - background: rgba(0, 0, 0, 0.5) - color: white diff --git a/app/templates/admin.jade b/app/templates/admin.jade index 4a507a440..cd323fc39 100644 --- a/app/templates/admin.jade +++ b/app/templates/admin.jade @@ -30,8 +30,6 @@ block content h4 Entities ul - li - a(href="/admin/level-sessions") Active Instances li a(href="/admin/trial-requests") Trial Requests li diff --git a/app/templates/admin/level_sessions.jade b/app/templates/admin/level_sessions.jade deleted file mode 100644 index 6d36de660..000000000 --- a/app/templates/admin/level_sessions.jade +++ /dev/null @@ -1,17 +0,0 @@ -extends /templates/base - -block content - - h1 Latest Games - - each session in view.sessions.models - - var url = '/play/level/'+session.get('levelID')+'?session='+session.id - .session_tile - a(href=url) - if session.get('screenshot') - img(src=session.get('screenshot')) - else - img(src="/images/generic-icon.png") - .session_info - .level_name= session.get('levelName') - .creator_name= session.get('creatorName') diff --git a/app/templates/editor/level/edit.jade b/app/templates/editor/level/edit.jade index 5496527d0..e64012f06 100644 --- a/app/templates/editor/level/edit.jade +++ b/app/templates/editor/level/edit.jade @@ -132,8 +132,9 @@ block outer_content div.tab-pane#editor-level-tasks-tab-view - div.tab-pane#editor-level-patches - .patches-view + div.tab-pane#editor-level-patches.nano + .nano-content + .patches-view div.tab-pane#related-achievements-view diff --git a/app/views/admin/AnalyticsView.coffee b/app/views/admin/AnalyticsView.coffee index 591a174a5..c38e9ba28 100644 --- a/app/views/admin/AnalyticsView.coffee +++ b/app/views/admin/AnalyticsView.coffee @@ -83,21 +83,21 @@ module.exports = class AnalyticsView extends RootView campaignDauTotal += count else if event.indexOf('DAU classroom') >= 0 classroomDauTotal += count - eventMap[event] = true; + eventMap[event] = true entry.events['DAU campaign total'] = campaignDauTotal - eventMap['DAU campaign total'] = true; + eventMap['DAU campaign total'] = true campaignDauTotals.unshift(campaignDauTotal) campaignDauTotals.pop() while campaignDauTotals.length > 30 if campaignDauTotals.length is 30 entry.events['DAU campaign 30-day average'] = Math.round(_.reduce(campaignDauTotals, (a, b) -> a + b) / 30) - eventMap['DAU campaign 30-day average'] = true; + eventMap['DAU campaign 30-day average'] = true entry.events['DAU classroom total'] = classroomDauTotal - eventMap['DAU classroom total'] = true; + eventMap['DAU classroom total'] = true classroomDauTotals.unshift(classroomDauTotal) classroomDauTotals.pop() while classroomDauTotals.length > 30 if classroomDauTotals.length is 30 entry.events['DAU classroom 30-day average'] = Math.round(_.reduce(classroomDauTotals, (a, b) -> a + b) / 30) - eventMap['DAU classroom 30-day average'] = true; + eventMap['DAU classroom 30-day average'] = true @activeUsers.sort (a, b) -> b.day.localeCompare(a.day) @activeUserEventNames = Object.keys(eventMap) diff --git a/app/views/admin/LevelSessionsView.coffee b/app/views/admin/LevelSessionsView.coffee deleted file mode 100644 index bd19ac763..000000000 --- a/app/views/admin/LevelSessionsView.coffee +++ /dev/null @@ -1,19 +0,0 @@ -RootView = require 'views/core/RootView' -template = require 'templates/admin/level_sessions' -LevelSession = require 'models/LevelSession' -CocoCollection = require 'collections/CocoCollection' - -class LevelSessionCollection extends CocoCollection - url: '/db/level.session/x/active?project=screenshot,levelName,creatorName' - model: LevelSession - -module.exports = class LevelSessionsView extends RootView - id: 'admin-level-sessions-view' - template: template - - constructor: (options) -> - super options - @getLevelSessions() - - getLevelSessions: -> - @sessions = @supermodel.loadCollection(new LevelSessionCollection(), 'sessions', {cache: false}).model diff --git a/app/views/admin/MainAdminView.coffee b/app/views/admin/MainAdminView.coffee index 97aab328b..dd4b33b32 100644 --- a/app/views/admin/MainAdminView.coffee +++ b/app/views/admin/MainAdminView.coffee @@ -23,6 +23,7 @@ module.exports = class MainAdminView extends RootView 'submit #user-search-form': 'onSubmitUserSearchForm' 'click #stop-spying-btn': 'onClickStopSpyingButton' 'click #increment-button': 'incrementUserAttribute' + 'click .user-spy-button': 'onClickUserSpyButton' 'click #user-search-result': 'onClickUserSearchResult' 'click #create-free-sub-btn': 'onClickFreeSubLink' 'click #terminal-create': 'onClickTerminalSubLink' @@ -59,6 +60,18 @@ module.exports = class MainAdminView extends RootView errors.showNotyNetworkError(arguments...) }) + onClickUserSpyButton: (e) -> + e.stopPropagation() + userID = $(e.target).closest('tr').data('user-id') + button = $(e.currentTarget) + forms.disableSubmit(button) + me.spy(userID, { + success: -> window.location.reload() + error: -> + forms.enableSubmit(button) + errors.showNotyNetworkError(arguments...) + }) + onSubmitUserSearchForm: (e) -> e.preventDefault() searchValue = @$el.find('#user-search').val() @@ -76,7 +89,7 @@ module.exports = class MainAdminView extends RootView forms.enableSubmit(@$('#user-search-button')) result = '' if users.length - result = ("#{user._id}#{_.escape(user.name or 'Anonymous')}#{_.escape(user.email)}" for user in users) + result = ("#{user._id}#{_.escape(user.name or 'Anonymous')}#{_.escape(user.email)}" for user in users) result = "#{result.join('\n')}
" @$el.find('#user-search-result').html(result) diff --git a/app/views/editor/level/thangs/ThangsTabView.coffee b/app/views/editor/level/thangs/ThangsTabView.coffee index 4dd28b836..1e794a40d 100644 --- a/app/views/editor/level/thangs/ThangsTabView.coffee +++ b/app/views/editor/level/thangs/ThangsTabView.coffee @@ -595,7 +595,7 @@ module.exports = class ThangsTabView extends CocoView @level.set 'thangs', thangs return if @editThangView return if skipSerialization - serializedLevel = @level.serialize @supermodel, null, null, true + serializedLevel = @level.serialize {@supermodel, session: null, otherSession: null, headless: false, sessionless: true, cached: true} try @world.loadFromLevel serializedLevel, false catch error diff --git a/app/views/editor/verifier/VerifierTest.coffee b/app/views/editor/verifier/VerifierTest.coffee index 7c84e7389..926ed1dee 100644 --- a/app/views/editor/verifier/VerifierTest.coffee +++ b/app/views/editor/verifier/VerifierTest.coffee @@ -25,9 +25,9 @@ module.exports = class VerifierTest extends CocoClass @loadStartTime = new Date() @god = new God maxAngels: 1, headless: true @levelLoader = new LevelLoader supermodel: @supermodel, levelID: @levelID, headless: true, fakeSessionConfig: {codeLanguage: @language, callback: @configureSession} - @listenToOnce @levelLoader, 'world-necessities-loaded', @onWorldNecessitiesLoaded + @listenToOnce @levelLoader, 'world-necessities-loaded', -> _.defer @onWorldNecessitiesLoaded - onWorldNecessitiesLoaded: -> + onWorldNecessitiesLoaded: => # Called when we have enough to build the world, but not everything is loaded @grabLevelLoaderData() @@ -62,7 +62,7 @@ module.exports = class VerifierTest extends CocoClass @solution = @levelLoader.session.solution setupGod: -> - @god.setLevel @level.serialize @supermodel, @session + @god.setLevel @level.serialize {@supermodel, @session, otherSession: null, headless: true, sessionless: false} @god.setLevelSessionIDs [@session.id] @god.setWorldClassMap @world.classMap @god.lastFlagHistory = @session.get('state').flagHistory @@ -134,8 +134,10 @@ module.exports = class VerifierTest extends CocoClass setTimeout @cleanup, 100 cleanup: => + if @levelLoader + @stopListening @levelLoader + @levelLoader.destroy() if @god @stopListening @god @god.destroy() - @world = null diff --git a/app/views/ladder/LadderView.coffee b/app/views/ladder/LadderView.coffee index b2bb6e9c6..d192a892a 100644 --- a/app/views/ladder/LadderView.coffee +++ b/app/views/ladder/LadderView.coffee @@ -42,6 +42,7 @@ module.exports = class LadderView extends RootView initialize: (options, @levelID, @leagueType, @leagueID) -> @level = @supermodel.loadModel(new Level(_id: @levelID)).model @level.once 'sync', => + return if @destroyed @levelDescription = marked(@level.get('description')) if @level.get('description') @teams = teamDataFromLevel @level @sessions = @supermodel.loadCollection(new LevelSessionsCollection(@levelID), 'your_sessions', {cache: false}).model diff --git a/app/views/play/SpectateView.coffee b/app/views/play/SpectateView.coffee index 769f75324..272b69d5b 100644 --- a/app/views/play/SpectateView.coffee +++ b/app/views/play/SpectateView.coffee @@ -69,7 +69,7 @@ module.exports = class SpectateLevelView extends RootView @load() setLevel: (@level, @supermodel) -> - serializedLevel = @level.serialize @supermodel, @session, @otherSession + serializedLevel = @level.serialize {@supermodel, @session, @otherSession, headless: false, sessionless: false} @god?.setLevel serializedLevel if @world @world.loadFromLevel serializedLevel, false @@ -106,7 +106,7 @@ module.exports = class SpectateLevelView extends RootView #at this point, all requisite data is loaded, and sessions are not denormalized team = @world.teamForPlayer(0) @loadOpponentTeam(team) - @god.setLevel @level.serialize @supermodel, @session, @otherSession + @god.setLevel @level.serialize {@supermodel, @session, @otherSession, headless: false, sessionless: false} @god.setLevelSessionIDs if @otherSession then [@session.id, @otherSession.id] else [@session.id] @god.setWorldClassMap @world.classMap @setTeam team diff --git a/app/views/play/level/PlayLevelView.coffee b/app/views/play/level/PlayLevelView.coffee index b764b6251..45340f0d7 100644 --- a/app/views/play/level/PlayLevelView.coffee +++ b/app/views/play/level/PlayLevelView.coffee @@ -69,7 +69,6 @@ module.exports = class PlayLevelView extends RootView 'god:infinite-loop': 'onInfiniteLoop' 'level:reload-from-data': 'onLevelReloadFromData' 'level:reload-thang-type': 'onLevelReloadThangType' - 'level:session-will-save': 'onSessionWillSave' 'level:started': 'onLevelStarted' 'level:loading-view-unveiling': 'onLoadingViewUnveiling' 'level:loading-view-unveiled': 'onLoadingViewUnveiled' @@ -112,7 +111,6 @@ module.exports = class PlayLevelView extends RootView @gameUIState = new GameUIState() $(window).on 'resize', @onWindowResize - @saveScreenshot = _.throttle @saveScreenshot, 30000 application.tracker?.enableInspectletJS(@levelID) @@ -130,7 +128,7 @@ module.exports = class PlayLevelView extends RootView @supermodel.collections = givenSupermodel.collections @supermodel.shouldSaveBackups = givenSupermodel.shouldSaveBackups - serializedLevel = @level.serialize @supermodel, @session, @otherSession + serializedLevel = @level.serialize {@supermodel, @session, @otherSession, headless: false, sessionless: false} @god?.setLevel serializedLevel if @world @world.loadFromLevel serializedLevel, false @@ -246,7 +244,7 @@ module.exports = class PlayLevelView extends RootView @session.set 'multiplayer', false setupGod: -> - @god.setLevel @level.serialize @supermodel, @session, @otherSession + @god.setLevel @level.serialize {@supermodel, @session, @otherSession, headless: false, sessionless: false} @god.setLevelSessionIDs if @otherSession then [@session.id, @otherSession.id] else [@session.id] @god.setWorldClassMap @world.classMap @@ -594,15 +592,6 @@ module.exports = class PlayLevelView extends RootView @bus.removeFirebaseData => @bus.disconnect() - onSessionWillSave: (e) -> - # Something interesting has happened, so (at a lower frequency), we'll save a screenshot. - #@saveScreenshot e.session - - # Throttled - saveScreenshot: (session) => - return unless screenshot = @surface?.screenshot() - session.save {screenshot: screenshot}, {patch: true, type: 'PUT'} - onContactClicked: (e) -> Backbone.Mediator.publish 'level:contact-button-pressed', {} @openModalView contactModal = new ContactModal levelID: @level.get('slug') or @level.id, courseID: @courseID, courseInstanceID: @courseInstanceID @@ -954,20 +943,6 @@ module.exports = class PlayLevelView extends RootView console.error 'Failed to read sessionState in onRealTimeMultiplayerCast' console.info 'Submitting my code' - # Transpiling code copied from scripts/transpile.coffee - # TODO: Should this live somewhere else? - transpiledCode = {} - for thang, spells of @session.get('code') - transpiledCode[thang] = {} - for spellID, spell of spells - spellName = thang + '/' + spellID - continue if @session.get('teamSpells') and not (spellName in @session.get('teamSpells')[@session.get('team')]) - # console.log "PlayLevelView Transpiling spell #{spellName}" - aetherOptions = createAetherOptions functionName: spellID, codeLanguage: @session.get('submittedCodeLanguage'), includeFlow: true - aether = new Aether aetherOptions - transpiledCode[thang][spellID] = aether.transpile spell - # console.log "PlayLevelView transpiled code", transpiledCode - @session.set 'transpiledCode', transpiledCode permissions = @session.get 'permissions' ? [] unless _.find(permissions, (p) -> p.target is 'public' and p.access is 'read') permissions.push target:'public', access:'read' diff --git a/app/views/play/level/modal/CourseVictoryModal.coffee b/app/views/play/level/modal/CourseVictoryModal.coffee index 60c68d716..8df142bd1 100644 --- a/app/views/play/level/modal/CourseVictoryModal.coffee +++ b/app/views/play/level/modal/CourseVictoryModal.coffee @@ -1,15 +1,9 @@ ModalView = require 'views/core/ModalView' template = require 'templates/play/level/modal/course-victory-modal' -Achievements = require 'collections/Achievements' Level = require 'models/Level' Course = require 'models/Course' -ThangType = require 'models/ThangType' -ThangTypes = require 'collections/ThangTypes' LevelSessions = require 'collections/LevelSessions' -EarnedAchievement = require 'models/EarnedAchievement' -LocalMongo = require 'lib/LocalMongo' ProgressView = require './ProgressView' -NewItemView = require './NewItemView' Classroom = require 'models/Classroom' utils = require 'core/utils' @@ -18,7 +12,6 @@ module.exports = class CourseVictoryModal extends ModalView template: template closesOnClickOutside: false - initialize: (options) -> @courseID = options.courseID @courseInstanceID = options.courseInstanceID @@ -26,20 +19,10 @@ module.exports = class CourseVictoryModal extends ModalView @session = options.session @level = options.level - @newItems = new ThangTypes() - @newHeroes = new ThangTypes() - + if @courseInstanceID @classroom = new Classroom() @supermodel.trackRequest(@classroom.fetchForCourseInstance(@courseInstanceID)) - @achievements = options.achievements - if not @achievements - @achievements = new Achievements() - @achievements.fetchRelatedToLevel(@session.get('level').original) - @achievements = @supermodel.loadCollection(@achievements, 'achievements').model - @listenToOnce @achievements, 'sync', @onAchievementsLoaded - else - @onAchievementsLoaded() @playSound 'victory' @nextLevel = new Level() @@ -68,69 +51,12 @@ module.exports = class CourseVictoryModal extends ModalView return super(arguments...) - - onAchievementsLoaded: -> - @achievements.models = _.filter @achievements.models, (m) -> not m.get('query')?.ladderAchievementDifficulty # Don't show higher AI difficulty achievements - itemOriginals = [] - heroOriginals = [] - achievementIDs = [] - for achievement in @achievements.models - rewards = achievement.get('rewards') or {} - heroOriginals.push rewards.heroes or [] - itemOriginals.push rewards.items or [] - achievement.completed = LocalMongo.matchesQuery(@session.attributes, achievement.get('query')) - achievementIDs.push(achievement.id) if achievement.completed - - itemOriginals = _.uniq _.flatten itemOriginals - heroOriginals = _.uniq _.flatten heroOriginals - #project = ['original', 'rasterIcon', 'name', 'soundTriggers', 'i18n'] # This is what we need, but the PlayHeroesModal needs more, and so we load more to fill up the supermodel. - project = ['original', 'rasterIcon', 'name', 'slug', 'soundTriggers', 'featureImages', 'gems', 'heroClass', 'description', 'components', 'extendedName', 'unlockLevelName', 'i18n'] - for [newThangTypeCollection, originals] in [[@newItems, itemOriginals], [@newHeroes, heroOriginals]] - for original in originals - thang= new ThangType() - thang.url = "/db/thang.type/#{original}/version" - thang.project = project - @supermodel.loadModel(thang) - newThangTypeCollection.add(thang) - - @newEarnedAchievements = [] - for achievement in @achievements.models - continue unless achievement.completed - ea = new EarnedAchievement({ - collection: achievement.get('collection') - triggeredBy: @session.id - achievement: achievement.id - }) - if me.isSessionless() - @newEarnedAchievements.push ea - else - ea.save() - # Can't just add models to supermodel because each ea has the same url - ea.sr = @supermodel.addSomethingResource(ea.cid) - @newEarnedAchievements.push ea - @listenToOnce ea, 'sync', (model) -> - model.sr.markLoaded() - if _.all((ea.id for ea in @newEarnedAchievements)) - unless me.loading - @supermodel.loadModel(me, {cache: false}) - @newEarnedAchievementsResource.markLoaded() - - unless me.isSessionless() - # have to use a something resource because addModelResource doesn't handle models being upserted/fetched via POST like we're doing here - @newEarnedAchievementsResource = @supermodel.addSomethingResource('earned achievements') if @newEarnedAchievements.length - - onLoaded: -> super() @views = [] - # TODO: Add main victory view - # TODO: Add level up view - # TODO: Add new hero view? - - for newItem in @newItems.models - @views.push(new NewItemView({item: newItem})) - + @levelSessions?.remove(@session) + @levelSessions?.add(@session) progressView = new ProgressView({ level: @level nextLevel: @nextLevel diff --git a/scripts/followupCloseIoLeads.js b/scripts/followupCloseIoLeads.js index bc8096dc0..31008e286 100644 --- a/scripts/followupCloseIoLeads.js +++ b/scripts/followupCloseIoLeads.js @@ -1,7 +1,7 @@ // Follow up on Close.io leads 'use strict'; -if (process.argv.length !== 7) { +if (process.argv.length !== 8) { log("Usage: node