Merge branch 'staging' of github.com:FreeCodeCamp/freecodecamp into staging
This commit is contained in:
@ -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.
|
||||
|
@ -66,6 +66,8 @@ bower install
|
||||
# Create a .env file and populate it with the necessary API keys and secrets:
|
||||
touch .env
|
||||
|
||||
# Install Gulp globally
|
||||
npm install -g gulp
|
||||
```
|
||||
|
||||
Edit your .env file with the following API keys accordingly (if you only use email login, only the MONGOHQ_URL, SESSION_SECRET, MANDRILL_USER and MANDRILL_PASSWORD fields are necessary. Keep in mind if you want to use more services you'll have to get your own API keys for those services.
|
||||
@ -112,6 +114,11 @@ DEBUG=true
|
||||
# Start the mongo server
|
||||
mongod
|
||||
|
||||
# Create your mongo database.
|
||||
# Type "mongo" in your terminal to access the mongo shell
|
||||
use freecodecamp
|
||||
# Exit the mongo shell with control + d
|
||||
|
||||
# Seed your database with the challenges
|
||||
node seed/
|
||||
|
||||
|
18
gulpfile.js
18
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']);
|
||||
|
@ -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",
|
||||
|
@ -13,7 +13,8 @@
|
||||
"<code>// This is a comment.</code>",
|
||||
"The slash-star-star-slash comment will comment out everything between the <code>/*</code> and the <code>*/</code> characters:",
|
||||
"<code>/* This is also a comment */</code>",
|
||||
"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 <code>assert()</code> functions (in some challenges <code>except()</code>, <code>assert.equal()</code> 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 <code>\\/\\/</code> style comment that contains at least five letters');",
|
||||
@ -606,7 +607,7 @@
|
||||
"Take the myArray array and <code>shift()</code> 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 @@
|
||||
"<code>function functionName (a, b) {</code>",
|
||||
"<code>  return(a + b);</code>",
|
||||
"<code>}</code>",
|
||||
"We can \"call\" our function like this: <code>functionName();</code>, and it will run and return it's <code>return</code> value to us.",
|
||||
"Create and call a function called <code>myFunction</code>."
|
||||
"We can \"call\" our function like this: <code>functionName();</code>, and it will run and return its <code>return</code> value to us.",
|
||||
"Create and call a function called <code>myFunction</code> 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');"
|
||||
@ -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":[
|
||||
|
@ -177,7 +177,7 @@
|
||||
"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 <code>text-center</code> to our <code>h1</code> and <code>h2</code> elements.",
|
||||
"Remember that you can add several classes to the same element by separating each of them with a space, like this: <code><h2 class=\"text-red text-center\">your text</h2></code>."
|
||||
"Remember that you can add several classes to the same element by separating each of them with a space, like this: <code><h2 class=\"red-text text-center\">your text</h2></code>."
|
||||
],
|
||||
"tests": [
|
||||
"assert($(\"h2\").hasClass(\"text-center\"), 'Your <code>h2</code> element should be centered by applying the class <code>text-center</code>')"
|
||||
@ -614,7 +614,7 @@
|
||||
"Note that these buttons still need the <code>btn</code> and <code>btn-block</code> classes."
|
||||
],
|
||||
"tests": [
|
||||
"assert(new RegExp(\"delete\",\"gi\").test($(\"button\").text()), 'Create a new <code>button</code> element with the text \"delete\".')",
|
||||
"assert(new RegExp(\"Delete\",\"gi\").test($(\"button\").text()), 'Create a new <code>button</code> element with the text \"Delete\".')",
|
||||
"assert($(\"button.btn-block.btn\").length > 2, 'All of your Bootstrap buttons should have the <code>btn</code> and <code>btn-block</code> classes.')",
|
||||
"assert($(\"button\").hasClass(\"btn-danger\"), 'Your new button should have the class <code>btn-danger</code>.')",
|
||||
"assert(editor.match(/<\\/button>/g) && editor.match(/<button/g) && editor.match(/<\\/button>/g).length === editor.match(/<button/g).length, 'Make sure all your <code>button</code> elements have a closing tag.')"
|
||||
@ -893,7 +893,7 @@
|
||||
"title": "Use Spans for Inline Elements",
|
||||
"difficulty": 2.105,
|
||||
"description": [
|
||||
"You can use use spans to create inline elements. Remember when we used the <code>btn-block</code> class to make the button fill the entire row?",
|
||||
"You can use spans to create inline elements. Remember when we used the <code>btn-block</code> class to make the button fill the entire row?",
|
||||
"This image illustrates the difference between <code>inline</code> elements and <code>block-level</code> elements:",
|
||||
"<img class=\"img-responsive\" src=\"http://i.imgur.com/O32cDWE.png\" alt=\"An \"inline\" button is as small as the text it contains. In this image, it's centered. Below it is a \"block-level\" button, which stretches to fill the entire horizontal space.'>",
|
||||
"By using the <code>span</code> element, you can put several elements together, and even style different parts of the same element differently.",
|
||||
|
@ -16,7 +16,7 @@
|
||||
"Choose Node.js in the selection area below the name field.",
|
||||
"Click the Create button. Then click into your new workspace.",
|
||||
"In the lower right hand corner you should see a terminal window. In this window use the following commands. You don't need to know what these mean at this point.",
|
||||
"Install <code>how-to-npm</code> with this command: <code>npm install -g git-it</code>",
|
||||
"Install <code>git-it</code> with this command: <code>npm install -g git-it</code>",
|
||||
"Now start the tutorial by running <code>git-it</code>.",
|
||||
"Note that you can resize the c9.io's windows by dragging their borders.",
|
||||
"Make sure that you are always in your project's \"workspace\" directory. You can always navigate back to this directory by running this command: <code>cd ~/workspace</code>.",
|
||||
|
@ -754,7 +754,7 @@
|
||||
"difficulty": 1.17,
|
||||
"description": [
|
||||
"You can add images to your website by using the <code>img</code> element, and point to a specific image's URL using the <code>src</code> attribute.",
|
||||
"An example of this would be <code><img src=\"www.your-image-source.com/your-image.jpg\"></code>. Note that in most cases, <code>img</code> elements are self-closing.",
|
||||
"An example of this would be <code><img src=\"http://www.your-image-source.com/your-image.jpg\"></code>. Note that in most cases, <code>img</code> elements are self-closing.",
|
||||
"Try it with this image: <code>https://bit.ly/fcc-relaxing-cat</code>."
|
||||
],
|
||||
"tests": [
|
||||
@ -3285,7 +3285,7 @@
|
||||
"Let's override your <code>pink-text</code> and <code>blue-text</code> classes, and make your <code>h1</code> element orange, by giving the <code>h1</code> element an id and then styling that id.",
|
||||
"Give your <code>h1</code> element the <code>id</code> attribute of <code>orange-text</code>. Remember, id styles look like this: <code><h1 id=\"orange-text\"></code>",
|
||||
"Leave the <code>blue-text</code> and <code>pink-text</code> classes on your <code>h1</code> element.",
|
||||
"Create a CSS declaration for your <code>orange-text</code> id in your <code>style</code> element. Here's and example of what this looks like: <code>#brown-text { color: brown; }</code>"
|
||||
"Create a CSS declaration for your <code>orange-text</code> id in your <code>style</code> element. Here's an example of what this looks like: <code>#brown-text { color: brown; }</code>"
|
||||
],
|
||||
"tests": [
|
||||
"assert($(\"h1\").hasClass(\"pink-text\"), 'Your <code>h1</code> element should have the class <code>pink-text</code>.')",
|
||||
|
@ -17,7 +17,7 @@
|
||||
"assert(editor.match(/<script>/g), 'Create a <code>script</code> element.')",
|
||||
"assert(editor.match(/<\\/script>/g) && editor.match(/<script/g) && editor.match(/<\\/script>/g).length === editor.match(/<script/g).length, 'Make sure your <code>script</code> element has a closing tag.')",
|
||||
"assert(editor.match(/\\$\\(document\\)\\.ready\\(function\\(\\)\\s?\\{/g), 'Add <code>$(document).ready(function() {</code> to the beginning of your <code>script</code> element.')",
|
||||
"assert(editor.match(/\\n\\s+?\\}\\);/g), 'Close your <code>$(document).ready(function() {</code> function with <code>});</code>.')"
|
||||
"assert(editor.match(/\\n?\\s+?\\}\\);/g), 'Close your <code>$(document).ready(function() {</code> function with <code>});</code>.')"
|
||||
],
|
||||
"challengeSeed": [
|
||||
"",
|
||||
|
@ -29,7 +29,7 @@ module.exports = function(loopbackApp) {
|
||||
|
||||
loopbackApp.once('started', function() {
|
||||
app.listen(port, function() {
|
||||
console.log('https redirect lisenting on port %s', port);
|
||||
console.log('https redirect listening on port %s', port);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
@ -1,12 +1,5 @@
|
||||
var path = require('path'),
|
||||
// debug = require('debug')('freecc:cntr:resources'),
|
||||
cheerio = require('cheerio'),
|
||||
var cheerio = require('cheerio'),
|
||||
request = require('request'),
|
||||
R = require('ramda'),
|
||||
_ = require('lodash'),
|
||||
fs = require('fs'),
|
||||
|
||||
|
||||
MDNlinks = require('../../seed/bonfireMDNlinks'),
|
||||
resources = require('./resources.json'),
|
||||
nonprofits = require('../../seed/nonprofits.json');
|
||||
@ -14,33 +7,7 @@ var path = require('path'),
|
||||
/**
|
||||
* Cached values
|
||||
*/
|
||||
var allNonprofitNames,
|
||||
challengeMap, challengeMapForDisplay, challengeMapWithIds,
|
||||
challengeMapWithNames, allChallengeIds,
|
||||
challengeMapWithDashedNames;
|
||||
|
||||
(function() {
|
||||
if (!challengeMap) {
|
||||
var localChallengeMap = {};
|
||||
var files = fs.readdirSync(
|
||||
path.join(__dirname, '../../seed/challenges')
|
||||
);
|
||||
var keyCounter = 0;
|
||||
files = files.map(function(file) {
|
||||
return require(
|
||||
path.join(__dirname, '../../seed/challenges/' + file)
|
||||
);
|
||||
});
|
||||
files = files.sort(function(a, b) {
|
||||
return a.order - b.order;
|
||||
});
|
||||
files.forEach(function(file) {
|
||||
localChallengeMap[keyCounter++] = file;
|
||||
});
|
||||
challengeMap = _.cloneDeep(localChallengeMap);
|
||||
}
|
||||
})();
|
||||
|
||||
var allNonprofitNames;
|
||||
|
||||
module.exports = {
|
||||
dasherize: function dasherize(name) {
|
||||
@ -59,75 +26,6 @@ module.exports = {
|
||||
.trim();
|
||||
},
|
||||
|
||||
getChallengeMapForDisplay: function() {
|
||||
if (!challengeMapForDisplay) {
|
||||
challengeMapForDisplay = {};
|
||||
Object.keys(challengeMap).forEach(function(key) {
|
||||
challengeMapForDisplay[key] = {
|
||||
name: challengeMap[key].title,
|
||||
dashedName: challengeMap[key].title.replace(/\s/g, '-'),
|
||||
challenges: challengeMap[key].challenges,
|
||||
completedCount: challengeMap[key].challenges
|
||||
};
|
||||
});
|
||||
}
|
||||
return challengeMapForDisplay;
|
||||
},
|
||||
|
||||
getChallengeMapWithIds: function() {
|
||||
if (!challengeMapWithIds) {
|
||||
challengeMapWithIds = {};
|
||||
Object.keys(challengeMap).forEach(function(key) {
|
||||
var onlyIds = challengeMap[key].challenges.map(function(elem) {
|
||||
return elem.id;
|
||||
});
|
||||
challengeMapWithIds[key] = onlyIds;
|
||||
});
|
||||
}
|
||||
return challengeMapWithIds;
|
||||
},
|
||||
|
||||
allChallengeIds: function() {
|
||||
|
||||
if (!allChallengeIds) {
|
||||
allChallengeIds = [];
|
||||
Object.keys(this.getChallengeMapWithIds()).forEach(function(key) {
|
||||
allChallengeIds.push(challengeMapWithIds[key]);
|
||||
});
|
||||
allChallengeIds = R.flatten(allChallengeIds);
|
||||
}
|
||||
return allChallengeIds;
|
||||
},
|
||||
|
||||
getChallengeMapWithNames: function() {
|
||||
if (!challengeMapWithNames) {
|
||||
challengeMapWithNames = {};
|
||||
Object.keys(challengeMap).
|
||||
forEach(function(key) {
|
||||
var onlyNames = challengeMap[key].challenges.map(function(elem) {
|
||||
return elem.name;
|
||||
});
|
||||
challengeMapWithNames[key] = onlyNames;
|
||||
});
|
||||
}
|
||||
return challengeMapWithNames;
|
||||
},
|
||||
|
||||
getChallengeMapWithDashedNames: function() {
|
||||
if (!challengeMapWithDashedNames) {
|
||||
challengeMapWithDashedNames = {};
|
||||
Object.keys(challengeMap).
|
||||
forEach(function(key) {
|
||||
var onlyNames = challengeMap[key].challenges.map(function(elem) {
|
||||
return elem.dashedName;
|
||||
});
|
||||
challengeMapWithDashedNames[key] = onlyNames;
|
||||
});
|
||||
}
|
||||
return challengeMapWithDashedNames;
|
||||
},
|
||||
|
||||
|
||||
randomPhrase: function() {
|
||||
return resources.phrases[
|
||||
Math.floor(Math.random() * resources.phrases.length)
|
||||
|
@ -14,7 +14,7 @@ block content
|
||||
else
|
||||
a.btn.btn-lg.btn-block.btn-github.btn-link-social(href='/link/github')
|
||||
i.fa.fa-github
|
||||
| Update my profile from Github
|
||||
| Update my profile from GitHub
|
||||
|
||||
if (!user.twitter)
|
||||
.col-xs-12
|
||||
@ -72,4 +72,4 @@ block content
|
||||
input(type='hidden', name='_csrf', value=_csrf)
|
||||
button.btn.btn-danger.btn-block(type='submit')
|
||||
span.ion-trash-b
|
||||
| Yes, Delete my account
|
||||
| Yes, delete my account
|
||||
|
@ -103,7 +103,7 @@ script.
|
||||
"</a>" +
|
||||
"</div>" +
|
||||
"<div class='story-byline col-xs-12 wrappable'>" +
|
||||
"<a class='btn btn-no-shadow btn-primary btn-xs btn-primary-ghost' href='/news/" + linkedName + "'>more info.more info...</a> · " +
|
||||
"<a class='btn btn-no-shadow btn-primary btn-xs btn-primary-ghost' href='/news/" + linkedName + "'>more info...</a> · " +
|
||||
rank + (rank > 1 ? " points" : " point") + " · posted " +
|
||||
moment(data[i].timePosted).fromNow() +
|
||||
" by <a href='/" + data[i].author.username + "'>@" + data[i].author.username +
|
||||
|
Reference in New Issue
Block a user