From 1fc3cffdbffebc11cfcc603d266a2d32e95b58d1 Mon Sep 17 00:00:00 2001
From: Nathan Leniz <terakilobyte@gmail.com>
Date: Sun, 29 Mar 2015 20:39:41 +0900
Subject: [PATCH] Add .editorconfig to enforce certain automatic behavior on
 all editors, Add logic for ziplines and basejumps completion.

---
 .editorconfig                                |  15 +
 app.js                                       |   2 +
 controllers/bonfire.js                       |  91 ++--
 controllers/courseware.js                    |  66 +--
 models/User.js                               |   5 +-
 public/js/main.js                            | 679 +++++++++++++++------------
 views/bonfire/show.jade                      |  10 -
 views/coursewares/showHTML.jade              |   3 +-
 views/coursewares/showJS.jade                |   3 +-
 views/coursewares/showVideo.jade             |   5 +-
 views/coursewares/showZiplineOrBasejump.jade |  35 +-
 11 files changed, 481 insertions(+), 433 deletions(-)
 create mode 100644 .editorconfig

diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..13ef57c
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,15 @@
+root = true
+
+[*]
+indent_style = space
+end_of_line = lf
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
+
+[package.json]
+indent_style = space
+indent_size = 2
+
+[*.md]
+trim_trailing_whitespace = false
diff --git a/app.js b/app.js
index 6e9e087..a37089d 100644
--- a/app.js
+++ b/app.js
@@ -438,6 +438,8 @@ app.get(
     coursewareController.returnIndividualCourseware
 );
 app.post('/completed-courseware/', coursewareController.completedCourseware);
+app.post('/completed-zipline-or-basejump',
+  coursewareController.completedZiplineOrBasejump);
 
 // Unique Check API route
 app.get('/api/checkUniqueUsername/:username', userController.checkUniqueUsername);
diff --git a/controllers/bonfire.js b/controllers/bonfire.js
index 90a8bde..8e7a919 100644
--- a/controllers/bonfire.js
+++ b/controllers/bonfire.js
@@ -1,17 +1,9 @@
 var _ = require('lodash'),
-<<<<<<< HEAD
   debug = require('debug')('freecc:cntr:bonfires'),
   Bonfire = require('./../models/Bonfire'),
   User = require('./../models/User'),
   resources = require('./resources'),
-  R = require('ramda');
-=======
-    debug = require('debug')('freecc:cntr:bonfires'),
-    Bonfire = require('./../models/Bonfire'),
-    User = require('./../models/User'),
-    resources = require('./resources'),
-    MDNlinks = require('./../seed_data/bonfireMDNlinks');
->>>>>>> upstream/master
+  MDNlinks = require('./../seed_data/bonfireMDNlinks');
 
 /**
  * Bonfire controller
@@ -103,34 +95,11 @@ exports.returnIndividualBonfire = function(req, res, next) {
       return res.redirect('/bonfires');
     }
 
-<<<<<<< HEAD
     bonfire = bonfire.pop();
     var dashedNameFull = bonfire.name.toLowerCase().replace(/\s/g, '-');
     if (dashedNameFull != dashedName) {
       return res.redirect('../bonfires/' + dashedNameFull);
     }
-=======
-        res.render('bonfire/show', {
-            completedWith: null,
-            title: bonfire.name,
-            dashedName: dashedName,
-            name: bonfire.name,
-            difficulty: Math.floor(+bonfire.difficulty),
-            brief: bonfire.description[0],
-            details: bonfire.description.slice(1),
-            tests: bonfire.tests,
-            challengeSeed: bonfire.challengeSeed,
-            cc: !!req.user,
-            points: req.user ? req.user.points : undefined,
-            verb: resources.randomVerb(),
-            phrase: resources.randomPhrase(),
-            compliment: resources.randomCompliment(),
-            bonfires: bonfire,
-            bonfireHash: bonfire._id,
-            MDNkeys: bonfire.MDNlinks,
-            MDNlinks: getMDNlinks(bonfire.MDNlinks)
->>>>>>> upstream/master
-
     res.render('bonfire/show', {
       completedWith: null,
       title: bonfire.name,
@@ -142,12 +111,14 @@ exports.returnIndividualBonfire = function(req, res, next) {
       tests: bonfire.tests,
       challengeSeed: bonfire.challengeSeed,
       cc: !!req.user,
-      progressTimestamps: req.user ? req.user.progressTimestamps : undefined,
+      points: req.user ? req.user.points : undefined,
       verb: resources.randomVerb(),
       phrase: resources.randomPhrase(),
       compliment: resources.randomCompliment(),
       bonfires: bonfire,
-      bonfireHash: bonfire._id
+      bonfireHash: bonfire._id,
+      MDNkeys: bonfire.MDNlinks,
+      MDNlinks: getMDNlinks(bonfire.MDNlinks)
     });
   });
 };
@@ -189,18 +160,18 @@ function randomString() {
 
 /**
  * Helper function to populate the MDN links array.
-*/
+ */
 
 function getMDNlinks(links) {
-    // takes in an array of links, which are strings
-    var populatedLinks = [];
+  // takes in an array of links, which are strings
+  var populatedLinks = [];
 
-    // for each key value, push the corresponding link from the MDNlinks object into a new array
-    links.forEach(function(value, index) {
-        populatedLinks.push(MDNlinks[value]);
-    });
+  // for each key value, push the corresponding link from the MDNlinks object into a new array
+  links.forEach(function(value, index) {
+    populatedLinks.push(MDNlinks[value]);
+  });
 
-    return populatedLinks;
+  return populatedLinks;
 
 };
 
