Merge branch 'staging' of github.com:FreeCodeCamp/freecodecamp into staging

Conflicts:
	seed/challenges/basic-javascript.json
This commit is contained in:
Quincy Larson
2015-07-28 23:11:00 -07:00
44 changed files with 969 additions and 552 deletions

View File

@ -1,3 +1,4 @@
This is the entry point for the client This is the entry point for the client
Code that should only run on the client should be put here. Code that should only run on the client should be put here.
NOTE(berks): For react specific stuff this should be the entry point NOTE(berks): For react specific stuff this should be the entry point

View File

@ -1,8 +0,0 @@
{
"restApiRoot": "/api",
"remoting": {
"context": {
"enableHttpContext": false
}
}
}

View File

@ -1,5 +0,0 @@
var globalConfig = require('../common/config.global');
module.exports = {
restApiRoot: globalConfig.restApi
};

View File

@ -1,10 +0,0 @@
{
"remote": {
"name": "remote",
"connector": "remote"
},
"local": {
"name": "local",
"connector": "memory"
}
}

View File

@ -1,7 +0,0 @@
var globalConfig = require('../common/config.global');
module.exports = {
remote: {
url: globalConfig.restApiUrl
}
};

View File

@ -1,8 +1,9 @@
import Rx from 'rx'; import Rx from 'rx';
import React from 'react'; import React from 'react';
import Fetchr from 'fetchr';
import debugFactory from 'debug';
import { Router } from 'react-router'; import { Router } from 'react-router';
import { history } from 'react-router/lib/BrowserHistory'; import { history } from 'react-router/lib/BrowserHistory';
import debugFactory from 'debug';
import { hydrate } from 'thundercats'; import { hydrate } from 'thundercats';
import { Render } from 'thundercats-react'; import { Render } from 'thundercats-react';
@ -11,6 +12,9 @@ import { app$ } from '../common/app';
const debug = debugFactory('fcc:client'); const debug = debugFactory('fcc:client');
const DOMContianer = document.getElementById('fcc'); const DOMContianer = document.getElementById('fcc');
const catState = window.__fcc__.data || {}; const catState = window.__fcc__.data || {};
const services = new Fetchr({
xhrPath: '/services'
});
Rx.longStackSupport = !!debug.enabled; Rx.longStackSupport = !!debug.enabled;
@ -18,7 +22,7 @@ Rx.longStackSupport = !!debug.enabled;
app$(history) app$(history)
.flatMap( .flatMap(
({ AppCat }) => { ({ AppCat }) => {
const appCat = AppCat(); const appCat = AppCat(null, services);
return hydrate(appCat, catState) return hydrate(appCat, catState)
.map(() => appCat); .map(() => appCat);
}, },

View File

@ -1,8 +0,0 @@
var loopback = require('loopback'),
boot = require('loopback-boot');
var app = loopback();
boot(app, __dirname);
module.exports = app;

View File

@ -1,32 +0,0 @@
{
"_meta": {
"sources": [
"../common/models",
"./models"
]
},
"user": {
"dataSource": "remote"
},
"bonfire": {
"dataSource": "remote"
},
"challenge": {
"dataSource": "remote"
},
"comment": {
"dataSource": "remote"
},
"fieldGuide": {
"dataSource": "remote"
},
"job": {
"dataSource": "remote"
},
"nonprofit": {
"dataSource": "remote"
},
"story": {
"dataSource": "remote"
}
}

View File

@ -1,28 +1,43 @@
import React, { PropTypes } from 'react'; import React, { PropTypes } from 'react';
import { contain } from 'thundercats-react';
import { Row } from 'react-bootstrap'; import { Row } from 'react-bootstrap';
import { Nav } from './components/Nav'; import { Nav } from './components/Nav';
import { Footer } from './components/Footer'; import { Footer } from './components/Footer';
export default class extends React.Component { export default contain(
constructor(props) { {
super(props); store: 'appStore',
} fetchAction: 'appActions.getUser',
getPayload(props) {
return {
isPrimed: !!props.username
};
}
},
React.createClass({
displayName: 'FreeCodeCamp',
static displayName = 'FreeCodeCamp' propTypes: {
static propTypes = { children: PropTypes.node,
children: PropTypes.node username: PropTypes.string,
} points: PropTypes.number,
picture: PropTypes.string
},
render() { render() {
return ( const { username, points, picture } = this.props;
<div> const navProps = { username, points, picture };
<Nav /> return (
<Row> <div>
{ this.props.children } <Nav
</Row> { ...navProps }/>
<Footer /> <Row>
</div> { this.props.children }
); </Row>
} <Footer />
} </div>
);
}
})
);

View File

@ -1,9 +1,17 @@
import { Cat } from 'thundercats'; import { Cat } from 'thundercats';
import { HikesActions, HikesStore } from './routes/Hikes/flux';
import { AppActions, AppStore } from './flux';
import { HikesActions, HikesStore } from './routes/Hikes/flux';
import { JobActions, JobsStore} from './routes/Jobs/flux';
export default Cat() export default Cat()
.init(({ instance }) => { .init(({ instance: cat, args: [services] }) => {
instance.register(HikesActions); cat.register(AppActions, null, services);
instance.register(HikesStore, null, instance); cat.register(AppStore, null, cat);
cat.register(HikesActions, null, services);
cat.register(HikesStore, null, cat);
cat.register(JobActions, null, services);
cat.register(JobsStore, null, cat);
}); });

View File

@ -1,5 +1,11 @@
import React from 'react'; import React, { PropTypes } from 'react';
import { Nav, Navbar, NavItem } from 'react-bootstrap'; import {
Col,
CollapsibleNav,
Nav,
Navbar,
NavItem
} from 'react-bootstrap';
import navLinks from './links.json'; import navLinks from './links.json';
import FCCNavItem from './NavItem.jsx'; import FCCNavItem from './NavItem.jsx';
@ -25,6 +31,14 @@ const logoElement = (
</a> </a>
); );
const toggleButton = (
<button className='hamburger'>
<Col xs={ 12 }>
<span className='hamburger-text'>Menu</span>
</Col>
</button>
);
export default class extends React.Component { export default class extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
@ -32,19 +46,36 @@ export default class extends React.Component {
static displayName = 'Nav' static displayName = 'Nav'
static propTypes = { static propTypes = {
signedIn: React.PropTypes.bool points: PropTypes.number,
picture: PropTypes.string,
signedIn: PropTypes.bool,
username: PropTypes.string
} }
renderBrand() { renderPoints(username, points) {
if (!username) {
return null;
}
return (
<NavItem
href={ '/' + username }>
[ { points } ]
</NavItem>
);
} }
renderSignin() { renderSignin(username, picture) {
if (this.props.signedIn) { if (username) {
return ( return (
<NavItem <div
className='hidden-xs hidden-sm'
eventKey={ 2 }> eventKey={ 2 }>
Show Picture <a href={ '/' + username }>
</NavItem> <img
className='profile-picture float-right'
src={ picture } />
</a>
</div>
); );
} else { } else {
return ( return (
@ -59,19 +90,24 @@ export default class extends React.Component {
} }
render() { render() {
const { username, points, picture } = this.props;
return ( return (
<Navbar <Navbar
brand={ logoElement } brand={ logoElement }
className='nav-height' className='nav-height'
fixedTop={ true } fixedTop={ true }
toggleButton={ toggleButton }
toggleNavKey={ 0 }> toggleNavKey={ 0 }>
<Nav <CollapsibleNav eventKey={ 0 }>
className='hamburger-dropdown' <Nav
eventKey={ 0 } className='hamburger-dropdown'
right={ true }> navbar={ true }
{ navElements } right={ true }>
{ this.renderSignin() } { navElements }
</Nav> { this.renderPoints(username, points)}
{ this.renderSignin(username, picture) }
</Nav>
</CollapsibleNav>
</Navbar> </Navbar>
); );
} }

View File

@ -0,0 +1,31 @@
import { Actions } from 'thundercats';
import debugFactory from 'debug';
const debug = debugFactory('freecc:app:actions');
export default Actions({
setUser({ username, picture, progressTimestamps = [] }) {
return {
username,
picture,
points: progressTimestamps.length
};
},
getUser: null
})
.refs({ displayName: 'AppActions' })
.init(({ instance: appActions, args: [services] }) => {
appActions.getUser.subscribe(({ isPrimed }) => {
if (isPrimed) {
debug('isPrimed');
return;
}
services.read('user', null, null, (err, user) => {
if (err) {
return debug('user service error');
}
debug('user service returned successful');
return appActions.setUser(user);
});
});
});

18
common/app/flux/Store.js Normal file
View File

@ -0,0 +1,18 @@
import { Store } from 'thundercats';
const { createRegistrar, setter } = Store;
const initValue = {
username: null,
picture: null,
points: 0
};
export default Store(initValue)
.refs({ displayName: 'AppStore' })
.init(({ instance: appStore, args: [cat] }) => {
const { setUser } = cat.getActions('appActions');
const register = createRegistrar(appStore);
register(setter(setUser));
return appStore;
});

2
common/app/flux/index.js Normal file
View File

@ -0,0 +1,2 @@
export AppActions from './Actions';
export AppStore from './Store';

View File

@ -1,12 +1,8 @@
import { Actions } from 'thundercats'; import { Actions } from 'thundercats';
import assign from 'object.assign'; import assign from 'object.assign';
import debugFactory from 'debug'; import debugFactory from 'debug';
import Fetchr from 'fetchr';
const debug = debugFactory('freecc:hikes:actions'); const debug = debugFactory('freecc:hikes:actions');
const service = new Fetchr({
xhrPath: '/services'
});
function getCurrentHike(hikes =[{}], dashedName, currentHike) { function getCurrentHike(hikes =[{}], dashedName, currentHike) {
if (!dashedName) { if (!dashedName) {
@ -36,12 +32,12 @@ export default Actions({
setHikes: null setHikes: null
}) })
.refs({ displayName: 'HikesActions' }) .refs({ displayName: 'HikesActions' })
.init(({ instance }) => { .init(({ instance: hikeActions, args: [services] }) => {
// set up hikes fetching // set up hikes fetching
instance.fetchHikes.subscribe( hikeActions.fetchHikes.subscribe(
({ isPrimed, dashedName }) => { ({ isPrimed, dashedName }) => {
if (isPrimed) { if (isPrimed) {
return instance.setHikes({ return hikeActions.setHikes({
transform: (oldState) => { transform: (oldState) => {
const { hikes } = oldState; const { hikes } = oldState;
const currentHike = getCurrentHike( const currentHike = getCurrentHike(
@ -53,11 +49,11 @@ export default Actions({
} }
}); });
} }
service.read('hikes', null, null, (err, hikes) => { services.read('hikes', null, null, (err, hikes) => {
if (err) { if (err) {
debug('an error occurred fetching hikes', err); debug('an error occurred fetching hikes', err);
} }
instance.setHikes({ hikeActions.setHikes({
set: { set: {
hikes: hikes, hikes: hikes,
currentHike: getCurrentHike(hikes, dashedName) currentHike: getCurrentHike(hikes, dashedName)

View File

@ -7,11 +7,10 @@ const initialValue = {
export default Store(initialValue) export default Store(initialValue)
.refs({ displayName: 'HikesStore'}) .refs({ displayName: 'HikesStore'})
.init(({ instance, args }) => { .init(({ instance: hikeStore, args: [cat] }) => {
const [cat] = args;
let { setHikes } = cat.getActions('hikesActions'); let { setHikes } = cat.getActions('hikesActions');
instance.register(setHikes); hikeStore.register(setHikes);
return instance; return hikeStore;
}); });

View File

@ -1,15 +0,0 @@
import { Actions } from 'thundercats';
export default class JobsActions extends Actions {
constructor() {
super();
}
static displayName = 'JobsActions'
getJob(id) {
return { id };
}
getJobs(params) {
return { params };
}
}

View File

@ -1,28 +1,62 @@
import React, { PropTypes } from 'react'; import React, { cloneElement, PropTypes } from 'react';
import { createContainer } from 'thundercats'; import { contain } from 'thundercats-react';
import { Grid, Row } from 'react-bootstrap'; import { Button, Jumbotron, Row } from 'react-bootstrap';
import ShowJobs from './Show.jsx';
@createContainer({ export default contain(
store: 'JobsStore' {
}) store: 'jobsStore',
export default class extends React.Component { fetchAction: 'jobActions.getJobs'
constructor(props) { },
super(props); React.createClass({
} displayName: 'Jobs',
propTypes: {
children: PropTypes.element,
jobs: PropTypes.array
},
renderShow(jobs) {
return (
<ShowJobs jobs={ jobs }/>
);
},
static displayName = 'Jobs' renderChild(child, jobs) {
static propTypes = { if (!child) {
jobs: PropTypes.array return null;
} }
return cloneElement(
child,
{ jobs }
);
},
render() { render() {
return ( const { children, jobs } = this.props;
<Grid>
<Row> return (
foo <div>
</Row> <Row>
</Grid> <Jumbotron>
); <h1>Free Code Camps' Job Board</h1>
} <p>
} Need to find the best junior developers?
Want to find dedicated developers eager to join your company?
Sign up now to post your job!
</p>
<Button
bsSize='large'
className='signup-btn'>
Try the first month 20% off!
</Button>
</Jumbotron>
</Row>
<Row>
{ this.renderChild(children, jobs) ||
this.renderShow(jobs) }
</Row>
</div>
);
}
})
);

View File

@ -1,13 +0,0 @@
import React, { PropTypes } from 'react';
export default class extends React.Component {
constructor(props) {
super(props);
}
static displayName = 'JobsList'
static propTypes = {}
render() {
return null;
}
}

View File

@ -0,0 +1,79 @@
import React, { PropTypes } from 'react';
import { contain } from 'thundercats-react';
import { Accordion, Thumbnail, Panel, Well } from 'react-bootstrap';
import moment from 'moment';
export default contain(
{
},
React.createClass({
displayName: 'ShowJobs',
propTypes: {
jobs: PropTypes.array
},
renderJobs(jobs =[]) {
const thumbnailStyle = {
backgroundColor: 'white',
maxHeight: '200px',
maxWidth: '200px'
};
return jobs.map((
{
id,
company,
position,
description,
logo,
city,
state,
email,
phone,
postedOn
},
index
) => {
const header = (
<div>
<h4 style={{ display: 'inline-block' }}>{ company }</h4>
<h5
className='pull-right hidden-xs hidden-md'
style={{ display: 'inline-block' }}>
{ position }
</h5>
</div>
);
return (
<Panel
collapsable={ true }
eventKey={ index }
header={ header }
key={ id }>
<Thumbnail
alt='200x200' src={ logo }
style={ thumbnailStyle } />
<Well>
Position: { position }
Location: { city }, { state }
<br />
Contact: { email || phone || 'N/A' }
<br />
Posted On: { moment(postedOn).format('MMMM Do, YYYY') }
</Well>
<p>{ description }</p>
</Panel>
);
});
},
render() {
const { jobs } = this.props;
return (
<Accordion>
{ this.renderJobs(jobs) }
</Accordion>
);
}
})
);

View File

@ -1,9 +0,0 @@
import { Store } from 'thundercats';
export default class JobsStore extends Store {
constructor(cat) {
super();
let JobsActions = cat.getActions('JobsActions');
}
static displayName = 'JobsStore'
}

View File

@ -0,0 +1,27 @@
import { Actions } from 'thundercats';
import debugFactory from 'debug';
const debug = debugFactory('freecc:jobs:actions');
export default Actions({
setJobs: null,
getJob(id) {
return { id };
},
getJobs(params) {
return { params };
}
})
.refs({ displayName: 'JobActions' })
.init(({ instance: jobActions, args: [services] }) => {
jobActions.getJobs.subscribe(() => {
services.read('job', null, null, (err, jobs) => {
if (err) {
debug('job services experienced an issue', err);
jobActions.setJobs({ jobs: [] });
}
jobActions.setJobs({ jobs });
});
});
return jobActions;
});

View File

@ -0,0 +1,10 @@
import { Store } from 'thundercats';
const { setter } = Store;
export default Store()
.refs({ displayName: 'JobsStore' })
.init(({ instance: jobsStore, args: [cat] }) => {
let jobActions = cat.getActions('JobActions');
jobsStore.register(setter(jobActions.setJobs));
});

View File

@ -0,0 +1,2 @@
export { default as JobActions } from './Actions';
export { default as JobsStore } from './Store';

View File

@ -9,10 +9,6 @@ import Jobs from './components/Jobs.jsx';
*/ */
export default { export default {
path: '/jobs/(:jobId)', path: 'jobs',
getComponents(cb) { component: Jobs
setTimeout(() => {
cb(null, Jobs);
}, 0);
}
}; };

View File

@ -1,4 +1,4 @@
// import Jobs from './Jobs'; import Jobs from './Jobs';
import Hikes from './Hikes'; import Hikes from './Hikes';
export default { export default {
@ -6,7 +6,7 @@ export default {
getChildRoutes(locationState, cb) { getChildRoutes(locationState, cb) {
setTimeout(() => { setTimeout(() => {
cb(null, [ cb(null, [
// Jobs, Jobs,
Hikes Hikes
]); ]);
}, 0); }, 0);

View File

@ -10,14 +10,42 @@
"company": { "company": {
"type": "string" "type": "string"
}, },
"logoUrl": { "logo": {
"type": "string" "type": "string"
}, },
"postingUrl": { "city": {
"type": "string" "type": "string"
}, },
"copy": { "email": {
"type": "array" "type": "string"
},
"phone": {
"type": "string"
},
"state": {
"type": "string"
},
"country": {
"type": "string"
},
"location": {
"type": "geopoint"
},
"description": {
"type": "string"
},
"isApproverd": {
"type": "boolean"
},
"isHighlighted": {
"type": "boolean"
},
"isPaid": {
"type": "boolean"
},
"postedOn": {
"type": "date",
"defaultFn": "now"
} }
}, },
"validations": [], "validations": [],

View File

@ -4,16 +4,11 @@ var Rx = require('rx'),
path = require('path'), path = require('path'),
// utils // utils
plumber = require('gulp-plumber'),
notify = require('gulp-notify'), notify = require('gulp-notify'),
debug = require('debug')('freecc:gulp'), debug = require('debug')('freecc:gulp'),
bower = require('bower-main-files'), bower = require('bower-main-files'),
// loopback client
browserify = require('browserify'),
boot = require('loopback-boot'),
envify = require('envify/custom'),
toVinylWithName = require('vinyl-source-stream'),
// react app // react app
webpack = require('gulp-webpack'), webpack = require('gulp-webpack'),
webpackConfig = require('./webpack.config.js'), webpackConfig = require('./webpack.config.js'),
@ -67,57 +62,58 @@ var paths = {
] ]
}; };
var webpackOptions = {
devtool: 'inline-source-map'
};
function errorHandler() {
var args = Array.prototype.slice.call(arguments);
// Send error to notification center with gulp-notify
notify.onError({
title: 'Compile Error',
message: '<%= error %>'
}).apply(this, args);
// Keep gulp from hanging on this task
this.emit('end');
}
gulp.task('inject', function() { gulp.task('inject', function() {
gulp.src('views/home.jade') gulp.src('views/home.jade')
.pipe(plumber({ errorHandler: errorHandler }))
.pipe(inject(gulp.src(bower()), { .pipe(inject(gulp.src(bower()), {
//ignorePath: '/public' //ignorePath: '/public'
})) }))
.pipe(gulp.dest('views')); .pipe(gulp.dest('views'));
}); });
// NOTE(berks): not using this for now as loopback client is just too large
gulp.task('loopback', function() {
var config = {
basedir: __dirname,
debug: true,
cache: {},
packageCache: {},
fullPaths: true,
standalone: paths.loopback.clientName
};
var b = browserify(config);
// compile loopback for the client
b.require(paths.loopback.client);
boot.compileToBrowserify(paths.loopback.root, b);
// sub process.env for proper strings
b.transform(envify({
NODE_ENV: 'development'
}));
return b.bundle()
.on('error', errorNotifier)
.pipe(toVinylWithName(paths.loopback.clientName + '.js'))
.pipe(gulp.dest(paths.publicJs));
});
gulp.task('pack-client', function() { gulp.task('pack-client', function() {
return gulp.src(webpackConfig.entry) return gulp.src(webpackConfig.entry)
.pipe(webpack(webpackConfig)) .pipe(plumber({ errorHandler: errorHandler }))
.pipe(webpack(Object.assign(
{},
webpackConfig,
webpackOptions
)))
.pipe(gulp.dest(webpackConfig.output.path)); .pipe(gulp.dest(webpackConfig.output.path));
}); });
gulp.task('pack-watch', function() { gulp.task('pack-watch', function() {
return gulp.src(webpackConfig.entry) return gulp.src(webpackConfig.entry)
.pipe(webpack(Object.assign(webpackConfig, { watch: true }))) .pipe(plumber({ errorHandler: errorHandler }))
.pipe(webpack(Object.assign(
{},
webpackConfig,
webpackOptions,
{ watch: true }
)))
.pipe(gulp.dest(webpackConfig.output.path)); .pipe(gulp.dest(webpackConfig.output.path));
}); });
gulp.task('pack-node', function() { gulp.task('pack-node', function() {
return gulp.src(webpackConfigNode.entry) return gulp.src(webpackConfigNode.entry)
.pipe(plumber({ errorHandler: errorHandler }))
.pipe(webpack(webpackConfigNode)) .pipe(webpack(webpackConfigNode))
.pipe(gulp.dest(webpackConfigNode.output.path)); .pipe(gulp.dest(webpackConfigNode.output.path));
}); });
@ -174,6 +170,7 @@ gulp.task('lint', function() {
gulp.task('less', function() { gulp.task('less', function() {
return gulp.src('./public/css/*.less') return gulp.src('./public/css/*.less')
.pipe(plumber({ errorHandler: errorHandler }))
.pipe(less({ .pipe(less({
paths: [ path.join(__dirname, 'less', 'includes') ] paths: [ path.join(__dirname, 'less', 'includes') ]
})) }))
@ -188,15 +185,3 @@ gulp.task('watch', ['less', 'serve', 'sync'], function() {
gulp.task('default', ['less', 'serve', 'sync', 'watch', 'pack-watch']); gulp.task('default', ['less', 'serve', 'sync', 'watch', 'pack-watch']);
function errorNotifier() {
var args = Array.prototype.slice.call(arguments);
// Send error to notification center with gulp-notify
notify.onError({
title: 'Compile Error',
message: '<%= error %>'
}).apply(this, args);
// Keep gulp from hanging on this task
this.emit('end');
}

View File

@ -5,15 +5,13 @@
"type": "git", "type": "git",
"url": "https://github.com/freecodecamp/freecodecamp.git" "url": "https://github.com/freecodecamp/freecodecamp.git"
}, },
"engines": {
"node": "0.10.35",
"npm": "2.3.0"
},
"scripts": { "scripts": {
"build-production": "webpack",
"start": "babel-node server/server.js", "start": "babel-node server/server.js",
"prestart-production": "bower cache clean && bower install && gulp build && npm run build-production",
"start-production": "node pm2Start",
"lint": "eslint --ext=.js,.jsx .", "lint": "eslint --ext=.js,.jsx .",
"test": "mocha", "test": "mocha"
"postinstall": "bower cache clean && bower install && gulp build"
}, },
"license": "BSD-3-Clause", "license": "BSD-3-Clause",
"contributors": [ "contributors": [
@ -120,6 +118,7 @@
"gulp-inject": "~1.0.2", "gulp-inject": "~1.0.2",
"gulp-nodemon": "^2.0.3", "gulp-nodemon": "^2.0.3",
"gulp-notify": "^2.2.0", "gulp-notify": "^2.2.0",
"gulp-plumber": "^1.0.1",
"istanbul": "^0.3.15", "istanbul": "^0.3.15",
"loopback-explorer": "^1.7.2", "loopback-explorer": "^1.7.2",
"loopback-testing": "^1.1.0", "loopback-testing": "^1.1.0",

View File

@ -1,9 +1,8 @@
require('babel/register');
var pm2 = require('pm2'); var pm2 = require('pm2');
pm2.connect(function() { pm2.connect(function() {
pm2.start({ pm2.start({
name: 'server', name: 'server',
script: 'server/server.js', script: 'server/production-start.js',
'exec_mode': 'cluster', 'exec_mode': 'cluster',
instances: '2', instances: '2',
'max_memory_restart': '900M' 'max_memory_restart': '900M'

View File

@ -334,6 +334,7 @@ ul {
.navbar { .navbar {
white-space: nowrap; white-space: nowrap;
border: none; border: none;
line-height: 1;
@media (min-width: 767px) { @media (min-width: 767px) {
padding-left: 30px; padding-left: 30px;
padding-right: 30px; padding-right: 30px;

View File

@ -1,13 +1,13 @@
{ {
"name": "Basic JavaScript", "name": "Basic JavaScript",
"order": 0.005, "order": 0.006,
"challenges": [ "challenges": [
{ {
"id": "bd7123c9c441eddfaeb4bdef", "id":"bd7123c9c441eddfaeb4bdef",
"name": "Welcome To Comments", "name":"Welcome To Comments",
"dashedName": "waypoint-welcome-to-comments", "dashedName":"waypoint-welcome-to-comments",
"difficulty": "9.98", "difficulty":"9.98",
"description": [ "description":[
"", "",
"A comment is a very useful line of code that is not actually ran by the machine executing it. With this property comments are the perfect way of creating notes to yourself or anyone else who reads your code describing what the code does", "A comment is a very useful line of code that is not actually ran by the machine executing it. With this property comments are the perfect way of creating notes to yourself or anyone else who reads your code describing what the code does",
"It's an extremely important part in writing good, efficient and maintainable code and a requirement by most employers", "It's an extremely important part in writing good, efficient and maintainable code and a requirement by most employers",
@ -18,12 +18,12 @@
"These comment out everything in between <code> /* </code> and <code> */ </code>", "These comment out everything in between <code> /* </code> and <code> */ </code>",
"Try creating one of each now." "Try creating one of each now."
], ],
"tests": [ "tests":[
"assert(editor.getValue().match(/(\\/\\*)...../g), 'Make sure you have at least one \/\\* \\*\/ style comment that has at least five letters in it');", "assert(editor.getValue().match(/(\\/\\*)...../g), 'Make sure you have at least one \/\\* \\*\/ style comment that has at least five letters in it');",
"assert(editor.getValue().match(/(\\*\\/)/g), 'Make sure that you close the coment with a \\*\/');", "assert(editor.getValue().match(/(\\*\\/)/g), 'Make sure that you close the coment with a \\*\/');",
"assert(editor.getValue().match(/(\\/\\/)...../g), 'Make sure that there is at least one \\/\\/ style comment with at least five letters in it');" "assert(editor.getValue().match(/(\\/\\/)...../g), 'Make sure that there is at least one \\/\\/ style comment with at least five letters in it');"
], ],
"challengeSeed": [ "challengeSeed":[
], ],
"challengeType": 1 "challengeType": 1
@ -265,7 +265,7 @@
"challengeType": 1 "challengeType": 1
}, },
{ {
"id": "bd1111c1c11feddfaeb3bdef", "id": "cf1111c1c11feddfaeb3bdef",
"name": "Magical Maths Addition", "name": "Magical Maths Addition",
"dashedName": "waypoint-magical-maths-addition", "dashedName": "waypoint-magical-maths-addition",
"difficulty": "9.98141", "difficulty": "9.98141",
@ -289,7 +289,7 @@
"challengeType": 1 "challengeType": 1
}, },
{ {
"id": "bd1111c1c11feddfaeb4bdef", "id": "cf1111c1c11feddfaeb4bdef",
"name": "Magical Maths Subtraction", "name": "Magical Maths Subtraction",
"dashedName": "waypoint-magical-maths-subtraction", "dashedName": "waypoint-magical-maths-subtraction",
"difficulty": "9.98142", "difficulty": "9.98142",
@ -313,7 +313,7 @@
"challengeType": 1 "challengeType": 1
}, },
{ {
"id": "bd1111c1c11feddfaeb5bdef", "id": "cf1231c1c11feddfaeb5bdef",
"name": "Magical Maths Multiplication", "name": "Magical Maths Multiplication",
"dashedName": "waypoint-magical-maths-multiplication", "dashedName": "waypoint-magical-maths-multiplication",
"difficulty": "9.98143", "difficulty": "9.98143",
@ -337,7 +337,7 @@
"challengeType": 1 "challengeType": 1
}, },
{ {
"id": "bd1111c1c11feddfaeb6bdef", "id": "cf1111c1c11feddfaeb6bdef",
"name": "Magical Maths Division", "name": "Magical Maths Division",
"dashedName": "waypoint-magical-maths-division", "dashedName": "waypoint-magical-maths-division",
"difficulty": "9.9814", "difficulty": "9.9814",
@ -361,7 +361,7 @@
"challengeType": 1 "challengeType": 1
}, },
{ {
"id": "bd1111c1c11feddfaeb4bdee", "id": "cf1391c1c11feddfaeb4bdef",
"name": "Creating Decimals", "name": "Creating Decimals",
"dashedName": "waypoint-creating-decimals", "dashedName": "waypoint-creating-decimals",
"difficulty": "9.9815", "difficulty": "9.9815",
@ -439,19 +439,19 @@
"challengeType": 1 "challengeType": 1
}, },
{ {
"id": "bd1111c1c11feddfaeb7bdef", "id":"cf1111c1c11feddfaeb7bdef",
"name": "Nesting Arrays", "name":"Nesting Arrays",
"dashedName": "waypoint-nesting-arrays", "dashedName":"waypoint-nesting-arrays",
"difficulty": "9.98161", "difficulty":"9.98161",
"description": [ "description":[
"", "",
"We are also able to create arrays within arrays. This technique is called <code>nesting</code>.", "We are also able to create arrays within arrays. This technique is called <code>nesting</code>.",
"Let's now go create a nested array called <code>myArray</code>" "Let's now go create a nested array called <code>myArray</code>"
], ],
"tests": [ "tests":[
"assert((function(){if(typeof(myArray) !== 'undefined' && typeof(myArray) === 'object' && typeof(myArray[0]) !== 'undefined' && typeof(myArray) === 'object'){return(true);}else{return(false);}})(), 'myArray should contain at least one array');" "assert((function(){if(typeof(myArray) !== 'undefined' && typeof(myArray) === 'object' && typeof(myArray[0]) !== 'undefined' && typeof(myArray) === 'object'){return(true);}else{return(false);}})(), 'myArray should contain at least one array');"
], ],
"challengeSeed": [ "challengeSeed":[
"var myArray = [];", "var myArray = [];",
"", "",
"", "",
@ -460,25 +460,26 @@
"challengeType": 1 "challengeType": 1
}, },
{ {
"id": "bg9997c9c79feddfaeb9bdef", "id":"bg9997c9c79feddfaeb9bdef",
"name": "Accessing data with Indexes", "name":"Accessing data with Indexes",
"dashedName": "waypoint-accessing-data-with-indexes", "dashedName":"waypoint-accessing-data-with-indexes",
"difficulty": "9.9817", "difficulty":"9.9817",
"description": [ "description":[
"", "",
"Once an array has been created we can access the data we have stored in them using indexes", "Once an array has been created we can access the data we have stored in them using indexes",
"Indexes are written in the same way as bracket notation that we covered earlier", "Indexes are written in the same way as bracket notation that we covered earlier",
"Example:", "Example:",
"<code>", "<code>",
"var array = [1,2,3]", "var array = [1,2,3];",
"array[0]//equals 1", "array[0];//equals 1",
"var data = array[1];",
"</code>", "</code>",
"Create a var called <code>data</code> and set it to equal the first value of <code>myArray</code>" "Create a var called <code>data</code> and set it to equal the first value of <code>myArray</code>"
], ],
"tests": [ "tests":[
"assert((function(){if(typeof(myArray) != 'undefined' && typeof(data) != 'undefined' && myArray[0] == data){return(true);}else{return(false);}})(), 'the variable data should equal the first value of myArray');" "assert((function(){if(typeof(myArray) != 'undefined' && typeof(data) != 'undefined' && myArray[0] == data){return(true);}else{return(false);}})(), 'the variable data should equal the first value of myArray');"
], ],
"challengeSeed": [ "challengeSeed":[
"//var ourArray = [1,2,3]", "//var ourArray = [1,2,3]",
"//var ourData = ourArray[0]//equals 1", "//var ourData = ourArray[0]//equals 1",
"", "",
@ -490,6 +491,39 @@
], ],
"challengeType": 1 "challengeType": 1
}, },
{
"id":"cf1111c1c11feddfaeb8bdef",
"name":"Modifying Data With Indexes",
"dashedName":"waypoint-modifying-data-with-indexes",
"difficulty":"9.98171",
"description":[
"",
"We are able to modify the data store in an array be using indexes",
"Example:",
"<code>",
"var ourArray = [1,2,3];",
"ourArray[0] = 3;//ourArray equals [3,2,3]",
"</code>",
"Now Let's modify <code>myArray</code> using an index",
""
],
"tests":[
"assert((function(){if(typeof(myArray) != 'undefined' && myArray[0] == 3 && myArray[1] == 2 && myArray[2] == 3){return(true);}else{return(false);}})(), 'myArray should now be [3,2,3]');",
"assert((function(){if(editor.getValue().match(/[0]/g).length >= 2 && editor.getValue().match(/=/g).length >= 2){return(true);}else{return(false);}})(), 'You should be using indexes to modify the values in myArray');"
],
"challengeSeed":[
"//var ourArray = [1,2,3];",
"//ourArray[0] = 3;",
"",
"var myArray = [1,2,3];",
"",
"",
"",
"",
"if(typeof(myArray) != 'undefined'){(function(){return(myArray);})();}"
],
"challengeType": 1
},
{ {
"id": "bg9994c9c69feddfaeb9bdef", "id": "bg9994c9c69feddfaeb9bdef",
"name": "Manipulating Arrays With pop()", "name": "Manipulating Arrays With pop()",
@ -593,141 +627,49 @@
"challengeType": 1 "challengeType": 1
}, },
{ {
"id": "bg9997c9c89feddfaeb9bdef", "id":"bg9997c9c89feddfaeb9bdef",
"name": "Make it functional", "name":"Make it functional",
"dashedName": "waypoint-make-it-functional", "dashedName":"waypoint-make-it-functional",
"difficulty": "9.9819", "difficulty":"9.9819",
"description": [ "description":[
"", "",
"In JavaScript we can divide up our code into separate and reusable parts called functions", "In JavaScript we can divide up our code into separate and reusable parts called functions",
"here's and example of a function", "here's and example of a function",
"<code>", "<code>",
"function funcitonName (one, two ,three){", "function functionName (a, b){",
" /*Some Code*/", " return(a + b);",
"}", "}",
"</code>", "</code>",
"our function can be called like this", "our function can be called like this",
"<code>functionName();</code>", "<code>functionName();</code>",
"Let's try creating and calling a function now." "Let's try creating and calling a function now called <code>myFunction</code>"
], ],
"tests": [ "tests":[
"assert(f==data);" "assert((function(){if(typeof(f) !== 'undefined' && typeof(f) === 'number' && f === 9){return(true);}else{return(false);}})(), 'Your function should return the value of a + b');"
], ],
"challengeSeed": [ "challengeSeed":[
"//var ourData = 'function called!';", "var a = 4;",
"//function ourFunction(ourData) {/*ourData is being passed to this function as an argument*/", "var b = 5;",
"//return(data);", "//Don not modify the above!",
"//}", "//Create a function called myFunction that adds a and b",
"",
"var data = 'Function Called!';",
"",
"//Create a function called myFunction that takes data as an argument and returns it like the example above",
"",
"", "",
"", "",
"", "",
"", "",
"//Don't modify this!", "//Don't modify this!",
"var f=myFunction(data);", "if(typeof(myFunction) != 'undefined'){",
"(function(){var f=myFunction(data);return(f);})('');" "var f=myFunction(a,b);",
"(function(){return(f);})();",
"}"
], ],
"challengeType": 1 "challengeType": 1
}, },
{ {
"id": "bg9997c9c99feddfaeb9bdef", "id":"bg9998c9c99feddfaeb9bdef",
"name": "Doing things inside functions", "name":"I Object!",
"dashedName": "waypoint-doing-things-inside-functions", "dashedName":"waypoint-i-object",
"difficulty": "9.982", "difficulty":"9.9822",
"description": [ "description":[
"",
"A function that takes the value you give it and returns it isn't very useful! So now let's get our functions to do something!",
"Starting from where we were last time let's make our function revers whatever we give it by chaining <code> .split('') </code>, <code> .reverse() </code> and <code> .join('') </code>"
],
"tests": [
"assert(f==data.split('').reverse().join(''), 'myFunction should now return the reversed version of data (!dellaC noitcnuF)');"
],
"challengeSeed": [
"//You can reverse strings like this",
"//var notReversed = 'String';",
"//var reversed = notReversed.split('').reverse().join('');",
"",
"var data = 'Function Called!';",
"",
"function myFunction(data){",
" ",
" return(data);",
"}",
"",
"",
"",
"//Don't modify this!",
"var f=myFunction(data);",
"(function(f){return(f);})(f);"
],
"challengeType": 1
},
{
"id": "bg9997c9c99feddfaeb9bdee",
"name": "Keeping In The Scope Of Things",
"dashedName": "waypoint-keeping-in-the-scope-of-things",
"difficulty": "9.9821",
"description": [
"",
"All variables are contained in something called a <code> scope </code>.",
"A Scope defines where are variable can be accessed.",
"All variables created outside any functions exist in what is called the <code> global scope </code>",
"All variables are container or are scope to inside that function.",
"<code>",
"var variable = 'Global Scope'",
"function test(){",
" return(variable);",
"}",
"test();//Returns Global Scope",
"",
"function change(){",
" variable = 'test';",
" return(variable);",
"}",
"",
"change();//Returns test",
"variable //equals Global Scope",
"",
"</code>",
"Let's give this a go!"
],
"tests": [
"assert(Global == access(Global), 'access should return your Global var');",
"assert(Global != localChange(Global), 'localChange should return your Global var');"
],
"challengeSeed": [
"//Create Your global variable with any value here",
"var Global = _;",
"",
"//Make access() return you global variable",
"function access(){",
" ",
"}",
"",
"access();",
"",
"//Pass you global variable into localChange and modify it within the function",
"function localChange(){",
" ",
"}",
"",
"//Don't forget to call localChange here and pass your global variable",
"",
"",
"(function(x,y,z){return('access returns: ' + y(x) + ' & localChange returns: ' + z(x));})(Global, access, localChange);"
],
"challengeType": 1
},
{
"id": "bg9998c9c99feddfaeb9bdef",
"name": "I Object!",
"dashedName": "waypoint-i-object",
"difficulty": "9.9822",
"description": [
"", "",
"A very important data type in javascript is the <code> Object </code>", "A very important data type in javascript is the <code> Object </code>",
"<code> Objects </code> a similar to <code> arrays </code> except that instead of using indexes to access and modify their data, Objects have what are called <code> properties </code>", "<code> Objects </code> a similar to <code> arrays </code> except that instead of using indexes to access and modify their data, Objects have what are called <code> properties </code>",
@ -744,13 +686,13 @@
"Let's try to make a Object that represents a dog called myDog!" "Let's try to make a Object that represents a dog called myDog!"
], ],
"tests": [ "tests":[
"assert((function(z){if(z.hasOwnProperty('name') && z.name != undefined && typeof(z.name) == 'string'){return(true);}else{return(false);}})(myDog), 'myDog should contain the property name and it should be a string');", "assert((function(z){if(z.hasOwnProperty('name') && z.name != undefined && typeof(z.name) == 'string'){return(true);}else{return(false);}})(myDog), 'myDog should contain the property name and it should be a string');",
"assert((function(z){if(z.hasOwnProperty('legs') && z.legs != undefined && typeof(z.legs) == 'number'){return(true);}else{return(false);}})(myDog), 'myDog should contain the property legs and it should be a number');", "assert((function(z){if(z.hasOwnProperty('legs') && z.legs != undefined && typeof(z.legs) == 'number'){return(true);}else{return(false);}})(myDog), 'myDog should contain the property legs and it should be a number');",
"assert((function(z){if(z.hasOwnProperty('tails') && z.tails != undefined && typeof(z.tails) == 'number'){return(true);}else{return(false);}})(myDog), 'myDog should contain the property tails and it should be a number');", "assert((function(z){if(z.hasOwnProperty('tails') && z.tails != undefined && typeof(z.tails) == 'number'){return(true);}else{return(false);}})(myDog), 'myDog should contain the property tails and it should be a number');",
"assert((function(z){if(z.hasOwnProperty('friends') && z.friends != undefined && Array.isArray(z.friends)){return(true);}else{return(false);}})(myDog), 'myDog should contain the property friends and it should be an array');" "assert((function(z){if(z.hasOwnProperty('friends') && z.friends != undefined && Array.isArray(z.friends)){return(true);}else{return(false);}})(myDog), 'myDog should contain the property friends and it should be an array');"
], ],
"challengeSeed": [ "challengeSeed":[
"//var ourDog = {", "//var ourDog = {",
"// \"name\": \"Camper\"", "// \"name\": \"Camper\"",
"// \"legs\": 4", "// \"legs\": 4",
@ -770,11 +712,11 @@
"challengeType": 1 "challengeType": 1
}, },
{ {
"id": "bg9999c9c99feddfaeb9bdef", "id":"bg9999c9c99feddfaeb9bdef",
"name": "Manipulating Objects", "name":"Manipulating Objects",
"dashedName": "waypoint-manipulating-objects", "dashedName":"waypoint-manipulating-objects",
"difficulty": "9.9823", "difficulty":"9.9823",
"description": [ "description":[
"", "",
"Now that we have an objects we need to know how to add and remove properties from it", "Now that we have an objects we need to know how to add and remove properties from it",
"We add properties to objects like this", "We add properties to objects like this",
@ -784,11 +726,11 @@
"Let's add the property bark", "Let's add the property bark",
"" ""
], ],
"tests": [ "tests":[
"assert(myDog.bark != undefined, 'The property tails should have been deleted');", "assert(myDog.bark != undefined, 'The property tails should have been deleted');",
"assert(myDog.tails == undefined, 'The property tails should have been deleted');" "assert(myDog.tails == undefined, 'The property tails should have been deleted');"
], ],
"challengeSeed": [ "challengeSeed":[
"//var ourDog = {", "//var ourDog = {",
"//\"name\": \"Camper\"", "//\"name\": \"Camper\"",
"//\"legs\": 4", "//\"legs\": 4",
@ -816,11 +758,11 @@
"challengeType": 1 "challengeType": 1
}, },
{ {
"id": "bd1111c1c11feddfaeb5bdee", "id":"cf1111c1c11feddfaeb5bdef",
"name": "Looping with for", "name":"Looping with for",
"dashedName": "waypoint-looping-with-for", "dashedName":"waypoint-looping-with-for",
"difficulty": "9.9824", "difficulty":"9.9824",
"description": [ "description":[
"", "",
"Loops are a critical part of any program! The next few challenges", "Loops are a critical part of any program! The next few challenges",
"first we will be taking a look at the for loop", "first we will be taking a look at the for loop",
@ -833,11 +775,11 @@
"ourArray now contains [0,1,2,3,4] ", "ourArray now contains [0,1,2,3,4] ",
"Let's try getting a for loop to work by pushing values to an array" "Let's try getting a for loop to work by pushing values to an array"
], ],
"tests": [ "tests":[
"assert(editor.getValue().match(/for\\(/g), 'You should be using a for loop for this!');", "assert(editor.getValue().match(/for\\(/g), 'You should be using a for loop for this!');",
"assert.deepEqual(myArray, [0,1,2,3,4], 'myArray should equal [0,1,2,3,4]');" "assert.deepEqual(myArray, [0,1,2,3,4], 'myArray should equal [0,1,2,3,4]');"
], ],
"challengeSeed": [ "challengeSeed":[
"var myArray = [];", "var myArray = [];",
"//Push the numbers 0-4 to myArray", "//Push the numbers 0-4 to myArray",
"", "",
@ -846,11 +788,11 @@
"challengeType": 1 "challengeType": 1
}, },
{ {
"id": "bd1111c1c11feddfaeb1bdef", "id":"cf1111c1c11feddfaeb1bdef",
"name": "Looping with while", "name":"Looping with while",
"dashedName": "waypoint-looping-with-while", "dashedName":"waypoint-looping-with-while",
"difficulty": "9.9825", "difficulty":"9.9825",
"description": [ "description":[
"", "",
"Loops are a critical part of any program! The next few challenges", "Loops are a critical part of any program! The next few challenges",
"first we will be taking a look at the for loop", "first we will be taking a look at the for loop",
@ -864,11 +806,11 @@
"</code>", "</code>",
"Let's try getting a for loop to work by pushing values to an array" "Let's try getting a for loop to work by pushing values to an array"
], ],
"tests": [ "tests":[
"assert(editor.getValue().match(/while\\(/g), 'You should be using a while loop for this!');", "assert(editor.getValue().match(/while\\(/g), 'You should be using a while loop for this!');",
"assert.deepEqual(myArray, [0,1,2,3,4], 'myArray should equal [0,1,2,3,4]');" "assert.deepEqual(myArray, [0,1,2,3,4], 'myArray should equal [0,1,2,3,4]');"
], ],
"challengeSeed": [ "challengeSeed":[
"var myArray = [];", "var myArray = [];",
"//Push the numbers 0-4 to myArray", "//Push the numbers 0-4 to myArray",
"", "",
@ -877,11 +819,11 @@
"challengeType": 1 "challengeType": 1
}, },
{ {
"id": "bd1111c1c11feddfaeb2bdef", "id":"cf1111c1c11feddfaeb2bdef",
"name": "Looping with do while", "name":"Looping with do while",
"dashedName": "waypoint-looping-with-do-while", "dashedName":"waypoint-looping-with-do-while",
"difficulty": "9.9826", "difficulty":"9.9826",
"description": [ "description":[
"", "",
"Let's now take a look at the do - while loop", "Let's now take a look at the do - while loop",
"<code>", "<code>",
@ -895,17 +837,238 @@
"A do - while has a very special difference when compared to the for and while loops. The do while loop is guaranteed to execute preform it's action once regardless of whether or not the condition inside the while is met!", "A do - while has a very special difference when compared to the for and while loops. The do while loop is guaranteed to execute preform it's action once regardless of whether or not the condition inside the while is met!",
"Let's try getting a do - while loop to work by pushing values to an array" "Let's try getting a do - while loop to work by pushing values to an array"
], ],
"tests": [ "tests":[
"assert.deepEqual(myArray, [0,1,2,3,4], 'myArray should equal [0,1,2,3,4]');", "assert.deepEqual(myArray, [0,1,2,3,4], 'myArray should equal [0,1,2,3,4]');",
"assert((function(){if(editor.getValue().match(/do/g) && editor.getValue(/while/g).match()){return(true);}else{return(false);}})(), 'You should be using a do while loop for this!');" "assert((function(){if(editor.getValue().match(/do/g) && editor.getValue(/while/g).match()){return(true);}else{return(false);}})(), 'You should be using a do while loop for this!');"
], ],
"challengeSeed": [ "challengeSeed":[
"var myArray = [];", "var myArray = [];",
"//Push the numbers 0-4 to myArray", "//Push the numbers 0-4 to myArray",
"", "",
"" ""
], ],
"challengeType": 1 "challengeType": 1
},
{
"id":"cf1111c1c11feddfaeb9bdef",
"name":"Random Numbers",
"dashedName":"waypoint-random-numbers",
"difficulty":"9.9827",
"description":[
"",
"Random numbers are a very useful for creating random behaviours and games",
"Javascript has a <code>Math.random()</code> method that can generate a random decimal number",
"Let's have a go of <code>Math.random()</code> now be getting <code>myFunction</code> to return a random number"
],
"tests":[
"assert(typeof(myFunction()) === 'number', 'myFunction should return a random number');",
"assert((myFunction()+''). match(/\\./g), 'The number returned by myFunction should be a decimal');",
"assert(editor.getValue().match(/Math\\.random/g).length >= 2, 'You should be using Math.random to generate the random decimal number');"
],
"challengeSeed":[
"",
"function myFunction(){",
" //Change the 0 to Math.random()",
" return(0);",
"}",
"",
"(function(){return(myFunction());})();"
],
"challengeType": 1
},
{
"id":"cf1111c1c12feddfaeb1bdef",
"name":"Random Whole Numbers",
"dashedName":"waypoint-random-whole-numbers",
"difficulty":"9.9828",
"description":[
"",
"While it's great that we can create random decimal numbers it's a lot more useful to generate a random whole number",
"To achieve this we can multiply the random number by ten and use the <code>Math.floor()</code> to convert the decimal number to a whole number",
"This technique gives us a whole number between zero and nine",
"Example:",
"<code>Math.floor(Math.random()*10);</code>",
"Let's give this technique a go now"
],
"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 but 10 to make it a number that\\'s greater then zero');",
"assert(editor.getValue().match(/Math.floor/g), 'You should use Math.floor to remove the decimal part of the number');"
],
"challengeSeed":[
"function myFunction(){",
" //Make myFunction return a random number between zero and nine instead of a float",
" return(Math.random());",
"}",
"",
"(function(){return(myFunction());})();"
],
"challengeType": 1
},
{
"id":"cf1111c1c12feddfaeb2bdef",
"name":"Random Whole Numbers In a Range",
"dashedName":"waypoint-random-whole-numbers-in-a-range",
"difficulty":"9.9829",
"description":[
"",
"We can use a certain mathematical expression to get a random number between between twp numbers.",
"<code>Math.floor(Math.random() * (max - min + 1)) + min</code>",
"By using this we can control the output of the random number.",
""
],
"tests":[
"assert(myFunction() >= min, 'The random number that\\'s generated by myFunction should be greater than or equal to the minimum number');",
"assert(myFunction() <= max, 'The random number that\\'s generated by myFunction should be less than or equal to the maximum number');",
"assert((function(){if(editor.getValue().match(/max/g).length >= 2 && editor.getValue().match(/min/g).length >= 3 && editor.getValue().match(/Math.floor/g) && editor.getValue().match(/Math.random/g)){return(true);}else{return(false);}})(), 'You should be using the function given in the description to calculate the random in number in a range');"
],
"challengeSeed":[
" var min = 0;",
" var max = 12;",
"function myFunction(){",
" //Make myFunction return a random number between zero and nine instead of a float",
" return(Math.random());",
"}",
"",
"(function(){return(myFunction());})();"
],
"challengeType": 1
},
{
"id":"cf1111c1c12feddfaeb3bdef",
"name":"If Else Statements",
"dashedName":"waypoint-if-else-statements",
"difficulty":"9.983",
"description":[
"",
"We can use if statements in JavaScript to only execute code if a certain condition is met",
"if statements require some sort of boolean condition evaluate",
"Example:",
"<code>if(1==2){",
" return(true);",
"}",
"else{",
" return(false);",
"}</code>",
"Let's have a go of using if statements now by making a coin-flip game",
"Create an if else statement to return <code>heads</code> if the flip var is zero and to return <code>tails</code> if it's not"
],
"tests":[
"assert((function(){if(myFunction() == 'heads' || myFunction() == 'tails'){return(true);}else{return(false);}})(), 'myFunction should either return heads or tails');",
"assert(editor.getValue().match(/if/g).length >= 3, 'You should have created a new if statement');",
"assert(editor.getValue().match(/else/g).length >= 2, 'You should have created a new else statement');"
],
"challengeSeed":[
"function myFunction(){",
" var flip = Math.floor(Math.random() * (1 - 0 + 1)) + 0;",
" //Create and if else statement here to return heads if flip is 0 otherwise return false",
" ",
"}",
"",
"(function(){return(myFunction());})();"
],
"challengeType": 1
},
{
"id":"cf1111c1c12feddfaeb6bdef",
"name":"An Intro To RegEx",
"dashedName":"waypoint-an-intro-to-regex",
"difficulty":"9.984",
"description":[
"",
"RegEx is a powerful tool we can use to find certain words or patterns in strings",
"RegEx can look difficult at first but there's not much to getting it working",
"If we wanted to find the number of times the word \"the\" occured in the string \"The dog chased the cat\" We could use the following RegEx:",
"<code>\/the+\/gi</code>",
"Let's break this down a bit",
"\"The\" is the pattern we want to match",
"\"+\" means we are looking for one or more occurrences of this pattern",
"\"g\" means that it searhces the whole string",
"\"i\" means that we are ignoring the case(upper or lower) of what we are looking for",
"Let's try finding the word and in the string \"John and Alan went to the shop and got some milk\" by replacing the <code>.+</code> in the currnet RegEx with something that will find the word \"and\" and count how many times it occurs"
],
"tests":[
"assert(test==2, 'You\\'re RegEx should have found two occurances of the word \"and\"');",
"assert(editor.getValue().match(/\\/and\\+\\/gi/), 'You should have used this RegEx to find the word \"and\"');"
],
"challengeSeed":[
"var test = (function(){",
" var testString = \"John and Alan went to the shop and got some milk\";",
"",
"//Do Not Modify Above",
"",
" var expression = /.+/gi;",
"",
"//Do Not Modify Below",
"",
" return(testString.match(expression).length);",
"})();(function(){return(test);})();"
],
"challengeType": 1
},
{
"id":"cf1111c1c12feddfaeb7bdef",
"name":"Finding Numbers",
"dashedName":"waypoint-finding-numbers",
"difficulty":"9.985",
"description":[
"",
"We can use special selectors in RegEx to select a particular type of value",
"One such selector is the digit selector <code>\\d</code> which is used to grab the numbers in a string",
"It is used like this:",
"<code>/\\d+/g</code>",
""
],
"tests":[
"assert(test === 2, 'Your RegEx should have found two numbers in the testString');",
"assert(editor.getValue().match(/\\/\\\\d\\+\\//gi), 'You should be using the following expression /\\d+/gi to find the numbers in the testString');"
],
"challengeSeed":[
"var test = (function(){",
" var testString = \"There's 3 cats but 4 dogs.\"",
"",
"//Do Not Modify Above",
"",
" var expression = /.+/gi;",
"",
"//Do Not Modify Below",
"",
" return(testString.match(expression).length);",
"})();(function(){return(test);})();"
],
"challengeType": 1
},
{
"id":"cf1111c1c12feddfaeb8bdef",
"name":"Finding WhiteSpace",
"dashedName":"waypoint-finding-whitespace",
"difficulty":"9.987",
"description":[
"",
"We can also use selectors like <code>\\s</code> to find spaces in a string",
"It is used like this:",
"<code>/\\s+/g</code>",
""
],
"tests":[
"assert(test === 7, 'Your RegEx should have found seven spaces in the testString');",
"assert(editor.getValue().match(/\\/\\\\s\\+\\//gi), 'You should be using the following expression /\\s+/gi to find the spaces in the testString');"
],
"challengeSeed":[
"var test = (function(){",
" var testString = \"How many spaces are there in this sentance.\";",
"",
"//Do Not Modify Above",
"",
" var expression = /.+/gi;",
"",
"//Do Not Modify Below",
"",
" return(testString.match(expression).length);",
"})();(function(){return(test);})();"
],
"challengeType": 1
} }
] ]
} }

View File

@ -1,30 +1,47 @@
[ [
{ {
"id": "bd7167d8c441cbafaeb5bdef", "id": "bd7167d8c441cbafaeb5bdef",
"email": "Ada_Gerlach@gmail.com",
"phone": "1-140-557-0727",
"company": "Livestream", "company": "Livestream",
"country": "Singapore",
"city": "Morar berg",
"state": "South Dakota",
"position": "Junior Backend Developer (Node.js)", "position": "Junior Backend Developer (Node.js)",
"logoUrl": "https://s3.amazonaws.com/prod-heroku/greenhouse_job_boards/logos/000/001/189/resized/livestream_logo-rgb_standard-cc718e67ce1a0f6fa400f609bdefe605.png?1429547161", "logo": "https://s3.amazonaws.com/prod-heroku/greenhouse_job_boards/logos/000/001/189/resized/livestream_logo-rgb_standard-cc718e67ce1a0f6fa400f609bdefe605.png?1429547161",
"postingUrl": "https://boards.greenhouse.io/livestream/jobs/59458?t=ek25h0#.VWeTk1xVhBc?source=freecodecamp.com" "description": "Live life one inhalation and one exhalation at a time. May you be healthy. Let the muscles in your neck and shoulders relax. May you be safe. Reflect on the fragility and preciousness of life. Empty your mind; be formless, shapeless like water. May you be at peace. Take a deep breath. You can do what you set out to do; yes, you can. You can do what you set out to do; yes, you can. Watch each breath appear and disappear, just breathing. Give yourself a break. Live life one inhalation and one exhalation at a time. Give yourself a break. Just acknowledge what's there and let be. You can get through this. Open your heart to change, forgiveness and lovingkindness. Love is the first seed of the soul. It will be ok. Impermanence and change is a powerful teacher and teaching. Bring love into your heart, into your breath and into your being. Briefly notice any emotions, thoughts or sensations that may be driving fear and anxiety and let them be. This discomfort will pass. Bring love into your heart, into your breath and into your being. Take a deep breath. Reflect on the fragility and preciousness of life."
}, },
{ {
"id": "bd7167d8c442cbafaeb5bdef", "id": "bd7167d8c442cbafaeb5bdef",
"email": "Ada_Gerlach@gmail.com",
"company": "Adobe", "company": "Adobe",
"country": "Singapore",
"city": "Morar berg",
"state": "South Dakota",
"position": "Junior JavaScript Engineer", "position": "Junior JavaScript Engineer",
"logoUrl": "http://cdn-3.famouslogos.us/images/adobe-logo.jpg", "logo": "http://cdn-3.famouslogos.us/images/adobe-logo.jpg",
"postingUrl": "https://adobe.taleo.net/careersection/2/jobdetail.ftl?job=32619&lang=en" "description": "Live life one inhalation and one exhalation at a time. May you be healthy. Let the muscles in your neck and shoulders relax. May you be safe. Reflect on the fragility and preciousness of life. Empty your mind; be formless, shapeless like water. May you be at peace. Take a deep breath. You can do what you set out to do; yes, you can. You can do what you set out to do; yes, you can. Watch each breath appear and disappear, just breathing. Give yourself a break. Live life one inhalation and one exhalation at a time. Give yourself a break. Just acknowledge what's there and let be. You can get through this. Open your heart to change, forgiveness and lovingkindness. Love is the first seed of the soul. It will be ok. Impermanence and change is a powerful teacher and teaching. Bring love into your heart, into your breath and into your being. Briefly notice any emotions, thoughts or sensations that may be driving fear and anxiety and let them be. This discomfort will pass. Bring love into your heart, into your breath and into your being. Take a deep breath. Reflect on the fragility and preciousness of life."
}, },
{ {
"id": "bd7167d8c443cbafaeb5bdef", "id": "bd7167d8c443cbafaeb5bdef",
"phone": "1-140-557-0727",
"company": "Bookspan", "company": "Bookspan",
"country": "Singapore",
"city": "Morar berg",
"state": "South Dakota",
"position": "Full Stack JavaScript Developer (Junior)", "position": "Full Stack JavaScript Developer (Junior)",
"logoUrl": "https://tm-prod.global.ssl.fastly.net/uploaded/companies/227/small_logo.png?v=db9dbe", "logo": "https://tm-prod.global.ssl.fastly.net/uploaded/companies/227/small_logo.png?v=db9dbe",
"postingUrl": "http://bookspan.theresumator.com/apply/10190b666b74087b537f4659756f7c5679000704722064232c1d2e3b2b102501310437/Fullstack-Javascript-Developer-junior?source=freecodecamp.com&sid=zvi9YD9OcHwoDZNgM3XI9uPszGvqxJo6eHf" "description": "Live life one inhalation and one exhalation at a time. May you be healthy. Let the muscles in your neck and shoulders relax. May you be safe. Reflect on the fragility and preciousness of life. Empty your mind; be formless, shapeless like water. May you be at peace. Take a deep breath. You can do what you set out to do; yes, you can. You can do what you set out to do; yes, you can. Watch each breath appear and disappear, just breathing. Give yourself a break. Live life one inhalation and one exhalation at a time. Give yourself a break. Just acknowledge what's there and let be. You can get through this. Open your heart to change, forgiveness and lovingkindness. Love is the first seed of the soul. It will be ok. Impermanence and change is a powerful teacher and teaching. Bring love into your heart, into your breath and into your being. Briefly notice any emotions, thoughts or sensations that may be driving fear and anxiety and let them be. This discomfort will pass. Bring love into your heart, into your breath and into your being. Take a deep breath. Reflect on the fragility and preciousness of life."
}, },
{ {
"id": "bd7167d8c444cbafaeb5bdef", "id": "bd7167d8c444cbafaeb5bdef",
"email": "Ada_Gerlach@gmail.com",
"company": "Good Eggs", "company": "Good Eggs",
"country": "Singapore",
"city": "Morar berg",
"state": "South Dakota",
"position": "Full Stack Developer", "position": "Full Stack Developer",
"logoUrl": "https://d1qb2nb5cznatu.cloudfront.net/startups/i/72165-64efbd521cdfe3357c811758f5436e7d-medium_jpg.jpg", "logo": "https://d1qb2nb5cznatu.cloudfront.net/startups/i/72165-64efbd521cdfe3357c811758f5436e7d-medium_jpg.jpg",
"postingUrl": "http://www.jobscore.com/jobs2/goodeggs/full-stack-developer/cQ_hd-0USr4Om7eJe4iefn?Board=freecodecamp.com" "description": "Live life one inhalation and one exhalation at a time. May you be healthy. Let the muscles in your neck and shoulders relax. May you be safe. Reflect on the fragility and preciousness of life. Empty your mind; be formless, shapeless like water. May you be at peace. Take a deep breath. You can do what you set out to do; yes, you can. You can do what you set out to do; yes, you can. Watch each breath appear and disappear, just breathing. Give yourself a break. Live life one inhalation and one exhalation at a time. Give yourself a break. Just acknowledge what's there and let be. You can get through this. Open your heart to change, forgiveness and lovingkindness. Love is the first seed of the soul. It will be ok. Impermanence and change is a powerful teacher and teaching. Bring love into your heart, into your breath and into your being. Briefly notice any emotions, thoughts or sensations that may be driving fear and anxiety and let them be. This discomfort will pass. Bring love into your heart, into your breath and into your being. Take a deep breath. Reflect on the fragility and preciousness of life."
} }
] ]

View File

@ -1,11 +1,12 @@
import React from 'react'; import React from 'react';
import Router from 'react-router'; import Router from 'react-router';
import Fetchr from 'fetchr';
import Location from 'react-router/lib/Location'; import Location from 'react-router/lib/Location';
import debugFactory from 'debug'; import debugFactory from 'debug';
import { app$ } from '../../common/app'; import { app$ } from '../../common/app';
import { RenderToString } from 'thundercats-react'; import { RenderToString } from 'thundercats-react';
const debug = debugFactory('freecc:servereact'); const debug = debugFactory('freecc:react-server');
// add routes here as they slowly get reactified // add routes here as they slowly get reactified
// remove their individual controllers // remove their individual controllers
@ -25,6 +26,7 @@ export default function reactSubRouter(app) {
app.use(router); app.use(router);
function serveReactApp(req, res, next) { function serveReactApp(req, res, next) {
const services = new Fetchr({ req });
const location = new Location(req.path, req.query); const location = new Location(req.path, req.query);
// returns a router wrapped app // returns a router wrapped app
@ -42,7 +44,7 @@ export default function reactSubRouter(app) {
// prefetches data and sets up it up for current state // prefetches data and sets up it up for current state
debug('rendering to string'); debug('rendering to string');
return RenderToString( return RenderToString(
AppCat(), AppCat(null, services),
React.createElement(Router, initialState) React.createElement(Router, initialState)
); );
}) })

View File

@ -1,8 +1,15 @@
import Fetchr from 'fetchr'; import Fetchr from 'fetchr';
import getHikesService from '../services/hikes'; import getHikesService from '../services/hikes';
import getJobServices from '../services/job';
import getUserServices from '../services/user';
export default function bootServices(app) { export default function bootServices(app) {
const hikesService = getHikesService(app); const hikesService = getHikesService(app);
const jobServices = getJobServices(app);
const userServices = getUserServices(app);
Fetchr.registerFetcher(hikesService); Fetchr.registerFetcher(hikesService);
Fetchr.registerFetcher(jobServices);
Fetchr.registerFetcher(userServices);
app.use('/services', Fetchr.middleware()); app.use('/services', Fetchr.middleware());
} }

View File

@ -121,6 +121,7 @@ module.exports = function(app) {
var challengeId = String(req.user.currentChallenge.challengeId); var challengeId = String(req.user.currentChallenge.challengeId);
var challengeBlock = req.user.currentChallenge.challengeBlock; var challengeBlock = req.user.currentChallenge.challengeBlock;
// TODO(berks) fix index call here
var indexOfChallenge = challengeMapWithIds[challengeBlock] var indexOfChallenge = challengeMapWithIds[challengeBlock]
.indexOf(challengeId); .indexOf(challengeId);

View File

@ -1,3 +1,4 @@
var Rx = require('rx');
var debug = require('debug')('freecc:nonprofits'); var debug = require('debug')('freecc:nonprofits');
var observeMethod = require('../utils/rx').observeMethod; var observeMethod = require('../utils/rx').observeMethod;
var unDasherize = require('../utils').unDasherize; var unDasherize = require('../utils').unDasherize;
@ -15,18 +16,19 @@ module.exports = function(app) {
app.use(router); app.use(router);
function nonprofitsDirectory(req, res, next) { function nonprofitsDirectory(req, res, next) {
var sum = 0; findNonprofits({
findNonprofits({}).subscribe( order: 'moneySaved DESC'
function(nonprofits) { })
nonprofits = nonprofits.sort(function(a, b) { .flatMap(
return b.moneySaved - a.moneySaved; (nonprofits = []) => {
}); // turn array of nonprofits into observable array
totalSavings = function() { return Rx.Observable.from(nonprofits)
for(i = 0; i < nonprofits.length; i++) { .pluck('moneySaved')
sum += nonprofits[i].moneySaved; .reduce((sum, moneySaved = 0) => sum + moneySaved, 0);
} },
return sum; (nonprofits = [], totalSavings) => ({ nonprofits, totalSavings })
}(); )
.subscribe(({ nonprofits, totalSavings }) => {
res.render('nonprofits/directory', { res.render('nonprofits/directory', {
title: 'Nonprofits we help', title: 'Nonprofits we help',
nonprofits: nonprofits, nonprofits: nonprofits,
@ -78,8 +80,6 @@ module.exports = function(app) {
} }
} }
res.render('nonprofits/show', { res.render('nonprofits/show', {
dashedName: dashedNameFull, dashedName: dashedNameFull,
title: nonprofit.name, title: nonprofit.name,

View File

@ -1,4 +1,5 @@
// use this file with runners like node-debug
// or mocha.
require('babel/register'); require('babel/register');
var app = require('./server'); var app = require('./server');
app.start(); app.start();

View File

@ -0,0 +1,31 @@
// this ensures node understands the future
require('babel/register');
var startTime = Date.now();
var timeoutHandler;
// this is where server starts booting up
var app = require('./server');
console.log('waiting for db to connect');
var onConnect = function() {
console.log('db connected in %s ms', Date.now() - startTime);
if (timeoutHandler) {
clearTimeout(timeoutHandler);
}
app.start();
};
var timeoutHandler = setTimeout(function() {
var message =
'db did not after ' +
(Date.now() - startTime) +
' ms connect crashing hard';
console.log(message);
// purposely shutdown server
// pm2 should restart this in production
throw new Error(message);
}, 5000);
app.dataSources.db.on('connected', onConnect);

View File

@ -2,8 +2,7 @@ require('dotenv').load();
var pmx = require('pmx'); var pmx = require('pmx');
pmx.init(); pmx.init();
var R = require('ramda'), var assign = require('lodash').assign,
assign = require('lodash').assign,
loopback = require('loopback'), loopback = require('loopback'),
boot = require('loopback-boot'), boot = require('loopback-boot'),
accepts = require('accepts'), accepts = require('accepts'),
@ -145,7 +144,7 @@ app.use(helmet.csp({
'*.d3js.org', '*.d3js.org',
'https://cdn.inspectlet.com/inspectlet.js', 'https://cdn.inspectlet.com/inspectlet.js',
'http://cdn.inspectlet.com/inspectlet.js', 'http://cdn.inspectlet.com/inspectlet.js',
'http://www.freecodecamp.org' 'http://beta.freecodecamp.com'
].concat(trusted), ].concat(trusted),
'connect-src': [ 'connect-src': [
'vimeo.com' 'vimeo.com'
@ -199,7 +198,6 @@ app.use(
}) })
); );
var startTime = Date.now();
boot(app, { boot(app, {
appRootDir: __dirname, appRootDir: __dirname,
dev: process.env.NODE_ENV dev: process.env.NODE_ENV
@ -249,7 +247,7 @@ var passportOptions = {
} }
}; };
R.keys(passportProviders).map(function(strategy) { Object.keys(passportProviders).map(function(strategy) {
var config = passportProviders[strategy]; var config = passportProviders[strategy];
config.session = config.session !== false; config.session = config.session !== false;
passportConfigurator.configureProvider( passportConfigurator.configureProvider(
@ -310,8 +308,6 @@ if (process.env.NODE_ENV === 'development') {
}); });
} }
module.exports = app;
app.start = function() { app.start = function() {
app.listen(app.get('port'), function() { app.listen(app.get('port'), function() {
app.emit('started'); app.emit('started');
@ -323,34 +319,12 @@ app.start = function() {
}); });
}; };
module.exports = app;
// start the server if `$ node server.js` // start the server if `$ node server.js`
// in production use `$npm start-production`
// or `$node server/production` to start the server
// and wait for DB handshake
if (require.main === module) { if (require.main === module) {
if (process.env.NODE_ENV === 'production') { app.start();
var timeoutHandler;
console.log('waiting for db to connect');
var onConnect = function() {
console.log('db connected in %s ms', Date.now() - startTime);
if (timeoutHandler) {
clearTimeout(timeoutHandler);
}
app.start();
};
var timeoutHandler = setTimeout(function() {
var message =
'db did not after ' +
(Date.now() - startTime) +
' ms connect crashing hard';
console.log(message);
// purposely shutdown server
// pm2 should restart this in production
throw new Error(message);
}, 5000);
app.dataSources.db.on('connected', onConnect);
} else {
app.start();
}
} }

12
server/services/job.js Normal file
View File

@ -0,0 +1,12 @@
export default function getJobServices(app) {
const { Job } = app.models;
return {
name: 'job',
read: (req, resource, params, config, cb) => {
Job.find({}, (err, jobs) => {
cb(err, jobs);
});
}
};
}

30
server/services/user.js Normal file
View File

@ -0,0 +1,30 @@
import debugFactory from 'debug';
import assign from 'object.assign';
const censor = '**********************:P********';
const debug = debugFactory('freecc:services:user');
const protectedUserFields = {
id: censor,
password: censor,
profiles: censor
};
export default function userServices(/* app */) {
return {
name: 'user',
read: (req, resource, params, config, cb) => {
let { user } = req;
if (user) {
debug('user is signed in');
// Zalgo!!!
return process.nextTick(() => {
cb(null, assign({}, user.toJSON(), protectedUserFields));
});
}
debug('user is not signed in');
return process.nextTick(() => {
cb(null, {});
});
}
};
}

View File

@ -1,88 +1,105 @@
extends ../layout-wide extends ../layout-wide
block content block content
script(src='/js/lib/codemirror/lib/codemirror.js') script(type='text/javascript', src='/js/lib/codemirror/lib/codemirror.js')
script(src='/js/lib/codemirror/addon/edit/closebrackets.js') script(type='text/javascript', src='/js/lib/codemirror/addon/edit/closebrackets.js')
script(src='/js/lib/codemirror/addon/edit/matchbrackets.js') script(type='text/javascript', src='/js/lib/codemirror/addon/edit/matchbrackets.js')
script(src='/js/lib/codemirror/addon/lint/lint.js') script(type='text/javascript', src='/js/lib/codemirror/addon/lint/lint.js')
script(src='/js/lib/codemirror/addon/lint/javascript-lint.js') script(type='text/javascript', src='/js/lib/codemirror/addon/lint/javascript-lint.js')
script(src='/bower_components/jshint/dist/jshint.js') script(type='text/javascript', src='/bower_components/jshint/dist/jshint.js')
script(src='/js/lib/chai/chai.js') script(type='text/javascript', src='/js/lib/chai/chai.js')
link(rel='stylesheet', href='/js/lib/codemirror/lib/codemirror.css') 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/addon/lint/lint.css')
link(rel='stylesheet', href='/js/lib/codemirror/theme/monokai.css') link(rel='stylesheet', href='/js/lib/codemirror/theme/monokai.css')
link(rel="stylesheet", href="//fonts.googleapis.com/css?family=Ubuntu+Mono") link(rel="stylesheet", href="//fonts.googleapis.com/css?family=Ubuntu+Mono")
script(src='/js/lib/codemirror/mode/javascript/javascript.js') script(type='text/javascript', src='/js/lib/codemirror/mode/javascript/javascript.js')
script(src='/js/lib/jailed/jailed.js') script(type='text/javascript', src='/js/lib/jailed/jailed.js')
script(src='/js/lib/coursewares/sandbox.js') script(type='text/javascript', src='/js/lib/coursewares/sandbox.js')
.row .row(ng-controller="pairedWithController")
.col-xs-12.col-sm-12.col-md-4.bonfire-top .col-xs-12.col-sm-12.col-md-4.col-lg-3
.scroll-locker .scroll-locker
#testCreatePanel #testCreatePanel.well
h1.text-center= name h3.text-center.negative-10= name
.well .row
.row .col-xs-12
.bonfire-instructions
for sentence in details
p.wrappable.negative-10!= sentence
.negative-bottom-margin-30
#MDN-links
p.negative-10 Here are some helpful links:
for link, index in MDNlinks
.negative-10
ul: li: a(href="" + link, target="_blank") !{MDNkeys[index]}
if (user)
form.form-horizontal(novalidate='novalidate', name='completedWithForm')
.form-group.text-center.negative-10
.col-xs-12 .col-xs-12
.bonfire-instructions // extra field to distract password tools like lastpass from injecting css into our username field
p.wrappable= brief label.negative-10.btn.btn-primary.btn-block#submitButton
#brief-instructions i.fa.fa-play
#more-info.btn.btn-primary.btn-block.btn-primary-ghost | &nbsp; Run code (ctrl + enter)
span.ion-arrow-down-b .button-spacer
| More information .btn-group.input-group.btn-group-justified
#long-instructions.row.hide label.btn.btn-success#trigger-reset-modal
.col-xs-12 i.fa.fa-refresh
for sentence in details | &nbsp; Reset
p.wrappable!= sentence label.btn.btn-success#trigger-help-modal
#less-info.btn.btn-primary.btn-block.btn-primary-ghost i.fa.fa-medkit
span.ion-arrow-up-b | &nbsp; Help
| Less information label.btn.btn-success#trigger-issue-modal
#submitButton.btn.btn-primary.btn-big.btn-block Run code (ctrl + enter) i.fa.fa-bug
.button-spacer | &nbsp; Bug
.btn-group.input-group.btn-group-justified .button-spacer
label.btn.btn-success#trigger-help-modal form.code
i.fa.fa-medkit .form-group.codeMirrorView
| &nbsp; Help textarea#codeOutput(style='display: none;')
label.btn.btn-success#trigger-pair-modal br
i.fa.fa-user-plus #testSuite.negative-10
| &nbsp; Pair br
label.btn.btn-success#trigger-issue-modal script(type="text/javascript").
i.fa.fa-bug var tests = !{JSON.stringify(tests)};
| &nbsp; Bug var challengeSeed = !{JSON.stringify(challengeSeed)};
.spacer var challenge_Id = !{JSON.stringify(challengeId)};
form.code var challenge_Name = !{JSON.stringify(name)};
.form-group.codeMirrorView var started = Math.floor(Date.now());
textarea#codeOutput(style='display: none;') var challengeType = !{JSON.stringify(challengeType)};
br var _ = R;
#testSuite var dashed = !{JSON.stringify(dashedName)};
br
script(type="text/javascript").
var tests = !{JSON.stringify(tests)};
var challengeSeed = !{JSON.stringify(challengeSeed)};
var challenge_Id = !{JSON.stringify(challengeId)};
var challenge_Name = !{JSON.stringify(name)};
var challengeType = !{JSON.stringify(challengeType)};
var started = Math.floor(Date.now());
.col-xs-12.col-sm-12.col-md-8 .col-xs-12.col-sm-12.col-md-8
#mainEditorPanel #mainEditorPanel
form.code form.code
.form-group.codeMirrorView .form-group.codeMirrorView
textarea#codeEditor(autofocus=true, style='display: none;') textarea#codeEditor(autofocus=true, style='display: none;')
script(src='/js/lib/coursewares/coursewaresJSFramework_0.0.5.js') script(src='/js/lib/coursewares/coursewaresJSFramework_0.0.6.js')
#complete-courseware-dialog.modal(tabindex='-1') #complete-courseware-dialog.modal(tabindex='-1')
.modal-dialog.animated.zoomIn.fast-animation .modal-dialog.animated.zoomIn.fast-animation
.modal-content .modal-content
.modal-header.challenge-list-header= compliment .modal-header.challenge-list-header= compliment
a.close.closing-x(href='#', data-dismiss='modal', aria-hidden='true') × a.close.closing-x(href='#', data-dismiss='modal', aria-hidden='true') ×
.modal-body(ng-controller="pairedWithController") .modal-body
.text-center .text-center
.animated.zoomInDown.delay-half .animated.zoomInDown.delay-half
span.completion-icon.ion-checkmark-circled.text-primary span.completion-icon.ion-checkmark-circled.text-primary
if (user) if (user)
a.animated.fadeIn.btn.btn-lg.btn-primary.btn-block#next-courseware-button(name='_csrf', value=_csrf, ng-disabled='completedWithForm.$invalid && existingUser.length > 0') Go to my next challenge (ctrl + enter) a.animated.fadeIn.btn.btn-lg.btn-primary.btn-block#next-courseware-button(name='_csrf', value=_csrf) Go to my next challenge (ctrl + enter)
if (points && points > 2) if (user.progressTimestamps.length > 2)
a.animated.fadeIn.btn.btn-lg.btn-block.btn-twitter(href="https://twitter.com/intent/tweet?text=I%20just%20#{verb}%20%40FreeCodeCamp%20#{name}&url=http%3A%2F%2Ffreecodecamp.com/challenges/#{dashedName}&hashtags=LearnToCode, JavaScript" target="_blank") a.animated.fadeIn.btn.btn-lg.btn-block.btn-twitter(target="_blank", href="https://twitter.com/intent/tweet?text=I%20just%20#{verb}%20%40FreeCodeCamp%20#{name}&url=http%3A%2F%2Ffreecodecamp.com/challenges/#{dashedName}&hashtags=LearnToCode, JavaScript")
i.fa.fa-twitter &thinsp; i.fa.fa-twitter &thinsp;
= phrase = phrase
else else
a.animated.fadeIn.btn.btn-lg.signup-btn.btn-block(href='/login') Sign in so you can save your progress a.animated.fadeIn.btn.btn-lg.signup-btn.btn-block(href='/login') Sign in so you can save your progress
#reset-modal.modal(tabindex='-1')
.modal-dialog.animated.fadeInUp.fast-animation
.modal-content
.modal-header.challenge-list-header Clear your code?
a.close.closing-x(href='#', data-dismiss='modal', aria-hidden='true') ×
.modal-body
h3 This will restore your code editor to its original state.
a.btn.btn-lg.btn-info.btn-block#reset-button(href='#', data-dismiss='modal', aria-hidden='true') Clear my code
a.btn.btn-lg.btn-primary.btn-block(href='#', data-dismiss='modal', aria-hidden='true') Cancel
include ../partials/challenge-modals include ../partials/challenge-modals
script.
var MDNlinks = !{JSON.stringify(MDNlinks)};
if (!MDNlinks.length) {
$('#MDN-links').addClass('collapse');
}

View File

@ -1,7 +1,6 @@
var path = require('path'); var path = require('path');
module.exports = { module.exports = {
devtool: 'inline-source-map',
entry: './client', entry: './client',
output: { output: {
filename: 'bundle.js', filename: 'bundle.js',