diff --git a/.travis.yml b/.travis.yml
index b6bd11e2c2..22cfb84161 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,7 +1,6 @@
language: node_js
node_js:
- - 'node'
- - '1.6.4'
+ - '4.2.1'
sudo: false
diff --git a/client/commonFramework.js b/client/commonFramework.js
index 2505fe08f4..d55ea45c1e 100644
--- a/client/commonFramework.js
+++ b/client/commonFramework.js
@@ -659,7 +659,11 @@ function ctrlEnterClickHandler(e) {
// ctrl + enter
if (e.ctrlKey && e.keyCode === 13) {
$('#complete-courseware-dialog').off('keydown', ctrlEnterClickHandler);
- $('#submit-challenge').click();
+ if ($('#submit-challenge').length > 0) {
+ $('#submit-challenge').click();
+ } else {
+ window.location = '/challenges/next-challenge?id=' + common.challengeId;
+ }
}
}
@@ -781,7 +785,7 @@ var scrapeTests = function(userJavaScript) {
};
function removeComments(userJavaScript) {
- var regex = new RegExp(/(\/\*[^(\*\/)]*\*\/)|\/\/[^\n]*/g);
+ var regex = new RegExp(/(\/\*[^(\*\/)]*\*\/)|([ \n]\/\/[^\n]*)/g);
return userJavaScript.replace(regex, '');
}
@@ -892,12 +896,32 @@ var runTests = function(err, data) {
// step challenge
common.init.push((function() {
var stepClass = '.challenge-step';
+ var prevBtnClass = '.challenge-step-btn-prev';
var nextBtnClass = '.challenge-step-btn-next';
var actionBtnClass = '.challenge-step-btn-action';
var finishBtnClass = '.challenge-step-btn-finish';
var submitBtnId = '#challenge-step-btn-submit';
var submitModalId = '#challenge-step-modal';
+ function getPreviousStep($challengeSteps) {
+ var length = $challengeSteps.length;
+ var $prevStep = false;
+ var prevStepIndex = 0;
+ $challengeSteps.each(function(index) {
+ var $step = $(this);
+ if (
+ !$step.hasClass('hidden') &&
+ index + 1 !== length
+ ) {
+ prevStepIndex = index - 1;
+ }
+ });
+
+ $prevStep = $challengeSteps[prevStepIndex];
+
+ return $prevStep;
+ }
+
function getNextStep($challengeSteps) {
var length = $challengeSteps.length;
var $nextStep = false;
@@ -917,11 +941,36 @@ common.init.push((function() {
return $nextStep;
}
+ function handlePrevStepClick(e) {
+ e.preventDefault();
+ var prevStep = getPreviousStep($(stepClass));
+ $(this)
+ .parent()
+ .removeClass('fadeOutLeft')
+ .addClass('animated fadeOutRight fast-animation')
+ .delay(250)
+ .queue(function(prev) {
+ $(this).addClass('hidden');
+ if (prevStep) {
+ $(prevStep)
+ .removeClass('hidden')
+ .removeClass('slideInRight')
+ .addClass('animated slideInLeft fast-animation')
+ .delay(500)
+ .queue(function(prev) {
+ prev();
+ });
+ }
+ prev();
+ });
+ }
+
function handleNextStepClick(e) {
e.preventDefault();
var nextStep = getNextStep($(stepClass));
$(this)
.parent()
+ .removeClass('fadeOutRight')
.addClass('animated fadeOutLeft fast-animation')
.delay(250)
.queue(function(next) {
@@ -929,10 +978,10 @@ common.init.push((function() {
if (nextStep) {
$(nextStep)
.removeClass('hidden')
+ .removeClass('slideInLeft')
.addClass('animated slideInRight fast-animation')
.delay(500)
.queue(function(next) {
- $(this).removeClass('slideInRight');
next();
});
}
@@ -1035,6 +1084,7 @@ common.init.push((function() {
}
return function($) {
+ $(prevBtnClass).click(handlePrevStepClick);
$(nextBtnClass).click(handleNextStepClick);
$(actionBtnClass).click(handleActionClick);
$(finishBtnClass).click(handleFinishClick);
diff --git a/client/less/main.less b/client/less/main.less
index 94c0e1d77a..59adf6fb44 100644
--- a/client/less/main.less
+++ b/client/less/main.less
@@ -694,6 +694,24 @@ iframe.iphone {
transition: background .2s ease-in-out, border .2s ease-in-out;
}
+.btn-warning-ghost {
+ background: transparent;
+ color: @brand-warning;
+
+ /* CSS Transition */
+ -webkit-transition: background .2s ease-in-out, border .2s ease-in-out;
+ -moz-transition: background .2s ease-in-out, border .2s ease-in-out;
+ -ms-transition: background .2s ease-in-out, border .2s ease-in-out;
+ -o-transition: background .2s ease-in-out, border .2s ease-in-out;
+ transition: background .2s ease-in-out, border .2s ease-in-out;
+}
+
+.population-table {
+ @media (max-width: 767px) {
+ font-size: 16px;
+ }
+}
+
@media (max-width: 991px) {
.navbar-header {
float: none;
diff --git a/common/models/challenge.json b/common/models/challenge.json
index 81d6af6eef..729cb97625 100644
--- a/common/models/challenge.json
+++ b/common/models/challenge.json
@@ -86,6 +86,9 @@
"solutions": {
"type": "array",
"default": []
+ },
+ "releasedOn": {
+ "type": "string"
}
},
"validations": [],
diff --git a/package.json b/package.json
index 38cdb03f2a..0271f59bf6 100644
--- a/package.json
+++ b/package.json
@@ -13,7 +13,11 @@
"prestart-production": "bower cache clean && bower install && gulp build",
"start-production": "node pm2Start",
"lint": "eslint --ext=.js,.jsx .",
- "test": "gulp test-challenges"
+ "lint-challenges": "jsonlint -q seed/challenges/*.json",
+ "lint-nonprofits": "jsonlint -q seed/nonprofits.json",
+ "test-challenges": "babel-node seed/test-challenges.js | tnyan",
+ "pretest": "npm run lint-challenges && npm run lint-nonprofits",
+ "test": "npm run test-challenges"
},
"license": "(BSD-3-Clause AND CC-BY-SA-4.0)",
"dependencies": {
@@ -127,11 +131,14 @@
"chai": "~1.10.0",
"envify": "^3.4.0",
"istanbul": "^0.3.15",
+ "jsonlint": "^1.6.2",
"loopback-explorer": "^1.7.2",
"loopback-testing": "^1.1.0",
"mocha": "~2.0.1",
"multiline": "~1.0.1",
"supertest": "~0.15.0",
+ "tap-nyan": "0.0.2",
+ "tape": "^4.2.2",
"vinyl-source-stream": "^1.1.0"
}
}
diff --git a/seed/challenge-migration.js b/seed/challenge-migration.js
deleted file mode 100644
index 7ef359781f..0000000000
--- a/seed/challenge-migration.js
+++ /dev/null
@@ -1,44 +0,0 @@
-require('dotenv').load();
-var bonfires = require('./bonfires.json'),
- app = require('../server/server'),
- mongodb = require('mongodb'),
- MongoClient = mongodb.MongoClient,
- User = app.models.User,
- UserIdentity = app.models.userIdentity,
- oldUri='mongodb://localhost:27017/app30893198',
- coursewares = require('./coursewares.json');
-
-MongoClient.connect(oldUri, function(err, database) {
-
- database.collection('users').find({}).batchSize(20).toArray(function(err, users) {
- if (users !== null && users.length !== 0) {
- var mappedUserArray = users.map(function(user) {
- Object.keys(user.profile).forEach(function(prop) {
- user[prop] = user.profile[prop];
- });
- Object.keys(user.portfolio).forEach(function(prop) {
- user[prop] = user.portfolio[prop];
- });
-
- user.completedCoursewares = Object.keys(user.challengesHash)
- .filter(function(key) {
- return user.challengesHash[key] !== 0;
- })
- .map(function(key) {
- return({
- id: coursewares[key].id,
- completedDate: user.challengesHash[key]
- });
- });
-
- return user;
- });
- User.create(mappedUserArray, function(err) {
- if (err) {
- console.log(err);
- }
- console.log("a batch finished");
- });
- }
- });
-});
diff --git a/seed/challengeMapping.json b/seed/challengeMapping.json
deleted file mode 100644
index db6686d266..0000000000
--- a/seed/challengeMapping.json
+++ /dev/null
@@ -1,226 +0,0 @@
-[
- {
- "oldNumber": "0",
- "newId": "bd7124d8c441eddfaeb5bdef"
- },
- {
- "oldNumber": "1",
- "newId": "bd7125d8c441eddfaeb5bd0f"
- },
- {
- "oldNumber": "2",
- "newId": ""
- },
- {
- "oldNumber": "3",
- "newId": "bd7127d8c441eddfaeb5bdef"
- },
- {
- "oldNumber": "4",
- "newId": "bd7128d8c441eddfaeb5bdef"
- },
- {
- "oldNumber": "5",
- "newId": "bd8129d8c441eddfaeb5bdef"
- },
- {
- "oldNumber": "6",
- "newId": ""
- },
- {
- "oldNumber": "7",
- "newId": ""
- },
- {
- "oldNumber": "8",
- "newId": "bd7112d8c441eddfaeb5bdef"
- },
- {
- "oldNumber": "9",
- "newId": "bd7113d8c441eddfaeb5bdef"
- },
- {
- "oldNumber": "10",
- "newId": "bd7114d8c441eddfaeb5bdef"
- },
- {
- "oldNumber": "11",
- "newId": "bd7115d8c441eddfaeb5bdef"
- },
- {
- "oldNumber": "12",
- "newId": "bd7116d8c441eddfaeb5bdef"
- },
- {
- "oldNumber": "13",
- "newId": "bd7117d8c441eddfaeb5bdef"
- },
- {
- "oldNumber": "14",
- "newId": "bd7118d8c441eddfaeb5bdef"
- },
- {
- "oldNumber": "15",
- "newId": ""
- },
- {
- "oldNumber": "16",
- "newId": ""
- },
- {
- "oldNumber": "17",
- "newId": ""
- },
- {
- "oldNumber": "18",
- "newId": ""
- },
- {
- "oldNumber": "19",
- "newId": "bd7123d8c441eddfaeb5bdef"
- },
- {
- "oldNumber": "20",
- "newId": "bd8124d8c441eddfaeb5bdef"
- },
- {
- "oldNumber": "21",
- "newId": "bd8126d8c441eddfaeb5bdef"
- },
- {
- "oldNumber": "22",
- "newId": "bd8127d8c441eddfaeb5bdef"
- },
- {
- "oldNumber": "23",
- "newId": "bd8128d8c441eddfaeb5bdef"
- },
- {
- "oldNumber": "24",
- "newId": "bd7129d8c441eddfaeb5bdef"
- },
- {
- "oldNumber": "25",
- "newId": "bd7130d8c441eddfaeb5bdef"
- },
- {
- "oldNumber": "26",
- "newId": "bd7131d8c441eddfaeb5bdef"
- },
- {
- "oldNumber": "27",
- "newId": "bd7132d8c441eddfaeb5bdef"
- },
- {
- "oldNumber": "28",
- "newId": "bd7133d8c441eddfaeb5bdef"
- },
- {
- "oldNumber": "29",
- "newId": "bd7134d8c441eddfaeb5bdef"
- },
- {
- "oldNumber": "30",
- "newId": "bd7135d8c441eddfaeb5bdef"
- },
- {
- "oldNumber": "31",
- "newId": "bd7136d8c441eddfaeb5bdef"
- },
- {
- "oldNumber": "32",
- "newId": ""
- },
- {
- "oldNumber": "33",
- "newId": "bd7138d8c441eddfaeb5bdef"
- },
- {
- "oldNumber": "34",
- "newId": "bd7137d8c441eddfaeb5bdef"
- },
- {
- "oldNumber": "35",
- "newId": "bd7140d8c441eddfaeb5bdef"
- },
- {
- "oldNumber": "36",
- "newId": ""
- },
- {
- "oldNumber": "37",
- "newId": ""
- },
- {
- "oldNumber": "38",
- "newId": ""
- },
- {
- "oldNumber": "39",
- "newId": ""
- },
- {
- "oldNumber": "40",
- "newId": ""
- },
- {
- "oldNumber": "41",
- "newId": ""
- },
- {
- "oldNumber": "42",
- "newId": ""
- },
- {
- "oldNumber": "43",
- "newId": ""
- },
- {
- "oldNumber": "44",
- "newId": ""
- },
- {
- "oldNumber": "45",
- "newId": ""
- },
- {
- "oldNumber": "46",
- "newId": ""
- },
- {
- "oldNumber": "47",
- "newId": ""
- },
- {
- "oldNumber": "48",
- "newId": "bd7153d8c441eddfaeb5bd2f"
- },
- {
- "oldNumber": "49",
- "newId": "bd7154d8c441eddfaeb5bdef"
- },
- {
- "oldNumber": "50",
- "newId": "bd7155d8c441eddfaeb5bdef"
- },
- {
- "oldNumber": "51",
- "newId": "bd7156d8c441eddfaeb5bdef"
- },
- {
- "oldNumber": "52",
- "newId": "bd7157d8c441eddfaeb5bdef"
- },
- {
- "oldNumber": "53",
- "newId": "bd7158d8c441eddfaeb5bdef"
- },
- {
- "oldNumber": "54",
- "newId": ""
- },
- {
- "oldNumber": "55",
- "newId": ""
- }
-]
diff --git a/seed/challenges/advanced-bonfires.json b/seed/challenges/advanced-bonfires.json
index 04ab7c18b2..115b236eba 100644
--- a/seed/challenges/advanced-bonfires.json
+++ b/seed/challenges/advanced-bonfires.json
@@ -157,7 +157,6 @@
"Global Object"
],
"solutions": [
- "var VALUES = [1, 5, 10, 25, 100, 500, 1000, 2000, 10000];\n\nfunction drawer(price, cash, cid) {\n cash = ~~(cash * 100);\n price = ~~(price * 100);\n var diff = cash-price;\n cid.forEach(function(c) {\n c[1] = ~~(c[1] * 100);\n });\n var totalCid = cid.reduce(function(a, c) {\n return a + c[1];\n }, 0);\n if (diff > totalCid) {\n return \"Insufficient Funds\";\n }\n if (diff === totalCid) {\n return \"Closed\";\n }\n \n var change = []; \n var index = cid.length;\n while (diff > 0 && --index > -1) {\n var t = 0;\n var value = VALUES[index];\n while (diff >= value && cid[index][1] > 0) {\n t += value;\n cid[index][1] -= value;\n diff -= value;\n }\n if (t) {\n change.push([cid[index][0], t/100]);\n }\n console.log(JSON.stringify(change));\n }\n // Here is your change, ma'am.\n return change;\n}\n\n// Example cash-in-drawer array:\n// [['PENNY', 1.01],\n// ['NICKEL', 2.05],\n// ['DIME', 3.10],\n// ['QUARTER', 4.25],\n// ['ONE', 90.00],\n// ['FIVE', 55.00],\n// ['TEN', 20.00],\n// ['TWENTY', 60.00],\n// ['ONE HUNDRED', 100.00]]\n\ndrawer(19.50, 20.00, [['PENNY', 1.01], ['NICKEL', 2.05], ['DIME', 3.10], ['QUARTER', 4.25], ['ONE', 90.00], ['FIVE', 55.00], ['TEN', 20.00], ['TWENTY', 60.00], ['ONE HUNDRED', 100.00]]);\n"
],
"type": "bonfire",
"challengeType": 5,
diff --git a/seed/challenges/angularjs.json b/seed/challenges/angularjs.json
index 905c120f33..c55221e0fe 100644
--- a/seed/challenges/angularjs.json
+++ b/seed/challenges/angularjs.json
@@ -14,7 +14,12 @@
],
"type": "waypoint",
"challengeType": 2,
- "tests": [],
+ "tests": [
+ "assert(true, 'No test needed');"
+ ],
+ "solutions": [
+ "/* no test needed */"
+ ],
"nameCn": "",
"descriptionCn": [],
"nameFr": "",
@@ -37,7 +42,12 @@
],
"type": "waypoint",
"challengeType": 2,
- "tests": [],
+ "tests": [
+ "assert(true, 'No test needed');"
+ ],
+ "solutions": [
+ "/* no test needed */"
+ ],
"nameCn": "",
"descriptionCn": [],
"nameFr": "",
@@ -60,7 +70,12 @@
],
"type": "waypoint",
"challengeType": 2,
- "tests": [],
+ "tests": [
+ "assert(true, 'No test needed');"
+ ],
+ "solutions": [
+ "/* no test needed */"
+ ],
"nameCn": "",
"descriptionCn": [],
"nameFr": "",
@@ -82,7 +97,12 @@
],
"type": "waypoint",
"challengeType": 2,
- "tests": [],
+ "tests": [
+ "assert(true, 'No test needed');"
+ ],
+ "solutions": [
+ "/* no test needed */"
+ ],
"nameCn": "",
"descriptionCn": [],
"nameFr": "",
@@ -105,7 +125,12 @@
],
"type": "waypoint",
"challengeType": 2,
- "tests": [],
+ "tests": [
+ "assert(true, 'No test needed');"
+ ],
+ "solutions": [
+ "/* no test needed */"
+ ],
"nameCn": "",
"descriptionCn": [],
"nameFr": "",
diff --git a/seed/challenges/basic-bonfires.json b/seed/challenges/basic-bonfires.json
index 8ac6cbcae7..505b91fd5e 100644
--- a/seed/challenges/basic-bonfires.json
+++ b/seed/challenges/basic-bonfires.json
@@ -116,7 +116,7 @@
"Arithmetic Operators"
],
"solutions": [
- "function factorialize(num) {\n return num === 1 ? 1 : num * factorialize(num-1);\n}\n\nfactorialize(5);\n"
+ "function factorialize(num) {\n return num < 1 ? 1 : num * factorialize(num-1);\n}\n\nfactorialize(5);\n"
],
"type": "bonfire",
"challengeType": 5,
@@ -169,7 +169,6 @@
"String.toLowerCase()"
],
"solutions": [
- "function palindrome(str) {\n var a = str.toLowerCase().replace(/[^a-z]/g, '');\n console.log(a.split('').reverse().join(''));\n return a == a.split('').reverse().join('');\n}\n\n\n\npalindrome(\"eye\");\npalindrome(\"A man, a plan, a canal. Panama\");\n"
],
"type": "bonfire",
"challengeType": 5,
@@ -243,8 +242,8 @@
"titleCase(\"I'm a little tea pot\");"
],
"tests": [
- "assert(typeof(titleCase(\"I'm a little tea pot\")) === \"string\", 'message: titleCase() should return a string.');",
- "assert(titleCase(\"I'm a little tea pot\") === \"I'm A Little Tea Pot\", 'message: titleCase(\"I'm a little tea pot\") should return \"I'm A Little Tea Pot\".');",
+ "assert(typeof(titleCase(\"I'm a little tea pot\")) === \"string\", 'message: titleCase() should return a string.');",
+ "assert(titleCase(\"I'm a little tea pot\") === \"I'm A Little Tea Pot\", 'message: titleCase(\"I'm a little tea pot\") should return \"I'm A Little Tea Pot\".');",
"assert(titleCase(\"sHoRt AnD sToUt\") === \"Short And Stout\", 'message: titleCase(\"sHoRt AnD sToUt\") should return \"Short And Stout\".');",
"assert(titleCase(\"HERE IS MY HANDLE HERE IS MY SPOUT\") === \"Here Is My Handle Here Is My Spout\", 'message: titleCase(\"HERE IS MY HANDLE HERE IS MY SPOUT\") should return \"Here Is My Handle Here Is My Spout\".');"
],
@@ -273,7 +272,6 @@
"description": [
"Return an array consisting of the largest number from each provided sub-array. For simplicity, the provided array will contain exactly 4 sub-arrays.",
"Remember, you can iterate through an array with a simple for loop, and access each member with array syntax arr[i] .",
- "If you are writing your own Chai.js tests, be sure to use a deep equal statement instead of an equal statement when comparing arrays.",
"Remember to use Read-Search-Ask if you get stuck. Write your own code."
],
"challengeSeed": [
@@ -418,7 +416,6 @@
"String.slice()"
],
"solutions": [
- "function truncate(str, num) {\n if (str.length > num) {\n return str.substring(0, num-3) + '...';\n }\n return str;\n}\n\ntruncate('A-tisket a-tasket A green and yellow basket', 11);\n"
],
"type": "bonfire",
"challengeType": 5,
@@ -664,9 +661,7 @@
"MDNlinks": [
"Array.sort()"
],
- "solutions": [
- "function where(arr, num) {\n // Find my place in this sorted array.\n return num;\n}\n\nwhere([40, 60], 50);\n"
- ],
+ "solutions": [],
"tests": [
"assert(where([10, 20, 30, 40, 50], 35) === 3, 'message: where([10, 20, 30, 40, 50], 35) should return 3.');",
"assert(where([10, 20, 30, 40, 50], 30) === 2, 'message: where([10, 20, 30, 40, 50], 30) should return 2.');",
diff --git a/seed/challenges/basic-javascript.json b/seed/challenges/basic-javascript.json
index 14769b9818..c8663c4f27 100644
--- a/seed/challenges/basic-javascript.json
+++ b/seed/challenges/basic-javascript.json
@@ -653,7 +653,7 @@
"In JavaScript, we can divide up our code into reusable parts called functions.",
"Here's an example of a function:",
"function functionName(a, b) {",
- " return a + b;",
+ " return a + b;",
"}",
"After writing the above lines in our code, we can then pass values to our function and the result following the return statement will be returned.",
"For example, we can pass numbers 4 and 2 by “calling” the function later in our code like this: functionName(4, 2).",
@@ -694,10 +694,10 @@
"Objects are similar to arrays, except that instead of using indexes to access and modify their data, you access the data in objects through what are called properties.",
"Here's a sample object:",
"var cat = {",
- " \"name\": \"Whiskers\",",
- " \"legs\": 4,",
- " \"tails\": 1,",
- " \"enemies\": [\"Water\", \"Dogs\"]",
+ " \"name\": \"Whiskers\",",
+ " \"legs\": 4,",
+ " \"tails\": 1,",
+ " \"enemies\": [\"Water\", \"Dogs\"]",
"};",
"",
"Objects are useful for storing data in a structured way, and can represent real world objects, like a cat.",
@@ -741,10 +741,10 @@
"After you've created a JavaScript object, you can update its properties at any time just like you would update any other variable.",
"For example, let's look at ourDog:",
"var ourDog = {",
- " \"name\": \"Camper\",",
- " \"legs\": 4,",
- " \"tails\": 1,,",
- " \"friends\": [\"everything!\"]",
+ " \"name\": \"Camper\",",
+ " \"legs\": 4,",
+ " \"tails\": 1,,",
+ " \"friends\": [\"everything!\"]",
"};",
"Since he's a particularly happy dog, let's change his name to \"Happy Camper\". Here's how we update his object's name property:",
"ourDog.name = \"Happy Camper\";",
@@ -868,16 +868,16 @@
"The most common type of JavaScript loop is called a \"for loop\" because it runs \"for\" a specific number of times.",
"For loops are declared with three optional expressions seperated by semicolons:",
"for([initialization]; [condition]; [final-expression])",
- "The initialization statement is executed one time only before the loop starts. It is typically used to define and setup your loop varaible.",
- "The condition statement is evaluated at the beginning of every loop and will continue as long as it evalutes true. When condition is false at the start of the loop, the loop will stop executing. This means if condition starts as false, your loop will never execute.",
+ "The initialization statement is executed one time only before the loop starts. It is typically used to define and setup your loop variable.",
+ "The condition statement is evaluated at the beginning of every loop iteration and will continue as long as it evalutes to true. When condition is false at the start of the iteration, the loop will stop executing. This means if condition starts as false, your loop will never execute.",
"The final-expression is executed at the end of each loop iteration, prior to the next condition check and is usually used to increment or decrement your loop counter.",
- "We'll initialize with i = 0 and loop while our condition i < 5 is true. We'll increment i by 1 each loop with i++ as our final-expression.",
+ "In the following example we initialize with i = 0 and iterate while our condition i < 5 is true. We'll increment i by 1 in each loop iteration with i++ as our final-expression.",
"var ourArray = [];",
"for(var i = 0; i < 5; i++) {",
- " ourArray.push(i);",
+ " ourArray.push(i);",
"}",
- "ourArray will now contain [0,1,2,3,4] ",
- "Let's try getting a for loop to work by pushing values to an array."
+ "ourArray will now contain [0,1,2,3,4].",
+ "Let's try getting a for loop to work by pushing values to an array."
],
"tests": [
"assert(editor.getValue().match(/for\\s*\\(/g).length > 1, 'message: You should be using a for loop for this.');",
@@ -912,7 +912,7 @@
"We'll start at i = 0 and loop while i < 10. We'll increment i by 2 each loop with i += 2.",
"var ourArray = [];",
"for(var i = 0; i < 10; i += 2) {",
- " ourArray.push(i);",
+ " ourArray.push(i);",
"}",
"ourArray will now contain [0,2,4,6,8] ",
"Let's change our initialization and final-expression so we can count by odd numbers.",
@@ -925,7 +925,7 @@
"challengeSeed":[
"var ourArray = [];",
"",
- "for(var i = 1; i < 10; i += 2){",
+ "for(var i = 0; i < 10; i += 2){",
" ourArray.push(i);",
"}",
"",
@@ -952,7 +952,7 @@
"We'll start at i = 10 and loop while i > 0. We'll decrement i by 2 each loop with i -= 2.",
"var ourArray = [];",
"for(var i = 10; i > 0; i -= 2) {",
- " ourArray.push(i);",
+ " ourArray.push(i);",
"}",
"ourArray will now contain [10,8,6,4,2]",
"Let's change our initialization and final-expression so we can count backward by twos for numbers.",
@@ -992,8 +992,8 @@
"var ourArray = [];",
"var i = 0;",
"while(i < 5) {",
- " ourArray.push(i);",
- " i++;",
+ " ourArray.push(i);",
+ " i++;",
"}",
"Let's try getting a while loop to work by pushing values to an array.",
"Push the numbers 0 through 4 to myArray using a while loop."
@@ -1093,7 +1093,7 @@
"Here's the formula we'll use. Take a moment to read it and try to understand what this code is doing:",
"Math.floor(Math.random() * (max - min + 1)) + min",
"Define two variables: myMin and myMax, and set them both equal to numbers.",
- "Then create a function called myFunction that returns a random number that's greater than or equal to myMin, and is less than myMax."
+ "Then create a function called myFunction that returns a random number that's greater than or equal to myMin, and is less than or equal to myMax."
],
"tests": [
"assert(myFunction() >= myMin, 'message: The random number generated by myFunction should be greater than or equal to your minimum number, myMin.');",
@@ -1140,9 +1140,9 @@
"if statements require some sort of boolean condition to evaluate.",
"For example:",
"if (1 === 2) {",
- " return true;",
+ " return true;",
"} else {",
- " return false;",
+ " return false;",
"}",
"Let's use if and else statements to make a coin-flip game.",
"Create if and else statements to return the string \"heads\" if the flip variable is zero, or else return the string \"tails\" if the flip variable is not zero."
@@ -1183,7 +1183,7 @@
"i means that we want to ignore the case (uppercase or lowercase) when searching for the pattern.",
"Regular expressions are written by surrounding the pattern with / symbols.",
"Let's try selecting all the occurrences of the word and in the string Ada Lovelace and Charles Babbage designed the first computer and the software that would have run on it.",
- "We can do this by replacing the . part of our regular expression with the current regular expression with the word and."
+ "We can do this by replacing the . part of our regular expression with the word and."
],
"tests": [
"assert(test==2, 'message: Your regular expression should find two occurrences of the word and.');",
@@ -1460,7 +1460,7 @@
"If all three numbers match, we should return the number that we have in three of slots or leave it as null.",
"Let's create an if statement with multiple conditions in order to check whether all numbers are equal.",
"if(slotOne !== slotTwo || slotTwo !== slotThree){",
- " return null;",
+ " return null;",
"}"
],
"tests": [
diff --git a/seed/challenges/bootstrap.json b/seed/challenges/bootstrap.json
index 4306f0b5f7..913d4a26db 100644
--- a/seed/challenges/bootstrap.json
+++ b/seed/challenges/bootstrap.json
@@ -183,7 +183,8 @@
"<h2 class=\"red-text text-center\">your text</h2>"
],
"tests": [
- "assert($(\"h2\").hasClass(\"text-center\"), 'Your h2 element should be centered by applying the class text-center')"
+ "assert($(\"h2\").hasClass(\"text-center\"), 'Your h2 element should be centered by applying the class text-center')",
+ "assert($(\"h2\").hasClass(\"red-text\"), 'Your h2 element should still have the class red-text')"
],
"challengeSeed": [
"",
diff --git a/seed/challenges/html5-and-css.json b/seed/challenges/html5-and-css.json
index 4372a5cf6b..6ceb796a9c 100644
--- a/seed/challenges/html5-and-css.json
+++ b/seed/challenges/html5-and-css.json
@@ -381,7 +381,7 @@
"</style>",
"Inside that style element, you can create a CSS selector for all h2 elements. For example, if you wanted all h2 elements to be red, your style element would look like this:",
"<style>",
- " h2 {color: red;}",
+ " h2 {color: red;}",
"</style>",
"Note that it's important to have both opening and closing curly braces ({ and }) around each element's style. You also need to make sure your element's style is between the opening and closing style tags. Finally, be sure to add the semicolon to the end of each of your element's styles.",
"Delete your h2 element's style attribute and instead create a CSS style element. Add the necessary CSS to turn all h2 elements blue."
@@ -390,7 +390,7 @@
"assert(!$(\"h2\").attr(\"style\"), 'Remove the style attribute from your h2 element.')",
"assert($(\"style\") && $(\"style\").length > 1, 'Create a style element.')",
"assert($(\"h2\").css(\"color\") === \"rgb(0, 0, 255)\", 'Your h2 element should be blue.')",
- "assert(editor.match(/h2\\s*\\{\\s*color:\\s*blue;\\s*\\}/g), 'Ensure that your stylesheet h2 declaration is valid with a semicolon and closing brace')",
+ "assert(editor.match(/h2\\s*\\{\\s*color\\s*:\\s*blue;\\s*\\}/g), 'Ensure that your stylesheet h2 declaration is valid with a semicolon and closing brace')",
"assert(editor.match(/<\\/style>/g) && editor.match(/<\\/style>/g).length === (editor.match(/