@@ -210,15 +181,15 @@ function getMDNlinks(links) {
 
 exports.testBonfire = function(req, res) {
   var bonfireName = req.body.name,
-      bonfireTests = req.body.tests,
-      bonfireDifficulty = req.body.difficulty,
-      bonfireDescription = req.body.description,
-      bonfireChallengeSeed = req.body.challengeSeed;
-      bonfireTests = bonfireTests.split('\r\n');
-      bonfireDescription = bonfireDescription.split('\r\n');
-      bonfireTests.filter(getRidOfEmpties);
-      bonfireDescription.filter(getRidOfEmpties);
-      bonfireChallengeSeed = bonfireChallengeSeed.replace('\r', '');
+    bonfireTests = req.body.tests,
+    bonfireDifficulty = req.body.difficulty,
+    bonfireDescription = req.body.description,
+    bonfireChallengeSeed = req.body.challengeSeed;
+  bonfireTests = bonfireTests.split('\r\n');
+  bonfireDescription = bonfireDescription.split('\r\n');
+  bonfireTests.filter(getRidOfEmpties);
+  bonfireDescription.filter(getRidOfEmpties);
+  bonfireChallengeSeed = bonfireChallengeSeed.replace('\r', '');
 
   res.render('bonfire/show', {
     completedWith: null,
@@ -251,15 +222,15 @@ exports.publicGenerator = function(req, res) {
 
 exports.generateChallenge = function(req, res) {
   var bonfireName = req.body.name,
-      bonfireTests = req.body.tests,
-      bonfireDifficulty = req.body.difficulty,
-      bonfireDescription = req.body.description,
-      bonfireChallengeSeed = req.body.challengeSeed;
-      bonfireTests = bonfireTests.split('\r\n');
-      bonfireDescription = bonfireDescription.split('\r\n');
-      bonfireTests.filter(getRidOfEmpties);
-      bonfireDescription.filter(getRidOfEmpties);
-      bonfireChallengeSeed = bonfireChallengeSeed.replace('\r', '');
+    bonfireTests = req.body.tests,
+    bonfireDifficulty = req.body.difficulty,
+    bonfireDescription = req.body.description,
+    bonfireChallengeSeed = req.body.challengeSeed;
+  bonfireTests = bonfireTests.split('\r\n');
+  bonfireDescription = bonfireDescription.split('\r\n');
+  bonfireTests.filter(getRidOfEmpties);
+  bonfireDescription.filter(getRidOfEmpties);
+  bonfireChallengeSeed = bonfireChallengeSeed.replace('\r', '');
 
 
   var response = {
diff --git a/controllers/courseware.js b/controllers/courseware.js
index f32e14b..5415868 100644
--- a/controllers/courseware.js
+++ b/controllers/courseware.js
@@ -100,7 +100,8 @@ exports.returnIndividualCourseware = function(req, res, next) {
           phrase: resources.randomPhrase(),
           compliment: resources.randomCompliment(),
           coursewareHash: courseware._id,
-          environment: resources.whichEnvironment()
+          environment: resources.whichEnvironment(),
+          challengeType: courseware.challengeType
         });
       },
 
@@ -117,7 +118,7 @@ exports.returnIndividualCourseware = function(req, res, next) {
           phrase: resources.randomPhrase(),
           compliment: resources.randomCompliment(),
           coursewareHash: courseware._id,
-
+          challengeType: courseware.challengeType
         });
       },
 
@@ -133,7 +134,7 @@ exports.returnIndividualCourseware = function(req, res, next) {
           phrase: resources.randomPhrase(),
           compliment: resources.randomCompliment(),
           coursewareHash: courseware._id,
-          challengeType: 'video'
+          challengeType: courseware.challengeType
         });
       },
 
@@ -160,16 +161,16 @@ exports.returnIndividualCourseware = function(req, res, next) {
 
 exports.testCourseware = function(req, res) {
   var coursewareName = req.body.name,
-  coursewareTests = req.body.tests,
-  coursewareDifficulty = req.body.difficulty,
-  coursewareDescription = req.body.description,
-  coursewareEntryPoint = req.body.challengeEntryPoint,
-  coursewareChallengeSeed = req.body.challengeSeed;
-  coursewareTests = coursewareTests.split('\r\n');
-  coursewareDescription = coursewareDescription.split('\r\n');
-  coursewareTests.filter(getRidOfEmpties);
-  coursewareDescription.filter(getRidOfEmpties);
-  coursewareChallengeSeed = coursewareChallengeSeed.replace('\r', '');
+      coursewareTests = req.body.tests,
+      coursewareDifficulty = req.body.difficulty,
+      coursewareDescription = req.body.description,
+      coursewareEntryPoint = req.body.challengeEntryPoint,
+      coursewareChallengeSeed = req.body.challengeSeed;
+      coursewareTests = coursewareTests.split('\r\n');
+      coursewareDescription = coursewareDescription.split('\r\n');
+      coursewareTests.filter(getRidOfEmpties);
+      coursewareDescription.filter(getRidOfEmpties);
+      coursewareChallengeSeed = coursewareChallengeSeed.replace('\r', '');
   res.render('courseware/show', {
     completedWith: null,
     title: coursewareName,
@@ -233,7 +234,9 @@ exports.completedCourseware = function (req, res, next) {
   req.user.completedCoursewares.push({
     _id: coursewareHash,
     completedDate: isCompletedDate,
-    name: req.body.coursewareInfo.coursewareName
+    name: req.body.coursewareInfo.coursewareName,
+    solution: null,
+    githubLink: null
   });
   var index = req.user.completedCoursewares.indexOf(coursewareHash);
 
@@ -247,19 +250,26 @@ exports.completedCourseware = function (req, res, next) {
       return next(err);
     }
     if (user) {
-      res.send(true);
+      res.sendStatus(200);
     }
   });
 };
 
 exports.completedZiplineOrBasejump = function (req, res, next) {
-  var isCompletedWith = req.body.bonfireInfo.completedWith || false;
+  debug('Inside controller for completed zipline or basejump with data %s',
+    req.body.coursewareInfo);
+  var isCompletedWith = req.body.coursewareInfo.completedWith || false;
   var isCompletedDate = Math.round(+new Date());
   var coursewareHash = req.body.coursewareInfo.coursewareHash;
-  var solutionLink = req.body.coursewareInfo.solutionLink;
-  if (!solutionLink) {
-    // flash error and redirect
-    return next(new Error('No solution provided'));
+  var solutionLink = req.body.coursewareInfo.publicURL;
+  var githubLink = req.body.coursewareInfo.challengeType === 4
+  ? req.body.coursewareInfo.githubURL : true;
+  if (!solutionLink || !githubLink) {
+    req.flash('errors', {
+      msg: 'You haven\'t supplied the necessary URLs for us to inspect ' +
+      'your work.'
+    });
+    return res.sendStatus(403);
   }
 
   if (isCompletedWith) {
@@ -286,14 +296,16 @@ exports.completedZiplineOrBasejump = function (req, res, next) {
           _id: coursewareHash,
           completedWith: req.user._id,
           completedDate: isCompletedDate,
-          solution: solutionLink
+          solution: solutionLink,
+          githubLink: githubLink
         });
 
         req.user.completedCoursewares.push({
           _id: coursewareHash,
           completedWith: pairedWith._id,
           completedDate: isCompletedDate,
-          solution: solutionLink
+          solution: solutionLink,
+          githubLink: githubLink
         });
 
         req.user.save(function (err, user) {
@@ -305,7 +317,7 @@ exports.completedZiplineOrBasejump = function (req, res, next) {
               return next(err);
             }
             if (user && paired) {
-              return res.send(true);
+              return res.sendStatus(200);
             }
           });
         });
@@ -317,10 +329,11 @@ exports.completedZiplineOrBasejump = function (req, res, next) {
       _id: coursewareHash,
       completedWith: null,
       completedDate: isCompletedDate,
-      solution: solutionLink
+      solution: solutionLink,
+      githubLink: githubLink
     });
 
-    var index = req.user.uncompletedCourse.indexOf(coursewareHash);
+    var index = req.user.uncompletedCoursewares.indexOf(coursewareHash);
     if (index > -1) {
       req.user.progressTimestamps.push(Date.now() || 0);
       req.user.uncompletedCoursewares.splice(index, 1);
@@ -331,8 +344,7 @@ exports.completedZiplineOrBasejump = function (req, res, next) {
         return next(err);
       }
       if (user) {
-        debug('Saving user');
-        return res.send(true);
+        return res.sendStatus(200);
       }
     });
   }
