diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 78e8e395da..ba4e245107 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,2 +1,2 @@ We're getting a lot of duplicate issues and bug reports that just aren't reporting actual bugs. -So, before you submit your issue, please read the [Help! I've Found a Bug](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Help!-I've-Found-a-Bug) wiki page. +So, before you submit your issue, please read the [Help I've Found a Bug](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Help-I've-Found-a-Bug) wiki page. diff --git a/gulpfile.js b/gulpfile.js index 8e1e345716..9cfded3db8 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -19,10 +19,12 @@ var Rx = require('rx'), sync = require('browser-sync'), inject = require('gulp-inject'), + // css less = require('gulp-less'), // lint + jsonlint = require('gulp-jsonlint'), eslint = require('gulp-eslint'); @@ -60,6 +62,11 @@ var paths = { syncWatch: [ 'public/**/*.*' + ], + + challenges: [ + 'seed/challenges/*.json', + 'seed/under-construction/*.json' ] }; @@ -163,12 +170,20 @@ gulp.task('sync', ['serve'], function() { }); }); -gulp.task('lint', function() { +gulp.task('lint-js', function() { return gulp.src(['public/js/lib/**/*']) .pipe(eslint()) .pipe(eslint.format()); }); +gulp.task('lint-json', function() { + return gulp.src(paths.challenges) + .pipe(jsonlint()) + .pipe(jsonlint.reporter()); +}); + +gulp.task('test-challenges', ['lint-json']); + gulp.task('less', function() { return gulp.src('./public/css/*.less') .pipe(plumber({ errorHandler: errorHandler })) @@ -182,6 +197,7 @@ gulp.task('build', ['less']); gulp.task('watch', ['less', 'serve', 'sync'], function() { gulp.watch('./public/css/*.less', ['less']); + gulp.watch(paths.challenges, ['test-challenges']); }); gulp.task('default', ['less', 'serve', 'sync', 'watch', 'pack-watch']); diff --git a/package.json b/package.json index b14ee1e15f..8aa3c12d40 100644 --- a/package.json +++ b/package.json @@ -120,6 +120,7 @@ "gulp": "~3.8.8", "gulp-eslint": "~0.9.0", "gulp-inject": "~1.0.2", + "gulp-jsonlint": "^1.1.0", "gulp-nodemon": "^2.0.3", "gulp-notify": "^2.2.0", "gulp-plumber": "^1.0.1", diff --git a/public/css/main.less b/public/css/main.less index 2deec50cca..45cd2daed4 100644 --- a/public/css/main.less +++ b/public/css/main.less @@ -683,9 +683,9 @@ thead { margin-right: 0px; padding-left: 10px; padding-right: 10px; + padding-top: 14px; + padding-bottom: 12px; &:hover { - padding-top: 14px; - padding-bottom: 12px; color: #4a2b0f; background-color: #eee; text-decoration: none; diff --git a/public/js/calculator.js b/public/js/calculator.js index 207611c9e6..9ae06e890a 100644 --- a/public/js/calculator.js +++ b/public/js/calculator.js @@ -28,7 +28,7 @@ $(document).ready(function () { $('#chosen').text('Coming from ' + city.replace(/-/g, ' ').replace(/\w\S*/g, function (txt) { return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase(); }) + ', and making $' + lastYearsIncome.toString().replace(/0000$/, '0,000') + ', your true costs will be:'); - var categoryNames = ['Lost Wages', 'Financing Cost', 'Housing Cost', 'Tuition / Wage Garnishing']; + var categoryNames = ['Lost Wages', 'Financing Cost', 'Housing Cost', 'Tuition / Est. Wage Garnishing']; bootcamps.forEach(function (camp) { var x0 = 0; if (camp.cities.indexOf(city) > -1) { @@ -38,7 +38,7 @@ $(document).ready(function () { } camp.mapping = [{ name: camp.name, - label: 'Tuition / Wage Garnishing', + label: 'Tuition / Est. Wage Garnishing', value: +camp.cost, x0: x0, x1: x0 += +camp.cost diff --git a/public/json/bootcamps.json b/public/json/bootcamps.json index 41b906c20b..19b016607c 100644 --- a/public/json/bootcamps.json +++ b/public/json/bootcamps.json @@ -221,7 +221,28 @@ "cities": [ "portland" ] -}, { +}, + { + "name": "Viking Code School", + "cost": "18000", + "housing": "0", + "finance": false, + "weeks": "16", + "cities": [ + "online" + ] + }, + { + "name": "App Academy", + "cost": "18000", + "housing": "500", + "finance": false, + "weeks": "12", + "cities": [ + "san-francisco" + ] + }, + { "name": "Turing School", "cost": "17500", "housing": "400", @@ -230,13 +251,4 @@ "cities": [ "denver" ] -}, { - "name": "Free Code Camp", - "cost": "0", - "housing": "0", - "finance": false, - "weeks": "0", - "cities": [ - "online" - ] }] diff --git a/seed/challenges/basic-javascript.json b/seed/challenges/basic-javascript.json index 5aeecfdae6..3465c9dcb1 100644 --- a/seed/challenges/basic-javascript.json +++ b/seed/challenges/basic-javascript.json @@ -13,7 +13,8 @@ "// This is a comment.", "The slash-star-star-slash comment will comment out everything between the /* and the */ characters:", "/* This is also a comment */", - "Try creating one of each." + "Try creating one of each.", + "And one more thing you need to notice. Starting at this waypoint in JavaScript related challenges (except AngularJS, all Ziplines, Git, Node.js and Express.js, MongoDB and Full Stack JavaScript Projects) you can see contents of assert() functions (in some challenges except(), assert.equal() and so on) which are used to test your code. It's part of these challenges that you are able to see the tests that are running against your code." ], "tests":[ "assert(editor.getValue().match(/(\\/\\/)...../g), 'Create a \\/\\/ style comment that contains at least five letters');", @@ -606,7 +607,7 @@ "Take the myArray array and shift() the first value off of it." ], "tests": [ - "assert((function(d){if(d[0] == 23 && d[1][0] == 'dog' && d[1][1] == 3 && d[2] == undefined){return(true);}else{return(false);}})(myArray), 'myArray should only have the first two values left([\"John\", 23])');", + "assert((function(d){if(d[0] == 23 && d[1][0] == 'dog' && d[1][1] == 3 && d[2] == undefined){return(true);}else{return(false);}})(myArray), 'myArray should only have the last two values left([23, [\"dog\", 3]])');", "assert((function(d){if(d === 'John' && typeof(myRemoved) === 'string'){return(true);}else{return(false);}})(myRemoved), 'myRemoved should contain \"John\"');" ], "challengeSeed": [ @@ -670,8 +671,8 @@ "function functionName (a, b) {", "  return(a + b);", "}", - "We can \"call\" our function like this: functionName();, and it will run and return it's return value to us.", - "Create and call a function called myFunction." + "We can \"call\" our function like this: functionName();, and it will run and return its return value to us.", + "Create and call a function called myFunction that returns the sum of a and b." ], "tests":[ "assert((function(){if(typeof(f) !== \"undefined\" && typeof(f) === \"number\" && f === a + b && editor.getValue().match(/return/gi).length >= 1 && editor.getValue().match(/a/gi).length >= 1 && editor.getValue().match(/b/gi).length >= 1 && editor.getValue().match(/\\+/gi).length >= 1){return(true);}else{return(false);}})(), 'Your function should return the value of a + b');" @@ -684,9 +685,9 @@ " return a - b;", "};", "", - "//Don't modify above this line", - "//Create a function called myFunction that returns the value of a plus b.", - " // Only change code below this line.", + "// Don't modify above this line", + "// Create a function called myFunction that returns the value of a plus b.", + "// Only change code below this line.", "", "", "", @@ -718,7 +719,7 @@ "};", "", "Objects are useful for storing data in a structured way, and can represents real world objects, like a cats.", - "Let's try to make an Object that represents a dog called myDog!" + "Let's try to make an Object that represents a dog called myDog which contains the properties 'name' (String), 'legs' (Number), 'tails' (Number) and 'friends' (Array)!" ], "tests":[ "assert((function(z){if(z.hasOwnProperty(\"name\") && z.name !== undefined && typeof(z.name) === \"string\"){return(true);}else{return(false);}})(myDog), 'myDog should contain the property name and it should be a string');", @@ -903,7 +904,7 @@ "tests":[ "assert(typeof(myFunction()) === \"number\", 'The result of myFunction should be a number');", "assert(editor.getValue().match(/Math.random/g), 'You should be using Math.random to create a random number');", - "assert(!(''+myFunction()).match(/\\./g), 'You should have multiplied the result of Math.random by 10 to make it a number that\\'s greater then zero');", + "assert(!(''+myFunction()).match(/\\./g), 'You should have multiplied the result of Math.random by 10 to make it a number that\\'s greater than zero');", "assert(editor.getValue().match(/Math.floor/g), 'You should use Math.floor to remove the decimal part of the number');" ], "challengeSeed":[ @@ -1006,7 +1007,7 @@ "g means that we want to search the entire string for this pattern.", "i means that we want to ignore the case (uppercase or lowercase) when searching for the pattern.", "Regular expressions are usually surrounded by / symbols.", - "Let's try selecting all the occurrences of the word and in the string George Boole and Alan Turing went to the shop and got some milk. We can do this by replacing the .+ part of our regular expression with the current regular expression with the word and." + "Let's try selecting all the occurrences of the word and in the string George Boole and Alan Turing went to the shop and got some milk. We can do this by replacing the . part of our regular expression with the word and." ], "tests":[ "assert(test==2, 'Your regular expression should find two occurrences of the word and');", @@ -1040,7 +1041,7 @@ ], "tests":[ "assert(test === 2, 'Your RegEx should have found two numbers in the testString');", - "assert(editor.getValue().match(/\\/\\\\d\\+\\//gi), 'You should be using the following expression /\\d+/gi to find the numbers in the testString');" + "assert(editor.getValue().match(/\\/\\\\d\\+\\//gi), 'You should be using the following expression /\\\\d+/gi to find the numbers in the testString');" ], "challengeSeed":[ "var test = (function() {", @@ -1070,7 +1071,7 @@ ], "tests":[ "assert(test === 7, 'Your RegEx should have found seven spaces in the testString.');", - "assert(editor.getValue().match(/\\/\\\\s\\+\\//gi), 'You should be using the following expression /\\s+/gi to find the spaces in the testString.');" + "assert(editor.getValue().match(/\\/\\\\s\\+\\//gi), 'You should be using the following expression /\\\\s+/gi to find the spaces in the testString.');" ], "challengeSeed":[ "var test = (function(){", @@ -1098,7 +1099,7 @@ ], "tests":[ "assert(test === 49, 'Your RegEx should have found forty nine non-space characters in the testString.');", - "assert(editor.getValue().match(/\\/\\\\S\\/gi/gi), 'You should be using the following expression /\\S/gi to find non-space characters in the testString.');" + "assert(editor.getValue().match(/\\/\\\\S\\/gi/gi), 'You should be using the following expression /\\\\S/gi to find non-space characters in the testString.');" ], "challengeSeed":[ "var test = (function(){", @@ -1277,8 +1278,8 @@ "description":[ "Now that our slots will each generate random numbers, we need to check whether they've all returned the same number.", "If they have, we should notify our user that they've won.", - "Otherwise, we should return null, which is a JavaScript literal representing null or an \"empty\" value, i.e. no object value is present.", - "If all three numbers match, we should return the number that we have in three of slots or leave it as null.", + "Otherwise, we should return null, which is a JavaScript data structure that means nothing.", + "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);", diff --git a/seed/challenges/basic-ziplines.json b/seed/challenges/basic-ziplines.json index 37e547c4e3..d97d049b80 100644 --- a/seed/challenges/basic-ziplines.json +++ b/seed/challenges/basic-ziplines.json @@ -45,6 +45,7 @@ "Rule #1: Don't look at the example project's code on CodePen. Figure it out for yourself.", "Rule #2: You may use whichever libraries or APIs you need.", "Rule #3: Reverse engineer the example project's functionality, and also feel free to personalize it.", + "Hint: If you don't want to start from scratch, you can fork this simple Bootstrap portfolio template on CodePen: http://codepen.io/FreeCodeCamp/pen/mJNqQj.", "Here are the user stories you must enable, and optional bonus user stories:", "User Story: As a user, I can access all of the portfolio webpage's content just by scrolling.", "User Story: As a user, I can click different buttons that will take me to the portfolio creator's different social media pages.", diff --git a/seed/challenges/bootstrap.json b/seed/challenges/bootstrap.json index 4211392b8a..5f5d0ff63e 100644 --- a/seed/challenges/bootstrap.json +++ b/seed/challenges/bootstrap.json @@ -176,8 +176,8 @@ "title": "Center Text with Bootstrap", "difficulty": 2.03, "description": [ - "Now that we're using Bootstrap, we can center our heading elements to make them look better. All we need to do is add the class text-center to our h1 and h2 elements.", - "Remember that you can add several classes to the same element by separating each of them with a space, like this: <h2 class=\"text-red text-center\">your text</h2>." + "Now that we're using Bootstrap, we can center our heading element to make it look better. All we need to do is add the class text-center to our h2 element.", + "Remember that you can add several classes to the same element by separating each of them with a space, like this: <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')" @@ -347,7 +347,7 @@ "description": [ "Normally, your button elements are only as wide as the text that they contain. By making them block elements, your button will stretch to fill your page's entire horizontal space.", "This image illustrates the difference between inline elements and block-level elements:", - "\"An", + "\"An", "Note that these buttons still need the btn class.", "Add Bootstrap's btn-block class to your Bootstrap button." ], @@ -614,7 +614,7 @@ "Note that these buttons still need the btn and btn-block classes." ], "tests": [ - "assert(new RegExp(\"delete\",\"gi\").test($(\"button\").text()), 'Create a new button element with the text \"delete\".')", + "assert(new RegExp(\"Delete\",\"gi\").test($(\"button\").text()), 'Create a new button element with the text \"Delete\".')", "assert($(\"button.btn-block.btn\").length > 2, 'All of your Bootstrap buttons should have the btn and btn-block classes.')", "assert($(\"button\").hasClass(\"btn-danger\"), 'Your new button should have the class btn-danger.')", "assert(editor.match(/<\\/button>/g) && editor.match(/