Merge branch 'master' into courseware

Conflicts:
	controllers/bonfire.js
	views/layout.jade
This commit is contained in:
Michael Q Larson
2015-02-02 23:32:46 -08:00
27 changed files with 360 additions and 186 deletions

View File

@ -73,6 +73,10 @@ exports.returnIndividualBonfire = function(req, res, next) {
if (err) { if (err) {
next(err); next(err);
} }
var dashedNameFull = bonfire[bonfireNumber].name.toLowerCase().replace(/\s/g, '-');
if (dashedNameFull != dashedName) {
return res.redirect('/bonfires/' + dashedNameFull);
}
if (bonfire.length < 1) { if (bonfire.length < 1) {
req.flash('errors', { req.flash('errors', {
msg: "404: We couldn't find a bonfire with that name. Please double check the name." msg: "404: We couldn't find a bonfire with that name. Please double check the name."

View File

@ -220,7 +220,10 @@
"Most triumphant!", "Most triumphant!",
"One loop to rule them all!", "One loop to rule them all!",
"Ain't got time to bleed!", "Ain't got time to bleed!",
"By the power of Grayskull!" "By the power of Grayskull!",
"You did it!",
"Storm that castle!",
"Face-melting guitar Solo!"
], ],
"phrases": [ "phrases": [
"Shout it from on top of a mountain", "Shout it from on top of a mountain",

View File

@ -93,25 +93,19 @@ exports.getEmailSignup = function(req, res) {
*/ */
exports.postEmailSignup = function(req, res, next) { exports.postEmailSignup = function(req, res, next) {
console.log('post email signup called');
req.assert('email', 'Email is not valid').isEmail();
req.assert('password', 'Password must be at least 4 characters long').len(4);
req.assert('confirmPassword', 'Passwords do not match')
.equals(req.body.password);
var errors = req.validationErrors(); var errors = req.validationErrors();
if (errors) { if (errors) {
req.flash('errors', errors); req.flash('errors', errors);
return res.redirect('/email-signup'); return res.redirect('/email-signup');
console.log(errors); debug(errors);
} }
var user = new User({ var user = new User({
email: req.body.email, email: req.body.email.trim(),
password: req.body.password, password: req.body.password,
profile : { profile : {
username: req.body.username username: req.body.username.trim()
} }
}); });
@ -132,6 +126,29 @@ exports.postEmailSignup = function(req, res, next) {
res.redirect('/email-signup'); res.redirect('/email-signup');
}); });
}); });
var transporter = nodemailer.createTransport({
service: 'Mandrill',
auth: {
user: secrets.mandrill.user,
pass: secrets.mandrill.password
}
});
var mailOptions = {
to: user.email,
from: 'Team@freecodecamp.com',
subject: 'Welcome to Free Code Camp!',
text: [
'Greetings from San Francisco!\n\n',
'Thank you for joining our community.\n',
'Feel free to email us at this address if you have any questions about Free Code Camp.\n',
"And if you have a moment, check out our blog: blog.freecodecamp.com.\n",
'Good luck with the challenges!\n\n',
'- the Volunteer Camp Counselor Team'
].join('')
};
transporter.sendMail(mailOptions, function(err) {
if (err) { return err; }
});
}); });
}; };
@ -141,17 +158,8 @@ exports.postEmailSignup = function(req, res, next) {
*/ */
exports.getAccount = function(req, res) { exports.getAccount = function(req, res) {
Challenge.find({}, null, { sort: { challengeNumber: 1 } }, function(err, c) {
if (err) {
console.error('Challenge err: ', err);
next(err);
}
res.render('account/account', { res.render('account/account', {
title: 'Manage your Free Code Camp Account', title: 'Manage your Free Code Camp Account'
challenges: c,
ch: req.user.challengesHash,
moment: moment
});
}); });
}; };
@ -160,15 +168,9 @@ exports.getAccount = function(req, res) {
*/ */
exports.getAccountAngular = function(req, res) { exports.getAccountAngular = function(req, res) {
Challenge.find({}, null, { sort: { challengeNumber: 1 } }, function(err, c) {
if (err) {
console.error('Challenge err: ', err);
next(err);
}
res.json({ res.json({
user: req.user user: req.user
}); });
});
}; };
/** /**
@ -322,26 +324,26 @@ exports.postUpdateProfile = function(req, res, next) {
return res.redirect('/account'); return res.redirect('/account');
} }
var user = req.user; var user = req.user;
user.email = req.body.email || ''; user.email = req.body.email.trim() || '';
user.profile.name = req.body.name || ''; user.profile.name = req.body.name.trim() || '';
user.profile.username = req.body.username || ''; user.profile.username = req.body.username.trim() || '';
user.profile.location = req.body.location || ''; user.profile.location = req.body.location.trim() || '';
user.profile.githubProfile = req.body.githubProfile || ''; user.profile.githubProfile = req.body.githubProfile.trim() || '';
user.profile.coderbyteProfile = req.body.coderbyteProfile || ''; user.profile.coderbyteProfile = req.body.coderbyteProfile.trim() || '';
user.profile.linkedinProfile = req.body.linkedinProfile || ''; user.profile.linkedinProfile = req.body.linkedinProfile.trim() || '';
user.profile.codepenProfile = req.body.codepenProfile || ''; user.profile.codepenProfile = req.body.codepenProfile.trim() || '';
user.profile.twitterHandle = req.body.twitterHandle || ''; user.profile.twitterHandle = req.body.twitterHandle.trim() || '';
user.profile.bio = req.body.bio || ''; user.profile.bio = req.body.bio.trim() || '';
user.profile.picture = req.body.picture || ''; user.profile.picture = req.body.picture.trim() || '';
user.portfolio.website1Title = req.body.website1Title || ''; user.portfolio.website1Title = req.body.website1Title.trim() || '';
user.portfolio.website1Link = req.body.website1Link || ''; user.portfolio.website1Link = req.body.website1Link.trim() || '';
user.portfolio.website1Image = req.body.website1Image || ''; user.portfolio.website1Image = req.body.website1Image.trim() || '';
user.portfolio.website2Title = req.body.website2Title || ''; user.portfolio.website2Title = req.body.website2Title.trim() || '';
user.portfolio.website2Link = req.body.website2Link || ''; user.portfolio.website2Link = req.body.website2Link.trim() || '';
user.portfolio.website2Image = req.body.website2Image || ''; user.portfolio.website2Image = req.body.website2Image.trim() || '';
user.portfolio.website3Title = req.body.website3Title || ''; user.portfolio.website3Title = req.body.website3Title.trim() || '';
user.portfolio.website3Link = req.body.website3Link || ''; user.portfolio.website3Link = req.body.website3Link.trim() || '';
user.portfolio.website3Image = req.body.website3Image || ''; user.portfolio.website3Image = req.body.website3Image.trim() || '';
user.save(function (err) { user.save(function (err) {
@ -456,9 +458,6 @@ exports.getReset = function(req, res) {
*/ */
exports.postReset = function(req, res, next) { exports.postReset = function(req, res, next) {
req.assert('password', 'Password must be at least 4 characters long.').len(4);
req.assert('confirm', 'Passwords must match.').equals(req.body.password);
var errors = req.validationErrors(); var errors = req.validationErrors();
if (errors) { if (errors) {
@ -547,8 +546,6 @@ exports.getForgot = function(req, res) {
*/ */
exports.postForgot = function(req, res, next) { exports.postForgot = function(req, res, next) {
req.assert('email', 'Please enter a valid email address.').isEmail();
var errors = req.validationErrors(); var errors = req.validationErrors();
if (errors) { if (errors) {

View File

@ -11,7 +11,8 @@
}, },
"scripts": { "scripts": {
"start": "node app.js", "start": "node app.js",
"test": "mocha" "test": "mocha",
"prepublish": "node seed_data/seed.js"
}, },
"dependencies": { "dependencies": {
"async": "^0.9.0", "async": "^0.9.0",
@ -32,12 +33,9 @@
"express-flash": "^0.0.2", "express-flash": "^0.0.2",
"express-session": "^1.9.2", "express-session": "^1.9.2",
"express-validator": "^2.8.0", "express-validator": "^2.8.0",
"fbgraph": "^0.3.0",
"github-api": "^0.7.0", "github-api": "^0.7.0",
"helmet": "^0.5.3", "helmet": "^0.5.3",
"instagram-node": "^0.5.1",
"jade": "^1.8.0", "jade": "^1.8.0",
"lastfm": "^0.9.2",
"less": "^1.7.5", "less": "^1.7.5",
"lodash": "^2.4.1", "lodash": "^2.4.1",
"lusca": "^1.0.2", "lusca": "^1.0.2",
@ -47,25 +45,18 @@
"morgan": "^1.5.0", "morgan": "^1.5.0",
"newrelic": "^1.13.3", "newrelic": "^1.13.3",
"node": "0.0.0", "node": "0.0.0",
"node-foursquare": "^0.2.1",
"node-linkedin": "^0.3.4",
"node-rest-client": "^1.4.3", "node-rest-client": "^1.4.3",
"nodemailer": "^1.3.0", "nodemailer": "^1.3.0",
"passport": "^0.2.1", "passport": "^0.2.1",
"passport-facebook": "^1.0.3", "passport-facebook": "^1.0.3",
"passport-github": "^0.1.5", "passport-github": "^0.1.5",
"passport-google-oauth": "^0.1.5", "passport-google-oauth": "^0.1.5",
"passport-instagram": "^0.1.2",
"passport-linkedin-oauth2": "^1.2.1", "passport-linkedin-oauth2": "^1.2.1",
"passport-local": "^1.0.0", "passport-local": "^1.0.0",
"passport-oauth": "^1.0.0", "passport-oauth": "^1.0.0",
"passport-twitter": "^1.0.2", "passport-twitter": "^1.0.2",
"request": "^2.49.0", "request": "^2.49.0",
"sitemap": "^0.7.4", "sitemap": "^0.7.4",
"stripe": "^3.0.2",
"tumblr.js": "^0.0.4",
"twilio": "^1.9.0",
"twit": "^1.1.18",
"uglify-js": "^2.4.15", "uglify-js": "^2.4.15",
"validator": "^3.22.1", "validator": "^3.22.1",
"yui": "^3.18.1" "yui": "^3.18.1"

12
public/browserconfig.xml Normal file
View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
<msapplication>
<tile>
<square70x70logo src="/mstile-70x70.png"/>
<square150x150logo src="/mstile-150x150.png"/>
<square310x310logo src="/mstile-310x310.png"/>
<wide310x150logo src="/mstile-310x150.png"/>
<TileColor>#492c14</TileColor>
</tile>
</msapplication>
</browserconfig>

View File

@ -154,6 +154,11 @@ ul {
} }
.landing-icon { .landing-icon {
height: 200px;
width: 200px;
}
.completion-icon{
font-size: 150px; font-size: 150px;
} }

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

17
public/favicons.html Normal file
View File

@ -0,0 +1,17 @@
<link rel="apple-touch-icon" sizes="57x57" href="/apple-touch-icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="/apple-touch-icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="/apple-touch-icon-72x72.png">
<link rel="apple-touch-icon" sizes="76x76" href="/apple-touch-icon-76x76.png">
<link rel="apple-touch-icon" sizes="114x114" href="/apple-touch-icon-114x114.png">
<link rel="apple-touch-icon" sizes="120x120" href="/apple-touch-icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="/apple-touch-icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="/apple-touch-icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon-180x180.png">
<link rel="icon" type="image/png" href="/favicon-32x32.png" sizes="32x32">
<link rel="icon" type="image/png" href="/android-chrome-192x192.png" sizes="192x192">
<link rel="icon" type="image/png" href="/favicon-96x96.png" sizes="96x96">
<link rel="icon" type="image/png" href="/favicon-16x16.png" sizes="16x16">
<link rel="manifest" href="/android-chrome-manifest.json">
<meta name="msapplication-TileColor" content="#492c14">
<meta name="msapplication-TileImage" content="/mstile-144x144.png">
<meta name="theme-color" content="#ffffff">

View File

@ -22,6 +22,11 @@ var editor = myCodeMirror;
editor.setSize("100%", "auto"); editor.setSize("100%", "auto");
var attempts = 0;
if (attempts) {
attempts = 0;
}
// Default value for editor if one isn't provided in (i.e. a challenge) // Default value for editor if one isn't provided in (i.e. a challenge)
var nonChallengeValue = '/*Welcome to Bonfire, Free Code Camp\'s future CoderByte replacement.\n' + var nonChallengeValue = '/*Welcome to Bonfire, Free Code Camp\'s future CoderByte replacement.\n' +
'Please feel free to use Bonfire as an in-browser playground and linting tool.\n' + 'Please feel free to use Bonfire as an in-browser playground and linting tool.\n' +
@ -100,15 +105,18 @@ $('#submitButton').on('click', function () {
}); });
function bonfireExecute() { function bonfireExecute() {
attempts++;
ga('send', 'event', 'Bonfire', 'ran-code', bonfireName);
userTests= null; userTests= null;
$('#codeOutput').empty(); $('#codeOutput').empty();
var userJavaScript = myCodeMirror.getValue(); var userJavaScript = myCodeMirror.getValue();
userJavaScript = removeComments(userJavaScript); userJavaScript = removeComments(userJavaScript);
userJavaScript = scrapeTests(userJavaScript); userJavaScript = scrapeTests(userJavaScript);
// simple fix in case the user forgets to invoke their function // simple fix in case the user forgets to invoke their function
if (challengeEntryPoint) { if (challengeEntryPoint && challengeSeed) {
userJavaScript = challengeEntryPoint + ' ' + userJavaScript; userJavaScript = challengeEntryPoint + ' ' + userJavaScript;
} }
console.log(userJavaScript);
submit(userJavaScript, function(cls, message) { submit(userJavaScript, function(cls, message) {
if (cls) { if (cls) {
codeOutput.setValue(message.error); codeOutput.setValue(message.error);
@ -224,5 +232,7 @@ var runTests = function(err, data) {
}; };
function showCompletion() { function showCompletion() {
ga('send', 'event', 'Bonfire', 'solved', bonfireName + ', Time: ' + (Math.floor(Date.now() / 1000) - started) +', Attempts: ' + attempts);
$('#complete-bonfire-dialog').modal('show'); $('#complete-bonfire-dialog').modal('show');
} }

View File

@ -1,4 +1,7 @@
$(document).ready(function() { $(document).ready(function() {
if (bonfireName !== undefined) {
ga('send', 'event', 'Bonfire', 'load', bonfireName + ':' + Math.floor(Date.now() / 1000));
}
var CSRF_HEADER = 'X-CSRF-Token'; var CSRF_HEADER = 'X-CSRF-Token';
@ -61,7 +64,6 @@ $(document).ready(function() {
var bonfireSolution = myCodeMirror.getValue(); var bonfireSolution = myCodeMirror.getValue();
var thisBonfireHash = passedBonfireHash || null; var thisBonfireHash = passedBonfireHash || null;
var didCompleteWith = $('#completed-with').val() || null; var didCompleteWith = $('#completed-with').val() || null;
completedBonfire(didCompleteWith, bonfireSolution, thisBonfireHash); completedBonfire(didCompleteWith, bonfireSolution, thisBonfireHash);
}); });
@ -83,6 +85,7 @@ $(document).ready(function() {
// Bonfire instructions functions // Bonfire instructions functions
$('#more-info').on('click', function() { $('#more-info').on('click', function() {
ga('send', 'event', 'Bonfire', 'more-info', bonfireName);
$('#brief-instructions').hide(); $('#brief-instructions').hide();
$('#long-instructions').show().removeClass('hide'); $('#long-instructions').show().removeClass('hide');

View File

@ -1,7 +1,7 @@
[ [
{ {
"_id" : "ad7123c8c441eddfaeb5bdef", "_id" : "ad7123c8c441eddfaeb5bdef",
"name": "Meet Bonfire", "name": "Meet Bonfire!",
"difficulty": "0", "difficulty": "0",
"description": [ "description": [
"Click the button below for further instructions.", "Click the button below for further instructions.",
@ -255,6 +255,34 @@
"assert.deepEqual(inventory([], [[2, 'Hair Pin'], [3, 'Half-Eaten Apple'], [67, 'Bowling Ball'], [7, 'Toothpaste']]), [[2, 'Hair Pin'], [3, 'Half-Eaten Apple'], [67, 'Bowling Ball'], [7, 'Toothpaste']]);", "assert.deepEqual(inventory([], [[2, 'Hair Pin'], [3, 'Half-Eaten Apple'], [67, 'Bowling Ball'], [7, 'Toothpaste']]), [[2, 'Hair Pin'], [3, 'Half-Eaten Apple'], [67, 'Bowling Ball'], [7, 'Toothpaste']]);",
"assert.deepEqual(inventory([[0, 'Bowling Ball'], [0, 'Dirty Sock'], [0, 'Hair pin'], [0, 'Microphone']], [[1, 'Hair Pin'], [1, 'Half-Eaten Apple'], [1, 'Bowling Ball'], [1, 'Toothpaste']]), [[1, 'Bowling Ball'], [1, 'Dirty Sock'], [1, 'Hair pin'], [1, 'Half-Eaten Apple'], [1, 'Microphone'], [1, 'Toothpaste']]);" "assert.deepEqual(inventory([[0, 'Bowling Ball'], [0, 'Dirty Sock'], [0, 'Hair pin'], [0, 'Microphone']], [[1, 'Hair Pin'], [1, 'Half-Eaten Apple'], [1, 'Bowling Ball'], [1, 'Toothpaste']]), [[1, 'Bowling Ball'], [1, 'Dirty Sock'], [1, 'Hair pin'], [1, 'Half-Eaten Apple'], [1, 'Microphone'], [1, 'Toothpaste']]);"
] ]
},
{
"_id": "a2f1d72d9b908d0bd72bb9f6",
"name": "Make a Person",
"difficulty": "3.12",
"description": [
"Fill in the object constructor with the methods specified in the tests.",
"Those methods are getFirstName(), getLastName(), getFullName(), setFirstName(), setLastName(), and setFullName().",
"These methods must be the only available means for interacting with the object.",
"There will be some linting errors on the tests, you may safely ignore them. You should see undefined in the console output."
],
"challengeEntryPoint": "var bob = new Person('Bob Ross');",
"challengeSeed": "var Person = function(firstAndLast) {\n return firstAndLast;\r\n};",
"tests": [
"expect(Object.keys(bob).length).to.eql(6);",
"expect(bob instanceof Person).to.be.true;",
"expect(bob.firstName).to.be.undefined();",
"expect(bob.lastName).to.be.undefined();",
"expect(bob.getFirstName()).to.eql('Bob');",
"expect(bob.getLastName()).to.eql('Ross');",
"expect(bob.getFullName()).to.eql('Bob Ross');",
"bob.setFirstName('Happy');",
"expect(bob.getFirstName()).to.eql('Happy');",
"bob.setLastName('Trees');",
"expect(bob.getLastName()).to.eql('Trees');",
"bob.setFullName('George Carlin');",
"expect(bob.getFullName()).to.eql('George Carlin');"
]
} }
] ]

View File

@ -420,8 +420,8 @@
"OK, we're finally ready to start pair programming!", "OK, we're finally ready to start pair programming!",
"Pair Programming is where two people code together on the same computer. It is an efficient way to collaborate, and widely practiced at software companies. Pair Programming is one of the core concepts of \"Agile\" Software Development, which you will hear more about later.", "Pair Programming is where two people code together on the same computer. It is an efficient way to collaborate, and widely practiced at software companies. Pair Programming is one of the core concepts of \"Agile\" Software Development, which you will hear more about later.",
"Many people use Skype or Google Hangouts to pair program, but if you talk with professional software engineers, they will tell you that it's not really pair programming unless both people have the ability to use the keyboard and mouse.", "Many people use Skype or Google Hangouts to pair program, but if you talk with professional software engineers, they will tell you that it's not really pair programming unless both people have the ability to use the keyboard and mouse.",
"The most popular tool for pair programming is Screen Hero. Note that Screen Hero isn't free, and isn't yet available for Linux. Screen Hero does come with a 14 day free trial, is free for students, and you can also use it for free if your pair has a 14-day trial or a paid subscription to it. Download Screen Hero here: <a href='https://screenhero.com/download.html' target='_blank'>https://screenhero.com/download.html</a>.", "The most popular tool for pair programming is Screen Hero. You can download Screen Hero for <a href='http://links.screenhero.com/e/c/eyJlbWFpbF9pZCI6Ik1qQTNNem9XQkNJQ1pBQUNjd0FYQVZrVEdnRkxNamtfX0JWZEdGVEpSZkVCWlRwbFpXRTBNamM0WVMxaE56SmlMVEV4WlRRdE9HUXpZUzFpWXpVNE1HRTJNalkxTldNNk1UUTJNVEEyQUE9PSIsInBvc2l0aW9uIjowLCJocmVmIjoiaHR0cDovL2RsLnNjcmVlbmhlcm8uY29tL3NtYXJ0ZG93bmxvYWQvZklYQU1UUUJBTEtQQkhQTC9TY3JlZW5oZXJvLnppcD9zb3VyY2U9d2ViIn0=' target='_blank'>Mac</a> or <a href='http://links.screenhero.com/e/c/eyJlbWFpbF9pZCI6Ik1qQTNNem9XQkNJQ1pBQUNjd0FYQVZrVEdnRkxNamtfX0JWZEdGVEpSZkVCWlRwbFpXRTBNamM0WVMxaE56SmlMVEV4WlRRdE9HUXpZUzFpWXpVNE1HRTJNalkxTldNNk1UUTJNVEEyQUE9PSIsInBvc2l0aW9uIjoxLCJocmVmIjoiaHR0cDovL2RsLnNjcmVlbmhlcm8uY29tL3NtYXJ0ZG93bmxvYWQvZklYQU1UUUJBTEtQQkhQTC9TY3JlZW5oZXJvLXNldHVwLmV4ZSJ9' target='_blank'>Windows</a>. Create your new user account from within the app.",
"If you are using Linux, or if your 14 day free trial for Screen Hero has expired and you don't want to pay $10 per month for it, go to <a href='http://www.freecodecamp.com/pair-program-with-team-viewer' target='_blank'>http://www.freecodecamp.com/pair-program-with-team-viewer</a> to learn how to use an alternative (but inferior) tool called Team Viewer.", "If you are using Linux, go to <a href='http://www.freecodecamp.com/pair-program-with-team-viewer' target='_blank'>http://www.freecodecamp.com/pair-program-with-team-viewer</a> to learn how to use an alternative (but inferior) tool called Team Viewer.",
"We have a special chat room for people ready to pair program. Go to <a href='https://gitter.im/FreeCodeCamp/LetsPair' target='_blank'>https://gitter.im/FreeCodeCamp/LetsPair</a> and type \"Hello Pair Programmers!\"", "We have a special chat room for people ready to pair program. Go to <a href='https://gitter.im/FreeCodeCamp/LetsPair' target='_blank'>https://gitter.im/FreeCodeCamp/LetsPair</a> and type \"Hello Pair Programmers!\"",
"If someone is available, they will be your \"pair\" - the person you pair programming with.", "If someone is available, they will be your \"pair\" - the person you pair programming with.",
"Private message your pair and ask for the email address he or she used to register Screen Hero.", "Private message your pair and ask for the email address he or she used to register Screen Hero.",

View File

@ -14,15 +14,15 @@ block content
label.col-sm-3.col-sm-offset-2.control-label(for='name') Name * label.col-sm-3.col-sm-offset-2.control-label(for='name') Name *
.col-sm-4 .col-sm-4
input.form-control(type='text', placeholder='Name', name='name', autocomplete="off", ng-model='user.profile.name', ng-minlength='3', ng-maxlength='50', required='required', id='name') input.form-control(type='text', placeholder='Name', name='name', autocomplete="off", ng-model='user.profile.name', ng-minlength='3', ng-maxlength='50', required='required', id='name')
.col-sm-4.col-sm-offset-5(ng-show="profileForm.name.$invalid && profileForm.name.$error.required") .col-sm-4.col-sm-offset-5(ng-cloak, ng-show="profileForm.name.$invalid && profileForm.name.$error.required")
alert(type='danger') alert(type='danger')
span.ion-close-circled(id='#name-error') span.ion-close-circled(id='#name-error')
| Your name is required. | Your name is required.
.col-sm-4.col-sm-offset-5(ng-show='profileForm.name.$error.minlength && !profileForm.name.$pristine') .col-sm-4.col-sm-offset-5(ng-cloak, ng-show='profileForm.name.$error.minlength && !profileForm.name.$pristine')
alert(type='danger') alert(type='danger')
span.ion-close-circled span.ion-close-circled
| Your name must be at least 3 characters. | Your name must be at least 3 characters.
.col-sm-4.col-sm-offset-5(ng-show='profileForm.name.$error.maxlength && !profileForm.name.$pristine') .col-sm-4.col-sm-offset-5(ng-cloak, ng-show='profileForm.name.$error.maxlength && !profileForm.name.$pristine')
alert(type='danger') alert(type='danger')
span.ion-close-circled span.ion-close-circled
| Your name must be fewer than 50 characters. | Your name must be fewer than 50 characters.
@ -31,43 +31,43 @@ block content
label.col-sm-3.col-sm-offset-2.control-label(for='username') Username (path to public profile) * label.col-sm-3.col-sm-offset-2.control-label(for='username') Username (path to public profile) *
.col-sm-4 .col-sm-4
input.form-control(type='text', placeholder='username' name='username', autocomplete="off", id='username', ng-model='user.profile.username', required='required', ng-minlength='5', ng-maxlength='20', ng-keypress='', unique-username='', ng-pattern="/^[A-z0-9_]+$/") input.form-control(type='text', placeholder='username' name='username', autocomplete="off", id='username', ng-model='user.profile.username', required='required', ng-minlength='5', ng-maxlength='20', ng-keypress='', unique-username='', ng-pattern="/^[A-z0-9_]+$/")
.col-sm-4.col-sm-offset-5(ng-show="profileForm.username.$error.pattern") .col-sm-4.col-sm-offset-5(ng-cloak, ng-show="profileForm.username.$error.pattern")
alert(type='danger') alert(type='danger')
span.ion-close-circled span.ion-close-circled
| Your username should only contain letters, numbers and underscores (az10_). | Your username should only contain letters, numbers and underscores (az10_).
.col-sm-4.col-sm-offset-5(ng-show="profileForm.username.$error.required") .col-sm-4.col-sm-offset-5(ng-cloak, ng-show="profileForm.username.$error.required")
alert(type='danger') alert(type='danger')
span.ion-close-circled span.ion-close-circled
| Your username is required. | Your username is required.
.col-sm-4.col-sm-offset-5(ng-show="profileForm.username.$error.minlength && !profileForm.username.$pristine") .col-sm-4.col-sm-offset-5(ng-cloak, ng-show="profileForm.username.$error.minlength && !profileForm.username.$pristine")
alert(type='danger') alert(type='danger')
span.ion-close-circled span.ion-close-circled
| Your username must be at least 5 characters. | Your username must be at least 5 characters.
.col-sm-4.col-sm-offset-5(ng-show="profileForm.username.$error.maxlength && !profileForm.username.$pristine") .col-sm-4.col-sm-offset-5(ng-cloak, ng-show="profileForm.username.$error.maxlength && !profileForm.username.$pristine")
alert(type='danger') alert(type='danger')
span.ion-close-circled span.ion-close-circled
| Your username must be fewer than 15 characters. | Your username must be fewer than 15 characters.
.col-sm-4.col-sm-offset-5(ng-show="profileForm.username.$error.unique && !profileForm.username.$pristine && $scope.storedUsername !== user.profile.username") .col-sm-4.col-sm-offset-5(ng-cloak, ng-show="profileForm.username.$error.unique && !profileForm.username.$pristine && $scope.storedUsername !== user.profile.username")
alert(type='danger') alert(type='danger')
span.ion-close-circled span.ion-close-circled
| That username is already taken. | That username is already in use.
.form-group .form-group
label.col-sm-3.col-sm-offset-2.control-label(for='email') Email * label.col-sm-3.col-sm-offset-2.control-label(for='email') Email *
.col-sm-4 .col-sm-4
input.form-control(type='email', name='email', id='email', autocomplete="off", ng-model='user.email', required='required', ng-keypress='', unique-email='') input.form-control(type='email', name='email', id='email', autocomplete="off", ng-model='user.email', required='required', ng-keypress='', unique-email='')
.col-sm-4.col-sm-offset-5(ng-show="profileForm.email.$error.required") .col-sm-4.col-sm-offset-5(ng-cloak, ng-show="profileForm.email.$error.required")
alert(type='danger') alert(type='danger')
span.ion-close-circled span.ion-close-circled
| Your email address is required. | Your email address is required.
.col-sm-4.col-sm-offset-5(ng-show="profileForm.$error.email && !profileForm.email.$pristine") .col-sm-4.col-sm-offset-5(ng-cloak, ng-show="profileForm.$error.email && !profileForm.email.$pristine")
alert(type='danger') alert(type='danger')
span.ion-close-circled span.ion-close-circled
| Please enter a valid email format. | Please enter a valid email format.
.col-sm-4.col-sm-offset-5(ng-show="profileForm.email.$error.unique && !profileForm.email.$pristine") .col-sm-4.col-sm-offset-5(ng-cloak, ng-show="profileForm.email.$error.unique && !profileForm.email.$pristine")
alert(type='danger') alert(type='danger')
span.ion-close-circled span.ion-close-circled
| That email is already taken. | That email is already in use.
.form-group .form-group
label.col-sm-3.col-sm-offset-2.control-label(for='location') Location label.col-sm-3.col-sm-offset-2.control-label(for='location') Location
@ -77,17 +77,20 @@ block content
.form-group .form-group
label.col-sm-3.col-sm-offset-2.control-label(for='email') Link to Profile Photo (1:1 ratio) label.col-sm-3.col-sm-offset-2.control-label(for='email') Link to Profile Photo (1:1 ratio)
.col-sm-4 .col-sm-4
input.form-control(type='url', name='picture', id='picture', ng-model='user.profile.picture', placeholder='http://') input.form-control(type='url', name='picture', id='picture', ng-model='user.profile.picture', placeholder='http://www.example.com/image.jpg', ng-pattern="/[\.](jpg|png|jpeg|gif)\s?$/")
.col-sm-4.col-sm-offset-5(ng-show="profileForm.picture.$error.url && !profileForm.picture.$pristine") .col-sm-4.col-sm-offset-5(ng-show="profileForm.picture.$error.url && !profileForm.picture.$pristine")
alert(type='danger') alert(type='danger')
span.ion-close-circled span.ion-close-circled
| Please enter a valid URL format (http://www.example.com). | Please enter a valid URL format (http://www.example.com/image.jpg).
.col-sm-4.col-sm-offset-5(ng-show="profileForm.picture.$error.pattern")
alert(type='danger')
span.ion-close-circled
| The image URL must end in .jpg, .png, .jpeg or .gif.
.form-group .form-group
label.col-sm-3.col-sm-offset-2.control-label(for='bio') Bio (140 characters) label.col-sm-3.col-sm-offset-2.control-label(for='bio') Bio (140 characters)
.col-sm-4 .col-sm-4
input.form-control(type='text', name='bio', autocomplete="off", ng-model='user.profile.bio', ng-maxlength='140', id='bio') input.form-control(type='text', name='bio', autocomplete="off", ng-model='user.profile.bio', ng-maxlength='140', id='bio')
.col-sm-4.col-sm-offset-5(ng-show='profileForm.bio.$error.maxlength && !profileForm.bio.$pristine') .col-sm-4.col-sm-offset-5(ng-cloak, ng-show='profileForm.bio.$error.maxlength && !profileForm.bio.$pristine')
alert(type='danger') alert(type='danger')
span.ion-close-circled span.ion-close-circled
| Your bio must be fewer than 140 characters. | Your bio must be fewer than 140 characters.
@ -107,11 +110,11 @@ block content
.input-group.twitter-input .input-group.twitter-input
span.input-group-addon @ span.input-group-addon @
input.form-control(type='text', name='twitterHandle', autocomplete="off", id='twitterHandle', ng-model='user.profile.twitterHandle', ng-maxlength='15', ng-pattern="/^[A-z0-9_]+$/") input.form-control(type='text', name='twitterHandle', autocomplete="off", id='twitterHandle', ng-model='user.profile.twitterHandle', ng-maxlength='15', ng-pattern="/^[A-z0-9_]+$/")
.col-sm-4.col-sm-offset-5(ng-show="profileForm.twitterHandle.$error.pattern") .col-sm-4.col-sm-offset-5(ng-cloak, ng-show="profileForm.twitterHandle.$error.pattern")
alert(type='danger') alert(type='danger')
span.ion-close-circled span.ion-close-circled
| Your Twitter handle should only contain letters, numbers and underscores (az10_). | Your Twitter handle should only contain letters, numbers and underscores (az10_).
.col-sm-4.col-sm-offset-5(ng-show='profileForm.twitterHandle.$error.maxlength && !profileForm.twitterHandle.$pristine') .col-sm-4.col-sm-offset-5(ng-cloak, ng-show='profileForm.twitterHandle.$error.maxlength && !profileForm.twitterHandle.$pristine')
alert(type='danger') alert(type='danger')
span.ion-close-circled span.ion-close-circled
| Your name must be fewer than 15 characters. | Your name must be fewer than 15 characters.
@ -119,7 +122,7 @@ block content
label.col-sm-3.col-sm-offset-2.control-label(for='email') Github label.col-sm-3.col-sm-offset-2.control-label(for='email') Github
.col-sm-4 .col-sm-4
input.form-control(type='url', name='githubProfile', id='githubProfile', autocomplete="off", ng-model='user.profile.githubProfile', placeholder='http://') input.form-control(type='url', name='githubProfile', id='githubProfile', autocomplete="off", ng-model='user.profile.githubProfile', placeholder='http://')
.col-sm-4.col-sm-offset-5(ng-show="profileForm.githubProfile.$error.url && !profileForm.githubProfile.$pristine") .col-sm-4.col-sm-offset-5(ng-cloak, ng-show="profileForm.githubProfile.$error.url && !profileForm.githubProfile.$pristine")
alert(type='danger') alert(type='danger')
span.ion-close-circled span.ion-close-circled
| Please enter a valid URL format (http://www.example.com). | Please enter a valid URL format (http://www.example.com).
@ -128,7 +131,7 @@ block content
label.col-sm-3.col-sm-offset-2.control-label(for='email') CodePen label.col-sm-3.col-sm-offset-2.control-label(for='email') CodePen
.col-sm-4 .col-sm-4
input.form-control(type='url', name='codepenProfile', id='codepenProfile', autocomplete="off", ng-model='user.profile.codepenProfile', placeholder='http://') input.form-control(type='url', name='codepenProfile', id='codepenProfile', autocomplete="off", ng-model='user.profile.codepenProfile', placeholder='http://')
.col-sm-4.col-sm-offset-5(ng-show="profileForm.codepenProfile.$error.url && !profileForm.codepenProfile.$pristine") .col-sm-4.col-sm-offset-5(ng-cloak, ng-show="profileForm.codepenProfile.$error.url && !profileForm.codepenProfile.$pristine")
alert(type='danger') alert(type='danger')
span.ion-close-circled span.ion-close-circled
| Please enter a valid URL format (http://www.example.com). | Please enter a valid URL format (http://www.example.com).
@ -137,7 +140,7 @@ block content
label.col-sm-3.col-sm-offset-2.control-label(for='email') CoderByte label.col-sm-3.col-sm-offset-2.control-label(for='email') CoderByte
.col-sm-4 .col-sm-4
input.form-control(type='url', name='coderbyteProfile', id='coderbyteProfile', autocomplete="off", ng-model='user.profile.coderbyteProfile', placeholder='http://') input.form-control(type='url', name='coderbyteProfile', id='coderbyteProfile', autocomplete="off", ng-model='user.profile.coderbyteProfile', placeholder='http://')
.col-sm-4.col-sm-offset-5(ng-show="profileForm.coderbyteProfile.$error.url && !profileForm.coderbyteProfile.$pristine") .col-sm-4.col-sm-offset-5(ng-cloak, ng-show="profileForm.coderbyteProfile.$error.url && !profileForm.coderbyteProfile.$pristine")
alert(type='danger') alert(type='danger')
span.ion-close-circled span.ion-close-circled
| Please enter a valid URL format (http://www.example.com). | Please enter a valid URL format (http://www.example.com).
@ -146,7 +149,7 @@ block content
label.col-sm-3.col-sm-offset-2.control-label(for='email') LinkedIn label.col-sm-3.col-sm-offset-2.control-label(for='email') LinkedIn
.col-sm-4 .col-sm-4
input.form-control(type='url', name='linkedinProfile', id='linkedinProfile', autocomplete="off", ng-model='user.profile.linkedinProfile', placeholder='http://') input.form-control(type='url', name='linkedinProfile', id='linkedinProfile', autocomplete="off", ng-model='user.profile.linkedinProfile', placeholder='http://')
.col-sm-4.col-sm-offset-5(ng-show="profileForm.linkedinProfile.$error.url && !profileForm.linkedinProfile.$pristine") .col-sm-4.col-sm-offset-5(ng-cloak, ng-show="profileForm.linkedinProfile.$error.url && !profileForm.linkedinProfile.$pristine")
alert(type='danger') alert(type='danger')
span.ion-close-circled span.ion-close-circled
| Please enter a valid URL format (http://www.example.com). | Please enter a valid URL format (http://www.example.com).
@ -167,7 +170,7 @@ block content
label.col-sm-3.col-sm-offset-2.control-label(for='website1Title') Title label.col-sm-3.col-sm-offset-2.control-label(for='website1Title') Title
.col-sm-4 .col-sm-4
input.form-control(type='text', name='website1Title', id='website1Title', autocomplete="off", ng-model='user.portfolio.website1Title', ng-maxlength='140') input.form-control(type='text', name='website1Title', id='website1Title', autocomplete="off", ng-model='user.portfolio.website1Title', ng-maxlength='140')
.col-sm-4.col-sm-offset-5(ng-show="profileForm.website1Title.$error.maxlength && !profileForm.website1Title.$pristine") .col-sm-4.col-sm-offset-5(ng-cloak, ng-show="profileForm.website1Title.$error.maxlength && !profileForm.website1Title.$pristine")
alert(type='danger') alert(type='danger')
span.ion-close-circled span.ion-close-circled
| Portfolio project title must be fewer than 140 characters. | Portfolio project title must be fewer than 140 characters.
@ -176,7 +179,7 @@ block content
label.col-sm-3.col-sm-offset-2.control-label(for='website1Link') Link label.col-sm-3.col-sm-offset-2.control-label(for='website1Link') Link
.col-sm-4 .col-sm-4
input.form-control(type='url', name='website1Link', id='website1Link', autocomplete="off", ng-model='user.portfolio.website1Link', placeholder='http://') input.form-control(type='url', name='website1Link', id='website1Link', autocomplete="off", ng-model='user.portfolio.website1Link', placeholder='http://')
.col-sm-4.col-sm-offset-5(ng-show="profileForm.website1Link.$error.url && !profileForm.website1Link.$pristine") .col-sm-4.col-sm-offset-5(ng-cloak, ng-show="profileForm.website1Link.$error.url && !profileForm.website1Link.$pristine")
alert(type='danger') alert(type='danger')
span.ion-close-circled span.ion-close-circled
| Please enter a valid URL format (http://www.example.com). | Please enter a valid URL format (http://www.example.com).
@ -184,11 +187,15 @@ block content
.form-group .form-group
label.col-sm-3.col-sm-offset-2.control-label(for='website1Image') Image Link (4:3 ratio) label.col-sm-3.col-sm-offset-2.control-label(for='website1Image') Image Link (4:3 ratio)
.col-sm-4 .col-sm-4
input.form-control(type='url', name='website1Image', id='website1Image', autocomplete="off", ng-model='user.portfolio.website1Image', placeholder='http://') input.form-control(type='url', name='website1Image', id='website1Image', autocomplete="off", ng-model='user.portfolio.website1Image', placeholder='http://www.example.com/image.jpg', ng-pattern="/[\.](jpg|png|jpeg|gif)\s?$/")
.col-sm-4.col-sm-offset-5(ng-show="profileForm.website1Image.$error.url && !profileForm.website1Image.$pristine") .col-sm-4.col-sm-offset-5(ng-show="profileForm.website1Image.$error.url && !profileForm.website1Image.$pristine")
alert(type='danger') alert(type='danger')
span.ion-close-circled span.ion-close-circled
| Please enter a valid URL format (http://www.example.com). | Please enter a valid URL format (http://www.example.com/image.jpg).
.col-sm-4.col-sm-offset-5(ng-show="profileForm.website1Image.$error.pattern")
alert(type='danger')
span.ion-close-circled
| The image URL must end in .jpg, .png, .jpeg or .gif.
.col-sm-4.col-sm-offset-5.flat-top .col-sm-4.col-sm-offset-5.flat-top
h3 Second Portfolio Project h3 Second Portfolio Project
@ -197,7 +204,7 @@ block content
label.col-sm-3.col-sm-offset-2.control-label(for='website2Title') Title label.col-sm-3.col-sm-offset-2.control-label(for='website2Title') Title
.col-sm-4 .col-sm-4
input.form-control(type='text', name='website2Title', id='website2Title', autocomplete="off", ng-model='user.portfolio.website2Title', ng-maxlength='140') input.form-control(type='text', name='website2Title', id='website2Title', autocomplete="off", ng-model='user.portfolio.website2Title', ng-maxlength='140')
.col-sm-4.col-sm-offset-5(ng-show="profileForm.website2Title.$error.maxlength && !profileForm.website2Title.$pristine") .col-sm-4.col-sm-offset-5(ng-cloak, ng-show="profileForm.website2Title.$error.maxlength && !profileForm.website2Title.$pristine")
alert(type='danger') alert(type='danger')
span.ion-close-circled span.ion-close-circled
| Portfolio project title must be fewer than 140 characters. | Portfolio project title must be fewer than 140 characters.
@ -206,18 +213,22 @@ block content
label.col-sm-3.col-sm-offset-2.control-label(for='website2Link') Link label.col-sm-3.col-sm-offset-2.control-label(for='website2Link') Link
.col-sm-4 .col-sm-4
input.form-control(type='url', name='website2Link', id='website2Link', autocomplete="off", ng-model='user.portfolio.website2Link', placeholder='http://') input.form-control(type='url', name='website2Link', id='website2Link', autocomplete="off", ng-model='user.portfolio.website2Link', placeholder='http://')
.col-sm-4.col-sm-offset-5(ng-show="profileForm.website2Link.$error.url && !profileForm.website2Link.$pristine") .col-sm-4.col-sm-offset-5(ng-cloak, ng-show="profileForm.website2Link.$error.url && !profileForm.website2Link.$pristine")
alert(type='danger') alert(type='danger')
span.ion-close-circled span.ion-close-circled
| Please enter a valid URL format (http://www.example.com). | Please enter a valid URL format (http://www.example.com).
.form-group .form-group
label.col-sm-3.col-sm-offset-2.control-label(for='website2Image') Image Link (4:3 ratio) label.col-sm-3.col-sm-offset-2.control-label(for='website2Image') Image Link (4:3 ratio)
.col-sm-4 .col-sm-4
input.form-control(type='url', name='website2Image', id='website2Image', autocomplete="off", ng-model='user.portfolio.website2Image', placeholder='http://') input.form-control(type='url', name='website2Image', id='website2Image', autocomplete="off", ng-model='user.portfolio.website2Image', placeholder='http://www.example.com/image.jpg', ng-pattern="/[\.](jpg|png|jpeg|gif)\s?$/")
.col-sm-4.col-sm-offset-5(ng-show="profileForm.website2Image.$error.url && !profileForm.website2Image.$pristine") .col-sm-4.col-sm-offset-5(ng-show="profileForm.website2Image.$error.url && !profileForm.website2Image.$pristine")
alert(type='danger') alert(type='danger')
span.ion-close-circled span.ion-close-circled
| Please enter a valid URL format (http://www.example.com). | Please enter a valid URL format (http://www.example.com/image.jpg).
.col-sm-4.col-sm-offset-5(ng-show="profileForm.website2Image.$error.pattern")
alert(type='danger')
span.ion-close-circled
| The image URL must end in .jpg, .png, .jpeg or .gif.
.col-sm-4.col-sm-offset-5.flat-top .col-sm-4.col-sm-offset-5.flat-top
h3 Third Portfolio Project h3 Third Portfolio Project
@ -226,7 +237,7 @@ block content
label.col-sm-3.col-sm-offset-2.control-label(for='website3Title') Title label.col-sm-3.col-sm-offset-2.control-label(for='website3Title') Title
.col-sm-4 .col-sm-4
input.form-control(type='text', name='website3Title', id='website3Title', autocomplete="off", ng-model='user.portfolio.website3Title', ng-maxlength='140') input.form-control(type='text', name='website3Title', id='website3Title', autocomplete="off", ng-model='user.portfolio.website3Title', ng-maxlength='140')
.col-sm-4.col-sm-offset-5(ng-show="profileForm.website3Title.$error.maxlength && !profileForm.website3Title.$pristine") .col-sm-4.col-sm-offset-5(ng-cloak, ng-show="profileForm.website3Title.$error.maxlength && !profileForm.website3Title.$pristine")
alert(type='danger') alert(type='danger')
span.ion-close-circled span.ion-close-circled
| Portfolio project title must be fewer than 140 characters. | Portfolio project title must be fewer than 140 characters.
@ -235,7 +246,7 @@ block content
label.col-sm-3.col-sm-offset-2.control-label(for='website3Link') Link label.col-sm-3.col-sm-offset-2.control-label(for='website3Link') Link
.col-sm-4 .col-sm-4
input.form-control(type='url', name='website3Link', id='website3Link', autocomplete="off", ng-model='user.portfolio.website3Link', placeholder='http://') input.form-control(type='url', name='website3Link', id='website3Link', autocomplete="off", ng-model='user.portfolio.website3Link', placeholder='http://')
.col-sm-4.col-sm-offset-5(ng-show="profileForm.website3Link.$error.url && !profileForm.website3Link.$pristine") .col-sm-4.col-sm-offset-5(ng-cloak, ng-show="profileForm.website3Link.$error.url && !profileForm.website3Link.$pristine")
alert(type='danger') alert(type='danger')
span.ion-close-circled span.ion-close-circled
| Please enter a valid URL format (http://www.example.com). | Please enter a valid URL format (http://www.example.com).
@ -243,11 +254,15 @@ block content
.form-group .form-group
label.col-sm-3.col-sm-offset-2.control-label(for='website3Image') Image Link (4:3 ratio) label.col-sm-3.col-sm-offset-2.control-label(for='website3Image') Image Link (4:3 ratio)
.col-sm-4 .col-sm-4
input.form-control(type='url', name='website3Image', id='website3Image', autocomplete="off", ng-model='user.portfolio.website3Image', placeholder='http://') input.form-control(type='url', name='website3Image', id='website3Image', autocomplete="off", ng-model='user.portfolio.website3Image', placeholder='http://www.example.com/image.jpg', ng-pattern='/[\.](jpg|png|jpeg|gif)(\s+)?$/')
.col-sm-4.col-sm-offset-5(ng-show="profileForm.website3Image.$error.url && !profileForm.website3Image.$pristine") .col-sm-4.col-sm-offset-5(ng-show="profileForm.website3Image.$error.url && !profileForm.website3Image.$pristine")
alert(type='danger') alert(type='danger')
span.ion-close-circled span.ion-close-circled
| Please enter a valid URL format (http://www.example.com). | Please enter a valid URL format (http://www.example.com/image.jpg).
.col-sm-4.col-sm-offset-5(ng-show="profileForm.website3Image.$error.pattern")
alert(type='danger')
span.ion-close-circled
| The image URL must end in .jpg, .png, .jpeg or .gif.
.form-group .form-group
.col-sm-offset-5.col-sm-4 .col-sm-offset-5.col-sm-4
@ -293,23 +308,7 @@ block content
a.btn.btn-lg.btn-block.btn-twitter.btn-link-social(href='/auth/twitter') a.btn.btn-lg.btn-block.btn-twitter.btn-link-social(href='/auth/twitter')
i.fa.fa-twitter i.fa.fa-twitter
| Link Twitter with your account | Link Twitter with your account
br
- if (ch[0] > 0)
.panel.panel-primary
.panel-heading.text-center Completed Challenges:
.panel-body
.col-xs-12
table.table.table-striped
thead
tr
th Challenge
th Date Finished
for challenge in challenges
if ch[challenge.challengeNumber] > 0
tr
td= challenges[challenge.challengeNumber].name
td= moment(ch[challenge.challengeNumber], 'X').format("MMM DD, YYYY")
br
.panel.panel-danger .panel.panel-danger
.panel-heading.text-center Danger Zone: .panel-heading.text-center Danger Zone:
.panel-body .panel-body

View File

@ -7,46 +7,54 @@ block content
.form-group .form-group
.col-sm-6.col-sm-offset-3 .col-sm-6.col-sm-offset-3
input.form-control(type='email', ng-model='email', ng-keypress='', name='email', id='email', placeholder='email', autofocus, required, autocomplete="off", unique-email='') input.form-control(type='email', ng-model='email', ng-keypress='', name='email', id='email', placeholder='email', autofocus, required, autocomplete="off", unique-email='')
.col-sm-6.col-sm-offset-3(ng-show="signupForm.email.$error.unique && !signupForm.email.$pristine") .col-sm-6.col-sm-offset-3(ng-cloak, ng-show="signupForm.email.$error.required && !signupForm.email.$pristine")
alert(type='danger') alert(type='danger')
span.ion-close-circled span.ion-close-circled
| This email is taken. | Your email address is required.
.col-sm-6.col-sm-offset-3(ng-cloak, ng-show="signupForm.$error.email && !signupForm.email.$pristine")
alert(type='danger')
span.ion-close-circled
| Please enter a valid email format.
.col-sm-6.col-sm-offset-3(ng-cloak, ng-show="signupForm.email.$error.unique && !signupForm.email.$pristine")
alert(type='danger')
span.ion-close-circled
| That email address is already in use.
.form-group .form-group
.col-sm-6.col-sm-offset-3 .col-sm-6.col-sm-offset-3
input.form-control(type='text', name='username', ng-keypress='', autocomplete="off", id='username', placeholder='username', ng-model='username', unique-username='', required, ng-minlength=5, ng-maxlength=20, ng-pattern="/^[A-z0-9_]+$/") input.form-control(type='text', name='username', ng-keypress='', autocomplete="off", id='username', placeholder='username', ng-model='username', unique-username='', required, ng-minlength=5, ng-maxlength=20, ng-pattern="/^[A-z0-9_]+$/")
.col-sm-4.col-sm-offset-5(ng-show="profileForm.username.$error.pattern && !signupForm.username.$pristine") .col-sm-6.col-sm-offset-3(ng-cloak, ng-show="profileForm.username.$error.pattern && !signupForm.username.$pristine")
alert(type='danger') alert(type='danger')
span.ion-close-circled span.ion-close-circled
| Your username should only contain letters, numbers and underscores (az10_). | Your username should only contain letters, numbers and underscores (az10_).
.col-sm-6.col-sm-offset-3(ng-show="signupForm.username.$error.unique && !signupForm.username.$pristine") .col-sm-6.col-sm-offset-3(ng-cloak, ng-show="signupForm.username.$error.unique && !signupForm.username.$pristine")
alert(type='danger') alert(type='danger')
span.ion-close-circled span.ion-close-circled
| This username is taken. | This username is taken.
.col-sm-6.col-sm-offset-3(ng-show="signupForm.username.$error.minlength && !signupForm.username.$pristine") .col-sm-6.col-sm-offset-3(ng-cloak, ng-show="signupForm.username.$error.minlength && !signupForm.username.$pristine")
alert(type='danger') alert(type='danger')
span.ion-close-circled span.ion-close-circled
| Your username must be at least 5 characters long. | Your username must be at least 5 characters long.
.col-sm-6.col-sm-offset-3(ng-show="signupForm.username.$error.maxlength && !signupForm.username.$pristine") .col-sm-6.col-sm-offset-3(ng-cloak, ng-show="signupForm.username.$error.maxlength && !signupForm.username.$pristine")
alert(type='danger') alert(type='danger')
span.ion-close-circled span.ion-close-circled
| Your usernames must be 20 characters or fewer. | Your usernames must be 20 characters or fewer.
.form-group .form-group
.col-sm-6.col-sm-offset-3 .col-sm-6.col-sm-offset-3
input.form-control(type='password', ng-model='password', name='password', id='password', placeholder='password', required, ng-minlength=5) input.form-control(type='password', ng-model='password', name='password', id='password', placeholder='password', required, ng-minlength=5)
.col-sm-6.col-sm-offset-3(ng-show="signupForm.password.$error.minlength && !signupForm.password.$pristine") .col-sm-6.col-sm-offset-3(ng-cloak, ng-show="signupForm.password.$error.minlength && !signupForm.password.$pristine")
alert(type='danger') alert(type='danger')
span.ion-close-circled span.ion-close-circled
| Your password must be at least 8 characters long. | Your password must be at least 8 characters long.
.form-group .form-group
.col-sm-6.col-sm-offset-3 .col-sm-6.col-sm-offset-3
input.form-control(type='password', ng-model='confirmPassword', name='confirmPassword', id='confirmPassword', placeholder='confirm password', required, ng-minlength=5) input.form-control(type='password', ng-model='confirmPassword', name='confirmPassword', id='confirmPassword', placeholder='confirm password', required, ng-minlength=5)
.col-sm-6.col-sm-offset-3(ng-show="(confirmPassword !== password) && !signupForm.confirmPassword.$pristine") .col-sm-6.col-sm-offset-3(ng-cloak, ng-show="(confirmPassword !== password) && !signupForm.confirmPassword.$pristine")
alert(type='danger') alert(type='danger')
span.ion-close-circled span.ion-close-circled
| Passwords must match. | Passwords must match.
.form-group .form-group
.col-sm-offset-3.col-sm-6 .col-sm-6.col-sm-offset-3
button.btn.btn-success(type='submit') button.btn.btn-success(type='submit', ng-disabled='signupForm.$invalid')
span.ion-person-add span.ion-person-add
| Signup | Signup
br br

View File

@ -33,6 +33,9 @@ block content
h3.flat-top.bolded.wrappable= location h3.flat-top.bolded.wrappable= location
h4.flat-top.wrappable= bio h4.flat-top.wrappable= bio
.col-xs-12.col-sm-12.col-md-3.text-center .col-xs-12.col-sm-12.col-md-3.text-center
if (user && user.profile.username === username)
a.btn.btn-warning(href="/account") Edit my Profile
.background-svg.img-center .background-svg.img-center
.points-on-top .points-on-top
= "[ " + points + " ]" = "[ " + points + " ]"

View File

@ -0,0 +1,45 @@
extends ../layout-wide
block content
script(src='/js/lib/codemirror/lib/codemirror.js')
script(src='/js/lib/codemirror/addon/edit/closebrackets.js')
script(src='/js/lib/codemirror/addon/edit/matchbrackets.js')
script(src='/js/lib/codemirror/addon/lint/lint.js')
script(src='/js/lib/codemirror/addon/lint/javascript-lint.js')
script(src='//ajax.aspnetcdn.com/ajax/jshint/r07/jshint.js')
script(src='/js/lib/chai/chai.js')
link(rel='stylesheet', href='/js/lib/codemirror/lib/codemirror.css')
link(rel='stylesheet', href='/js/lib/codemirror/addon/lint/lint.css')
link(rel='stylesheet', href='/js/lib/codemirror/theme/monokai.css')
link(rel="stylesheet", href="http://fonts.googleapis.com/css?family=Ubuntu+Mono")
script(src='/js/lib/codemirror/mode/javascript/javascript.js')
script(src='/js/lib/jailed/jailed.js')
script(src='/js/lib/bonfire/bonfireInit.js')
.row
script(type="text/javascript").
var tests = !{JSON.stringify(tests)};
var challengeSeed = !{JSON.stringify(challengeSeed)};
var challengeEntryPoint = !{JSON.stringify(challengeEntryPoint)};
var title = !{JSON.stringify(title)};
#mainEditorPanel.col-sm-12.col-md-7.col-xs-12
.panel.panel-primary.panel-bonfire
.panel-heading.text-center Playground
.panel.panel-body
form.code
.form-group.codeMirrorView
textarea#codeEditor(autofocus=true)
#testCreatePanel.col-sm-12.col-md-5.col-xs-12
.panel.panel-primary.panel-bonfire
.panel-heading.text-center Output
.panel.panel-body
#submitButton.btn.btn-primary.btn-big.btn-block Run code (ctrl + enter)
br
form.code
.form-group.codeMirrorView
textarea#codeOutput
br
ul#testSuite.list-group
br
script(src='/js/lib/bonfire/bonfireFramework.js')

View File

@ -90,6 +90,8 @@ block content
var challengeSeed = !{JSON.stringify(challengeSeed)}; var challengeSeed = !{JSON.stringify(challengeSeed)};
var challengeEntryPoint = !{JSON.stringify(challengeEntryPoint)}; var challengeEntryPoint = !{JSON.stringify(challengeEntryPoint)};
var passedBonfireHash = !{JSON.stringify(bonfireHash)}; var passedBonfireHash = !{JSON.stringify(bonfireHash)};
var bonfireName = !{JSON.stringify(name)};
var started = Math.floor(Date.now() / 1000);
.col-xs-12.col-sm-12.col-md-8 .col-xs-12.col-sm-12.col-md-8
#mainEditorPanel #mainEditorPanel
form.code form.code
@ -108,7 +110,7 @@ block content
.text-center .text-center
.animated.zoomInDown.delay-half .animated.zoomInDown.delay-half
span.landing-icon.ion-checkmark-circled.text-primary span.completion-icon.ion-checkmark-circled.text-primary
- if (cc) - if (cc)
form.form-horizontal(novalidate='novalidate', name='completedWithForm') form.form-horizontal(novalidate='novalidate', name='completedWithForm')
.form-group.text-center .form-group.text-center
@ -116,7 +118,7 @@ block content
// extra field to distract password tools like lastpass from injecting css into our username field // extra field to distract password tools like lastpass from injecting css into our username field
input.form-control(ng-show="false") input.form-control(ng-show="false")
input.form-control#completed-with(name="existingUser", placeholder="If you paired, enter your pair's username here", existing-username='', ng-model="existingUser", autofocus) input.form-control#completed-with(name="existingUser", placeholder="If you paired, enter your pair's username here", existing-username='', ng-model="existingUser", autofocus)
.col-xs-10.col-xs-offset-1.col-sm-8.col-sm-offset-2.col-md-8.col-md-offset-2(ng-show="completedWithForm.$error.exists && !completedWithForm.existingUser.$pristine && existingUser.length > 0") .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') alert(type='danger')
span.ion-close-circled span.ion-close-circled
| Username not found | Username not found

View File

@ -24,7 +24,7 @@ block content
.modal-body .modal-body
.text-center .text-center
.animated.zoomInDown.delay-half .animated.zoomInDown.delay-half
span.landing-icon.ion-checkmark-circled.text-primary span.completion-icon.ion-checkmark-circled.text-primary
- if (cc) - if (cc)
a.animated.fadeIn.btn.btn-lg.btn-primary.btn-block.next-challenge-button(name='_csrf', value=_csrf, aria-hidden='true') Take me to my next challenge a.animated.fadeIn.btn.btn-lg.btn-primary.btn-block.next-challenge-button(name='_csrf', value=_csrf, aria-hidden='true') Take me to my next challenge
- if (points && points > 2) - if (points && points > 2)

View File

@ -14,11 +14,11 @@ block content
label(class='col-sm-3 control-label', for='email') Your email * label(class='col-sm-3 control-label', for='email') Your email *
.col-sm-8 .col-sm-8
input.form-control(type='text', name='email', id='email', autocomplete="off", ng-model='email', required='required', ng-keypress='') input.form-control(type='text', name='email', id='email', autocomplete="off", ng-model='email', required='required', ng-keypress='')
.col-sm-8.col-sm-offset-3(ng-show="doneWithFirst100HoursForm.$error.email && !doneWithFirst100HoursForm.email.$pristine") .col-sm-8.col-sm-offset-3(ng-cloak, ng-show="doneWithFirst100HoursForm.$error.email && !doneWithFirst100HoursForm.email.$pristine")
alert(type='danger') alert(type='danger')
span.ion-close-circled span.ion-close-circled
| Please enter a valid email format. | Please enter a valid email format.
.col-sm-8.col-sm-offset-3(ng-show="doneWithFirst100HoursForm.email.$invalid && doneWithFirst100HoursForm.email.$error.required && !doneWithFirst100HoursForm.email.$pristine") .col-sm-8.col-sm-offset-3(ng-cloak, ng-show="doneWithFirst100HoursForm.email.$invalid && doneWithFirst100HoursForm.email.$error.required && !doneWithFirst100HoursForm.email.$pristine")
alert(type='danger') alert(type='danger')
span.ion-close-circled(id='#email-error'). span.ion-close-circled(id='#email-error').
Your email is required. Your email is required.

View File

@ -20,7 +20,7 @@ block content
label(class='col-sm-2 control-label', for='name') Your name * label(class='col-sm-2 control-label', for='name') Your name *
.col-sm-8 .col-sm-8
input.form-control(type='text', name='name', id='name', autocomplete="off", ng-model='name', required='required') input.form-control(type='text', name='name', id='name', autocomplete="off", ng-model='name', required='required')
.col-sm-8.col-sm-offset-2(ng-show="nonprofitForm.name.$invalid && nonprofitForm.name.$error.required && !nonprofitForm.name.$pristine") .col-sm-8.col-sm-offset-2(ng-cloak, ng-show="nonprofitForm.name.$invalid && nonprofitForm.name.$error.required && !nonprofitForm.name.$pristine")
alert(type='danger') alert(type='danger')
span.ion-close-circled(id='#name-error') span.ion-close-circled(id='#name-error')
| Your name is required. | Your name is required.
@ -28,7 +28,7 @@ block content
label(class='col-sm-2 control-label', for='email') Your email * label(class='col-sm-2 control-label', for='email') Your email *
.col-sm-8 .col-sm-8
input.form-control(type='text', name='email', id='email', autocomplete="off", ng-model='email', required='required') input.form-control(type='text', name='email', id='email', autocomplete="off", ng-model='email', required='required')
.col-sm-8.col-sm-offset-2(ng-show="nonprofitForm.email.$invalid && nonprofitForm.email.$error.required && !nonprofitForm.email.$pristine") .col-sm-8.col-sm-offset-2(ng-cloak, ng-show="nonprofitForm.email.$invalid && nonprofitForm.email.$error.required && !nonprofitForm.email.$pristine")
alert(type='danger') alert(type='danger')
span.ion-close-circled(id='#email-error'). span.ion-close-circled(id='#email-error').
Your email is required. Your email is required.
@ -36,7 +36,7 @@ block content
label(class='col-sm-2 control-label', for='message') Briefly describe what problem you need to solve, and for whom. * label(class='col-sm-2 control-label', for='message') Briefly describe what problem you need to solve, and for whom. *
.col-sm-8 .col-sm-8
textarea.form-control(type='text', name='message', id='message', rows='7', autocomplete="off", ng-model='message', required='required') textarea.form-control(type='text', name='message', id='message', rows='7', autocomplete="off", ng-model='message', required='required')
.col-sm-8.col-sm-offset-2(ng-show="nonprofitForm.message.$invalid && nonprofitForm.message.$error.required && !nonprofitForm.message.$pristine") .col-sm-8.col-sm-offset-2(ng-cloak, ng-show="nonprofitForm.message.$invalid && nonprofitForm.message.$error.required && !nonprofitForm.message.$pristine")
alert(type='danger') alert(type='danger')
span.ion-close-circled(id='#message-error') span.ion-close-circled(id='#message-error')
| Your message is required. | Your message is required.

View File

@ -7,19 +7,19 @@ block content
.row .row
.col-xs-12.col-sm-12.col-md-3 .col-xs-12.col-sm-12.col-md-3
h3.nowrap Get Connected h3.nowrap Get Connected
img.img-responsive(src= 'https://s3.amazonaws.com/freecodecamp/landingIcons_connect.svg', title='Get great references and connections to help you get a job') img.img-responsive.landing-icon.img-center(src= 'https://s3.amazonaws.com/freecodecamp/landingIcons_connect.svg', title='Get great references and connections to help you get a job')
p.landing-p Join a community of busy, motivated professionals. p.landing-p Join a community of busy, motivated professionals.
.col-xs-12.col-sm-12.col-md-3 .col-xs-12.col-sm-12.col-md-3
h3.nowrap Learn JavaScript h3.nowrap Learn JavaScript
img.img-responsive(src= 'https://s3.amazonaws.com/freecodecamp/landingIcons_learn.svg', title='Learn to code') img.img-responsive.landing-icon.img-center(src= 'https://s3.amazonaws.com/freecodecamp/landingIcons_learn.svg', title='Learn to code')
p.landing-p Work together on Full Stack JavaScript coding challenges. p.landing-p Work together on Full Stack JavaScript coding challenges.
.col-xs-12.col-sm-12.col-md-3 .col-xs-12.col-sm-12.col-md-3
h3.nowrap Build your Portfolio h3.nowrap Build your Portfolio
img.img-responsive(src= 'https://s3.amazonaws.com/freecodecamp/landingIcons_portfolio.svg', title='Build a portfolio of apps for nonprofits') img.img-responsive.landing-icon.img-center(src= 'https://s3.amazonaws.com/freecodecamp/landingIcons_portfolio.svg', title='Build a portfolio of apps for nonprofits')
p.landing-p Build apps that solve real problems for real people. p.landing-p Build apps that solve real problems for real people.
.col-xs-12.col-sm-12.col-md-3 .col-xs-12.col-sm-12.col-md-3
h3.nowrap Help Nonprofits h3.nowrap Help Nonprofits
img.img-responsive(src= 'https://s3.amazonaws.com/freecodecamp/landingIcons_nonprofits.svg', title='Help nonprofits') img.img-responsive.landing-icon.img-center(src= 'https://s3.amazonaws.com/freecodecamp/landingIcons_nonprofits.svg', title='Help nonprofits')
p.landing-p Give nonprofits a boost by empowering them with code. p.landing-p Give nonprofits a boost by empowering them with code.
.big-break .big-break
a.btn.btn-cta.signup-btn(href="/login") Start learning to code (it's free) a.btn.btn-cta.signup-btn(href="/login") Start learning to code (it's free)

View File

@ -2,7 +2,7 @@ doctype html
html(ng-app='profileValidation', lang='en') html(ng-app='profileValidation', lang='en')
head head
script(src="//ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js") script(src="//ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js")
script(src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.8/angular.min.js") script(src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.11/angular.min.js")
script(src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.12.0/ui-bootstrap-tpls.min.js") script(src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.12.0/ui-bootstrap-tpls.min.js")
link(rel='shortcut icon', href='//s3.amazonaws.com/freecodecamp/favicon.ico') link(rel='shortcut icon', href='//s3.amazonaws.com/freecodecamp/favicon.ico')
link(rel='stylesheet', href='//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css') link(rel='stylesheet', href='//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css')
@ -30,4 +30,3 @@ script.
ga('create', 'UA-55446531-1', 'auto'); ga('create', 'UA-55446531-1', 'auto');
ga('require', 'displayfeatures'); ga('require', 'displayfeatures');
ga('send', 'pageview'); ga('send', 'pageview');
script(src="//cdn.optimizely.com/js/999692993.js")

View File

@ -2,12 +2,10 @@ doctype html
html(ng-app='profileValidation', lang='en') html(ng-app='profileValidation', lang='en')
head head
script(src="//ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js") script(src="//ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js")
script(src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.8/angular.min.js") script(src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.11/angular.min.js")
script(src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.12.0/ui-bootstrap-tpls.min.js") script(src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.12.0/ui-bootstrap-tpls.min.js")
link(rel='shortcut icon', href='//s3.amazonaws.com/freecodecamp/favicon.ico')
link(rel='stylesheet', href='//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css') link(rel='stylesheet', href='//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css')
link(rel='stylesheet', href='//maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css') link(rel='stylesheet', href='//maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css')
link(rel='stylesheet', href='/css/lib/ionicons/ionicons.min.css')
include partials/meta include partials/meta
title #{title} | Free Code Camp title #{title} | Free Code Camp
meta(charset='utf-8') meta(charset='utf-8')
@ -31,4 +29,3 @@ script.
ga('create', 'UA-55446531-1', 'auto'); ga('create', 'UA-55446531-1', 'auto');
ga('require', 'displayfeatures'); ga('require', 'displayfeatures');
ga('send', 'pageview'); ga('send', 'pageview');
script(src="//cdn.optimizely.com/js/999692993.js")

View File

@ -126,3 +126,9 @@
img.profile-image(src='https://s3.amazonaws.com/freecodecamp/kamal-sharif.jpg' alt="Kamal Sharif's picture") img.profile-image(src='https://s3.amazonaws.com/freecodecamp/kamal-sharif.jpg' alt="Kamal Sharif's picture")
h4.text-nowrap Dhaka, Bangladesh h4.text-nowrap Dhaka, Bangladesh
p.negative-10 "I build applications that help other people improve their own lives." p.negative-10 "I build applications that help other people improve their own lives."
.col-xs-12.col-sm-4.col-md-3.team-member
h3.negative-10.text-nowrap Patrick Ly
h4.negative-10.text-nowrap Community Builder
img.profile-image(src='https://s3.amazonaws.com/freecodecamp/patrick-ly.jpg' alt="Patrick Ly's picture")
h4.text-nowrap Los Angeles, California
p.negative-10 "I'm a student and self-taught Hip Hop dancer. Just using the web isn't enough for me. I want to create and maintain web apps, too"

View File

@ -4,24 +4,54 @@ meta(http-equiv='X-UA-Compatible', content='IE=edge')
meta(name='viewport', content='width=device-width, initial-scale=1.0') meta(name='viewport', content='width=device-width, initial-scale=1.0')
meta(name='csrf-token', content=_csrf) meta(name='csrf-token', content=_csrf)
meta(name='keywords', content='learn to code, learn how to code, code, coding, software engineer, software developer, mean stack, pair programming, node.js, angular.js, express.js, mongoDB, coding bootcamp') meta(name='keywords', content='learn to code, learn how to code, code, coding, software engineer, software developer, mean stack, pair programming, node.js, angular.js, express.js, mongoDB, coding bootcamp')
meta(content="Free Code Camp is a community of busy people who learn to code by collaborating on projects for nonprofits. Build your full stack JavaScript Portfolio today.", property="og:title") meta(property="og:title", content="Free Code Camp is a community of busy people who learn to code by collaborating on projects for nonprofits. Build your full stack JavaScript Portfolio today.")
meta(content="FreeCodeCamp", property="og:site_name") meta(property="og:site_name", content="FreeCodeCamp")
meta(name='twitter:widgets:csp', content='on') meta(name='twitter:widgets:csp', content='on')
meta(name='p:domain_verify', content='d0bc047a482c03c24f1168004c2a216a') meta(name='p:domain_verify', content='d0bc047a482c03c24f1168004c2a216a')
meta(content="http://www.freecodecamp.com", property="og:url") meta(property="og:url", content="http://www.freecodecamp.com")
meta(content="Free Code Camp is a community of busy people who learn to code by collaborating on projects for nonprofits. Build your full stack JavaScript Portfolio today.", property="og:description") meta(property="og:description", content="Free Code Camp is a community of busy people who learn to code by collaborating on projects for nonprofits. Build your full stack JavaScript Portfolio today.")
meta(content="https://pbs.twimg.com/profile_images/522961310212833280/XE6vGAaO.jpeg", property="og:image") meta(property="og:image", content="https://pbs.twimg.com/profile_images/522961310212833280/XE6vGAaO.jpeg")
meta(content="article", property="og:type") meta(property="og:type", content="article")
meta(content="https://www.facebook.com/freecodecamp", property="article:publisher") meta(property="article:publisher", content="https://www.facebook.com/freecodecamp")
meta(content="Responsive", property="article:section") meta(property="article:section", content="Responsive")
link(href="https://plus.google.com/+Freecodecamp", rel="publisher") link(rel="publisher", href="https://plus.google.com/+Freecodecamp")
link(href="https://plus.google.com/+Freecodecamp", rel="author") link(rel="author", href="https://plus.google.com/+Freecodecamp")
meta(content="Free Code Camp is a community of busy people who learn to code by collaborating on projects for nonprofits. Build your full stack JavaScript Portfolio today.", name="description") meta(name="description", content="Free Code Camp is a community of busy people who learn to code by collaborating on projects for nonprofits. Build your full stack JavaScript Portfolio today.")
meta(content="@freecodecamp", name="twitter:creator") meta(name="twitter:creator", content="@freecodecamp")
meta(content="http://www.freecodecamp.com", name="twitter:url") meta(name="twitter:url", content="http://www.freecodecamp.com")
meta(content="@freecodecamp", name="twitter:site") meta(name="twitter:site", content="@freecodecamp")
meta(content="summary_large_image", name="twitter:card") meta(name="twitter:card", content="summary_large_image")
meta(content="https://s3.amazonaws.com/freecodecamp/challenges.png", name="twitter:image:src") meta(name="twitter:image:src", content="https://s3.amazonaws.com/freecodecamp/challenges.png")
meta(content="Free Code Camp: a community of busy people learning to code", name="twitter:title") meta(name="twitter:title", content="Free Code Camp: a community of busy people learning to code")
meta(content="We're a community of busy people learning to code by collaborating on projects for nonprofits. Learn Full-stack JavaScript, build a portfolio, and get great references with our online coding bootcamp.", name="twitter:description") meta(name="twitter:description", content="We're a community of busy people learning to code by collaborating on projects for nonprofits. Learn Full-stack JavaScript, build a portfolio, and get great references with our online coding bootcamp.")
meta(content="a40ee5d5dba3bb091ad783ebd2b1383f", name="p:domain_verify") meta(content="a40ee5d5dba3bb091ad783ebd2b1383f", name="p:domain_verify")
meta(name="msapplication-TileColor", content="#FFFFFF")
meta(name="msapplication-TileImage", content="/")
link(rel="android-chrome", sizes="144x144" href="https://s3.amazonaws.com/freecodecamp/favicons/android-chrome-144x144.png")
link(rel="android-chrome", sizes="192x192" href="https://s3.amazonaws.com/freecodecamp/favicons/android-chrome-192x192.png")
link(rel="android-chrome", sizes="36x36" href="https://s3.amazonaws.com/freecodecamp/favicons/android-chrome-36x36.png")
link(rel="android-chrome", sizes="48x48" href="https://s3.amazonaws.com/freecodecamp/favicons/android-chrome-48x48.png")
link(rel="android-chrome", sizes="72x72" href="https://s3.amazonaws.com/freecodecamp/favicons/android-chrome-72x72.png")
link(rel="android-chrome", sizes="96x96" href="https://s3.amazonaws.com/freecodecamp/favicons/android-chrome-96x96.png")
link(rel="android-chrome-manifest", href="https://s3.amazonaws.com/freecodecamp/favicons/android-chrome-manifest.json")
link(rel="apple-touch-icon", sizes="114x114", href="https://s3.amazonaws.com/freecodecamp/favicons/apple-touch-icon-114x114.png")
link(rel="apple-touch-icon", sizes="120x120", href="https://s3.amazonaws.com/freecodecamp/favicons/apple-touch-icon-120x120.png")
link(rel="apple-touch-icon", sizes="144x144", href="https://s3.amazonaws.com/freecodecamp/favicons/apple-touch-icon-144x144.png")
link(rel="apple-touch-icon", sizes="152x152", href="https://s3.amazonaws.com/freecodecamp/favicons/apple-touch-icon-152x152.png")
link(rel="apple-touch-icon", sizes="180x180", href="https://s3.amazonaws.com/freecodecamp/favicons/apple-touch-icon-180x180.png")
link(rel="apple-touch-icon", sizes="57x57", href="https://s3.amazonaws.com/freecodecamp/favicons/apple-touch-icon-57x57.png")
link(rel="apple-touch-icon", sizes="60x60", href="https://s3.amazonaws.com/freecodecamp/favicons/apple-touch-icon-60x60.png")
link(rel="apple-touch-icon", sizes="72x72", href="https://s3.amazonaws.com/freecodecamp/favicons/apple-touch-icon-72x72.png")
link(rel="apple-touch-icon", sizes="76x76", href="https://s3.amazonaws.com/freecodecamp/favicons/apple-touch-icon-76x76.png")
link(rel="apple-touch-icon-precomposed", href="https://s3.amazonaws.com/freecodecamp/favicons/apple-touch-icon-precomposed.png")
link(rel="apple-touch-icon", href="https://s3.amazonaws.com/freecodecamp/favicons/apple-touch-icon.png")
link(rel="favicon", sizes="16x16", href="https://s3.amazonaws.com/freecodecamp/favicons/favicon-16x16.png")
link(rel="favicon", sizes="32x32", href="https://s3.amazonaws.com/freecodecamp/favicons/favicon-32x32.png")
link(rel="favicon", sizes="96x96", href="https://s3.amazonaws.com/freecodecamp/favicons/favicon-96x96.png")
link(rel="mstile", sizes="144x144", href="https://s3.amazonaws.com/freecodecamp/favicons/mstile-144x144.png")
link(rel="mstile", sizes="150x150", href="https://s3.amazonaws.com/freecodecamp/favicons/mstile-150x150.png")
link(rel="mstile", sizes="310x310", href="https://s3.amazonaws.com/freecodecamp/favicons/mstile-310x310.png")
link(rel="mstile", sizes="310x150", href="https://s3.amazonaws.com/freecodecamp/favicons/mstile-310x150.png")
link(rel="mstile", sizes="70x70", href="https://s3.amazonaws.com/freecodecamp/favicons/mstile-70x70.png")
link(rel="favicon", href="https://s3.amazonaws.com/freecodecamp/favicons/favicon.ico")
link(rel='shortcut icon', href='//s3.amazonaws.com/freecodecamp/favicons/favicon.ico')

View File

@ -37,8 +37,16 @@
a(href='/account') [&nbsp;#{user.points}&nbsp;] a(href='/account') [&nbsp;#{user.points}&nbsp;]
.hidden-xs .hidden-xs
if user.profile.picture if user.profile.picture
a(href='/account') if (user.profile.username)
a(href='/' + user.profile.username)
img.profile-picture.float-right(src='#{user.profile.picture}') img.profile-picture.float-right(src='#{user.profile.picture}')
else
a(href='/account')
img.profile-picture.float-right(src='#{user.profile.picture}')
else
if (user.profile.username)
a(href='/' + user.profile.username)
img.profile-picture.float-right(src='#{user.gravatar(60)}')
else else
a(href='/account') a(href='/account')
img.profile-picture.float-right(src='#{user.gravatar(60)}') img.profile-picture.float-right(src='#{user.gravatar(60)}')

View File

@ -10,6 +10,13 @@ block content
.col-md-8.col-xs-12 .col-md-8.col-xs-12
.embed-responsive.embed-responsive-16by9 .embed-responsive.embed-responsive-16by9
iframe(src='http://www.twitch.tv/freecodecamp/embed', frameborder='0', scrolling='no') iframe(src='http://www.twitch.tv/freecodecamp/embed', frameborder='0', scrolling='no')
.col-md-4.col-xs-12
.visible-sm.visible-xs
.embed-responsive.embed-responsive-16by9
iframe(src='http://www.twitch.tv/freecodecamp/chat?popout=', frameborder='0', scrolling='no')
.visible-md.visible-lg
.embed-responsive.embed-responsive-twitch-chat
iframe(src='http://www.twitch.tv/freecodecamp/chat?popout=', frameborder='0', scrolling='no')
h1 Previous Live Pair Programming Sessions h1 Previous Live Pair Programming Sessions
.col-xs-12 .col-xs-12
.embed-responsive.embed-responsive-16by9.big-break .embed-responsive.embed-responsive-16by9.big-break