diff --git a/models/User.js b/models/User.js
index 1e1d828..a05e664 100644
--- a/models/User.js
+++ b/models/User.js
@@ -347,7 +347,10 @@ var userSchema = new mongoose.Schema({
       {
         completedDate: Long,
         _id: String,
-        name: String
+        name: String,
+        completedWith: String,
+        solution: String,
+        githubLink: String
       }
     ],
   currentStreak: {
diff --git a/public/js/main.js b/public/js/main.js
index 9a903a1..c422d2b 100644
--- a/public/js/main.js
+++ b/public/js/main.js
@@ -1,377 +1,432 @@
 $(document).ready(function() {
-    var challengeName = typeof challengeName !== undefined ? challengeName : 'Untitled';
-    if (challengeName) {
-        ga('send', 'event',  'Challenge', 'load', challengeName);
-    }
-
-    // When introducing a new announcement, change the localStorage attribute
-    // and the HTML located in the footer
-    if (!localStorage || !localStorage.nodeSchoolAnnouncement) {
-        $('#announcementModal').modal('show');
-        localStorage.fccShowAnnouncement = "true";
-    }
-
-    var CSRF_HEADER = 'X-CSRF-Token';
-
-    var setCSRFToken = function(securityToken) {
-        jQuery.ajaxPrefilter(function(options, _, xhr) {
-            if (!xhr.crossDomain) {
-                xhr.setRequestHeader(CSRF_HEADER, securityToken);
-            }
-        });
-    };
-
-    setCSRFToken($('meta[name="csrf-token"]').attr('content'));
-
-    $('.start-challenge').on('click', function() {
-        $(this).parent().remove();
-        $('.challenge-content')
-            .removeClass('hidden-element')
-            .addClass('animated fadeInDown');
-    });
-
-    //$('.completed-challenge').on('click', function() {
-    //    $('#complete-challenge-dialog').modal('show');
-    //    // Only post to server if there is an authenticated user
-    //    if ($('.signup-btn-nav').length < 1) {
-    //        l = location.pathname.split('/');
-    //        cn = l[l.length - 1];
-    //        $.ajax({
-    //            type: 'POST',
-    //            data: {challengeNumber: cn},
-    //            url: '/completed-challenge/'
-    //        });
-    //    }
-    //});
-
-
-    function completedBonfire(didCompleteWith, bonfireSolution, thisBonfireHash) {
-        $('#complete-bonfire-dialog').modal('show');
-        // Only post to server if there is an authenticated user
-        if ($('.signup-btn-nav').length < 1) {
-
-            $.post(
-                '/completed-bonfire',
-                {
-                    bonfireInfo: {
-                        completedWith : didCompleteWith,
-                        solution: bonfireSolution,
-                        bonfireHash: thisBonfireHash
-                    }
-                },
-                function(res) {
-                if (res) {
-                    window.location.href = '/bonfires'
-                }
-            });
-        }
-    }
-
-    $('.next-bonfire-button').on('click', function() {
-        var bonfireSolution = myCodeMirror.getValue();
-        var thisBonfireHash = passedBonfireHash || null;
-        var didCompleteWith = $('#completed-with').val() || null;
-        completedBonfire(didCompleteWith, bonfireSolution, thisBonfireHash);
-
-    });
-
-    $('#completed-courseware').on('click', function() {
-        $('#complete-courseware-dialog').modal('show');
-    });
-
-    $('#complete-courseware-dialog').on('keypress', function(e) {
-        if (e.ctrlKey && e.keyCode == 13) {
-            $('#next-courseware-button').click();
+  var challengeName = typeof challengeName !== undefined ? challengeName : 'Untitled';
+  if (challengeName) {
+    ga('send', 'event',  'Challenge', 'load', challengeName);
+  }
+
+  // When introducing a new announcement, change the localStorage attribute
+  // and the HTML located in the footer
+  if (!localStorage || !localStorage.nodeSchoolAnnouncement) {
+    $('#announcementModal').modal('show');
+    localStorage.fccShowAnnouncement = "true";
+  }
+
+  var CSRF_HEADER = 'X-CSRF-Token';
+
+  var setCSRFToken = function(securityToken) {
+    jQuery.ajaxPrefilter(function(options, _, xhr) {
+      if (!xhr.crossDomain) {
+        xhr.setRequestHeader(CSRF_HEADER, securityToken);
       }
     });
+  };
+
+  setCSRFToken($('meta[name="csrf-token"]').attr('content'));
+
+  $('.start-challenge').on('click', function() {
+    $(this).parent().remove();
+    $('.challenge-content')
+      .removeClass('hidden-element')
+      .addClass('animated fadeInDown');
+  });
+
+  //$('.completed-challenge').on('click', function() {
+  //    $('#complete-challenge-dialog').modal('show');
+  //    // Only post to server if there is an authenticated user
+  //    if ($('.signup-btn-nav').length < 1) {
+  //        l = location.pathname.split('/');
+  //        cn = l[l.length - 1];
+  //        $.ajax({
+  //            type: 'POST',
+  //            data: {challengeNumber: cn},
+  //            url: '/completed-challenge/'
+  //        });
+  //    }
+  //});
+
+
+  function completedBonfire(didCompleteWith, bonfireSolution, thisBonfireHash) {
+    $('#complete-bonfire-dialog').modal('show');
+    // Only post to server if there is an authenticated user
+    if ($('.signup-btn-nav').length < 1) {
+
+      $.post(
+        '/completed-bonfire',
+        {
+          bonfireInfo: {
+            completedWith : didCompleteWith,
+            solution: bonfireSolution,
+            bonfireHash: thisBonfireHash
+          }
+        },
+        function(res) {
+          if (res) {
+            window.location.href = '/bonfires'
+          }
+        });
+    }
+  }
 
-    $('#complete-bonfire-dialog').on('hidden.bs.modal', function() {
-        editor.focus();
-    });
-
-    $('#all-bonfires-dialog').on('hidden.bs.modal', function() {
-        editor.focus();
-    });
-
-    $('#showAllCoursewares').on('click', function() {
-        $('#all-coursewares-dialog').modal('show');
-    });
-
-    $('#all-coursewares-dialog').on('hidden.bs.modal', function() {
-        editor.focus();
-    });
-
-
-    $('#complete-courseware-dialog').on('hidden.bs.modal', function() {
-        editor.focus();
-    });
-    $('#next-courseware-button').on('click', function() {
-      console.log(passedCoursewareHash);
-        if ($('.signup-btn-nav').length < 1) {
-            $.post(
-                '/completed-courseware/',
-                {
-                    coursewareInfo: {
-                        coursewareHash: passedCoursewareHash,
-                        coursewareName: passedCoursewareName
-                    }
-                }).success(
-                function(res) {
-                  if (res) {
-                    window.location.href = '/challenges';
-                  }
-                }
-            );
-
-        }
-    });
-
-
-    $('.all-challenges').on('click', function() {
-        $('#all-challenges-dialog').modal('show');
-    });
+  $('.next-bonfire-button').on('click', function() {
+    var bonfireSolution = myCodeMirror.getValue();
+    var thisBonfireHash = passedBonfireHash || null;
+    var didCompleteWith = $('#completed-with').val() || null;
+    completedBonfire(didCompleteWith, bonfireSolution, thisBonfireHash);
 
-    $('#showAllButton').on('click', function() {
-        $('#all-bonfires-dialog').modal('show');
-    });
+  });
 
-    $('.next-challenge-button').on('click', function() {
-        l = location.pathname.split('/');
-        window.location = '/challenges/' + (parseInt(l[l.length - 1]) + 1);
-    });
+  $('#completed-courseware').on('click', function() {
+    $('#complete-courseware-dialog').modal('show');
+  });
 
+  $('#completed-zipline-or-basejump').on('click', function() {
+    $('#complete-zipline-or-basejump-dialog').modal('show');
+  });
 
-    // Bonfire instructions functions
-    $('#more-info').on('click', function() {
-        ga('send', 'event',  'Challenge', 'more-info', challengeName);
-        $('#brief-instructions').hide();
-        $('#long-instructions').show().removeClass('hide');
 
-    });
-    $('#less-info').on('click', function() {
-        $('#brief-instructions').show();
-        $('#long-instructions').hide();
-    });
-
-    var upvoteHandler = function () {
-        var _id = storyId;
-        $('#upvote').unbind('click');
-        var alreadyUpvoted = false;
-        for (var i = 0; i < upVotes.length; i++) {
-            if (upVotes[i].upVotedBy === user._id) {
-                alreadyUpvoted = true;
-                break;
+  $('#complete-courseware-dialog').on('keypress', function(e) {
+    if (e.ctrlKey && e.keyCode === 13) {
+      $('#next-courseware-button').click();
+    }
+  });
+
+  $('#complete-bonfire-dialog').on('hidden.bs.modal', function() {
+    editor.focus();
+  });
+
+  $('#all-bonfires-dialog').on('hidden.bs.modal', function() {
+    editor.focus();
+  });
+
+  $('#showAllCoursewares').on('click', function() {
+    $('#all-coursewares-dialog').modal('show');
+  });
+
+  $('#all-coursewares-dialog').on('hidden.bs.modal', function() {
+    editor.focus();
+  });
+
+
+  $('#complete-courseware-dialog').on('hidden.bs.modal', function() {
+    editor.focus();
+  });
+  $('#next-courseware-button').on('click', function() {
+    console.log(passedCoursewareHash);
+    if ($('.signup-btn-nav').length < 1) {
+      switch (challengeType) {
+        case 0:
+        case 1:
+        case 2:
+          $.post(
+            '/completed-courseware/',
+            {
+              coursewareInfo: {
+                coursewareHash: passedCoursewareHash,
+                coursewareName: passedCoursewareName
+              }
+            }).success(
+            function(res) {
+              if (res) {
+                window.location.href = '/challenges';
+              }
             }
-        }
-        if (!alreadyUpvoted) {
-            $.post('/stories/upvote',
-                {
-                    data: {
-                        id: _id,
-                        upVoter: user
-                    }
-                })
-                .fail(function (xhr, textStatus, errorThrown) {
-                    $('#upvote').bind('click', upvoteHandler);
-                })
-                .done(function (data, textStatus, xhr) {
-                    $('#upvote').text('Upvoted!').addClass('disabled');
-
-                    $('#storyRank').text(data.rank + " points");
-                });
-        }
-    };
-    $('#upvote').on('click', upvoteHandler);
-
-
-    var storySubmitButtonHandler = function storySubmitButtonHandler() {
-
-        var link = $('#story-url').val();
-        var headline = $('#story-title').val();
-        var description = $('#description-box').val();
-        var userDataForUpvote = {
-            upVotedBy: user._id,
-            upVotedByUsername: user.profile.username
-        };
-        $('#story-submit').unbind('click');
-        $.post('/stories/',
+          );
+          break;
+        case 3:
+          var didCompleteWith = $('#completed-with').val() || null;
+          var publicURL = $('#public-url').val() || null;
+          $.post(
+            '/completed-zipline-or-basejump/',
             {
-                data: {
-                    link: link,
-                    headline: headline,
-                    timePosted: Date.now(),
-                    description: description,
-                    storyMetaDescription: storyMetaDescription,
-                    rank: 1,
-                    upVotes: [userDataForUpvote],
-                    author: {
-                        picture: user.profile.picture,
-                        userId: user._id,
-                        username: user.profile.username
-                    },
-                    comments: [],
-                    image: storyImage
-                }
-            })
-            .fail(function (xhr, textStatus, errorThrown) {
-                $('#story-submit').bind('click', storySubmitButtonHandler);
-            })
-            .done(function (data, textStatus, xhr) {
-                window.location = '/stories/' + JSON.parse(data).storyLink;
+              coursewareInfo: {
+                coursewareHash: passedCoursewareHash,
+                coursewareName: passedCoursewareName,
+                completedWith: didCompleteWith,
+                publicURL: publicURL,
+                challengeType: challengeType
+              }
+            }).success(
+            function() {
+              window.location.href = '/challenges';
+            }).fail(
+            function() {
+              window.location.href = '/challenges';
             });
+          break;
+        case 4:
+          var didCompleteWith = $('#completed-with').val() || null;
+          var publicURL = $('#public-url').val() || null;
+          var githubURL = $('#github-url').val() || null;
+          $.post(
+            '/completed-zipline-or-basejump/',
+            {
+              coursewareInfo: {
+                coursewareHash: passedCoursewareHash,
+                coursewareName: passedCoursewareName,
+                completedWith: didCompleteWith,
+                publicURL: publicURl,
+                githubURL: githubURL,
+                challengeType: challengeType
+              }
+            }).success(function() {
+              window.location.href = '/challenges';
+            }).fail(function() {
+              window.location.replace(window.location.href);
+            });
+          break;
+        default:
+          break;
+      }
 
-    };
-
-    $('#story-submit').on('click', storySubmitButtonHandler);
+    }
+  });
+
+
+  $('.all-challenges').on('click', function() {
+    $('#all-challenges-dialog').modal('show');
+  });
+
+  $('#showAllButton').on('click', function() {
+    $('#all-bonfires-dialog').modal('show');
+  });
+
+  $('.next-challenge-button').on('click', function() {
+    l = location.pathname.split('/');
+    window.location = '/challenges/' + (parseInt(l[l.length - 1]) + 1);
+  });
+
+
+// Bonfire instructions functions
+  $('#more-info').on('click', function() {
+    ga('send', 'event',  'Challenge', 'more-info', challengeName);
+    $('#brief-instructions').hide();
+    $('#long-instructions').show().removeClass('hide');
+
+  });
+  $('#less-info').on('click', function() {
+    $('#brief-instructions').show();
+    $('#long-instructions').hide();
+  });
+
+  var upvoteHandler = function () {
+    var _id = storyId;
+    $('#upvote').unbind('click');
+    var alreadyUpvoted = false;
+    for (var i = 0; i < upVotes.length; i++) {
+      if (upVotes[i].upVotedBy === user._id) {
+        alreadyUpvoted = true;
+        break;
+      }
+    }
+    if (!alreadyUpvoted) {
+      $.post('/stories/upvote',
+        {
+          data: {
+            id: _id,
+            upVoter: user
+          }
+        })
+        .fail(function (xhr, textStatus, errorThrown) {
+          $('#upvote').bind('click', upvoteHandler);
+        })
+        .done(function (data, textStatus, xhr) {
+          $('#upvote').text('Upvoted!').addClass('disabled');
+
+          $('#storyRank').text(data.rank + " points");
+        });
+    }
+  };
+  $('#upvote').on('click', upvoteHandler);
 
-    var commentSubmitButtonHandler = function commentSubmitButtonHandler() {
-        $('comment-button').unbind('click');
-        var data = $('#comment-box').val();
 
-        $('#comment-button').attr('disabled', 'disabled');
-        $.post('/stories/comment/',
-            {
-                data: {
-                    associatedPost: storyId,
-                    body: data,
-                    author: {
-                        picture: user.profile.picture,
-                        userId: user._id,
-                        username: user.profile.username
-                    }
-                }
-            })
-            .fail(function (xhr, textStatus, errorThrown) {
-                $('#comment-button').attr('disabled', false);
-            })
-            .done(function (data, textStatus, xhr) {
-                window.location.reload();
-            });
+  var storySubmitButtonHandler = function storySubmitButtonHandler() {
 
+    var link = $('#story-url').val();
+    var headline = $('#story-title').val();
+    var description = $('#description-box').val();
+    var userDataForUpvote = {
+      upVotedBy: user._id,
+      upVotedByUsername: user.profile.username
     };
+    $('#story-submit').unbind('click');
+    $.post('/stories/',
+      {
+        data: {
+          link: link,
+          headline: headline,
+          timePosted: Date.now(),
+          description: description,
+          storyMetaDescription: storyMetaDescription,
+          rank: 1,
+          upVotes: [userDataForUpvote],
+          author: {
+            picture: user.profile.picture,
+            userId: user._id,
+            username: user.profile.username
+          },
+          comments: [],
+          image: storyImage
+        }
+      })
+      .fail(function (xhr, textStatus, errorThrown) {
+        $('#story-submit').bind('click', storySubmitButtonHandler);
+      })
+      .done(function (data, textStatus, xhr) {
+        window.location = '/stories/' + JSON.parse(data).storyLink;
+      });
+
+  };
+
+  $('#story-submit').on('click', storySubmitButtonHandler);
+
+  var commentSubmitButtonHandler = function commentSubmitButtonHandler() {
+    $('comment-button').unbind('click');
+    var data = $('#comment-box').val();
+
+    $('#comment-button').attr('disabled', 'disabled');
+    $.post('/stories/comment/',
+      {
+        data: {
+          associatedPost: storyId,
+          body: data,
+          author: {
+            picture: user.profile.picture,
+            userId: user._id,
+            username: user.profile.username
+          }
+        }
+      })
+      .fail(function (xhr, textStatus, errorThrown) {
+        $('#comment-button').attr('disabled', false);
+      })
+      .done(function (data, textStatus, xhr) {
+        window.location.reload();
+      });
 
-    $('#comment-button').on('click', commentSubmitButtonHandler);
+  };
+
+  $('#comment-button').on('click', commentSubmitButtonHandler);
 });
 
 var profileValidation = angular.module('profileValidation',['ui.bootstrap']);
 profileValidation.controller('profileValidationController', ['$scope', '$http',
-    function($scope, $http) {
-        $http.get('/account/api').success(function(data) {
-            $scope.user = data.user;
-            $scope.user.profile.username = $scope.user.profile.username ? $scope.user.profile.username.toLowerCase() : undefined;
-            $scope.storedUsername = data.user.profile.username;
-            $scope.storedEmail = data.user.email;
-            $scope.user.email = $scope.user.email ? $scope.user.email.toLowerCase() : undefined;
-            $scope.user.profile.twitterHandle = $scope.user.profile.twitterHandle ? $scope.user.profile.twitterHandle.toLowerCase() : undefined;
-            $scope.asyncComplete = true;
-        });
-    }
+  function($scope, $http) {
+    $http.get('/account/api').success(function(data) {
+      $scope.user = data.user;
+      $scope.user.profile.username = $scope.user.profile.username ? $scope.user.profile.username.toLowerCase() : undefined;
+      $scope.storedUsername = data.user.profile.username;
+      $scope.storedEmail = data.user.email;
+      $scope.user.email = $scope.user.email ? $scope.user.email.toLowerCase() : undefined;
+      $scope.user.profile.twitterHandle = $scope.user.profile.twitterHandle ? $scope.user.profile.twitterHandle.toLowerCase() : undefined;
+      $scope.asyncComplete = true;
+    });
+  }
 ]);
 
 profileValidation.controller('pairedWithController', ['$scope',
-    function($scope) {
-        $scope.existingUser = null;
-    }
+  function($scope) {
+    $scope.existingUser = null;
+  }
 ]);
 
 profileValidation.controller('emailSignUpController', ['$scope',
-    function($scope) {
+  function($scope) {
 
-    }
+  }
 ]);
 
 profileValidation.controller('emailSignInController', ['$scope',
-    function($scope) {
+  function($scope) {
 
-    }
+  }
 ]);
 
 profileValidation.controller('URLSubmitController', ['$scope',
-    function($scope) {
+  function($scope) {
 
-    }
+  }
 ]);
 
 profileValidation.controller('nonprofitFormController', ['$scope',
-    function($scope) {
+  function($scope) {
 
-    }
+  }
 ]);
 
 profileValidation.controller('doneWithFirst100HoursFormController', ['$scope',
-    function($scope) {
+  function($scope) {
 
-    }
+  }
 ]);
 
 profileValidation.controller('submitStoryController', ['$scope',
-    function($scope) {
+  function($scope) {
 
-    }
+  }
 ]);
 
 profileValidation.directive('uniqueUsername',['$http',function($http) {
-    return {
-        restrict: 'A',
-        require: 'ngModel',
-        link: function (scope, element, attrs, ngModel) {
-            element.bind("keyup", function (event) {
-                ngModel.$setValidity('unique', true);
-                if (element.val()) {
-                    $http.get("/api/checkUniqueUsername/" + element.val()).success(function (data) {
-                        if (element.val() == scope.storedUsername) {
-                            ngModel.$setValidity('unique', true);
-                        } else if (data) {
-                            ngModel.$setValidity('unique', false);
-                        }
-                    });
-                }
-            });
+  return {
+    restrict: 'A',
+    require: 'ngModel',
+    link: function (scope, element, attrs, ngModel) {
+      element.bind("keyup", function (event) {
+        ngModel.$setValidity('unique', true);
+        if (element.val()) {
+          $http.get("/api/checkUniqueUsername/" + element.val()).success(function (data) {
+            if (element.val() == scope.storedUsername) {
+              ngModel.$setValidity('unique', true);
+            } else if (data) {
+              ngModel.$setValidity('unique', false);
+            }
+          });
         }
+      });
     }
+  }
 }]);
 
 profileValidation.directive('existingUsername', ['$http', function($http) {
-    return {
-        restrict: 'A',
-        require: 'ngModel',
-        link: function (scope, element, attrs, ngModel) {
-            element.bind("keyup", function (event) {
-                if (element.val().length > 0) {
-                    ngModel.$setValidity('exists', false);
-                } else {
-                    element.removeClass('ng-dirty');
-                    ngModel.$setPristine();
-                }
-                if (element.val()) {
-                    $http
-                    .get("/api/checkExistingUsername/" + element.val())
-                    .success(function (data) {
-                        ngModel.$setValidity('exists', data);
-                    });
-                }
+  return {
+    restrict: 'A',
+    require: 'ngModel',
+    link: function (scope, element, attrs, ngModel) {
+      element.bind("keyup", function (event) {
+        if (element.val().length > 0) {
+          ngModel.$setValidity('exists', false);
+        } else {
+          element.removeClass('ng-dirty');
+          ngModel.$setPristine();
+        }
+        if (element.val()) {
+          $http
+            .get("/api/checkExistingUsername/" + element.val())
+            .success(function (data) {
+              ngModel.$setValidity('exists', data);
             });
         }
+      });
     }
+  }
 }]);
 
 profileValidation.directive('uniqueEmail', ['$http', function($http) {
-    return {
-        restrict: 'A',
-        require: 'ngModel',
-        link: function getUnique (scope, element, attrs, ngModel) {
-            element.bind("keyup", function (event) {
-                ngModel.$setValidity('unique', true);
-                if (element.val()) {
-                    $http.get("/api/checkUniqueEmail/" + encodeURIComponent(element.val())).success(function (data) {
-                        if (element.val() == scope.storedEmail) {
-                            ngModel.$setValidity('unique', true);
-                        } else if (data) {
-                            ngModel.$setValidity('unique', false);
-                        }
-                    });
-                };
-            });
-        }
+  return {
+    restrict: 'A',
+    require: 'ngModel',
+    link: function getUnique (scope, element, attrs, ngModel) {
+      element.bind("keyup", function (event) {
+        ngModel.$setValidity('unique', true);
+        if (element.val()) {
+          $http.get("/api/checkUniqueEmail/" + encodeURIComponent(element.val())).success(function (data) {
+            if (element.val() == scope.storedEmail) {
+              ngModel.$setValidity('unique', true);
+            } else if (data) {
+              ngModel.$setValidity('unique', false);
+            }
+          });
+        };
+      });
     }
+  }
 }]);
diff --git a/views/bonfire/show.jade b/views/bonfire/show.jade
index 4810949..2f68cab 100644
--- a/views/bonfire/show.jade
+++ b/views/bonfire/show.jade
@@ -148,16 +148,6 @@ block content
                     include ../partials/bonfires
 
     script.
-        $.ajax({
-            url: 'https://api-ssl.bitly.com/v3/shorten?access_token=75e7931a19befaafcf108021b6d597e554b2c5c3&longUrl=http%3A%2F%2Ffreecodecamp.com%2Fbonfires%2F' + dashed + '&format=txt'
-        })
-                .success(
-                function (data) {
-                    console.log(data);
-                    url = "https://twitter.com/intent/tweet?text=I%20just%20#{verb}%20%40FreeCodeCamp%20Bonfire:%20#{name}&url=" + data + "&hashtags=LearnToCode, JavaScript";
-                    $('.btn-twitter').attr('href', url);
-                }
-        );
         var MDNlinks = !{JSON.stringify(MDNlinks)};
         if (!MDNlinks.length) {
             $('#MDN-links').addClass('collapse');
diff --git a/views/coursewares/showHTML.jade b/views/coursewares/showHTML.jade
index 9966844..7ad3530 100644
--- a/views/coursewares/showHTML.jade
+++ b/views/coursewares/showHTML.jade
@@ -60,6 +60,7 @@ block content
                 var challengeName = !{JSON.stringify(name)};
                 var passedCoursewareName = challengeName;
                 var prodOrDev = !{JSON.stringify(environment)};
+                var challengeType = !{JSON.stringify(challengeType)};
                 var started = Math.floor(Date.now());
         .col-xs-12.col-sm-12.col-md-5.col-lg-6
             #mainEditorPanel
@@ -81,4 +82,4 @@ block content
                             .animated.zoomInDown.delay-half
                                 span.completion-icon.ion-checkmark-circled.text-primary
                             a.animated.fadeIn.btn.btn-lg.signup-btn.btn-block(href='/login') Sign in so you can save your progress
-    script(src="/js/lib/coursewares/coursewaresHCJQFramework_v0.1.1.js")
\ No newline at end of file
+    script(src="/js/lib/coursewares/coursewaresHCJQFramework_v0.1.1.js")
diff --git a/views/coursewares/showJS.jade b/views/coursewares/showJS.jade
index 182d25a..3e33ee4 100644
--- a/views/coursewares/showJS.jade
+++ b/views/coursewares/showJS.jade
@@ -47,6 +47,7 @@ block content
                     var challengeSeed = !{JSON.stringify(challengeSeed)};
                     var passedCoursewareHash = !{JSON.stringify(coursewareHash)};
                     var challengeName = !{JSON.stringify(name)};
+                    var challengeType = !{JSON.stringify(challengeType)};
                     var passedCoursewareName = challengeName;
                     var started = Math.floor(Date.now());
 
@@ -72,4 +73,4 @@ block content
                                 i.fa.fa-twitter &thinsp;
                                     = phrase
                     - else
-                        a.animated.fadeIn.btn.btn-lg.signup-btn.btn-block(href='/login') Sign in so you can save your progress
\ No newline at end of file
+                        a.animated.fadeIn.btn.btn-lg.signup-btn.btn-block(href='/login') Sign in so you can save your progress
diff --git a/views/coursewares/showVideo.jade b/views/coursewares/showVideo.jade
index fa85520..b6264c3 100644
--- a/views/coursewares/showVideo.jade
+++ b/views/coursewares/showVideo.jade
@@ -27,6 +27,7 @@ block content
                 var challengeName = !{JSON.stringify(name)};
                 var passedCoursewareName = challengeName;
                 var started = Math.floor(Date.now());
+                var challengeType = !{JSON.stringify(challengeType)};
     #complete-courseware-dialog.modal(tabindex='-1')
         .modal-dialog.animated.zoomIn.fast-animation
             .modal-content
@@ -46,10 +47,8 @@ block content
                             a.animated.fadeIn.btn.btn-lg.signup-btn.btn-block(href='/login') Sign in so you can save your progress
                                 h1 #{name}
         script.
-            var challengeName = !{JSON.stringify(name)};
-            var passedCoursewareHash = !{JSON.stringify(coursewareHash)};
             $('body').on('keypress', function(e) {
                 if (e.ctrlKey && e.keyCode == 13) {
                     $('#complete-courseware-dialog').modal('show');
                 }
-            });
\ No newline at end of file
+            });
diff --git a/views/coursewares/showZiplineOrBasejump.jade b/views/coursewares/showZiplineOrBasejump.jade
index c5df3c0..c630d7a 100644
--- a/views/coursewares/showZiplineOrBasejump.jade
+++ b/views/coursewares/showZiplineOrBasejump.jade
@@ -13,7 +13,7 @@ block content
                 iframe.embed-responsive-item(src='//player.vimeo.com/video/#{video}')
             br
             - if (user)
-                a.btn.btn-primary.btn-lg.btn-block#completed-courseware I've completed this challenge  (ctrl + enter)
+                a.btn.btn-primary.btn-lg.btn-block#completed-zipline-or-basejump I've completed this challenge  (ctrl + enter)
                 script.
                     var userLoggedIn = true;
             - else
@@ -26,6 +26,7 @@ block content
                 var challengeName = !{JSON.stringify(name)};
                 var passedCoursewareName = challengeName;
                 var started = Math.floor(Date.now());
+                var challengeType = !{JSON.stringify(challengeType)};
     #complete-zipline-or-basejump-dialog.modal(tabindex='-1')
         .modal-dialog.animated.zoomIn.fast-animation
             .modal-content
@@ -40,21 +41,21 @@ block content
                             .form-group.text-center
                                 .col-xs-10.col-xs-offset-1.col-sm-8.col-sm-offset-2.col-md-8.col-md-offset-2.animated.fadeIn
 
-                                // extra field to distract password tools like lastpass from injecting css into our username field
-                                input.form-control(ng-show="false")
-                                if (challengeType === 'zipline')
-                                    input.form-control#public-url(name="codepenUrl", placeholder="http://codepen.io/your-pen-here", autofocus)
-                                else
-                                    input.form-control#public-url(name="depoloymentUrl", placeholder="http://yourapp.com", autofocus)
-                                    input.form-control#github-url(name="githubUrl", placeholder="http://github.com/camper/project")
+                                    // extra field to distract password tools like lastpass from injecting css into our username field
+                                    input.form-control(ng-show="false")
+                                    if (challengeType === 3)
+                                        input.form-control#public-url(name="codepenUrl", placeholder="http://codepen.io/your-pen-here", autofocus)
+                                    else
+                                        input.form-control#public-url(name="depoloymentUrl", placeholder="http://yourapp.com", autofocus)
+                                        input.form-control#github-url(name="githubUrl", placeholder="http://github.com/camper/project")
 
-                                input.form-control#completed-with(name="existingUser", placeholder="If you paired, enter your pair's username here", existing-username='', ng-model="existingUser")
-                            .col-xs-10.col-xs-offset-1.col-sm-8.col-sm-offset-2.col-md-8.col-md-offset-2(ng-cloak, ng-show="completedWithForm.$error.exists && !completedWithForm.existingUser.$pristine && existingUser.length > 0")
-                                alert(type='danger')
-                                    span.ion-close-circled
-                                    | Username not found
+                                    input.form-control#completed-with(name="existingUser", placeholder="If you paired, enter your pair's username here", existing-username='', ng-model="existingUser")
+                                .col-xs-10.col-xs-offset-1.col-sm-8.col-sm-offset-2.col-md-8.col-md-offset-2(ng-cloak, ng-show="completedWithForm.$error.exists && !completedWithForm.existingUser.$pristine && existingUser.length > 0")
+                                    alert(type='danger')
+                                        span.ion-close-circled
+                                        | Username not found
 
-                    a.animated.fadeIn.btn.btn-lg.btn-primary.btn-block.next-bonfire-button(name='_csrf', value=_csrf, ng-disabled='completedWithForm.$invalid && existingUser.length > 0') Go to my next bonfire (ctrl + enter)
+                    a.animated.fadeIn.btn.btn-lg.btn-primary.btn-block#next-courseware-button(name='_csrf', value=_csrf, ng-disabled='completedWithForm.$invalid && existingUser.length > 0') Go to my next challenge (ctrl + enter)
 
 
                     - if (user.progressTimestamps.length > 2)
@@ -64,10 +65,8 @@ block content
                     - else
                         a.animated.fadeIn.btn.btn-lg.signup-btn.btn-block(href='/login') Sign in so you can save your progress
         script.
-            var challengeName = !{JSON.stringify(name)};
-            var passedCoursewareHash = !{JSON.stringify(coursewareHash)};
             $('body').on('keypress', function(e) {
                 if (e.ctrlKey && e.keyCode == 13) {
-                    $('#complete-courseware-dialog').modal('show');
+                    $('#complete-zipline-or-basejump-dialog').modal('show');
                 }
-            });
\ No newline at end of file
+            });
