├── client
├── sagas
│ ├── README.md
│ ├── index.js
│ ├── title-saga.js
│ ├── err-saga.js
│ └── hard-go-to-saga.js
├── es6-shims.js
├── less
│ ├── lib
│ │ ├── ionicons
│ │ │ ├── ionicons.less
│ │ │ └── _ionicons-font.less
│ │ ├── font-awesome-4.3.0
│ │ │ ├── fonts
│ │ │ │ ├── FontAwesome.otf
│ │ │ │ ├── fontawesome-webfont.eot
│ │ │ │ ├── fontawesome-webfont.ttf
│ │ │ │ ├── fontawesome-webfont.woff
│ │ │ │ └── fontawesome-webfont.woff2
│ │ │ ├── less
│ │ │ │ ├── fixed-width.less
│ │ │ │ ├── bordered-pulled.less
│ │ │ │ ├── larger.less
│ │ │ │ ├── list.less
│ │ │ │ ├── font-awesome.less
│ │ │ │ ├── core.less
│ │ │ │ ├── stacked.less
│ │ │ │ ├── rotated-flipped.less
│ │ │ │ ├── path.less
│ │ │ │ ├── animated.less
│ │ │ │ └── mixins.less
│ │ │ └── scss
│ │ │ │ ├── _fixed-width.scss
│ │ │ │ ├── _bordered-pulled.scss
│ │ │ │ ├── _larger.scss
│ │ │ │ ├── _list.scss
│ │ │ │ ├── font-awesome.scss
│ │ │ │ ├── _core.scss
│ │ │ │ ├── _stacked.scss
│ │ │ │ ├── _rotated-flipped.scss
│ │ │ │ ├── _path.scss
│ │ │ │ ├── _animated.scss
│ │ │ │ └── _mixins.scss
│ │ └── bootstrap
│ │ │ ├── mixins
│ │ │ ├── center-block.less
│ │ │ ├── text-emphasis.less
│ │ │ ├── size.less
│ │ │ ├── background-variant.less
│ │ │ ├── opacity.less
│ │ │ ├── text-overflow.less
│ │ │ ├── tab-focus.less
│ │ │ ├── labels.less
│ │ │ ├── resize.less
│ │ │ ├── progress-bar.less
│ │ │ ├── nav-divider.less
│ │ │ ├── reset-filter.less
│ │ │ ├── alerts.less
│ │ │ ├── nav-vertical-align.less
│ │ │ ├── responsive-visibility.less
│ │ │ ├── pagination.less
│ │ │ ├── border-radius.less
│ │ │ ├── panels.less
│ │ │ ├── list-group.less
│ │ │ ├── hide-text.less
│ │ │ ├── clearfix.less
│ │ │ ├── table-row.less
│ │ │ ├── image.less
│ │ │ └── buttons.less
│ │ │ ├── wells.less
│ │ │ ├── breadcrumbs.less
│ │ │ ├── responsive-embed.less
│ │ │ ├── close.less
│ │ │ ├── media.less
│ │ │ ├── component-animations.less
│ │ │ ├── thumbnails.less
│ │ │ ├── utilities.less
│ │ │ ├── pager.less
│ │ │ ├── jumbotron.less
│ │ │ ├── mixins.less
│ │ │ ├── badges.less
│ │ │ ├── bootstrap.less
│ │ │ └── labels.less
│ ├── signin.less
│ ├── jobs.less
│ └── chat.less
├── README.md
└── commonFramework
│ ├── add-loop-protect.js
│ ├── get-iframe.js
│ ├── display-test-results.js
│ ├── run-tests-stream.js
│ └── output-display.js
├── common
├── app
│ ├── middlewares.js
│ ├── components
│ │ ├── Flash
│ │ │ ├── index.jsx
│ │ │ └── Queue.jsx
│ │ ├── Footer
│ │ │ ├── README.md
│ │ │ ├── index.js
│ │ │ ├── links.json
│ │ │ └── Footer.jsx
│ │ ├── Nav
│ │ │ ├── index.js
│ │ │ └── links.json
│ │ ├── README.md
│ │ └── NotFound
│ │ │ └── index.jsx
│ ├── index.js
│ ├── routes
│ │ ├── Admin
│ │ │ └── README.md
│ │ ├── Jobs
│ │ │ ├── README.md
│ │ │ ├── redux
│ │ │ │ ├── index.js
│ │ │ │ ├── types.js
│ │ │ │ ├── save-job-saga.js
│ │ │ │ ├── apply-promo-saga.js
│ │ │ │ ├── actions.js
│ │ │ │ ├── jobs-form-normalizer.js
│ │ │ │ └── fetch-jobs-saga.js
│ │ │ ├── utils.js
│ │ │ ├── index.js
│ │ │ └── components
│ │ │ │ ├── JobNotFound.jsx
│ │ │ │ └── NewJobCompleted.jsx
│ │ ├── Bonfires
│ │ │ └── README.md
│ │ ├── Hikes
│ │ │ ├── index.js
│ │ │ ├── redux
│ │ │ │ ├── index.js
│ │ │ │ ├── selectors.js
│ │ │ │ ├── types.js
│ │ │ │ └── fetch-hikes-saga.js
│ │ │ └── components
│ │ │ │ └── Map.jsx
│ │ └── index.js
│ ├── shared
│ │ └── README.md
│ ├── redux
│ │ ├── index.js
│ │ ├── types.js
│ │ ├── reducer.js
│ │ ├── actions.js
│ │ └── fetch-user-saga.js
│ ├── sagas.js
│ ├── provide-store.js
│ ├── utils
│ │ ├── create-types.js
│ │ ├── render.js
│ │ ├── shallow-equals.js
│ │ └── Professor-Context.js
│ └── create-reducer.js
├── utils
│ ├── constantStrings.json
│ ├── index.js
│ └── services-creator.js
├── config.global.js
└── models
│ ├── User-Credential.json
│ ├── User-Identity.json
│ └── pledge.json
├── .eslintignore
├── server
├── views
│ ├── sponsors
│ │ └── sponsors.html
│ ├── certificate
│ │ ├── index.jade
│ │ ├── back-end.jade
│ │ ├── front-end.jade
│ │ ├── full-stack.jade
│ │ ├── data-vis.jade
│ │ ├── script.jade
│ │ └── font.jade
│ ├── resources
│ │ ├── unsubscribed.jade
│ │ ├── nonprofits-form.jade
│ │ ├── pmi-acp-agile-project-managers-form.jade
│ │ ├── the-fastest-web-page-on-the-internet.jade
│ │ ├── labs.jade
│ │ ├── shop.jade
│ │ ├── dashboard.jade
│ │ └── stories.jade
│ ├── wiki
│ │ └── show.jade
│ ├── layout.jade
│ ├── layout-react.jade
│ ├── partials
│ │ ├── stylesheets.jade
│ │ ├── challenge-footer.jade
│ │ ├── flash.jade
│ │ ├── react-stylesheets.jade
│ │ ├── scripts.jade
│ │ └── challenge-modals.jade
│ ├── layout-wide.jade
│ ├── account
│ │ ├── forgot.jade
│ │ ├── reset.jade
│ │ ├── email-signup.jade
│ │ └── email-signin.jade
│ ├── feed.jade
│ ├── commit
│ │ ├── directory.jade
│ │ └── pledge.jade
│ ├── stories
│ │ └── index.jade
│ └── redirect-https.jade
├── config.production.js
├── boot
│ ├── authentication.js
│ ├── restApi.js
│ ├── t-wiki.js
│ ├── a-services.js
│ ├── home.js
│ ├── explorer.js
│ ├── redirects.js
│ ├── redirectHttps.js
│ └── about.js
├── debug-entry.js
├── utils
│ ├── certTypes.json
│ ├── commit-goals.json
│ ├── constantStrings.json
│ ├── date-utils.js
│ ├── middleware.js
│ ├── constants.js
│ ├── bad-id-map.js
│ ├── rx.js
│ ├── commit.js
│ └── auth.js
├── datasources.json
├── middlewares
│ ├── cookie-parser.js
│ ├── global-locals.js
│ ├── constant-headers.js
│ ├── express-rx.js
│ ├── jade-helpers.js
│ ├── validator.js
│ ├── sessions.js
│ ├── keymetrics.js
│ ├── add-return-to.js
│ ├── revision-helpers.js
│ └── error-handlers.js
├── README.md
├── config.development.js
├── manifests
│ └── README.md
├── ssl-config.js
├── datasources.local.js
├── config.local.js
├── config.json
├── services
│ ├── user.js
│ ├── hikes.js
│ └── job.js
├── production-start.js
└── model-config.json
├── .node-inspectorrc
├── .bowerrc
├── .travis.yml
├── public
├── favicon.ico
├── images
│ ├── 1.png
│ ├── 2.png
│ ├── 3.png
│ ├── 4.png
│ ├── Wendy.jpg
│ ├── bill.jpg
│ ├── date.png
│ ├── fcc.jpg
│ ├── fcc.png
│ ├── intro.png
│ ├── juhe.png
│ ├── media.png
│ ├── weibo.png
│ ├── 8v3t84p.jpg
│ ├── D7Y5luw.jpg
│ ├── Elb3dfj.jpg
│ ├── Et3iD74.jpg
│ ├── PDGQ9ZM.jpg
│ ├── QPpjPac.jpg
│ ├── Shirly.jpg
│ ├── Taylor.jpg
│ ├── UVB9hxp.jpg
│ ├── WvQvNGN.gif
│ ├── caonana.jpg
│ ├── commit.png
│ ├── enroll.png
│ ├── favicon.ico
│ ├── github.jpg
│ ├── github.png
│ ├── gitter.png
│ ├── jianshu.png
│ ├── k8btNUB.jpg
│ ├── n6GeSEm.gif
│ ├── nsvNixW.jpg
│ ├── pbW7K5S.jpg
│ ├── qianjie.jpg
│ ├── startup.jpg
│ ├── startup.png
│ ├── vDTMJSh.gif
│ ├── weixin.png
│ ├── wilddog.png
│ ├── wjlDigg.jpg
│ ├── wujing.jpg
│ ├── yXyxbDd.jpg
│ ├── zuanshi.png
│ ├── as-seen-on.png
│ ├── chenghui.jpg
│ ├── community.png
│ ├── fcc-code.png
│ ├── fcc-weibo.png
│ ├── fourcircle.png
│ ├── funny-cat.jpg
│ ├── grumpy-cat.jpg
│ ├── myCatPhoto.png
│ ├── eightskills.png
│ ├── fcczhongguo.jpg
│ ├── freecodecamp.png
│ ├── logo-navbar.png
│ ├── relaxing-cat.jpg
│ ├── running-cat.jpg
│ ├── simonSound1.mp3
│ ├── simonSound2.mp3
│ ├── simonSound3.mp3
│ ├── simonSound4.mp3
│ ├── threepeople.png
│ ├── iphone6-frame.png
│ ├── mischievous-cat.jpg
│ ├── zhangjianqiang.jpg
│ ├── cover-green-brown.png
│ ├── fcc-performance-1.png
│ ├── fcc-performance-2.png
│ ├── qrcode_for_nearest.jpg
│ ├── wide-social-banner.png
│ └── camper-image-placeholder.png
├── robots.txt
├── favicons
│ ├── green.ico
│ ├── favicon.ico
│ ├── favicon-16x16.png
│ ├── favicon-32x32.png
│ ├── favicon-96x96.png
│ ├── ms-icon-70x70.png
│ ├── ms-icon-144x144.png
│ ├── ms-icon-150x150.png
│ ├── ms-icon-310x310.png
│ ├── apple-touch-icon.png
│ ├── android-chrome-36x36.png
│ ├── android-chrome-48x48.png
│ ├── android-chrome-72x72.png
│ ├── android-chrome-96x96.png
│ ├── android-chrome-144x144.png
│ ├── android-chrome-192x192.png
│ ├── apple-touch-icon-57x57.png
│ ├── apple-touch-icon-60x60.png
│ ├── apple-touch-icon-72x72.png
│ ├── apple-touch-icon-76x76.png
│ ├── apple-touch-icon-114x114.png
│ ├── apple-touch-icon-120x120.png
│ ├── apple-touch-icon-144x144.png
│ ├── apple-touch-icon-152x152.png
│ ├── apple-touch-icon-180x180.png
│ ├── apple-touch-icon-precomposed.png
│ ├── browserconfig.xml
│ └── android-chrome-manifest.json
├── fonts
│ ├── ionicons.eot
│ ├── ionicons.ttf
│ ├── saxmono.ttf
│ ├── FontAwesome.otf
│ ├── Lato-Bold.ttf
│ ├── Lato-Light.ttf
│ ├── ionicons.woff
│ ├── Lato-Regular.ttf
│ ├── Ubuntu-Regular.ttf
│ ├── UbuntuMono-Regular.ttf
│ ├── fontawesome-webfont.eot
│ ├── fontawesome-webfont.ttf
│ ├── fontawesome-webfont.woff
│ ├── fontawesome-webfont.woff2
│ └── glyphicons-halflings-regular.eot
├── js
│ ├── lib
│ │ ├── jailed
│ │ │ └── _frame.html
│ │ └── loop-protect
│ │ │ └── LICENSE.md
│ └── dashboard.js
├── css
│ ├── ubuntu.css
│ └── lato.css
├── browserconfig.xml
├── json
│ └── cats.json
└── favicons.html
├── .gitattributes
├── .babelrc
├── seed
├── create-challenge-bundle.js
├── challenges
│ ├── 04-video-challenges
│ │ ├── agile.json
│ │ ├── tools.json
│ │ ├── devops.json
│ │ ├── statistics.json
│ │ ├── gamification.json
│ │ ├── visual-design.json
│ │ ├── accessibility.json
│ │ ├── computer-science.json
│ │ ├── game-development.json
│ │ ├── machine-learning.json
│ │ ├── data-visualization.json
│ │ ├── math-for-programmers.json
│ │ ├── user-experience-design.json
│ │ ├── mobile-javascript-development.json
│ │ ├── embedded-and-internet-of-things.json
│ │ └── software-engineering-principles.json
│ └── 02-data-visualization-certification
│ │ ├── d3.json
│ │ ├── react.json
│ │ └── sass.json
└── get-emails.js
├── .editorconfig
├── .github
├── ISSUE_TEMPLATE.md
└── PULL_REQUEST_TEMPLATE.md
├── sample.env
├── bower.json
├── .gitignore
├── pm2Start.js
├── webpack.config.js
├── leanTest.js
└── webpack.config.node.js
/client/sagas/README.md:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/common/app/middlewares.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | public/**/*.js
2 |
--------------------------------------------------------------------------------
/common/app/components/Flash/index.jsx:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/server/views/sponsors/sponsors.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.node-inspectorrc:
--------------------------------------------------------------------------------
1 | {
2 | "save-live-edit": true
3 | }
--------------------------------------------------------------------------------
/common/app/components/Footer/README.md:
--------------------------------------------------------------------------------
1 | Currently not used
2 |
--------------------------------------------------------------------------------
/common/app/index.js:
--------------------------------------------------------------------------------
1 | export default from './create-app.jsx';
2 |
--------------------------------------------------------------------------------
/.bowerrc:
--------------------------------------------------------------------------------
1 | {
2 | "directory" : "public/bower_components"
3 | }
4 |
--------------------------------------------------------------------------------
/common/app/components/Nav/index.js:
--------------------------------------------------------------------------------
1 | export default from './Nav.jsx';
2 |
--------------------------------------------------------------------------------
/common/app/components/README.md:
--------------------------------------------------------------------------------
1 | things like NavBar and Footer go here
2 |
--------------------------------------------------------------------------------
/common/app/routes/Admin/README.md:
--------------------------------------------------------------------------------
1 | in case we ever want an admin panel
2 |
--------------------------------------------------------------------------------
/common/app/components/Footer/index.js:
--------------------------------------------------------------------------------
1 | export default from './Footer.jsx';
2 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 |
3 | node_js:
4 | - '4.2.1'
5 |
6 | sudo: false
7 |
--------------------------------------------------------------------------------
/client/es6-shims.js:
--------------------------------------------------------------------------------
1 | require('object.assign').shim();
2 | require('es6-map/implement');
3 |
--------------------------------------------------------------------------------
/common/app/routes/Jobs/README.md:
--------------------------------------------------------------------------------
1 | This folder contains everything relative to Jobs board
2 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/favicon.ico
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | public/js/lib/codemirror/* linguist-vendored
2 | *.jsx linguist-language=JavaScript
3 |
--------------------------------------------------------------------------------
/common/app/routes/Bonfires/README.md:
--------------------------------------------------------------------------------
1 | This folder contains things relative to the bonfires' screens
2 |
--------------------------------------------------------------------------------
/common/app/shared/README.md:
--------------------------------------------------------------------------------
1 | Here is where all components that are shared between multiple views
2 |
--------------------------------------------------------------------------------
/public/images/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/1.png
--------------------------------------------------------------------------------
/public/images/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/2.png
--------------------------------------------------------------------------------
/public/images/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/3.png
--------------------------------------------------------------------------------
/public/images/4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/4.png
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | User-agent: *
2 | Allow: /
3 | Sitemap: http://www.freecodecamp.cn/sitemap.xml
4 |
--------------------------------------------------------------------------------
/server/config.production.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | host: process.env.HOST || 'localhost'
3 | };
4 |
--------------------------------------------------------------------------------
/public/images/Wendy.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/Wendy.jpg
--------------------------------------------------------------------------------
/public/images/bill.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/bill.jpg
--------------------------------------------------------------------------------
/public/images/date.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/date.png
--------------------------------------------------------------------------------
/public/images/fcc.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/fcc.jpg
--------------------------------------------------------------------------------
/public/images/fcc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/fcc.png
--------------------------------------------------------------------------------
/public/images/intro.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/intro.png
--------------------------------------------------------------------------------
/public/images/juhe.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/juhe.png
--------------------------------------------------------------------------------
/public/images/media.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/media.png
--------------------------------------------------------------------------------
/public/images/weibo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/weibo.png
--------------------------------------------------------------------------------
/public/favicons/green.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/favicons/green.ico
--------------------------------------------------------------------------------
/public/fonts/ionicons.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/fonts/ionicons.eot
--------------------------------------------------------------------------------
/public/fonts/ionicons.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/fonts/ionicons.ttf
--------------------------------------------------------------------------------
/public/fonts/saxmono.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/fonts/saxmono.ttf
--------------------------------------------------------------------------------
/public/images/8v3t84p.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/8v3t84p.jpg
--------------------------------------------------------------------------------
/public/images/D7Y5luw.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/D7Y5luw.jpg
--------------------------------------------------------------------------------
/public/images/Elb3dfj.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/Elb3dfj.jpg
--------------------------------------------------------------------------------
/public/images/Et3iD74.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/Et3iD74.jpg
--------------------------------------------------------------------------------
/public/images/PDGQ9ZM.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/PDGQ9ZM.jpg
--------------------------------------------------------------------------------
/public/images/QPpjPac.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/QPpjPac.jpg
--------------------------------------------------------------------------------
/public/images/Shirly.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/Shirly.jpg
--------------------------------------------------------------------------------
/public/images/Taylor.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/Taylor.jpg
--------------------------------------------------------------------------------
/public/images/UVB9hxp.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/UVB9hxp.jpg
--------------------------------------------------------------------------------
/public/images/WvQvNGN.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/WvQvNGN.gif
--------------------------------------------------------------------------------
/public/images/caonana.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/caonana.jpg
--------------------------------------------------------------------------------
/public/images/commit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/commit.png
--------------------------------------------------------------------------------
/public/images/enroll.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/enroll.png
--------------------------------------------------------------------------------
/public/images/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/favicon.ico
--------------------------------------------------------------------------------
/public/images/github.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/github.jpg
--------------------------------------------------------------------------------
/public/images/github.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/github.png
--------------------------------------------------------------------------------
/public/images/gitter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/gitter.png
--------------------------------------------------------------------------------
/public/images/jianshu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/jianshu.png
--------------------------------------------------------------------------------
/public/images/k8btNUB.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/k8btNUB.jpg
--------------------------------------------------------------------------------
/public/images/n6GeSEm.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/n6GeSEm.gif
--------------------------------------------------------------------------------
/public/images/nsvNixW.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/nsvNixW.jpg
--------------------------------------------------------------------------------
/public/images/pbW7K5S.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/pbW7K5S.jpg
--------------------------------------------------------------------------------
/public/images/qianjie.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/qianjie.jpg
--------------------------------------------------------------------------------
/public/images/startup.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/startup.jpg
--------------------------------------------------------------------------------
/public/images/startup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/startup.png
--------------------------------------------------------------------------------
/public/images/vDTMJSh.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/vDTMJSh.gif
--------------------------------------------------------------------------------
/public/images/weixin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/weixin.png
--------------------------------------------------------------------------------
/public/images/wilddog.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/wilddog.png
--------------------------------------------------------------------------------
/public/images/wjlDigg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/wjlDigg.jpg
--------------------------------------------------------------------------------
/public/images/wujing.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/wujing.jpg
--------------------------------------------------------------------------------
/public/images/yXyxbDd.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/yXyxbDd.jpg
--------------------------------------------------------------------------------
/public/images/zuanshi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/zuanshi.png
--------------------------------------------------------------------------------
/public/js/lib/jailed/_frame.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/public/favicons/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/favicons/favicon.ico
--------------------------------------------------------------------------------
/public/fonts/FontAwesome.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/fonts/FontAwesome.otf
--------------------------------------------------------------------------------
/public/fonts/Lato-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/fonts/Lato-Bold.ttf
--------------------------------------------------------------------------------
/public/fonts/Lato-Light.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/fonts/Lato-Light.ttf
--------------------------------------------------------------------------------
/public/fonts/ionicons.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/fonts/ionicons.woff
--------------------------------------------------------------------------------
/public/images/as-seen-on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/as-seen-on.png
--------------------------------------------------------------------------------
/public/images/chenghui.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/chenghui.jpg
--------------------------------------------------------------------------------
/public/images/community.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/community.png
--------------------------------------------------------------------------------
/public/images/fcc-code.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/fcc-code.png
--------------------------------------------------------------------------------
/public/images/fcc-weibo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/fcc-weibo.png
--------------------------------------------------------------------------------
/public/images/fourcircle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/fourcircle.png
--------------------------------------------------------------------------------
/public/images/funny-cat.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/funny-cat.jpg
--------------------------------------------------------------------------------
/public/images/grumpy-cat.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/grumpy-cat.jpg
--------------------------------------------------------------------------------
/public/images/myCatPhoto.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/myCatPhoto.png
--------------------------------------------------------------------------------
/public/fonts/Lato-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/fonts/Lato-Regular.ttf
--------------------------------------------------------------------------------
/public/images/eightskills.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/eightskills.png
--------------------------------------------------------------------------------
/public/images/fcczhongguo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/fcczhongguo.jpg
--------------------------------------------------------------------------------
/public/images/freecodecamp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/freecodecamp.png
--------------------------------------------------------------------------------
/public/images/logo-navbar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/logo-navbar.png
--------------------------------------------------------------------------------
/public/images/relaxing-cat.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/relaxing-cat.jpg
--------------------------------------------------------------------------------
/public/images/running-cat.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/running-cat.jpg
--------------------------------------------------------------------------------
/public/images/simonSound1.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/simonSound1.mp3
--------------------------------------------------------------------------------
/public/images/simonSound2.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/simonSound2.mp3
--------------------------------------------------------------------------------
/public/images/simonSound3.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/simonSound3.mp3
--------------------------------------------------------------------------------
/public/images/simonSound4.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/simonSound4.mp3
--------------------------------------------------------------------------------
/public/images/threepeople.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/threepeople.png
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["es2015", "react", "stage-0"],
3 | "plugins": ["babel-plugin-add-module-exports"]
4 | }
5 |
--------------------------------------------------------------------------------
/public/favicons/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/favicons/favicon-16x16.png
--------------------------------------------------------------------------------
/public/favicons/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/favicons/favicon-32x32.png
--------------------------------------------------------------------------------
/public/favicons/favicon-96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/favicons/favicon-96x96.png
--------------------------------------------------------------------------------
/public/favicons/ms-icon-70x70.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/favicons/ms-icon-70x70.png
--------------------------------------------------------------------------------
/public/fonts/Ubuntu-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/fonts/Ubuntu-Regular.ttf
--------------------------------------------------------------------------------
/public/images/iphone6-frame.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/iphone6-frame.png
--------------------------------------------------------------------------------
/public/images/mischievous-cat.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/mischievous-cat.jpg
--------------------------------------------------------------------------------
/public/images/zhangjianqiang.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/zhangjianqiang.jpg
--------------------------------------------------------------------------------
/public/favicons/ms-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/favicons/ms-icon-144x144.png
--------------------------------------------------------------------------------
/public/favicons/ms-icon-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/favicons/ms-icon-150x150.png
--------------------------------------------------------------------------------
/public/favicons/ms-icon-310x310.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/favicons/ms-icon-310x310.png
--------------------------------------------------------------------------------
/public/fonts/UbuntuMono-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/fonts/UbuntuMono-Regular.ttf
--------------------------------------------------------------------------------
/public/images/cover-green-brown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/cover-green-brown.png
--------------------------------------------------------------------------------
/public/images/fcc-performance-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/fcc-performance-1.png
--------------------------------------------------------------------------------
/public/images/fcc-performance-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/fcc-performance-2.png
--------------------------------------------------------------------------------
/common/utils/constantStrings.json:
--------------------------------------------------------------------------------
1 | {
2 | "defaultProfileImage": "https://freecodecamp.cn/images/camper-image-placeholder.png"
3 | }
4 |
--------------------------------------------------------------------------------
/public/favicons/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/favicons/apple-touch-icon.png
--------------------------------------------------------------------------------
/public/fonts/fontawesome-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/fonts/fontawesome-webfont.eot
--------------------------------------------------------------------------------
/public/fonts/fontawesome-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/fonts/fontawesome-webfont.ttf
--------------------------------------------------------------------------------
/public/fonts/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/fonts/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/public/fonts/fontawesome-webfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/fonts/fontawesome-webfont.woff2
--------------------------------------------------------------------------------
/public/images/qrcode_for_nearest.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/qrcode_for_nearest.jpg
--------------------------------------------------------------------------------
/public/images/wide-social-banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/wide-social-banner.png
--------------------------------------------------------------------------------
/public/favicons/android-chrome-36x36.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/favicons/android-chrome-36x36.png
--------------------------------------------------------------------------------
/public/favicons/android-chrome-48x48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/favicons/android-chrome-48x48.png
--------------------------------------------------------------------------------
/public/favicons/android-chrome-72x72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/favicons/android-chrome-72x72.png
--------------------------------------------------------------------------------
/public/favicons/android-chrome-96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/favicons/android-chrome-96x96.png
--------------------------------------------------------------------------------
/public/favicons/android-chrome-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/favicons/android-chrome-144x144.png
--------------------------------------------------------------------------------
/public/favicons/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/favicons/android-chrome-192x192.png
--------------------------------------------------------------------------------
/public/favicons/apple-touch-icon-57x57.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/favicons/apple-touch-icon-57x57.png
--------------------------------------------------------------------------------
/public/favicons/apple-touch-icon-60x60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/favicons/apple-touch-icon-60x60.png
--------------------------------------------------------------------------------
/public/favicons/apple-touch-icon-72x72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/favicons/apple-touch-icon-72x72.png
--------------------------------------------------------------------------------
/public/favicons/apple-touch-icon-76x76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/favicons/apple-touch-icon-76x76.png
--------------------------------------------------------------------------------
/public/images/camper-image-placeholder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/images/camper-image-placeholder.png
--------------------------------------------------------------------------------
/public/favicons/apple-touch-icon-114x114.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/favicons/apple-touch-icon-114x114.png
--------------------------------------------------------------------------------
/public/favicons/apple-touch-icon-120x120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/favicons/apple-touch-icon-120x120.png
--------------------------------------------------------------------------------
/public/favicons/apple-touch-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/favicons/apple-touch-icon-144x144.png
--------------------------------------------------------------------------------
/public/favicons/apple-touch-icon-152x152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/favicons/apple-touch-icon-152x152.png
--------------------------------------------------------------------------------
/public/favicons/apple-touch-icon-180x180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/favicons/apple-touch-icon-180x180.png
--------------------------------------------------------------------------------
/public/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/server/boot/authentication.js:
--------------------------------------------------------------------------------
1 | module.exports = function enableAuthentication(app) {
2 | // enable authentication
3 | app.enableAuth();
4 | };
5 |
--------------------------------------------------------------------------------
/public/favicons/apple-touch-icon-precomposed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/public/favicons/apple-touch-icon-precomposed.png
--------------------------------------------------------------------------------
/client/less/lib/ionicons/ionicons.less:
--------------------------------------------------------------------------------
1 | @import "_ionicons-variables";
2 | @import "_ionicons-font";
3 | @import "_ionicons-animation";
4 | @import "_ionicons-icons";
--------------------------------------------------------------------------------
/server/debug-entry.js:
--------------------------------------------------------------------------------
1 | // use this file with runners like node-debug
2 | // or mocha.
3 | require('babel-register');
4 | var app = require('./server');
5 | app.start();
6 |
--------------------------------------------------------------------------------
/client/less/lib/font-awesome-4.3.0/fonts/FontAwesome.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/client/less/lib/font-awesome-4.3.0/fonts/FontAwesome.otf
--------------------------------------------------------------------------------
/server/boot/restApi.js:
--------------------------------------------------------------------------------
1 | module.exports = function mountRestApi(app) {
2 | var restApiRoot = app.get('restApiRoot');
3 | app.use(restApiRoot, app.loopback.rest());
4 | };
5 |
--------------------------------------------------------------------------------
/server/utils/certTypes.json:
--------------------------------------------------------------------------------
1 | {
2 | "frontEnd": "isFrontEndCert",
3 | "backEnd": "isBackEndCert",
4 | "dataVis": "isDataVisCert",
5 | "fullStack": "isFullStackCert"
6 | }
7 |
--------------------------------------------------------------------------------
/client/less/lib/font-awesome-4.3.0/fonts/fontawesome-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/client/less/lib/font-awesome-4.3.0/fonts/fontawesome-webfont.eot
--------------------------------------------------------------------------------
/client/less/lib/font-awesome-4.3.0/fonts/fontawesome-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/client/less/lib/font-awesome-4.3.0/fonts/fontawesome-webfont.ttf
--------------------------------------------------------------------------------
/client/less/lib/font-awesome-4.3.0/fonts/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/client/less/lib/font-awesome-4.3.0/fonts/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/client/less/lib/bootstrap/mixins/center-block.less:
--------------------------------------------------------------------------------
1 | // Center-align a block level element
2 |
3 | .center-block() {
4 | display: block;
5 | margin-left: auto;
6 | margin-right: auto;
7 | }
8 |
--------------------------------------------------------------------------------
/client/less/lib/font-awesome-4.3.0/fonts/fontawesome-webfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/calamus0427/freecodecamp.cn/dev/client/less/lib/font-awesome-4.3.0/fonts/fontawesome-webfont.woff2
--------------------------------------------------------------------------------
/server/datasources.json:
--------------------------------------------------------------------------------
1 | {
2 | "db": {
3 | "name": "db",
4 | "connector": "mongodb"
5 | },
6 | "mail": {
7 | "name": "mail",
8 | "connector": "mail"
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/client/less/lib/bootstrap/mixins/text-emphasis.less:
--------------------------------------------------------------------------------
1 | // Typography
2 |
3 | .text-emphasis-variant(@color) {
4 | color: @color;
5 | a&:hover {
6 | color: darken(@color, 10%);
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/client/less/lib/font-awesome-4.3.0/less/fixed-width.less:
--------------------------------------------------------------------------------
1 | // Fixed Width Icons
2 | // -------------------------
3 | .@{fa-css-prefix}-fw {
4 | width: (18em / 14);
5 | text-align: center;
6 | }
7 |
--------------------------------------------------------------------------------
/client/less/lib/font-awesome-4.3.0/scss/_fixed-width.scss:
--------------------------------------------------------------------------------
1 | // Fixed Width Icons
2 | // -------------------------
3 | .#{$fa-css-prefix}-fw {
4 | width: (18em / 14);
5 | text-align: center;
6 | }
7 |
--------------------------------------------------------------------------------
/client/README.md:
--------------------------------------------------------------------------------
1 | This is the entry point for the client code.
2 | Code that should run only on the client should be put here.
3 |
4 | NOTE(berks): For react specific stuff this should be the entry point
5 |
--------------------------------------------------------------------------------
/server/middlewares/cookie-parser.js:
--------------------------------------------------------------------------------
1 | import cookieParser from 'cookie-parser';
2 | import secrets from '../../config/secrets';
3 |
4 | export default cookieParser.bind(cookieParser, secrets.cookieSecret);
5 |
--------------------------------------------------------------------------------
/server/views/certificate/index.jade:
--------------------------------------------------------------------------------
1 | extends ../layout
2 | block content
3 | .panel.panel-info
4 | .panel-heading.text-center
5 | h1 Certificate
6 | .panel-body
7 | p foo
8 |
--------------------------------------------------------------------------------
/client/less/lib/bootstrap/mixins/size.less:
--------------------------------------------------------------------------------
1 | // Sizing shortcuts
2 |
3 | .size(@width; @height) {
4 | width: @width;
5 | height: @height;
6 | }
7 |
8 | .square(@size) {
9 | .size(@size; @size);
10 | }
11 |
--------------------------------------------------------------------------------
/client/less/lib/bootstrap/mixins/background-variant.less:
--------------------------------------------------------------------------------
1 | // Contextual backgrounds
2 |
3 | .bg-variant(@color) {
4 | background-color: @color;
5 | a&:hover {
6 | background-color: darken(@color, 10%);
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/client/less/lib/bootstrap/mixins/opacity.less:
--------------------------------------------------------------------------------
1 | // Opacity
2 |
3 | .opacity(@opacity) {
4 | opacity: @opacity;
5 | // IE8 filter
6 | @opacity-ie: (@opacity * 100);
7 | filter: ~"alpha(opacity=@{opacity-ie})";
8 | }
9 |
--------------------------------------------------------------------------------
/server/README.md:
--------------------------------------------------------------------------------
1 | Everything to do with the server.
2 |
3 | One file that is not tracked here is `rev-manifest.json`.
4 | It is generated at runtime and its contents changes as the contents
5 | of client side files change.
6 |
--------------------------------------------------------------------------------
/server/middlewares/global-locals.js:
--------------------------------------------------------------------------------
1 | export default function globalLocals() {
2 | return function(req, res, next) {
3 | // Make user object available in templates.
4 | res.locals.user = req.user;
5 | next();
6 | };
7 | }
8 |
--------------------------------------------------------------------------------
/client/less/lib/bootstrap/mixins/text-overflow.less:
--------------------------------------------------------------------------------
1 | // Text overflow
2 | // Requires inline-block or block for proper styling
3 |
4 | .text-overflow() {
5 | overflow: hidden;
6 | text-overflow: ellipsis;
7 | white-space: nowrap;
8 | }
9 |
--------------------------------------------------------------------------------
/seed/create-challenge-bundle.js:
--------------------------------------------------------------------------------
1 | var fs = require('fs');
2 | var getChallenges = require('./getChallenges');
3 |
4 | var challengeSpecs = getChallenges();
5 |
6 | fs.writeFileSync('seed/challenge-bundle.json', JSON.stringify(challengeSpecs));
7 |
--------------------------------------------------------------------------------
/client/less/lib/bootstrap/mixins/tab-focus.less:
--------------------------------------------------------------------------------
1 | // WebKit-style focus
2 |
3 | .tab-focus() {
4 | // Default
5 | outline: thin dotted;
6 | // WebKit
7 | outline: 5px auto -webkit-focus-ring-color;
8 | outline-offset: -2px;
9 | }
10 |
--------------------------------------------------------------------------------
/server/views/resources/unsubscribed.jade:
--------------------------------------------------------------------------------
1 | extends ../layout
2 | block content
3 | .panel.panel-info
4 | .panel-body.text-center
5 | h1 You have successfully been unsubscribed.
6 | h2 Whatever you do, keep coding! :)
7 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = space
5 | indent_size = 2
6 | end_of_line = lf
7 | charset = utf-8
8 | trim_trailing_whitespace = true
9 | insert_final_newline = true
10 |
11 | [*.md]
12 | trim_trailing_whitespace = false
13 |
--------------------------------------------------------------------------------
/client/less/signin.less:
--------------------------------------------------------------------------------
1 | .github-login {
2 | position: relative;
3 | width: 300px;
4 | margin-left: auto;
5 | margin-right: auto;
6 | .first {
7 | position: relative;
8 | height:0;
9 | top:-30px;
10 | right:-180px;
11 | color:red
12 | }
13 | }
--------------------------------------------------------------------------------
/client/less/lib/bootstrap/mixins/labels.less:
--------------------------------------------------------------------------------
1 | // Labels
2 |
3 | .label-variant(@color) {
4 | background-color: @color;
5 |
6 | &[href] {
7 | &:hover,
8 | &:focus {
9 | background-color: darken(@color, 10%);
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/client/less/lib/bootstrap/mixins/resize.less:
--------------------------------------------------------------------------------
1 | // Resize anything
2 |
3 | .resizable(@direction) {
4 | resize: @direction; // Options: horizontal, vertical, both
5 | overflow: auto; // Per CSS3 UI, `resize` only applies when `overflow` isn't `visible`
6 | }
7 |
--------------------------------------------------------------------------------
/public/css/ubuntu.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: "Ubuntu";
3 | src: url(/fonts/Ubuntu-Regular.ttf) format("truetype");
4 | }
5 |
6 | @font-face {
7 | font-family: "Ubuntu Mono";
8 | src: url(/fonts/UbuntuMono-Regular.ttf) format("truetype");
9 | }
10 |
--------------------------------------------------------------------------------
/common/app/redux/index.js:
--------------------------------------------------------------------------------
1 | export { default as reducer } from './reducer';
2 | export { default as actions } from './actions';
3 | export { default as types } from './types';
4 |
5 | import fetchUserSaga from './fetch-user-saga';
6 | export const sagas = [ fetchUserSaga ];
7 |
--------------------------------------------------------------------------------
/server/views/certificate/back-end.jade:
--------------------------------------------------------------------------------
1 | include font
2 | #name.cert-name= name
3 | img#cert.img-abs(src='//i.imgur.com/yBKoMVP.jpg')
4 | .cert-date= date
5 | .cert-link verify this certification at: http://freecodecamp.cn/#{username}/back-end-certification
6 | include script
7 |
--------------------------------------------------------------------------------
/server/utils/commit-goals.json:
--------------------------------------------------------------------------------
1 | {
2 | "frontEndCert": "Front End Development Certification",
3 | "backEndCert": "Back End Development Certification",
4 | "dataVisCert": "Data Visualisation Certification",
5 | "fullStackCert": "Full Stack Development Certification"
6 | }
7 |
--------------------------------------------------------------------------------
/server/views/certificate/front-end.jade:
--------------------------------------------------------------------------------
1 | include font
2 | #name.cert-name= name
3 | img#cert.img-abs(src='//i.imgur.com/ToFZKBd.jpg')
4 | .cert-date= date
5 | .cert-link verify this certification at: http://freecodecamp.cn/#{username}/front-end-certification
6 | include script
7 |
--------------------------------------------------------------------------------
/server/views/certificate/full-stack.jade:
--------------------------------------------------------------------------------
1 | include font
2 | #name.cert-name= name
3 | img#cert.img-abs(src='//i.imgur.com/Z4PgjBQ.jpg')
4 | .cert-date= date
5 | .cert-link verify this certification at: http://freecodecamp.cn/#{username}/full-stack-certification
6 | include script
7 |
--------------------------------------------------------------------------------
/client/sagas/index.js:
--------------------------------------------------------------------------------
1 | import errSaga from './err-saga';
2 | import titleSaga from './title-saga';
3 | import localStorageSaga from './local-storage-saga';
4 | import hardGoToSaga from './hard-go-to-saga';
5 |
6 | export default [ errSaga, titleSaga, localStorageSaga, hardGoToSaga ];
7 |
--------------------------------------------------------------------------------
/server/views/certificate/data-vis.jade:
--------------------------------------------------------------------------------
1 | include font
2 | #name.cert-name= name
3 | img#cert.img-abs(src='//i.imgur.com/l7tIptn.jpg')
4 | .cert-date= date
5 | .cert-link verify this certification at: http://freecodecamp.cn/#{username}/data-visualization-certification
6 | include script
7 |
--------------------------------------------------------------------------------
/client/less/lib/bootstrap/mixins/progress-bar.less:
--------------------------------------------------------------------------------
1 | // Progress bars
2 |
3 | .progress-bar-variant(@color) {
4 | background-color: @color;
5 |
6 | // Deprecated parent class requirement as of v3.2.0
7 | .progress-striped & {
8 | #gradient > .striped();
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/common/app/sagas.js:
--------------------------------------------------------------------------------
1 | import { sagas as appSagas } from './redux';
2 | import { sagas as hikesSagas} from './routes/Hikes/redux';
3 | import { sagas as jobsSagas } from './routes/Jobs/redux';
4 |
5 | export default [
6 | ...appSagas,
7 | ...hikesSagas,
8 | ...jobsSagas
9 | ];
10 |
--------------------------------------------------------------------------------
/common/app/routes/Hikes/index.js:
--------------------------------------------------------------------------------
1 | import Hikes from './components/Hikes.jsx';
2 | import Hike from './components/Hike.jsx';
3 |
4 | export default {
5 | path: 'videos',
6 | component: Hikes,
7 | childRoutes: [{
8 | path: ':dashedName',
9 | component: Hike
10 | }]
11 | };
12 |
--------------------------------------------------------------------------------
/common/app/routes/Hikes/redux/index.js:
--------------------------------------------------------------------------------
1 | export actions from './actions';
2 | export reducer from './reducer';
3 | export types from './types';
4 |
5 | import answerSaga from './answer-saga';
6 | import fetchHikesSaga from './fetch-hikes-saga';
7 |
8 | export const sagas = [ answerSaga, fetchHikesSaga ];
9 |
--------------------------------------------------------------------------------
/server/views/resources/nonprofits-form.jade:
--------------------------------------------------------------------------------
1 | extends ../layout
2 | block content
3 | iframe(src="https://docs.google.com/forms/d/1MtQDh8E1Nvkg5jdOucS4LSyk6oMQrN8XTwmQGtgJPAQ/viewform?embedded=true", frameborder="0", marginheight="0", marginwidth="0", width='102%', height=2550, scrolling="no") Loading...
4 |
--------------------------------------------------------------------------------
/public/favicons/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 | #ffffff
--------------------------------------------------------------------------------
/server/views/wiki/show.jade:
--------------------------------------------------------------------------------
1 | extends ../layout-wide
2 | block content
3 | iframe#wikiFrame(frameborder='no')
4 | script.
5 | var lang = window.location.toString().match(/\/\w{2}\//);
6 | lang = (lang) ? lang[0] : '/en/';
7 | $('#wikiFrame').attr('src','//freecodecamp.github.io/wiki' + lang);
8 |
--------------------------------------------------------------------------------
/public/js/dashboard.js:
--------------------------------------------------------------------------------
1 | var app = angular.module('app',[]);
2 | app.controller('dashboard',['$scope','$http', function($scope,$http){
3 | $http.post('/dashboard').then(function(res){
4 | var out = res.data;
5 | $scope.items = out;
6 | },function(err){
7 | console.log(err);
8 | })
9 | }])
10 |
--------------------------------------------------------------------------------
/common/app/provide-store.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable react/display-name */
2 | import React from 'react';
3 | import { Provider } from 'react-redux';
4 |
5 | export default function provideStore(element, store) {
6 | return React.createElement(
7 | Provider,
8 | { store },
9 | element
10 | );
11 | }
12 |
--------------------------------------------------------------------------------
/common/app/redux/types.js:
--------------------------------------------------------------------------------
1 | import createTypes from '../utils/create-types';
2 |
3 | export default createTypes([
4 | 'updateTitle',
5 |
6 | 'fetchUser',
7 | 'setUser',
8 |
9 | 'makeToast',
10 | 'updatePoints',
11 | 'handleError',
12 | // used to hit the server
13 | 'hardGoTo'
14 | ], 'app');
15 |
--------------------------------------------------------------------------------
/client/less/jobs.less:
--------------------------------------------------------------------------------
1 | .jobs-list-highlight {
2 | background-color: #ffc
3 | }
4 |
5 | a.jobs-list-highlight:hover {
6 | background-color: #ffc
7 | }
8 |
9 | .jobs-list {
10 | cursor: pointer;
11 | cursor: hand;
12 | }
13 |
14 | .jobs-checkbox-spacer input[type="checkbox"] {
15 | margin-left: -23px
16 | }
17 |
--------------------------------------------------------------------------------
/client/less/lib/bootstrap/mixins/nav-divider.less:
--------------------------------------------------------------------------------
1 | // Horizontal dividers
2 | //
3 | // Dividers (basically an hr) within dropdowns and nav lists
4 |
5 | .nav-divider(@color: #e5e5e5) {
6 | height: 1px;
7 | margin: ((@line-height-computed / 2) - 1) 0;
8 | overflow: hidden;
9 | background-color: @color;
10 | }
11 |
--------------------------------------------------------------------------------
/client/less/lib/bootstrap/mixins/reset-filter.less:
--------------------------------------------------------------------------------
1 | // Reset filters for IE
2 | //
3 | // When you need to remove a gradient background, do not forget to use this to reset
4 | // the IE filter for IE9 and below.
5 |
6 | .reset-filter() {
7 | filter: e(%("progid:DXImageTransform.Microsoft.gradient(enabled = false)"));
8 | }
9 |
--------------------------------------------------------------------------------
/server/views/resources/pmi-acp-agile-project-managers-form.jade:
--------------------------------------------------------------------------------
1 | extends ../layout
2 | block content
3 | iframe(src="https://docs.google.com/forms/d/1Y9wvQAx5s_puGcC-NRZpKLMgT0iZwajGMbkKlh-piGg/viewform?embedded=true", frameborder="0", marginheight="0", marginwidth="0", width='102%', height=2000, scrolling="no") Loading...
4 |
--------------------------------------------------------------------------------
/server/boot/t-wiki.js:
--------------------------------------------------------------------------------
1 | module.exports = function(app) {
2 | var router = app.loopback.Router();
3 | router.get('/wiki/*', showWiki);
4 | router.get('/wiki', showWiki);
5 |
6 | app.use(router);
7 |
8 | function showWiki(req, res) {
9 | res.render('wiki/show', { title: 'Wiki | Free Code Camp' });
10 | }
11 | };
12 |
--------------------------------------------------------------------------------
/common/app/routes/index.js:
--------------------------------------------------------------------------------
1 | import Jobs from './Jobs';
2 | import Hikes from './Hikes';
3 | import NotFound from '../components/NotFound/index.jsx';
4 |
5 | export default {
6 | path: '/',
7 | childRoutes: [
8 | Jobs,
9 | Hikes,
10 | {
11 | path: '*',
12 | component: NotFound
13 | }
14 | ]
15 | };
16 |
--------------------------------------------------------------------------------
/server/middlewares/constant-headers.js:
--------------------------------------------------------------------------------
1 | export default function constantHeaders() {
2 | return function(req, res, next) {
3 | res.header('Access-Control-Allow-Origin', '*');
4 | res.header('Access-Control-Allow-Headers',
5 | 'Origin, X-Requested-With, Content-Type, Accept'
6 | );
7 | next();
8 | };
9 | }
10 |
--------------------------------------------------------------------------------
/server/middlewares/express-rx.js:
--------------------------------------------------------------------------------
1 | import { Observable } from 'rx';
2 |
3 | // add rx methods to express
4 | export default function expressRx() {
5 | return function expressRx(req, res, next) {
6 | // render to observable stream
7 | res.render$ = Observable.fromNodeCallback(res.render, res);
8 | next();
9 | };
10 | }
11 |
--------------------------------------------------------------------------------
/server/utils/constantStrings.json:
--------------------------------------------------------------------------------
1 | {
2 | "gitHubUserAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1521.3 Safari/537.36",
3 | "frontEndChallengeId": "561add10cb82ac38a17513be",
4 | "dataVisChallengeId": "561add10cb82ac38a17513b3",
5 | "backEndChallengeId": "660add10cb82ac38a17513be"
6 | }
7 |
--------------------------------------------------------------------------------
/common/app/routes/Hikes/redux/selectors.js:
--------------------------------------------------------------------------------
1 | // use this file for common selectors
2 | import { createSelector } from 'reselect';
3 |
4 | export const getCurrentHike = createSelector(
5 | state => state.hikesApp.hikes.entities,
6 | state => state.hikesApp.currentHike,
7 | (hikesMap, currentHikeDashedName) => (hikesMap[currentHikeDashedName] || {})
8 | );
9 |
--------------------------------------------------------------------------------
/server/views/layout.jade:
--------------------------------------------------------------------------------
1 | doctype html
2 | html(lang='en')
3 | head
4 | include partials/meta
5 | include partials/stylesheets
6 | body.top-and-bottom-margins
7 | include partials/scripts
8 | include partials/navbar
9 | .container-fluid
10 | include partials/flash
11 | block content
12 | include partials/footer
13 |
--------------------------------------------------------------------------------
/client/less/lib/bootstrap/mixins/alerts.less:
--------------------------------------------------------------------------------
1 | // Alerts
2 |
3 | .alert-variant(@background; @border; @text-color) {
4 | background-color: @background;
5 | border-color: @border;
6 | color: @text-color;
7 |
8 | hr {
9 | border-top-color: darken(@border, 5%);
10 | }
11 | .alert-link {
12 | color: darken(@text-color, 10%);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/common/config.global.js:
--------------------------------------------------------------------------------
1 | // The path where to mount the REST API app
2 | exports.restApiRoot = '/api';
3 | //
4 | // The URL where the browser client can access the REST API is available
5 | // Replace with a full url (including hostname) if your client is being
6 | // served from a different server than your REST API.
7 | exports.restApiUrl = exports.restApiRoot;
8 |
--------------------------------------------------------------------------------
/server/views/certificate/script.jade:
--------------------------------------------------------------------------------
1 | script.
2 | (function() {
3 | var containerWidth = document.getElementById('cert').offsetWidth;
4 | var nameDiv = document.getElementById('name');
5 | var nameWidth = nameDiv.offsetWidth;
6 | console.log(containerWidth, nameWidth);
7 | nameDiv.style.left = ((containerWidth - nameWidth) / 2) + 15;
8 | })();
9 |
--------------------------------------------------------------------------------
/server/utils/date-utils.js:
--------------------------------------------------------------------------------
1 | import moment from 'moment-timezone';
2 |
3 | // day count between two epochs (inclusive)
4 | export function dayCount([head, tail], timezone = 'UTC') {
5 | return Math.ceil(
6 | moment(moment(head).tz(timezone).endOf('day')).diff(
7 | moment(tail).tz(timezone).startOf('day'),
8 | 'days',
9 | true)
10 | );
11 | }
12 |
--------------------------------------------------------------------------------
/server/views/layout-react.jade:
--------------------------------------------------------------------------------
1 | doctype html
2 | html(lang='en')
3 | head
4 | if title
5 | title= title
6 | else
7 | title Free Code Camp
8 | include partials/react-stylesheets
9 | body.top-and-bottom-margins(style='overflow: hidden')
10 | .container
11 | #fcc!= markup
12 | script!= state
13 | script(src=rev('/js', 'bundle.js'))
14 |
--------------------------------------------------------------------------------
/common/app/utils/create-types.js:
--------------------------------------------------------------------------------
1 | // createTypes(types: String[], prefix: String) => Object
2 | export default function createTypes(types = [], prefix = '') {
3 | if (!Array.isArray(types) || typeof prefix !== 'string') {
4 | return {};
5 | }
6 | return types.reduce((types, type) => {
7 | types[type] = prefix + '.' + type;
8 | return types;
9 | }, {});
10 | }
11 |
--------------------------------------------------------------------------------
/common/models/User-Credential.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "userCredential",
3 | "plural": "userCredentials",
4 | "base": "UserCredential",
5 | "properties": {},
6 | "validations": [],
7 | "relations": {
8 | "user": {
9 | "type": "belongsTo",
10 | "model": "user",
11 | "foreignKey": "userId"
12 | }
13 | },
14 | "acls": [],
15 | "methods": []
16 | }
17 |
--------------------------------------------------------------------------------
/server/middlewares/jade-helpers.js:
--------------------------------------------------------------------------------
1 | const challengesRegex = /^(bonfire|waypoint|zipline|basejump|checkpoint):\s/i;
2 |
3 | export default function jadeHelpers() {
4 | return function jadeHelpersMiddleware(req, res, next) {
5 | res.locals.removeOldTerms = function removeOldTerms(str = '') {
6 | return str.replace(challengesRegex, '');
7 | };
8 |
9 | next();
10 | };
11 | }
12 |
--------------------------------------------------------------------------------
/server/views/resources/the-fastest-web-page-on-the-internet.jade:
--------------------------------------------------------------------------------
1 | h1 This is the fastest web page on the internet.
2 | h2 This is raw HTML with no CSS and no JavaScript.
3 | h2 This is served to you lightning fast from the cloud using Node.js and NGINX.
4 | h2 Unfortunately, this doesn't do anything.
5 | h2 I guess speed isn't everything, after all.
6 | h2
7 | a(href='/') Learn to code more useful websites than this one
8 |
--------------------------------------------------------------------------------
/common/app/components/Nav/links.json:
--------------------------------------------------------------------------------
1 | [{
2 | "content": "Map",
3 | "link": "/map"
4 | }, {
5 | "content": "Chat",
6 | "link": "//gitter.im/FreeCodeCamp/chinese",
7 | "target": "_blank"
8 | },{
9 | "content": "Wiki",
10 | "link": "/wiki",
11 | "target": "_blank"
12 | },{
13 | "content": "About",
14 | "link": "/about"
15 | },{
16 | "content": "Shop",
17 | "link": "/shop",
18 | "target": "_blank"
19 | }]
20 |
--------------------------------------------------------------------------------
/server/views/partials/stylesheets.jade:
--------------------------------------------------------------------------------
1 | link(rel='stylesheet', type='text/css' href='/css/lato.css')
2 | link(rel="stylesheet" type="text/css" href="/bower_components/cal-heatmap/cal-heatmap.css")
3 | link(rel='stylesheet', href='/bower_components/font-awesome/css/font-awesome.min.css')
4 | link(rel='stylesheet', href='/bower_components/lightbox2/dist/css/lightbox.css')
5 | link(rel='stylesheet', href=rev('/css', 'main-f928abf444.css'))
6 |
--------------------------------------------------------------------------------
/server/config.development.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | host: '127.0.0.1',
3 | sessionSecret: process.env.SESSION_SECRET,
4 |
5 | trello: {
6 | key: process.env.TRELLO_KEY,
7 | secret: process.env.TRELLO_SECRET
8 | },
9 |
10 | blogger: {
11 | key: process.env.BLOGGER_KEY
12 | },
13 |
14 | github: {
15 | clientID: process.env.GITHUB_ID,
16 | clientSecret: process.env.GITHUB_SECRET
17 | }
18 | };
19 |
--------------------------------------------------------------------------------
/common/app/routes/Jobs/redux/index.js:
--------------------------------------------------------------------------------
1 | export actions from './actions';
2 | export reducer from './reducer';
3 | export types from './types';
4 |
5 | import fetchJobsSaga from './fetch-jobs-saga';
6 | import saveJobSaga from './save-job-saga';
7 | import applyPromoSaga from './apply-promo-saga';
8 |
9 | export formNormalizer from './jobs-form-normalizer';
10 |
11 | export const sagas = [ fetchJobsSaga, saveJobSaga, applyPromoSaga ];
12 |
--------------------------------------------------------------------------------
/common/utils/index.js:
--------------------------------------------------------------------------------
1 | export function nameSpacedTransformer(ns, transformer) {
2 | if (!transformer) {
3 | return nameSpacedTransformer.bind(null, ns);
4 | }
5 | return (state) => {
6 | const newState = transformer(state[ns]);
7 |
8 | // nothing has changed
9 | // noop
10 | if (!newState || newState === state[ns]) {
11 | return null;
12 | }
13 |
14 | return { ...state, [ns]: newState };
15 | };
16 | }
17 |
--------------------------------------------------------------------------------
/server/manifests/README.md:
--------------------------------------------------------------------------------
1 | This folder contains a list of json files representing the name
2 | of revisioned client files. It is empty due to the fact that the
3 | files are generated at runtime and their content is determined by
4 | the content of the files they are derived from.
5 |
6 | Since the build process is not exactly the same on every machine,
7 | these files are not tracked in github otherwise conflicts arise when
8 | building on our servers.
9 |
--------------------------------------------------------------------------------
/server/ssl-config.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by nathanleniz on 6/16/15.
3 | */
4 |
5 | var path = require('path');
6 | var fs = require('fs');
7 |
8 | if (process.env.NODE_ENV === 'production') {
9 | exports.privateKey =
10 | fs.readFileSync(path.join(__dirname,
11 | '../../private/privatekey.pem'));
12 | exports.certificate =
13 | fs.readFileSync(path.join(__dirname,
14 | '../../private/certificate.pem'));
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/client/less/lib/bootstrap/mixins/nav-vertical-align.less:
--------------------------------------------------------------------------------
1 | // Navbar vertical align
2 | //
3 | // Vertically center elements in the navbar.
4 | // Example: an element has a height of 30px, so write out `.navbar-vertical-align(30px);` to calculate the appropriate top margin.
5 |
6 | .navbar-vertical-align(@element-height) {
7 | margin-top: ((@navbar-height - @element-height) / 2);
8 | margin-bottom: ((@navbar-height - @element-height) / 2);
9 | }
10 |
--------------------------------------------------------------------------------
/client/less/lib/font-awesome-4.3.0/less/bordered-pulled.less:
--------------------------------------------------------------------------------
1 | // Bordered & Pulled
2 | // -------------------------
3 |
4 | .@{fa-css-prefix}-border {
5 | padding: .2em .25em .15em;
6 | border: solid .08em @fa-border-color;
7 | border-radius: .1em;
8 | }
9 |
10 | .pull-right { float: right; }
11 | .pull-left { float: left; }
12 |
13 | .@{fa-css-prefix} {
14 | &.pull-left { margin-right: .3em; }
15 | &.pull-right { margin-left: .3em; }
16 | }
17 |
--------------------------------------------------------------------------------
/public/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | #492c14
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/public/css/lato.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: "Lato";
3 | src: url(/fonts/Lato-Regular.ttf) format("truetype");
4 | }
5 |
6 | @font-face {
7 | font-family: "Lato Light";
8 | src: url(/fonts/Lato-Light.ttf) format("truetype");
9 | }
10 |
11 | @font-face {
12 | font-family: "Lato Bold";
13 | src: url(/fonts/Lato-Bold.ttf) format("truetype");
14 | }
15 | .qr_code_pc {
16 | position: fixed;
17 | top: 100px;
18 | right: 100px;
19 | }
20 |
--------------------------------------------------------------------------------
/server/middlewares/validator.js:
--------------------------------------------------------------------------------
1 | import validator from 'express-validator';
2 |
3 | export default function() {
4 | return validator({
5 | customValidators: {
6 | matchRegex(param, regex) {
7 | return regex.test(param);
8 | },
9 | isString(value) {
10 | return typeof value === 'string';
11 | },
12 | isNumber(value) {
13 | return typeof value === 'number';
14 | }
15 | }
16 | });
17 | }
18 |
--------------------------------------------------------------------------------
/client/less/lib/bootstrap/mixins/responsive-visibility.less:
--------------------------------------------------------------------------------
1 | // Responsive utilities
2 |
3 | //
4 | // More easily include all the states for responsive-utilities.less.
5 | .responsive-visibility() {
6 | display: block !important;
7 | table& { display: table; }
8 | tr& { display: table-row !important; }
9 | th&,
10 | td& { display: table-cell !important; }
11 | }
12 |
13 | .responsive-invisibility() {
14 | display: none !important;
15 | }
16 |
--------------------------------------------------------------------------------
/client/less/lib/font-awesome-4.3.0/scss/_bordered-pulled.scss:
--------------------------------------------------------------------------------
1 | // Bordered & Pulled
2 | // -------------------------
3 |
4 | .#{$fa-css-prefix}-border {
5 | padding: .2em .25em .15em;
6 | border: solid .08em $fa-border-color;
7 | border-radius: .1em;
8 | }
9 |
10 | .pull-right { float: right; }
11 | .pull-left { float: left; }
12 |
13 | .#{$fa-css-prefix} {
14 | &.pull-left { margin-right: .3em; }
15 | &.pull-right { margin-left: .3em; }
16 | }
17 |
--------------------------------------------------------------------------------
/seed/challenges/04-video-challenges/agile.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Agile",
3 | "order": 6,
4 | "time": "0 hours",
5 | "isComingSoon": true,
6 | "challenges": [
7 | {
8 | "id": "bd7128d8c441eddfbec5bdde",
9 | "title": "Learn Agile Challenges",
10 | "description": [],
11 | "challengeSeed": [],
12 | "tests": [],
13 | "type": "hike",
14 | "challengeType": 6,
15 | "nameEs": "Agile"
16 | }
17 | ]
18 | }
--------------------------------------------------------------------------------
/seed/challenges/04-video-challenges/tools.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Tools",
3 | "order": 19,
4 | "time": "0 hours",
5 | "isComingSoon": true,
6 | "challenges": [
7 | {
8 | "id": "bd7128d8c441eddfbeb5bdd3",
9 | "title": "Learn Tools Challenges",
10 | "description": [],
11 | "challengeSeed": [],
12 | "tests": [],
13 | "type": "hike",
14 | "challengeType": 6,
15 | "nameEs": "Tools"
16 | }
17 | ]
18 | }
--------------------------------------------------------------------------------
/common/app/routes/Jobs/redux/types.js:
--------------------------------------------------------------------------------
1 | import createTypes from '../../../utils/create-types';
2 |
3 | export default createTypes([
4 | 'fetchJobs',
5 | 'fetchJobsCompleted',
6 |
7 | 'findJob',
8 | 'saveJob',
9 | 'saveForm',
10 |
11 | 'saveCompleted',
12 |
13 | 'clearForm',
14 |
15 | 'loadSavedForm',
16 | 'loadSavedFormCompleted',
17 |
18 | 'clearPromo',
19 | 'updatePromo',
20 | 'applyPromo',
21 | 'applyPromoCompleted'
22 | ], 'jobs');
23 |
--------------------------------------------------------------------------------
/seed/challenges/02-data-visualization-certification/d3.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "D3",
3 | "order": 16,
4 | "isComingSoon": true,
5 | "time": "5 hours",
6 | "helpRoom": "chinese",
7 | "challenges": [
8 | {
9 | "id": "bd7158d8c423ede2aab5bdee",
10 | "title": "Learn D3 Challenges",
11 | "description": [],
12 | "challengeSeed": [],
13 | "tests": [],
14 | "type": "waypoint",
15 | "challengeType": 3
16 | }
17 | ]
18 | }
--------------------------------------------------------------------------------
/seed/challenges/04-video-challenges/devops.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "DevOps",
3 | "order": 16,
4 | "time": "0 hours",
5 | "isComingSoon": true,
6 | "challenges": [
7 | {
8 | "id": "bd7128d8c441eddfbeb5bdd5",
9 | "title": "Learn DevOps Challenges",
10 | "description": [],
11 | "challengeSeed": [],
12 | "tests": [],
13 | "type": "hike",
14 | "challengeType": 6,
15 | "nameEs": "DevOps"
16 | }
17 | ]
18 | }
--------------------------------------------------------------------------------
/server/middlewares/sessions.js:
--------------------------------------------------------------------------------
1 | import session from 'express-session';
2 | import MongoStoreFactory from 'connect-mongo';
3 | import secrets from '../../config/secrets';
4 |
5 | const MongoStore = MongoStoreFactory(session);
6 |
7 | export default function sessionsMiddleware() {
8 | return session({
9 | resave: true,
10 | saveUninitialized: true,
11 | secret: secrets.sessionSecret,
12 | store: new MongoStore({ url: secrets.db })
13 | });
14 | }
15 |
--------------------------------------------------------------------------------
/client/less/lib/font-awesome-4.3.0/less/larger.less:
--------------------------------------------------------------------------------
1 | // Icon Sizes
2 | // -------------------------
3 |
4 | /* makes the font 33% larger relative to the icon container */
5 | .@{fa-css-prefix}-lg {
6 | font-size: (4em / 3);
7 | line-height: (3em / 4);
8 | vertical-align: -15%;
9 | }
10 | .@{fa-css-prefix}-2x { font-size: 2em; }
11 | .@{fa-css-prefix}-3x { font-size: 3em; }
12 | .@{fa-css-prefix}-4x { font-size: 4em; }
13 | .@{fa-css-prefix}-5x { font-size: 5em; }
14 |
--------------------------------------------------------------------------------
/client/less/lib/font-awesome-4.3.0/scss/_larger.scss:
--------------------------------------------------------------------------------
1 | // Icon Sizes
2 | // -------------------------
3 |
4 | /* makes the font 33% larger relative to the icon container */
5 | .#{$fa-css-prefix}-lg {
6 | font-size: (4em / 3);
7 | line-height: (3em / 4);
8 | vertical-align: -15%;
9 | }
10 | .#{$fa-css-prefix}-2x { font-size: 2em; }
11 | .#{$fa-css-prefix}-3x { font-size: 3em; }
12 | .#{$fa-css-prefix}-4x { font-size: 4em; }
13 | .#{$fa-css-prefix}-5x { font-size: 5em; }
14 |
--------------------------------------------------------------------------------
/seed/challenges/02-data-visualization-certification/react.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "React",
3 | "order": 14,
4 | "isComingSoon": true,
5 | "time": "5 hours",
6 | "helpRoom": "chinese",
7 | "challenges": [
8 | {
9 | "id": "bd7158d8c423ede3aeb5bdee",
10 | "title": "Learn React Challenges",
11 | "description": [],
12 | "challengeSeed": [],
13 | "tests": [],
14 | "type": "waypoint",
15 | "challengeType": 3
16 | }
17 | ]
18 | }
--------------------------------------------------------------------------------
/seed/challenges/02-data-visualization-certification/sass.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Sass",
3 | "order": 13,
4 | "isComingSoon": true,
5 | "time": "5 hours",
6 | "helpRoom": "chinese",
7 | "challenges": [
8 | {
9 | "id": "bd7158d8c423ede2aeb5bdee",
10 | "title": "Learn Sass Challenges",
11 | "description": [],
12 | "challengeSeed": [],
13 | "tests": [],
14 | "type": "waypoint",
15 | "challengeType": 3
16 | }
17 | ]
18 | }
--------------------------------------------------------------------------------
/server/datasources.local.js:
--------------------------------------------------------------------------------
1 | var secrets = require('../config/secrets');
2 |
3 | module.exports = {
4 | db: {
5 | connector: 'mongodb',
6 | connectionTimeout: 10000,
7 | url: secrets.db
8 | },
9 | mail: {
10 | connector: 'mail',
11 | transports: [{
12 | type: 'smtp',
13 | service: 'Mandrill',
14 | auth: {
15 | user: secrets.mandrill.user,
16 | pass: secrets.mandrill.password
17 | }
18 | }]
19 | }
20 | };
21 |
--------------------------------------------------------------------------------
/seed/challenges/04-video-challenges/statistics.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Statistics",
3 | "order": 18,
4 | "time": "0 hours",
5 | "isComingSoon": true,
6 | "challenges": [
7 | {
8 | "id": "bd7128d8c441eddfbeb5bdd4",
9 | "title": "Learn Statistics Challenges",
10 | "description": [],
11 | "challengeSeed": [],
12 | "tests": [],
13 | "type": "hike",
14 | "challengeType": 6,
15 | "nameEs": "Statistics"
16 | }
17 | ]
18 | }
--------------------------------------------------------------------------------
/seed/challenges/04-video-challenges/gamification.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Gamification",
3 | "order": 12,
4 | "time": "0 hours",
5 | "isComingSoon": true,
6 | "challenges": [
7 | {
8 | "id": "bd7128d8c441eddfbeb5bdd9",
9 | "title": "Learn Gamification Challenges",
10 | "description": [],
11 | "challengeSeed": [],
12 | "tests": [],
13 | "type": "hike",
14 | "challengeType": 6,
15 | "nameEs": "Gamification"
16 | }
17 | ]
18 | }
--------------------------------------------------------------------------------
/seed/challenges/04-video-challenges/visual-design.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Visual Design",
3 | "order": 21,
4 | "time": "0 hours",
5 | "isComingSoon": true,
6 | "challenges": [
7 | {
8 | "id": "bd7128d8c441eddfbeb5bdd1",
9 | "title": "Learn Visual Design Challenges",
10 | "description": [],
11 | "challengeSeed": [],
12 | "tests": [],
13 | "type": "hike",
14 | "challengeType": 6,
15 | "nameEs": "Visual Design"
16 | }
17 | ]
18 | }
--------------------------------------------------------------------------------
/seed/challenges/04-video-challenges/accessibility.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Accessibility",
3 | "order": 5.5,
4 | "time": "0 hours",
5 | "isComingSoon": true,
6 | "challenges": [
7 | {
8 | "id": "bd7128d8c441eddfbeb5bddd",
9 | "title": "Learn Accessibility Challenges",
10 | "description": [],
11 | "challengeSeed": [],
12 | "tests": [],
13 | "type": "hike",
14 | "challengeType": 6,
15 | "nameEs": "Accessibility"
16 | }
17 | ]
18 | }
--------------------------------------------------------------------------------
/client/less/lib/font-awesome-4.3.0/less/list.less:
--------------------------------------------------------------------------------
1 | // List Icons
2 | // -------------------------
3 |
4 | .@{fa-css-prefix}-ul {
5 | padding-left: 0;
6 | margin-left: @fa-li-width;
7 | list-style-type: none;
8 | > li { position: relative; }
9 | }
10 | .@{fa-css-prefix}-li {
11 | position: absolute;
12 | left: -@fa-li-width;
13 | width: @fa-li-width;
14 | top: (2em / 14);
15 | text-align: center;
16 | &.@{fa-css-prefix}-lg {
17 | left: (-@fa-li-width + (4em / 14));
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/seed/challenges/04-video-challenges/computer-science.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Computer Science",
3 | "order": 7,
4 | "time": "0 hours",
5 | "isComingSoon": true,
6 | "challenges": [
7 | {
8 | "id": "bd7128d8c441eddfbeb5bddc",
9 | "title": "Learn Computer Science Challenges",
10 | "description": [],
11 | "challengeSeed": [],
12 | "tests": [],
13 | "type": "hike",
14 | "challengeType": 6,
15 | "nameEs": "Computer Science"
16 | }
17 | ]
18 | }
--------------------------------------------------------------------------------
/seed/challenges/04-video-challenges/game-development.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Game Development",
3 | "order": 10,
4 | "time": "0 hours",
5 | "isComingSoon": true,
6 | "challenges": [
7 | {
8 | "id": "bd7128d8c441eddfbeb5bdd0",
9 | "title": "Learn Game Development Challenges",
10 | "description": [],
11 | "challengeSeed": [],
12 | "tests": [],
13 | "type": "hike",
14 | "challengeType": 6,
15 | "nameEs": "Game Development"
16 | }
17 | ]
18 | }
--------------------------------------------------------------------------------
/seed/challenges/04-video-challenges/machine-learning.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Machine Learning",
3 | "order": 13,
4 | "time": "0 hours",
5 | "isComingSoon": true,
6 | "challenges": [
7 | {
8 | "id": "bd7128d8c441eddfbeb5bdd8",
9 | "title": "Learn Machine Learning Challenges",
10 | "description": [],
11 | "challengeSeed": [],
12 | "tests": [],
13 | "type": "hike",
14 | "challengeType": 6,
15 | "nameEs": "Machine Learning"
16 | }
17 | ]
18 | }
--------------------------------------------------------------------------------
/server/config.local.js:
--------------------------------------------------------------------------------
1 | var globalConfig = require('../common/config.global');
2 |
3 | module.exports = {
4 | restApiRoot: globalConfig.restApi,
5 | sessionSecret: process.env.SESSION_SECRET,
6 |
7 | trello: {
8 | key: process.env.TRELLO_KEY,
9 | secret: process.env.TRELLO_SECRET
10 | },
11 |
12 | blogger: {
13 | key: process.env.BLOGGER_KEY
14 | },
15 |
16 | github: {
17 | clientID: process.env.GITHUB_ID,
18 | clientSecret: process.env.GITHUB_SECRET
19 | }
20 | };
21 |
--------------------------------------------------------------------------------
/client/less/lib/font-awesome-4.3.0/scss/_list.scss:
--------------------------------------------------------------------------------
1 | // List Icons
2 | // -------------------------
3 |
4 | .#{$fa-css-prefix}-ul {
5 | padding-left: 0;
6 | margin-left: $fa-li-width;
7 | list-style-type: none;
8 | > li { position: relative; }
9 | }
10 | .#{$fa-css-prefix}-li {
11 | position: absolute;
12 | left: -$fa-li-width;
13 | width: $fa-li-width;
14 | top: (2em / 14);
15 | text-align: center;
16 | &.#{$fa-css-prefix}-lg {
17 | left: -$fa-li-width + (4em / 14);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/seed/challenges/04-video-challenges/data-visualization.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Data Visualization",
3 | "order": 8,
4 | "time": "0 hours",
5 | "isComingSoon": true,
6 | "challenges": [
7 | {
8 | "id": "bd7128d8c441eddfbeb5bdde",
9 | "title": "Learn Data Visualization Challenges",
10 | "description": [],
11 | "challengeSeed": [],
12 | "tests": [],
13 | "type": "hike",
14 | "challengeType": 6,
15 | "nameEs": "Data Visualization"
16 | }
17 | ]
18 | }
--------------------------------------------------------------------------------
/server/views/layout-wide.jade:
--------------------------------------------------------------------------------
1 | doctype html
2 | html(lang='en')
3 | head
4 | include partials/meta
5 | include partials/stylesheets
6 | if showAside
7 | body.map-aside-body
8 | include partials/scripts
9 | block content
10 | else
11 | body.no-top-and-bottom-margins.full-screen-body-background
12 | include partials/scripts
13 | include partials/navbar
14 | include partials/flash
15 | block content
16 | include partials/footer
17 |
--------------------------------------------------------------------------------
/seed/challenges/04-video-challenges/math-for-programmers.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Math for Programmers",
3 | "order": 14,
4 | "time": "0 hours",
5 | "isComingSoon": true,
6 | "challenges": [
7 | {
8 | "id": "bd7128d8c441eddfbeb5bdd7",
9 | "title": "Learn Math for Programmers Challenges",
10 | "description": [],
11 | "challengeSeed": [],
12 | "tests": [],
13 | "type": "hike",
14 | "challengeType": 6,
15 | "nameEs": "Math for Programmers"
16 | }
17 | ]
18 | }
--------------------------------------------------------------------------------
/client/less/chat.less:
--------------------------------------------------------------------------------
1 | .chat-embed-main-title {
2 | display: flex;
3 | flex-grow: 1;
4 | padding-left: 31px;
5 | padding-top: 7px;
6 | }
7 |
8 | .gitter-chat-embed {
9 | z-index: 100;
10 | position: fixed;
11 |
12 | top: 0;
13 | left: 60%;
14 | bottom: 0;
15 | right: 0;
16 |
17 | display: flex;
18 | flex-direction: row;
19 | transition: transform 0.3s cubic-bezier(0.16, 0.22, 0.22, 1.7);
20 | }
21 |
22 | .gitter-chat-embed.is-collapsed:not(.is-loading) {
23 | transform: translateX(110%);
24 | }
25 |
--------------------------------------------------------------------------------
/client/less/lib/font-awesome-4.3.0/scss/font-awesome.scss:
--------------------------------------------------------------------------------
1 | /*!
2 | * Font Awesome 4.3.0 by @davegandy - http://fontawesome.io - @fontawesome
3 | * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
4 | */
5 |
6 | @import "variables";
7 | @import "mixins";
8 | @import "path";
9 | @import "core";
10 | @import "larger";
11 | @import "fixed-width";
12 | @import "list";
13 | @import "bordered-pulled";
14 | @import "animated";
15 | @import "rotated-flipped";
16 | @import "stacked";
17 | @import "icons";
18 |
--------------------------------------------------------------------------------
/seed/challenges/04-video-challenges/user-experience-design.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "User Experience Design",
3 | "order": 20,
4 | "time": "0 hours",
5 | "isComingSoon": true,
6 | "challenges": [
7 | {
8 | "id": "bd7128d8c441eddfbeb5bdd2",
9 | "title": "Learn User Experience Design Challenges",
10 | "description": [],
11 | "challengeSeed": [],
12 | "tests": [],
13 | "type": "hike",
14 | "challengeType": 6,
15 | "nameEs": "User Experience Design"
16 | }
17 | ]
18 | }
--------------------------------------------------------------------------------
/common/app/routes/Hikes/redux/types.js:
--------------------------------------------------------------------------------
1 | import createTypes from '../../../utils/create-types';
2 |
3 | export default createTypes([
4 | 'fetchHikes',
5 | 'fetchHikesCompleted',
6 | 'resetHike',
7 |
8 | 'toggleQuestionView',
9 | 'grabQuestion',
10 | 'releaseQuestion',
11 | 'moveQuestion',
12 |
13 | 'answerQuestion',
14 |
15 | 'startShake',
16 | 'endShake',
17 |
18 | 'primeNextQuestion',
19 | 'goToNextQuestion',
20 | 'transitionHike',
21 |
22 | 'hikeCompleted',
23 | 'goToNextHike'
24 | ], 'videos');
25 |
--------------------------------------------------------------------------------
/common/models/User-Identity.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "userIdentity",
3 | "plural": "userIdentities",
4 | "base": "UserIdentity",
5 | "properties": {},
6 | "validations": [],
7 | "relations": {
8 | "user": {
9 | "type": "belongsTo",
10 | "model": "user",
11 | "foreignKey": "userId"
12 | }
13 | },
14 | "acls": [
15 | {
16 | "accessType": "*",
17 | "principalType": "ROLE",
18 | "principalId": "$everyone",
19 | "permission": "DENY"
20 | }
21 | ],
22 | "methods": []
23 | }
24 |
--------------------------------------------------------------------------------
/seed/challenges/04-video-challenges/mobile-javascript-development.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Mobile JavaScript Development",
3 | "order": 15,
4 | "time": "0 hours",
5 | "isComingSoon": true,
6 | "challenges": [
7 | {
8 | "id": "bd7128d8c441eddfbeb5bdd6",
9 | "title": "Learn Mobile JavaScript Development Challenges",
10 | "description": [],
11 | "challengeSeed": [],
12 | "tests": [],
13 | "type": "hike",
14 | "challengeType": 6,
15 | "nameEs": "Mobile JavaScript Development"
16 | }
17 | ]
18 | }
--------------------------------------------------------------------------------
/client/sagas/title-saga.js:
--------------------------------------------------------------------------------
1 | // (doc: Object) =>
2 | // () =>
3 | // (next: (action: Action) => Object) =>
4 | // titleSage(action: Action) => Object|Void
5 | export default ({ doc }) => ({ getState }) => next => {
6 | return function titleSage(action) {
7 | // get next state
8 | const result = next(action);
9 | if (action.type !== 'app.updateTitle') {
10 | return result;
11 | }
12 | const state = getState();
13 | const newTitle = state.app.title;
14 | doc.title = newTitle;
15 | return result;
16 | };
17 | };
18 |
--------------------------------------------------------------------------------
/seed/challenges/04-video-challenges/embedded-and-internet-of-things.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Embedded and Internet of Things",
3 | "order": 9,
4 | "time": "0 hours",
5 | "isComingSoon": true,
6 | "challenges": [
7 | {
8 | "id": "bd7128d8c441eddfbeb5bdda",
9 | "title": "Learn Embedded and Internet of Things Challenges",
10 | "description": [],
11 | "challengeSeed": [],
12 | "tests": [],
13 | "type": "hike",
14 | "challengeType": 6,
15 | "nameEs": "Embedded and Internet of Things"
16 | }
17 | ]
18 | }
--------------------------------------------------------------------------------
/seed/challenges/04-video-challenges/software-engineering-principles.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Software Engineering Principles",
3 | "order": 17,
4 | "time": "0 hours",
5 | "isComingSoon": true,
6 | "challenges": [
7 | {
8 | "id": "bd7128d8c441ecdfbeb5bdd5",
9 | "title": "Learn Software Engineering Principles Challenges",
10 | "description": [],
11 | "challengeSeed": [],
12 | "tests": [],
13 | "type": "hike",
14 | "challengeType": 6,
15 | "nameEs": "Software Engineering Principles"
16 | }
17 | ]
18 | }
--------------------------------------------------------------------------------
/client/less/lib/bootstrap/mixins/pagination.less:
--------------------------------------------------------------------------------
1 | // Pagination
2 |
3 | .pagination-size(@padding-vertical; @padding-horizontal; @font-size; @border-radius) {
4 | > li {
5 | > a,
6 | > span {
7 | padding: @padding-vertical @padding-horizontal;
8 | font-size: @font-size;
9 | }
10 | &:first-child {
11 | > a,
12 | > span {
13 | .border-left-radius(@border-radius);
14 | }
15 | }
16 | &:last-child {
17 | > a,
18 | > span {
19 | .border-right-radius(@border-radius);
20 | }
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/public/json/cats.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "id": 0,
4 | "imageLink": "/images/funny-cat.jpg",
5 | "codeNames": [
6 | "Juggernaut",
7 | "Mrs. Wallace",
8 | "Buttercup"
9 | ]
10 | },
11 | {
12 | "id": 1,
13 | "imageLink": "/images/grumpy-cat.jpg",
14 | "codeNames": [
15 | "Oscar",
16 | "Scrooge",
17 | "Tyrion"
18 | ]
19 | },
20 | {
21 | "id": 2,
22 | "imageLink": "/images/mischievous-cat.jpg",
23 | "codeNames": [
24 | "The Doctor",
25 | "Loki",
26 | "Joker"
27 | ]
28 | }
29 | ]
30 |
--------------------------------------------------------------------------------
/client/less/lib/font-awesome-4.3.0/less/font-awesome.less:
--------------------------------------------------------------------------------
1 | /*!
2 | * Font Awesome 4.3.0 by @davegandy - http://fontawesome.io - @fontawesome
3 | * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
4 | */
5 |
6 | @import "variables.less";
7 | @import "mixins.less";
8 | @import "path.less";
9 | @import "core.less";
10 | @import "larger.less";
11 | @import "fixed-width.less";
12 | @import "list.less";
13 | @import "bordered-pulled.less";
14 | @import "animated.less";
15 | @import "rotated-flipped.less";
16 | @import "stacked.less";
17 | @import "icons.less";
18 |
--------------------------------------------------------------------------------
/client/less/lib/bootstrap/mixins/border-radius.less:
--------------------------------------------------------------------------------
1 | // Single side border-radius
2 |
3 | .border-top-radius(@radius) {
4 | border-top-right-radius: @radius;
5 | border-top-left-radius: @radius;
6 | }
7 | .border-right-radius(@radius) {
8 | border-bottom-right-radius: @radius;
9 | border-top-right-radius: @radius;
10 | }
11 | .border-bottom-radius(@radius) {
12 | border-bottom-right-radius: @radius;
13 | border-bottom-left-radius: @radius;
14 | }
15 | .border-left-radius(@radius) {
16 | border-bottom-left-radius: @radius;
17 | border-top-left-radius: @radius;
18 | }
19 |
--------------------------------------------------------------------------------
/common/app/components/NotFound/index.jsx:
--------------------------------------------------------------------------------
1 | import React, { PropTypes } from 'react';
2 |
3 | const win = typeof window !== 'undefined' ? window : {};
4 |
5 | function goToServer(path) {
6 | win.location = '/' + path;
7 | }
8 |
9 | export default class extends React.Component {
10 | static displayName = 'NotFound';
11 |
12 | static propTypes = {
13 | params: PropTypes.object
14 | };
15 |
16 | componentWillMount() {
17 | goToServer(this.props.params.splat);
18 | }
19 |
20 | componentDidMount() {
21 | }
22 |
23 | render() {
24 | return ;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/common/app/create-reducer.js:
--------------------------------------------------------------------------------
1 | import { combineReducers } from 'redux';
2 | import { reducer as formReducer } from 'redux-form';
3 |
4 | import { reducer as app } from './redux';
5 | import { reducer as hikesApp } from './routes/Hikes/redux';
6 | import {
7 | reducer as jobsApp,
8 | formNormalizer as jobsNormalizer
9 | } from './routes/Jobs/redux';
10 |
11 | export default function createReducer(sideReducers = {}) {
12 | return combineReducers({
13 | ...sideReducers,
14 | app,
15 | hikesApp,
16 | jobsApp,
17 | form: formReducer.normalize(jobsNormalizer)
18 | });
19 | }
20 |
--------------------------------------------------------------------------------
/server/boot/a-services.js:
--------------------------------------------------------------------------------
1 | import Fetchr from 'fetchr';
2 | import getHikesService from '../services/hikes';
3 | import getJobServices from '../services/job';
4 | import getUserServices from '../services/user';
5 |
6 | export default function bootServices(app) {
7 | const hikesService = getHikesService(app);
8 | const jobServices = getJobServices(app);
9 | const userServices = getUserServices(app);
10 |
11 | Fetchr.registerFetcher(hikesService);
12 | Fetchr.registerFetcher(jobServices);
13 | Fetchr.registerFetcher(userServices);
14 | app.use('/services', Fetchr.middleware());
15 | }
16 |
--------------------------------------------------------------------------------
/client/less/lib/font-awesome-4.3.0/less/core.less:
--------------------------------------------------------------------------------
1 | // Base Class Definition
2 | // -------------------------
3 |
4 | .@{fa-css-prefix} {
5 | display: inline-block;
6 | font: normal normal normal @fa-font-size-base/1 FontAwesome; // shortening font declaration
7 | font-size: inherit; // can't have font-size inherit on line above, so need to override
8 | text-rendering: auto; // optimizelegibility throws things off #1094
9 | -webkit-font-smoothing: antialiased;
10 | -moz-osx-font-smoothing: grayscale;
11 | transform: translate(0, 0); // ensures no half-pixel rendering in firefox
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/client/less/lib/font-awesome-4.3.0/less/stacked.less:
--------------------------------------------------------------------------------
1 | // Stacked Icons
2 | // -------------------------
3 |
4 | .@{fa-css-prefix}-stack {
5 | position: relative;
6 | display: inline-block;
7 | width: 2em;
8 | height: 2em;
9 | line-height: 2em;
10 | vertical-align: middle;
11 | }
12 | .@{fa-css-prefix}-stack-1x, .@{fa-css-prefix}-stack-2x {
13 | position: absolute;
14 | left: 0;
15 | width: 100%;
16 | text-align: center;
17 | }
18 | .@{fa-css-prefix}-stack-1x { line-height: inherit; }
19 | .@{fa-css-prefix}-stack-2x { font-size: 2em; }
20 | .@{fa-css-prefix}-inverse { color: @fa-inverse; }
21 |
--------------------------------------------------------------------------------
/client/less/lib/font-awesome-4.3.0/scss/_core.scss:
--------------------------------------------------------------------------------
1 | // Base Class Definition
2 | // -------------------------
3 |
4 | .#{$fa-css-prefix} {
5 | display: inline-block;
6 | font: normal normal normal #{$fa-font-size-base}/1 FontAwesome; // shortening font declaration
7 | font-size: inherit; // can't have font-size inherit on line above, so need to override
8 | text-rendering: auto; // optimizelegibility throws things off #1094
9 | -webkit-font-smoothing: antialiased;
10 | -moz-osx-font-smoothing: grayscale;
11 | transform: translate(0, 0); // ensures no half-pixel rendering in firefox
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/client/less/lib/font-awesome-4.3.0/scss/_stacked.scss:
--------------------------------------------------------------------------------
1 | // Stacked Icons
2 | // -------------------------
3 |
4 | .#{$fa-css-prefix}-stack {
5 | position: relative;
6 | display: inline-block;
7 | width: 2em;
8 | height: 2em;
9 | line-height: 2em;
10 | vertical-align: middle;
11 | }
12 | .#{$fa-css-prefix}-stack-1x, .#{$fa-css-prefix}-stack-2x {
13 | position: absolute;
14 | left: 0;
15 | width: 100%;
16 | text-align: center;
17 | }
18 | .#{$fa-css-prefix}-stack-1x { line-height: inherit; }
19 | .#{$fa-css-prefix}-stack-2x { font-size: 2em; }
20 | .#{$fa-css-prefix}-inverse { color: $fa-inverse; }
21 |
--------------------------------------------------------------------------------
/server/views/partials/challenge-footer.jade:
--------------------------------------------------------------------------------
1 | script(src=rev('/js', 'vendor-challenges.js'))
2 | script(src=rev('/js', 'commonFramework.js'))
3 | script.
4 | if (typeof localStorage !== 'undefined') {
5 | localStorage.setItem('currentDashedName', typeof common !== 'undefined' && common.dashedName || '');
6 | }
7 | var common = window.common || { init: [] };
8 | common.helpRoom = !{JSON.stringify(helpRoom)};
9 | document.addEventListener('gitter-sidecar-ready', function(e) {
10 | if (window.main) {
11 | window.main.chat.createHelpChat(common.helpRoom, '#challenge-help-btn');
12 | }
13 | });
14 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ## 注意:这里只处理 FreeCodeCamp.cn 的相关问题,不处理 w3cschool 的任何问题
2 | ## 注意:请不要乱开无意义的 Issue,违者直接加黑名单
3 | ## 注意:Issue 是用来处理代码库中的 bug,不是用来提问题的。完成挑战过程中遇到的代码问题请在[gitter 讨论组](https://gitter.im/FreeCodeCamp/chinese) 或者 QQ 群 526289580 中讨论 (QQ 群验证答案: ___**freeCodeCamp**___ 注意大小写)
4 |
5 | #### FreeCodeCamp.cn Issue 模板
6 | 如何使用本模板:
7 | * 尽可能多填些相关信息,方便管理员参考
8 | * 对于无法给出的内容,请删除掉那一行
9 |
10 | # 以上内容请在提交 Issue 之前删除
11 |
12 | #### 浏览器信息
13 | * 浏览器名称,版本号
14 | * 操作系统
15 |
16 | #### 问题描述
17 | * 问题是在什么时候,什么情况下遇到的
18 | * 简要说明如何重现
19 |
20 | #### 你的代码
21 |
22 | ```
23 | 如果和代码相关,请在这里粘贴你的全部代码
24 | ```
25 |
26 | #### 截图(如果有)
27 |
--------------------------------------------------------------------------------
/common/app/components/Flash/Queue.jsx:
--------------------------------------------------------------------------------
1 | import React, { PropTypes } from 'react';
2 | import { Alert } from 'react-bootstrap';
3 |
4 | export default React.createClass({
5 | displayName: 'FlashQueue',
6 |
7 | propTypes: {
8 | messages: PropTypes.array
9 | },
10 |
11 | renderMessages(messages) {
12 | return messages.map(() => {
13 | return (
14 |
15 | );
16 | });
17 | },
18 |
19 | render() {
20 | const { messages = [] } = this.props;
21 | return (
22 |
23 | { this.renderMessages(messages) }
24 |
25 | );
26 | }
27 | });
28 |
--------------------------------------------------------------------------------
/sample.env:
--------------------------------------------------------------------------------
1 | MONGOHQ_URL='mongodb://localhost:27017/freecodecamp'
2 |
3 | FACEBOOK_ID=stuff
4 | FACEBOOK_SECRET=stuff
5 |
6 | GITHUB_ID=stuff
7 | GITHUB_SECRET=stuff
8 |
9 | GOOGLE_ID=stuff
10 | GOOGLE_SECRET=stuff
11 |
12 | LINKEDIN_ID=stuff
13 | LINKEDIN_SECRET=stuff
14 |
15 | MANDRILL_PASSWORD=stuff
16 | MANDRILL_USER=stuff
17 |
18 | TRELLO_KEY=stuff
19 | TRELLO_SECRET=stuff
20 |
21 | TWITTER_KEY=stuff
22 | TWITTER_SECRET=stuff
23 | TWITTER_TOKEN=stuff
24 | TWITTER_TOKEN_SECRET=stuff
25 |
26 | BLOGGER_KEY=stuff
27 |
28 | SESSION_SECRET=secretstuff
29 | COOKIE_SECRET='this is a secret'
30 |
31 | PEER=stuff
32 | DEBUG=true
33 |
--------------------------------------------------------------------------------
/client/sagas/err-saga.js:
--------------------------------------------------------------------------------
1 | // () =>
2 | // (store: Store) =>
3 | // (next: (action: Action) => Object) =>
4 | // errSaga(action: Action) => Object|Void
5 | export default () => ({ dispatch }) => next => {
6 | return function errorSaga(action) {
7 | const result = next(action);
8 | if (!action.error) { return result; }
9 |
10 | console.error(action.error);
11 | return dispatch({
12 | type: 'app.makeToast',
13 | payload: {
14 | type: 'error',
15 | title: 'Oops, something went wrong',
16 | message: 'Something went wrong, please try again later'
17 | }
18 | });
19 | };
20 | };
21 |
--------------------------------------------------------------------------------
/common/app/routes/Jobs/utils.js:
--------------------------------------------------------------------------------
1 | const defaults = {
2 | 'string': {
3 | value: '',
4 | valid: false,
5 | pristine: true,
6 | type: 'string'
7 | },
8 | bool: {
9 | value: false,
10 | type: 'boolean'
11 | }
12 | };
13 |
14 | export function getDefaults(type, value) {
15 | if (!type) {
16 | return defaults['string'];
17 | }
18 | if (value) {
19 | return Object.assign({}, defaults[type], { value });
20 | }
21 | return Object.assign({}, defaults[type]);
22 | }
23 |
24 | export function isJobValid(job) {
25 | return job &&
26 | !job.isFilled &&
27 | job.isApproved &&
28 | job.isPaid;
29 | }
30 |
--------------------------------------------------------------------------------
/client/sagas/hard-go-to-saga.js:
--------------------------------------------------------------------------------
1 | import { hardGoTo } from '../../common/app/redux/types';
2 |
3 | const loc = typeof window !== 'undefined' ?
4 | window.location :
5 | {};
6 |
7 | export default () => ({ dispatch }) => next => {
8 | return function hardGoToSaga(action) {
9 | const result = next(action);
10 | if (action.type !== hardGoTo) {
11 | return result;
12 | }
13 |
14 | if (!loc.pathname) {
15 | dispatch({
16 | type: 'app.error',
17 | error: new Error('no location object found')
18 | });
19 | }
20 |
21 | loc.pathname = action.payload || '/map';
22 | return null;
23 | };
24 | };
25 |
--------------------------------------------------------------------------------
/server/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "restApiRoot": "/api",
3 | "host": "127.0.0.1",
4 | "port": 3000,
5 | "legacyExplorer": false,
6 | "remoting": {
7 | "context": {
8 | "enableHttpContext": false
9 | },
10 | "rest": {
11 | "normalizeHttpPath": false,
12 | "xml": false
13 | },
14 | "json": {
15 | "strict": false,
16 | "limit": "100kb"
17 | },
18 | "urlencoded": {
19 | "extended": true,
20 | "limit": "100kb"
21 | },
22 | "cors": {
23 | "origin": true,
24 | "credentials": true
25 | },
26 | "errorHandler": {
27 | "disableStackTrace": false
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/server/middlewares/keymetrics.js:
--------------------------------------------------------------------------------
1 | import pmx from 'pmx';
2 |
3 | export default function keymetrics() {
4 | if (process.env.NODE_ENV !== 'production') {
5 | return (err, req, res, next) => next(err);
6 | }
7 | return (err, req, res, next) => {
8 | if (res.statusCode < 400) { res.statusCode = 500; }
9 |
10 | err.url = req.url;
11 | err.component = req.url;
12 | err.action = req.method;
13 | err.params = req.body;
14 | err.session = req.session;
15 | err.username = req.user ? req.user.username : 'anonymous';
16 | err.userId = req.user ? req.user.id : 'anonymous';
17 |
18 | return next(pmx.notify(err));
19 | };
20 | }
21 |
--------------------------------------------------------------------------------
/client/less/lib/bootstrap/mixins/panels.less:
--------------------------------------------------------------------------------
1 | // Panels
2 |
3 | .panel-variant(@border; @heading-text-color; @heading-bg-color; @heading-border) {
4 | border-color: @border;
5 |
6 | & > .panel-heading {
7 | color: @heading-text-color;
8 | background-color: @heading-bg-color;
9 | border-color: @heading-border;
10 |
11 | + .panel-collapse > .panel-body {
12 | border-top-color: @border;
13 | }
14 | .badge {
15 | color: @heading-bg-color;
16 | background-color: @heading-text-color;
17 | }
18 | }
19 | & > .panel-footer {
20 | + .panel-collapse > .panel-body {
21 | border-bottom-color: @border;
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/client/less/lib/bootstrap/wells.less:
--------------------------------------------------------------------------------
1 | //
2 | // Wells
3 | // --------------------------------------------------
4 |
5 |
6 | // Base class
7 | .well {
8 | min-height: 20px;
9 | padding: 19px;
10 | margin-bottom: 20px;
11 | background-color: @well-bg;
12 | border: 1px solid @well-border;
13 | border-radius: @border-radius-base;
14 | .box-shadow(inset 0 1px 1px rgba(0,0,0,.05));
15 | blockquote {
16 | border-color: #ddd;
17 | border-color: rgba(0,0,0,.15);
18 | }
19 | }
20 |
21 | // Sizes
22 | .well-lg {
23 | padding: 24px;
24 | border-radius: @border-radius-large;
25 | }
26 | .well-sm {
27 | padding: 9px;
28 | border-radius: @border-radius-small;
29 | }
30 |
--------------------------------------------------------------------------------
/client/commonFramework/add-loop-protect.js:
--------------------------------------------------------------------------------
1 | window.common = (function(global) {
2 | const {
3 | loopProtect,
4 | common = { init: [] }
5 | } = global;
6 |
7 | loopProtect.hit = function hit(line) {
8 | var err = 'Error: Exiting potential infinite loop at line ' +
9 | line +
10 | '. To disable loop protection, write: \n\\/\\/ noprotect\nas the first' +
11 | 'line. Beware that if you do have an infinite loop in your code' +
12 | 'this will crash your browser.';
13 | console.error(err);
14 | };
15 |
16 | common.addLoopProtect = function addLoopProtect(code = '') {
17 | return loopProtect(code);
18 | };
19 |
20 | return common;
21 | })(window);
22 |
--------------------------------------------------------------------------------
/client/less/lib/bootstrap/mixins/list-group.less:
--------------------------------------------------------------------------------
1 | // List Groups
2 |
3 | .list-group-item-variant(@state; @background; @color) {
4 | .list-group-item-@{state} {
5 | color: @color;
6 | background-color: @background;
7 |
8 | a& {
9 | color: @color;
10 |
11 | .list-group-item-heading {
12 | color: inherit;
13 | }
14 |
15 | &:hover,
16 | &:focus {
17 | color: @color;
18 | background-color: darken(@background, 5%);
19 | }
20 | &.active,
21 | &.active:hover,
22 | &.active:focus {
23 | color: #fff;
24 | background-color: @color;
25 | border-color: @color;
26 | }
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/server/views/account/forgot.jade:
--------------------------------------------------------------------------------
1 | extends ../layout
2 | block content
3 | .col-sm-6.col-sm-offset-3
4 | form(method='POST', action="/forgot")
5 | h2.text-center 密码重置
6 | input(type='hidden', name='_csrf', value=_csrf)
7 | .form-group
8 | p.large-p 我们会把密码重置链接发送到你的邮箱里
9 | input.form-control.input-lg(type='email', name='email', id='email', placeholder='邮箱', autofocus=true required)
10 | .form-group
11 | button.btn.btn-primary.btn-lg.btn-block(type='submit')
12 | i.fa.fa-key
13 | | 重置密码
14 | br
15 | br
16 | br
17 | br
18 | br
19 | br
20 | br
21 | br
22 |
--------------------------------------------------------------------------------
/client/less/lib/bootstrap/mixins/hide-text.less:
--------------------------------------------------------------------------------
1 | // CSS image replacement
2 | //
3 | // Heads up! v3 launched with with only `.hide-text()`, but per our pattern for
4 | // mixins being reused as classes with the same name, this doesn't hold up. As
5 | // of v3.0.1 we have added `.text-hide()` and deprecated `.hide-text()`.
6 | //
7 | // Source: https://github.com/h5bp/html5-boilerplate/commit/aa0396eae757
8 |
9 | // Deprecated as of v3.0.1 (will be removed in v4)
10 | .hide-text() {
11 | font: ~"0/0" a;
12 | color: transparent;
13 | text-shadow: none;
14 | background-color: transparent;
15 | border: 0;
16 | }
17 |
18 | // New mixin to use as of v3.0.1
19 | .text-hide() {
20 | .hide-text();
21 | }
22 |
--------------------------------------------------------------------------------
/client/commonFramework/get-iframe.js:
--------------------------------------------------------------------------------
1 | window.common = (function(global) {
2 | const {
3 | common = { init: [] },
4 | document: doc
5 | } = global;
6 |
7 | common.getIframe = function getIframe(id = 'preview') {
8 | let previewFrame = doc.getElementById(id);
9 |
10 | // create and append a hidden preview frame
11 | if (!previewFrame) {
12 | previewFrame = doc.createElement('iframe');
13 | previewFrame.id = id;
14 | previewFrame.setAttribute('style', 'display: none');
15 | doc.body.appendChild(previewFrame);
16 | }
17 |
18 | return previewFrame.contentDocument ||
19 | previewFrame.contentWindow.document;
20 | };
21 |
22 | return common;
23 | })(window);
24 |
--------------------------------------------------------------------------------
/server/views/feed.jade:
--------------------------------------------------------------------------------
1 | doctype xml
2 | rss(version="2.0", xmlns:atom="http://www.w3.org/2005/Atom")
3 | channel
4 | title= title
5 | link= url
6 | description= description
7 | atom:link(href="http://www.freecodecamp.com/news/feed", rel="self", type="application/rss+xml")
8 | for post in FeedPosts
9 | if (post.link).match(/https*:\/\/\w+(\.\w+)*/)
10 | item
11 | title #{ post.headline.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"') }
12 | description
13 | pubDate= (new Date(post.timePosted)).toUTCString()
14 | link= post.link
15 | guid(isPermaLink="false")= post.link
16 |
--------------------------------------------------------------------------------
/client/less/lib/bootstrap/mixins/clearfix.less:
--------------------------------------------------------------------------------
1 | // Clearfix
2 | //
3 | // For modern browsers
4 | // 1. The space content is one way to avoid an Opera bug when the
5 | // contenteditable attribute is included anywhere else in the document.
6 | // Otherwise it causes space to appear at the top and bottom of elements
7 | // that are clearfixed.
8 | // 2. The use of `table` rather than `block` is only necessary if using
9 | // `:before` to contain the top-margins of child elements.
10 | //
11 | // Source: http://nicolasgallagher.com/micro-clearfix-hack/
12 |
13 | .clearfix() {
14 | &:before,
15 | &:after {
16 | content: " "; // 1
17 | display: table; // 2
18 | }
19 | &:after {
20 | clear: both;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/client/less/lib/bootstrap/breadcrumbs.less:
--------------------------------------------------------------------------------
1 | //
2 | // Breadcrumbs
3 | // --------------------------------------------------
4 |
5 |
6 | .breadcrumb {
7 | padding: @breadcrumb-padding-vertical @breadcrumb-padding-horizontal;
8 | margin-bottom: @line-height-computed;
9 | list-style: none;
10 | background-color: @breadcrumb-bg;
11 | border-radius: @border-radius-base;
12 |
13 | > li {
14 | display: inline-block;
15 |
16 | + li:before {
17 | content: "@{breadcrumb-separator}\00a0"; // Unicode space added since inline-block means non-collapsing white-space
18 | padding: 0 5px;
19 | color: @breadcrumb-color;
20 | }
21 | }
22 |
23 | > .active {
24 | color: @breadcrumb-active-color;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/server/views/commit/directory.jade:
--------------------------------------------------------------------------------
1 | extends ../layout
2 | block content
3 | h1.text-center Commit to one of these nonprofits
4 | hr
5 | .row
6 | .col-xs-12.col-sm-10.col-sm-offset-1
7 | for nonprofit in nonprofits
8 | .col-xs-12.col-sm-6.col-md-4.height-400
9 | .text-center
10 | h2= nonprofit.displayName
11 | img.testimonial-image.img-responsive.img-center(src=nonprofit.imgUrl)
12 | .button-spacer
13 | a.text-center(href='/commit?nonprofit=#{nonprofit.name}') Commit to #{nonprofit.displayName}
14 | p= nonprofit.description
15 |
--------------------------------------------------------------------------------
/client/less/lib/font-awesome-4.3.0/less/rotated-flipped.less:
--------------------------------------------------------------------------------
1 | // Rotated & Flipped Icons
2 | // -------------------------
3 |
4 | .@{fa-css-prefix}-rotate-90 { .fa-icon-rotate(90deg, 1); }
5 | .@{fa-css-prefix}-rotate-180 { .fa-icon-rotate(180deg, 2); }
6 | .@{fa-css-prefix}-rotate-270 { .fa-icon-rotate(270deg, 3); }
7 |
8 | .@{fa-css-prefix}-flip-horizontal { .fa-icon-flip(-1, 1, 0); }
9 | .@{fa-css-prefix}-flip-vertical { .fa-icon-flip(1, -1, 2); }
10 |
11 | // Hook for IE8-9
12 | // -------------------------
13 |
14 | :root .@{fa-css-prefix}-rotate-90,
15 | :root .@{fa-css-prefix}-rotate-180,
16 | :root .@{fa-css-prefix}-rotate-270,
17 | :root .@{fa-css-prefix}-flip-horizontal,
18 | :root .@{fa-css-prefix}-flip-vertical {
19 | filter: none;
20 | }
21 |
--------------------------------------------------------------------------------
/server/utils/middleware.js:
--------------------------------------------------------------------------------
1 | export function ifNoUserRedirectTo(url, message, type = 'errors') {
2 | return function(req, res, next) {
3 | const { path } = req;
4 | if (req.user) {
5 | return next();
6 | }
7 |
8 | req.flash(type, {
9 | msg: message || `You must be signed to go to ${path}`
10 | });
11 |
12 | return res.redirect(url);
13 | };
14 | }
15 |
16 | export function ifNoUserSend(sendThis) {
17 | return function(req, res, next) {
18 | if (req.user) {
19 | return next();
20 | }
21 | return res.status(200).send(sendThis);
22 | };
23 | }
24 |
25 | export function ifNoUser401(req, res, next) {
26 | if (req.user) {
27 | return next();
28 | }
29 | return res.status(401).end();
30 | }
31 |
--------------------------------------------------------------------------------
/client/less/lib/bootstrap/responsive-embed.less:
--------------------------------------------------------------------------------
1 | // Embeds responsive
2 | //
3 | // Credit: Nicolas Gallagher and SUIT CSS.
4 |
5 | .embed-responsive {
6 | position: relative;
7 | display: block;
8 | height: 0;
9 | padding: 0;
10 | overflow: hidden;
11 |
12 | .embed-responsive-item,
13 | iframe,
14 | embed,
15 | object,
16 | video {
17 | position: absolute;
18 | top: 0;
19 | left: 0;
20 | bottom: 0;
21 | height: 100%;
22 | width: 100%;
23 | border: 0;
24 | }
25 |
26 | // Modifier class for 16:9 aspect ratio
27 | &.embed-responsive-16by9 {
28 | padding-bottom: 56.25%;
29 | }
30 |
31 | // Modifier class for 4:3 aspect ratio
32 | &.embed-responsive-4by3 {
33 | padding-bottom: 75%;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "freecodecamp",
3 | "version": "0.0.0",
4 | "homepage": "http://freecodecamp.cn",
5 | "private": true,
6 | "ignore": [
7 | "**/.*",
8 | "node_modules",
9 | "bower_components",
10 | "public/bower_components",
11 | "test",
12 | "tests"
13 | ],
14 | "dependencies": {
15 | "d3": "~3.5.5",
16 | "jquery": "~2.1.4",
17 | "cal-heatmap": "~3.5.2",
18 | "bootstrap": "~3.3.4",
19 | "font-awesome": "~4.5.0",
20 | "moment": "~2.10.2",
21 | "moment-timezone": "~0.5.0",
22 | "jshint": "~2.9.0",
23 | "lightbox2": "~2.8.1",
24 | "rxjs": "~4.0.6",
25 | "CodeMirror": "~5.8.0",
26 | "chai": "~3.4.1",
27 | "clipboard": "~1.5.5",
28 | "mousetrap": "~1.5.3"
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | lib-cov
2 | *.seed
3 | *.log
4 | *.csv
5 | *.dat
6 | *.out
7 | *.pid
8 | *.gz
9 | *.swp
10 | .floo
11 | .flooignore
12 | builtAssets/
13 | pm2.js
14 | *.env
15 | pids
16 | logs
17 | results
18 | tmp
19 |
20 | npm-debug.log
21 | node_modules
22 | .idea
23 | *.iml
24 | .git
25 | .DS_Store
26 | Thumbs.db
27 | bower_components
28 | bundle.js
29 | coverage
30 | .remote-sync.json
31 |
32 | server/*.bundle.js
33 | public/js/bundle*
34 |
35 | *.map
36 |
37 | // revision manifest
38 | server/rev-manifest.json
39 | server/manifests/*
40 | !server/manifests/README.md
41 |
42 | public/js/main*
43 | // public/js/commonFramework*
44 | public/js/sandbox*
45 | public/js/iFrameScripts*
46 | public/js/plugin*
47 | public/js/vendor*
48 | public/js/faux*
49 |
50 |
51 | server/rev-manifest.json
52 |
--------------------------------------------------------------------------------
/server/utils/constants.js:
--------------------------------------------------------------------------------
1 | exports.blacklistedUsernames = [
2 | 'bonfire',
3 | 'account',
4 | 'user',
5 | 'challenge',
6 | 'challenges',
7 | 'completed-challenge',
8 | 'completed-zipline-or-basejump',
9 | 'completed-bonfire',
10 | 'map',
11 | 'learn-to-code',
12 | 'about',
13 | 'api',
14 | 'explorer',
15 | 'field-guide',
16 | 'completed-field-guide',
17 | 'jobs',
18 | 'nonprofits',
19 | 'api',
20 | 'sitemap.xml',
21 | 'get-help',
22 | 'chat',
23 | 'twitch',
24 | 'get-pai',
25 | 'get-help',
26 | 'nonprofits',
27 | 'nonproifts-form',
28 | 'jobs-form',
29 | 'unsubscribe',
30 | 'unsubscribed',
31 | 'cats.json',
32 | 'agile',
33 | 'privacy',
34 | 'stories',
35 | 'signin',
36 | 'signout',
37 | 'forgot',
38 | 'reset'
39 | ];
40 |
--------------------------------------------------------------------------------
/common/app/utils/render.js:
--------------------------------------------------------------------------------
1 | import ReactDOM from 'react-dom';
2 | import { Disposable, Observable } from 'rx';
3 | import ProfessorContext from './Professor-Context';
4 |
5 | export default function render(Component, DOMContainer) {
6 | let ContextedComponent;
7 | try {
8 | ContextedComponent = ProfessorContext.wrap(Component);
9 | } catch (e) {
10 | return Observable.throw(e);
11 | }
12 |
13 | return Observable.create(observer => {
14 | try {
15 | ReactDOM.render(ContextedComponent, DOMContainer, function() {
16 | observer.onNext(this);
17 | });
18 | } catch (e) {
19 | return observer.onError(e);
20 | }
21 |
22 | return Disposable.create(() => {
23 | return ReactDOM.unmountComponentAtNode(DOMContainer);
24 | });
25 | });
26 | }
27 |
--------------------------------------------------------------------------------
/client/less/lib/font-awesome-4.3.0/scss/_rotated-flipped.scss:
--------------------------------------------------------------------------------
1 | // Rotated & Flipped Icons
2 | // -------------------------
3 |
4 | .#{$fa-css-prefix}-rotate-90 { @include fa-icon-rotate(90deg, 1); }
5 | .#{$fa-css-prefix}-rotate-180 { @include fa-icon-rotate(180deg, 2); }
6 | .#{$fa-css-prefix}-rotate-270 { @include fa-icon-rotate(270deg, 3); }
7 |
8 | .#{$fa-css-prefix}-flip-horizontal { @include fa-icon-flip(-1, 1, 0); }
9 | .#{$fa-css-prefix}-flip-vertical { @include fa-icon-flip(1, -1, 2); }
10 |
11 | // Hook for IE8-9
12 | // -------------------------
13 |
14 | :root .#{$fa-css-prefix}-rotate-90,
15 | :root .#{$fa-css-prefix}-rotate-180,
16 | :root .#{$fa-css-prefix}-rotate-270,
17 | :root .#{$fa-css-prefix}-flip-horizontal,
18 | :root .#{$fa-css-prefix}-flip-vertical {
19 | filter: none;
20 | }
21 |
--------------------------------------------------------------------------------
/server/views/resources/labs.jade:
--------------------------------------------------------------------------------
1 | extends ../layout
2 | block content
3 | h2.text-center Projects Created by Free Code Camp Campers
4 | hr
5 | .row
6 | .col-xs-12.col-sm-10.col-sm-offset-1
7 | for project in projects
8 | .spacer
9 | .row
10 | .col-xs-12.col-sm-3
11 | img.img-responsive(src=project.image)
12 | .col-xs-12.col-sm-9.negative-15
13 | h3
14 | a(href=project.url) #{project.name}
15 | h4 by
16 | a(href='https://freecodecamp.com/' + project.camper) #{project.camper}
17 | p= project.description
18 |
--------------------------------------------------------------------------------
/server/views/commit/pledge.jade:
--------------------------------------------------------------------------------
1 | extends ../layout
2 | block content
3 | .panel.panel-info
4 | .panel-body
5 | h3.text-center You've committed!
6 | .row
7 | .col-xs-12.col-sm-6.col-sm-offset-3
8 | p Congratulations, you have committed to giving
9 | span(style='text-transform: capitalize') #{nonprofit}
10 | | #{amount} dollars a month until you have reached your goal
11 | | of completing your #{goal}
12 | .row
13 | .col-xs-12.col-sm-6.col-sm-offset-3
14 | img.img-responsive(src='//i.imgur.com/U1CyEuA.jpg' alt="Girl Develop It participants coding at tables.")
15 | p Girl Develop It is a nonprofit that provides in-person classes for women to learn to code.
16 |
--------------------------------------------------------------------------------
/server/boot/home.js:
--------------------------------------------------------------------------------
1 | import { defaultProfileImage } from '../../common/utils/constantStrings.json';
2 |
3 | const message =
4 | 'Learn to Code and Help Nonprofits';
5 |
6 | module.exports = function(app) {
7 | var router = app.loopback.Router();
8 | router.get('/', addDefaultImage, index);
9 |
10 | app.use(router);
11 |
12 | function addDefaultImage(req, res, next) {
13 | if (!req.user || req.user.picture) {
14 | return next();
15 | }
16 | req.user.picture = defaultProfileImage;
17 | return req.user.save(function(err) {
18 | if (err) { return next(err); }
19 | return next();
20 | });
21 | }
22 |
23 | function index(req, res) {
24 | if (req.user) {
25 | return res.redirect('/challenges/current-challenge');
26 | }
27 | return res.render('home', { title: message });
28 | }
29 | };
30 |
--------------------------------------------------------------------------------
/server/views/account/reset.jade:
--------------------------------------------------------------------------------
1 | extends ../layout
2 |
3 | block content
4 | .col-sm-8.col-sm-offset-2.jumbotron
5 | form(action='/reset-password?access_token=#{accessToken}', method='POST')
6 | h1 Reset Password
7 | input(type='hidden', name='_csrf', value=_csrf)
8 | .form-group
9 | label(for='password') 新密码
10 | input.form-control(type='password', name='password', value='', placeholder='新密码', autofocus=true)
11 | .form-group
12 | label(for='confirm') 确认密码
13 | input.form-control(type='password', name='confirm', value='', placeholder='确认密码')
14 | .form-group
15 | button.btn.btn-primary.btn-reset(type='submit')
16 | i.fa.fa-keyboard-o
17 | | 更改密码
18 | br
19 | br
20 | br
21 | br
22 | br
23 | br
24 | br
25 | br
26 |
--------------------------------------------------------------------------------
/client/less/lib/bootstrap/close.less:
--------------------------------------------------------------------------------
1 | //
2 | // Close icons
3 | // --------------------------------------------------
4 |
5 |
6 | .close {
7 | float: right;
8 | font-size: (@font-size-base * 1.5);
9 | font-weight: @close-font-weight;
10 | line-height: 1;
11 | color: @close-color;
12 | text-shadow: @close-text-shadow;
13 | .opacity(.2);
14 |
15 | &:hover,
16 | &:focus {
17 | color: @close-color;
18 | text-decoration: none;
19 | cursor: pointer;
20 | .opacity(.5);
21 | }
22 |
23 | // Additional properties for button version
24 | // iOS requires the button element instead of an anchor tag.
25 | // If you want the anchor version, it requires `href="#"`.
26 | button& {
27 | padding: 0;
28 | cursor: pointer;
29 | background: transparent;
30 | border: 0;
31 | -webkit-appearance: none;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/client/less/lib/bootstrap/mixins/table-row.less:
--------------------------------------------------------------------------------
1 | // Tables
2 |
3 | .table-row-variant(@state; @background) {
4 | // Exact selectors below required to override `.table-striped` and prevent
5 | // inheritance to nested tables.
6 | .table > thead > tr,
7 | .table > tbody > tr,
8 | .table > tfoot > tr {
9 | > td.@{state},
10 | > th.@{state},
11 | &.@{state} > td,
12 | &.@{state} > th {
13 | background-color: @background;
14 | }
15 | }
16 |
17 | // Hover states for `.table-hover`
18 | // Note: this is not available for cells or rows within `thead` or `tfoot`.
19 | .table-hover > tbody > tr {
20 | > td.@{state}:hover,
21 | > th.@{state}:hover,
22 | &.@{state}:hover > td,
23 | &:hover > .@{state},
24 | &.@{state}:hover > th {
25 | background-color: darken(@background, 5%);
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/client/less/lib/font-awesome-4.3.0/less/path.less:
--------------------------------------------------------------------------------
1 | /* FONT PATH
2 | * -------------------------- */
3 |
4 | @font-face {
5 | font-family: 'FontAwesome';
6 | src: url('@{fa-font-path}/fontawesome-webfont.eot?v=@{fa-version}');
7 | src: url('@{fa-font-path}/fontawesome-webfont.eot?#iefix&v=@{fa-version}') format('embedded-opentype'),
8 | url('@{fa-font-path}/fontawesome-webfont.woff2?v=@{fa-version}') format('woff2'),
9 | url('@{fa-font-path}/fontawesome-webfont.woff?v=@{fa-version}') format('woff'),
10 | url('@{fa-font-path}/fontawesome-webfont.ttf?v=@{fa-version}') format('truetype'),
11 | url('@{fa-font-path}/fontawesome-webfont.svg?v=@{fa-version}#fontawesomeregular') format('svg');
12 | // src: url('@{fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts
13 | font-weight: normal;
14 | font-style: normal;
15 | }
16 |
--------------------------------------------------------------------------------
/server/services/user.js:
--------------------------------------------------------------------------------
1 | import debugFactory from 'debug';
2 | import assign from 'object.assign';
3 |
4 | const censor = '**********************:P********';
5 | const debug = debugFactory('fcc:services:user');
6 | const protectedUserFields = {
7 | id: censor,
8 | password: censor,
9 | profiles: censor
10 | };
11 |
12 | export default function userServices() {
13 | return {
14 | name: 'user',
15 | read: (req, resource, params, config, cb) => {
16 | let { user } = req;
17 | if (user) {
18 | debug('user is signed in');
19 | // Zalgo!!!
20 | return process.nextTick(() => {
21 | cb(null, assign({}, user.toJSON(), protectedUserFields));
22 | });
23 | }
24 | debug('user is not signed in');
25 | return process.nextTick(() => {
26 | cb(null, {});
27 | });
28 | }
29 | };
30 | }
31 |
--------------------------------------------------------------------------------
/client/less/lib/font-awesome-4.3.0/scss/_path.scss:
--------------------------------------------------------------------------------
1 | /* FONT PATH
2 | * -------------------------- */
3 |
4 | @font-face {
5 | font-family: 'FontAwesome';
6 | src: url('#{$fa-font-path}/fontawesome-webfont.eot?v=#{$fa-version}');
7 | src: url('#{$fa-font-path}/fontawesome-webfont.eot?#iefix&v=#{$fa-version}') format('embedded-opentype'),
8 | url('#{$fa-font-path}/fontawesome-webfont.woff2?v=#{$fa-version}') format('woff2'),
9 | url('#{$fa-font-path}/fontawesome-webfont.woff?v=#{$fa-version}') format('woff'),
10 | url('#{$fa-font-path}/fontawesome-webfont.ttf?v=#{$fa-version}') format('truetype'),
11 | url('#{$fa-font-path}/fontawesome-webfont.svg?v=#{$fa-version}#fontawesomeregular') format('svg');
12 | // src: url('#{$fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts
13 | font-weight: normal;
14 | font-style: normal;
15 | }
16 |
--------------------------------------------------------------------------------
/seed/get-emails.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-process-exit */
2 | require('dotenv').load();
3 | var secrets = require('../config/secrets'),
4 | mongodb = require('mongodb'),
5 | MongoClient = mongodb.MongoClient;
6 |
7 | MongoClient.connect(secrets.db, function(err, database) {
8 | if (err) {
9 | throw err;
10 | }
11 |
12 | database.collection('user').aggregate([
13 | {$match: { 'email': { $exists: true } } },
14 | {$match: { 'email': { $ne: '' } } },
15 | {$match: { 'email': { $ne: null } } },
16 | {$match: { 'sendMonthlyEmail': true } },
17 | {$match: { 'email': { $not: /(test|fake)/i } } },
18 | {$group: { '_id': 1, 'emails': {$addToSet: '$email' } } }
19 | ], function(err, results) {
20 | if (err) { throw err; }
21 |
22 | console.log('\"email\"\n\"' + results[0].emails.join('\"\n\"') + '\"');
23 | process.exit(0);
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/server/views/partials/flash.jade:
--------------------------------------------------------------------------------
1 | .row.flashMessage
2 | .col-xs-12
3 | if (messages.errors || messages.error)
4 | .alert.alert-danger.fade.in
5 | button.close(type='button', data-dismiss='alert')
6 | span.ion-close-circled
7 | for error in (messages.errors || messages.error)
8 | div!= error.msg || error
9 | if messages.info
10 | .alert.alert-info.fade.in
11 | button.close(type='button', data-dismiss='alert')
12 | span.ion-close-circled
13 | for info in messages.info
14 | div!= info.msg
15 | if messages.success
16 | .alert.alert-success.fade.in
17 | button.close(type='button', data-dismiss='alert')
18 | span.ion-close-circled
19 | for success in messages.success
20 | div!= success.msg
21 |
--------------------------------------------------------------------------------
/client/less/lib/bootstrap/media.less:
--------------------------------------------------------------------------------
1 | .media {
2 | // Proper spacing between instances of .media
3 | margin-top: 15px;
4 |
5 | &:first-child {
6 | margin-top: 0;
7 | }
8 | }
9 |
10 | .media-right,
11 | .media > .pull-right {
12 | padding-left: 10px;
13 | }
14 |
15 | .media-left,
16 | .media > .pull-left {
17 | padding-right: 10px;
18 | }
19 |
20 | .media-left,
21 | .media-right,
22 | .media-body {
23 | display: table-cell;
24 | vertical-align: top;
25 | }
26 |
27 | .media-middle {
28 | vertical-align: middle;
29 | }
30 |
31 | .media-bottom {
32 | vertical-align: bottom;
33 | }
34 |
35 | // Reset margins on headings for tighter default spacing
36 | .media-heading {
37 | margin-top: 0;
38 | margin-bottom: 5px;
39 | }
40 |
41 | // Media list variation
42 | //
43 | // Undo default ul/ol styles
44 | .media-list {
45 | padding-left: 0;
46 | list-style: none;
47 | }
48 |
--------------------------------------------------------------------------------
/client/less/lib/bootstrap/component-animations.less:
--------------------------------------------------------------------------------
1 | //
2 | // Component animations
3 | // --------------------------------------------------
4 |
5 | // Heads up!
6 | //
7 | // We don't use the `.opacity()` mixin here since it causes a bug with text
8 | // fields in IE7-8. Source: https://github.com/twbs/bootstrap/pull/3552.
9 |
10 | .fade {
11 | opacity: 0;
12 | .transition(opacity .15s linear);
13 | &.in {
14 | opacity: 1;
15 | }
16 | }
17 |
18 | .collapse {
19 | display: none;
20 | visibility: hidden;
21 |
22 | &.in { display: block; visibility: visible; }
23 | tr&.in { display: table-row; }
24 | tbody&.in { display: table-row-group; }
25 | }
26 |
27 | .collapsing {
28 | position: relative;
29 | height: 0;
30 | overflow: hidden;
31 | .transition-property(~"height, visibility");
32 | .transition-duration(.35s);
33 | .transition-timing-function(ease);
34 | }
35 |
--------------------------------------------------------------------------------
/server/production-start.js:
--------------------------------------------------------------------------------
1 | // this ensures node understands the future
2 | require('babel-register');
3 |
4 | var startTime = Date.now();
5 | var timeoutHandler;
6 | // this is where server starts booting up
7 | var app = require('./server');
8 | console.log('waiting for db to connect');
9 |
10 |
11 | var onConnect = function() {
12 | console.log('db connected in %s ms', Date.now() - startTime);
13 | if (timeoutHandler) {
14 | clearTimeout(timeoutHandler);
15 | }
16 | app.start();
17 | };
18 |
19 | var timeoutHandler = setTimeout(function() {
20 | var message =
21 | 'db did not after ' +
22 | (Date.now() - startTime) +
23 | ' ms connect crashing hard';
24 |
25 | console.log(message);
26 | // purposely shutdown server
27 | // pm2 should restart this in production
28 | throw new Error(message);
29 | }, 15000);
30 |
31 | app.dataSources.db.on('connected', onConnect);
32 |
--------------------------------------------------------------------------------
/client/less/lib/font-awesome-4.3.0/less/animated.less:
--------------------------------------------------------------------------------
1 | // Animated Icons
2 | // --------------------------
3 |
4 | .@{fa-css-prefix}-spin {
5 | -webkit-animation: fa-spin 2s infinite linear;
6 | animation: fa-spin 2s infinite linear;
7 | }
8 |
9 | .@{fa-css-prefix}-pulse {
10 | -webkit-animation: fa-spin 1s infinite steps(8);
11 | animation: fa-spin 1s infinite steps(8);
12 | }
13 |
14 | @-webkit-keyframes fa-spin {
15 | 0% {
16 | -webkit-transform: rotate(0deg);
17 | transform: rotate(0deg);
18 | }
19 | 100% {
20 | -webkit-transform: rotate(359deg);
21 | transform: rotate(359deg);
22 | }
23 | }
24 |
25 | @keyframes fa-spin {
26 | 0% {
27 | -webkit-transform: rotate(0deg);
28 | transform: rotate(0deg);
29 | }
30 | 100% {
31 | -webkit-transform: rotate(359deg);
32 | transform: rotate(359deg);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/client/less/lib/font-awesome-4.3.0/scss/_animated.scss:
--------------------------------------------------------------------------------
1 | // Spinning Icons
2 | // --------------------------
3 |
4 | .#{$fa-css-prefix}-spin {
5 | -webkit-animation: fa-spin 2s infinite linear;
6 | animation: fa-spin 2s infinite linear;
7 | }
8 |
9 | .#{$fa-css-prefix}-pulse {
10 | -webkit-animation: fa-spin 1s infinite steps(8);
11 | animation: fa-spin 1s infinite steps(8);
12 | }
13 |
14 | @-webkit-keyframes fa-spin {
15 | 0% {
16 | -webkit-transform: rotate(0deg);
17 | transform: rotate(0deg);
18 | }
19 | 100% {
20 | -webkit-transform: rotate(359deg);
21 | transform: rotate(359deg);
22 | }
23 | }
24 |
25 | @keyframes fa-spin {
26 | 0% {
27 | -webkit-transform: rotate(0deg);
28 | transform: rotate(0deg);
29 | }
30 | 100% {
31 | -webkit-transform: rotate(359deg);
32 | transform: rotate(359deg);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/pm2Start.js:
--------------------------------------------------------------------------------
1 | require('dotenv').load();
2 | var pm2 = require('pm2');
3 | var nodemailer = require('nodemailer');
4 | var moment = require('moment-timezone');
5 | var _ = require('lodash');
6 |
7 | var instances = process.env.INSTANCES || 1;
8 | var serverName = process.env.SERVER_NAME || 'server';
9 | var maxMemory = process.env.MAX_MEMORY || '590M';
10 |
11 |
12 | var mailReceiver = process.env.MAIL_RECEIVER || false;
13 |
14 | pm2.connect(function() {
15 | pm2.start({
16 | name: serverName,
17 | script: 'server/production-start.js',
18 | 'exec_mode': 'cluster',
19 | instances: instances,
20 | 'max_memory_restart': maxMemory,
21 | 'NODE_ENV': 'production'
22 | }, function() {
23 | console.log(
24 | 'pm2 started %s with %s instances at %s max memory',
25 | serverName,
26 | instances,
27 | maxMemory
28 | );
29 | pm2.disconnect();
30 | });
31 | });
32 |
--------------------------------------------------------------------------------
/server/views/certificate/font.jade:
--------------------------------------------------------------------------------
1 | style.
2 | @font-face {
3 | font-family: "Sax Mono";
4 | src: url("/fonts/saxmono.ttf") format("truetype");
5 | }
6 |
7 | body {
8 | display: inline-block;
9 | font-family: "Sax Mono", monospace;
10 | margin: 0;
11 | position: absolute;
12 | text-align: center;
13 | }
14 |
15 | .img-abs {
16 | left 0;
17 | position: relative;
18 | top: 0;
19 | width: 2000px
20 | }
21 |
22 | .cert-name {
23 | font-size: 64px;
24 | left: 1000px;
25 | position: absolute;
26 | top: 704px;
27 | z-index: 1000;
28 | }
29 |
30 | .cert-date {
31 | font-size: 60px;
32 | left: 760px;
33 | position: absolute;
34 | top: 1004.8px;
35 | z-index: 1000;
36 | }
37 |
38 | .cert-link {
39 | font-size: 22px;
40 | left: 120px;
41 | position: absolute;
42 | top: 1488px;
43 | z-index: 1000;
44 | }
45 |
46 |
--------------------------------------------------------------------------------
/common/app/redux/reducer.js:
--------------------------------------------------------------------------------
1 | import { handleActions } from 'redux-actions';
2 | import types from './types';
3 |
4 | export default handleActions(
5 | {
6 | [types.updateTitle]: (state, { payload = 'Learn To Code' }) => ({
7 | ...state,
8 | title: payload + ' | Free Code Camp'
9 | }),
10 |
11 | [types.makeToast]: (state, { payload: toast }) => ({
12 | ...state,
13 | toast
14 | }),
15 |
16 | [types.setUser]: (state, { payload: user }) => ({ ...state, ...user }),
17 |
18 | [types.challengeSaved]: (state, { payload: { points = 0 } }) => ({
19 | ...state,
20 | points
21 | }),
22 |
23 | [types.updatePoints]: (state, { payload: points }) => ({
24 | ...state,
25 | points
26 | })
27 | },
28 | {
29 | title: 'Learn To Code | Free Code Camp',
30 | username: null,
31 | picture: null,
32 | points: 0,
33 | isSignedIn: false
34 | }
35 | );
36 |
--------------------------------------------------------------------------------
/public/favicons/android-chrome-manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "App",
3 | "icons": [
4 | {
5 | "src": "\/android-icon-36x36.png",
6 | "sizes": "36x36",
7 | "type": "image\/png",
8 | "density": "0.75"
9 | },
10 | {
11 | "src": "\/android-icon-48x48.png",
12 | "sizes": "48x48",
13 | "type": "image\/png",
14 | "density": "1.0"
15 | },
16 | {
17 | "src": "\/android-icon-72x72.png",
18 | "sizes": "72x72",
19 | "type": "image\/png",
20 | "density": "1.5"
21 | },
22 | {
23 | "src": "\/android-icon-96x96.png",
24 | "sizes": "96x96",
25 | "type": "image\/png",
26 | "density": "2.0"
27 | },
28 | {
29 | "src": "\/android-icon-144x144.png",
30 | "sizes": "144x144",
31 | "type": "image\/png",
32 | "density": "3.0"
33 | },
34 | {
35 | "src": "\/android-icon-192x192.png",
36 | "sizes": "192x192",
37 | "type": "image\/png",
38 | "density": "4.0"
39 | }
40 | ]
41 | }
--------------------------------------------------------------------------------
/common/app/routes/Jobs/redux/save-job-saga.js:
--------------------------------------------------------------------------------
1 | import { push } from 'react-router-redux';
2 | import { Observable } from 'rx';
3 |
4 | import { saveCompleted } from './actions';
5 | import { saveJob } from './types';
6 |
7 | import { handleError } from '../../../redux/types';
8 |
9 | export default ({ services }) => ({ dispatch }) => next => {
10 | return function saveJobSaga(action) {
11 | const result = next(action);
12 | if (action.type !== saveJob) {
13 | return result;
14 | }
15 | const { payload: job } = action;
16 |
17 | return services.createService$({
18 | service: 'jobs',
19 | params: { job }
20 | })
21 | .retry(3)
22 | .flatMap(job => Observable.of(
23 | saveCompleted(job),
24 | push('/jobs/new/check-out')
25 | ))
26 | .catch(error => Observable.just({
27 | type: handleError,
28 | error
29 | }))
30 | .doOnNext(dispatch);
31 | };
32 | };
33 |
--------------------------------------------------------------------------------
/client/less/lib/bootstrap/thumbnails.less:
--------------------------------------------------------------------------------
1 | //
2 | // Thumbnails
3 | // --------------------------------------------------
4 |
5 |
6 | // Mixin and adjust the regular image class
7 | .thumbnail {
8 | display: block;
9 | padding: @thumbnail-padding;
10 | margin-bottom: @line-height-computed;
11 | line-height: @line-height-base;
12 | background-color: @thumbnail-bg;
13 | border: 1px solid @thumbnail-border;
14 | border-radius: @thumbnail-border-radius;
15 | .transition(border .2s ease-in-out);
16 |
17 | > img,
18 | a > img {
19 | &:extend(.img-responsive);
20 | margin-left: auto;
21 | margin-right: auto;
22 | }
23 |
24 | // Add a hover state for linked versions only
25 | a&:hover,
26 | a&:focus,
27 | a&.active {
28 | border-color: @link-color;
29 | }
30 |
31 | // Image captions
32 | .caption {
33 | padding: @thumbnail-caption-padding;
34 | color: @thumbnail-caption-color;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/common/app/routes/Jobs/index.js:
--------------------------------------------------------------------------------
1 | import Jobs from './components/Jobs.jsx';
2 | import NewJob from './components/NewJob.jsx';
3 | import Show from './components/Show.jsx';
4 | import Preview from './components/Preview.jsx';
5 | import JobTotal from './components/JobTotal.jsx';
6 | import NewJobCompleted from './components/NewJobCompleted.jsx';
7 |
8 | /*
9 | * index: /jobs list jobs
10 | * show: /jobs/:id show one job
11 | * create /jobs/new create a new job
12 | */
13 |
14 | export default {
15 | childRoutes: [{
16 | path: '/jobs',
17 | component: Jobs
18 | }, {
19 | path: 'jobs/new',
20 | component: NewJob
21 | }, {
22 | path: 'jobs/new/preview',
23 | component: Preview
24 | }, {
25 | path: 'jobs/new/check-out',
26 | component: JobTotal
27 | }, {
28 | path: 'jobs/new/completed',
29 | component: NewJobCompleted
30 | }, {
31 | path: 'jobs/:id',
32 | component: Show
33 | }]
34 | };
35 |
--------------------------------------------------------------------------------
/client/commonFramework/display-test-results.js:
--------------------------------------------------------------------------------
1 | window.common = (function({ $, common = { init: [] }}) {
2 |
3 | common.displayTestResults = function displayTestResults(data = []) {
4 | $('#testSuite').children().remove();
5 | data.forEach(({ err = false, text = '' }) => {
6 | var iconClass = err ?
7 | '"ion-close-circled big-error-icon"' :
8 | '"ion-checkmark-circled big-success-icon"';
9 |
10 | $('
').html(`
11 |
12 |
13 |
14 |
15 |
16 | ${text.split('message: ').pop().replace(/\'\);/g, '')}
17 |
18 |
19 |
20 | `)
21 | .appendTo($('#testSuite'));
22 | });
23 |
24 | return data;
25 | };
26 |
27 | return common;
28 | }(window));
29 |
--------------------------------------------------------------------------------
/common/app/utils/shallow-equals.js:
--------------------------------------------------------------------------------
1 | // original sourc
2 | // https://github.com/rackt/react-redux/blob/master/src/utils/shallowEqual.js
3 | // MIT license
4 | export default function shallowEqual(objA, objB) {
5 | if (objA === objB) {
6 | return true;
7 | }
8 |
9 | if (
10 | typeof objA !== 'object' ||
11 | objA === null ||
12 | typeof objB !== 'object' ||
13 | objB === null
14 | ) {
15 | return false;
16 | }
17 |
18 | var keysA = Object.keys(objA);
19 | var keysB = Object.keys(objB);
20 |
21 | if (keysA.length !== keysB.length) {
22 | return false;
23 | }
24 |
25 | // Test for A's keys different from B.
26 | var bHasOwnProperty = Object.prototype.hasOwnProperty.bind(objB);
27 | for (var i = 0; i < keysA.length; i++) {
28 | if (
29 | !bHasOwnProperty(keysA[i]) ||
30 | objA[keysA[i]] !== objB[keysA[i]]
31 | ) {
32 | return false;
33 | }
34 | }
35 |
36 | return true;
37 | }
38 |
--------------------------------------------------------------------------------
/server/services/hikes.js:
--------------------------------------------------------------------------------
1 | import debugFactory from 'debug';
2 | import assign from 'object.assign';
3 |
4 | const debug = debugFactory('fcc:services:hikes');
5 |
6 | export default function hikesService(app) {
7 | const Challenge = app.models.Challenge;
8 |
9 | return {
10 | name: 'hikes',
11 | read: (req, resource, { dashedName } = {}, config, cb) => {
12 | const query = {
13 | where: { challengeType: '6' },
14 | order: ['order ASC', 'suborder ASC' ]
15 | };
16 |
17 | debug('dashedName', dashedName);
18 | if (dashedName) {
19 | assign(query.where, {
20 | dashedName: { like: dashedName, options: 'i' }
21 | });
22 | }
23 | debug('query', query);
24 | Challenge.find(query, (err, hikes) => {
25 | if (err) {
26 | return cb(err);
27 | }
28 | return cb(null, hikes.map(hike => hike.toJSON()));
29 | });
30 | }
31 | };
32 | }
33 |
--------------------------------------------------------------------------------
/common/app/routes/Jobs/components/JobNotFound.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { LinkContainer } from 'react-router-bootstrap';
3 | import { Button, Row, Col } from 'react-bootstrap';
4 |
5 | export default class extends React.Component {
6 | static displayName = 'NoJobFound';
7 |
8 | shouldComponentUpdate() {
9 | return false;
10 | }
11 |
12 | render() {
13 | return (
14 |
15 |
16 |
19 |
20 | No job found...
21 |
22 |
26 | Go to the job board
27 |
28 |
29 |
30 |
31 |
32 |
33 | );
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/server/boot/explorer.js:
--------------------------------------------------------------------------------
1 | module.exports = function mountLoopBackExplorer(app) {
2 | if (process.env.NODE_ENV === 'production') {
3 | return;
4 | }
5 | var explorer;
6 | try {
7 | explorer = require('loopback-component-explorer');
8 | } catch (err) {
9 | // Print the message only when the app was started via `app.listen()`.
10 | // Do not print any message when the project is used as a component.
11 | app.once('started', function() {
12 | console.log(
13 | 'Run `npm install loopback-component-explorer` to enable ' +
14 | 'the LoopBack explorer'
15 | );
16 | });
17 | return;
18 | }
19 |
20 | var restApiRoot = app.get('restApiRoot');
21 | var mountPath = '/explorer';
22 |
23 | explorer(app, { basePath: restApiRoot, mountPath });
24 | app.once('started', function() {
25 | var baseUrl = app.get('url').replace(/\/$/, '');
26 |
27 | console.log('Browse your REST API at %s%s', baseUrl, mountPath);
28 | });
29 | };
30 |
--------------------------------------------------------------------------------
/common/app/redux/actions.js:
--------------------------------------------------------------------------------
1 | import { createAction } from 'redux-actions';
2 | import types from './types';
3 |
4 | // updateTitle(title: String) => Action
5 | export const updateTitle = createAction(types.updateTitle);
6 |
7 | let id = 0;
8 | // makeToast({ type?: String, message: String, title: String }) => Action
9 | export const makeToast = createAction(
10 | types.makeToast,
11 | toast => {
12 | id += 1;
13 | return {
14 | ...toast,
15 | id,
16 | type: toast.type || 'info'
17 | };
18 | }
19 | );
20 |
21 | // fetchUser() => Action
22 | // used in combination with fetch-user-saga
23 | export const fetchUser = createAction(types.fetchUser);
24 |
25 | // setUser(userInfo: Object) => Action
26 | export const setUser = createAction(types.setUser);
27 |
28 | // updatePoints(points: Number) => Action
29 | export const updatePoints = createAction(types.updatePoints);
30 |
31 | // hardGoTo(path: String) => Action
32 | export const hardGoTo = createAction(types.hardGoTo);
33 |
--------------------------------------------------------------------------------
/common/app/routes/Hikes/components/Map.jsx:
--------------------------------------------------------------------------------
1 | import React, { PropTypes } from 'react';
2 | import { Link } from 'react-router';
3 | import { ListGroup, ListGroupItem } from 'react-bootstrap';
4 |
5 | export default React.createClass({
6 | displayName: 'HikesMap',
7 |
8 | propTypes: {
9 | hikes: PropTypes.array
10 | },
11 |
12 | render() {
13 | const {
14 | hikes = [{}]
15 | } = this.props;
16 |
17 | const vidElements = hikes.map(({ title, dashedName }) => {
18 | return (
19 |
20 |
21 | { title }
22 |
23 |
24 | );
25 | });
26 |
27 | return (
28 |
29 |
30 |
Welcome To Hikes!
31 |
32 |
33 |
34 | { vidElements }
35 |
36 |
37 | );
38 | }
39 | });
40 |
--------------------------------------------------------------------------------
/server/views/stories/index.jade:
--------------------------------------------------------------------------------
1 | extends ../layout
2 | block content
3 | if (user)
4 | script.
5 | var isLoggedIn = true;
6 | var userId = !{JSON.stringify(user.id)};
7 | var username = !{JSON.stringify(user.username)};
8 | else
9 | script.
10 | var isLoggedIn = false;
11 | script.
12 | var challengeName = 'Camper News';
13 | var page = !{JSON.stringify(page)};
14 | h1.text-center Camper News
15 | hr
16 | .spacer
17 | include news-nav
18 | .spacer
19 | if (page === 'hot')
20 | include hot-stories
21 | if (page === 'submit')
22 | if (user)
23 | include preliminary-submit
24 | else
25 | .spacer
26 | .text-center
27 | a.btn.btn-cta.signup-btn.btn-primary(href="/login") Sign in to post your story (it's free)
28 | .spacer
29 | if (page === 'storySubmission')
30 | include submit-story
31 | if (page === 'show')
32 | include show
33 |
--------------------------------------------------------------------------------
/client/less/lib/ionicons/_ionicons-font.less:
--------------------------------------------------------------------------------
1 | // Ionicons Font Path
2 | // --------------------------
3 |
4 | @font-face {
5 | font-family: @ionicons-font-family;
6 | src:url("@{ionicons-font-path}/ionicons.eot?v=@{ionicons-version}");
7 | src:url("@{ionicons-font-path}/ionicons.eot?v=@{ionicons-version}#iefix") format("embedded-opentype"),
8 | url("@{ionicons-font-path}/ionicons.ttf?v=@{ionicons-version}") format("truetype"),
9 | url("@{ionicons-font-path}/ionicons.woff?v=@{ionicons-version}") format("woff"),
10 | url("@{ionicons-font-path}/ionicons.svg?v=@{ionicons-version}#Ionicons") format("svg");
11 | font-weight: normal;
12 | font-style: normal;
13 | }
14 |
15 | .ion {
16 | display: inline-block;
17 | font-family: @ionicons-font-family;
18 | speak: none;
19 | font-style: normal;
20 | font-weight: normal;
21 | font-variant: normal;
22 | text-transform: none;
23 | text-rendering: auto;
24 | line-height: 1;
25 | -webkit-font-smoothing: antialiased;
26 | -moz-osx-font-smoothing: grayscale;
27 | }
--------------------------------------------------------------------------------
/server/boot/redirects.js:
--------------------------------------------------------------------------------
1 | module.exports = function(app) {
2 | var router = app.loopback.Router();
3 |
4 | router.get('/nonprofit-project-instructions', function(req, res) {
5 | res.redirect(
6 | 301,
7 | '//github.com/FreeCodeCamp/freecodecamp/wiki/' +
8 | "How-Free-Code-Camp's-Nonprofit-Projects-work"
9 | );
10 | });
11 |
12 | router.get('/agile', function(req, res) {
13 | res.redirect(301, '/pmi-acp-agile-project-managers');
14 | });
15 |
16 | router.get('/privacy', function(req, res) {
17 | res.redirect(
18 | 301,
19 | '//github.com/FreeCodeCamp/freecodecamp/wiki/' +
20 | "Free-Code-Camp's-Privacy-Policy"
21 | );
22 | });
23 |
24 | router.get('/learn-to-code', function(req, res) {
25 | res.redirect(301, '/map');
26 | });
27 |
28 | router.get('/field-guide/*', function(req, res) {
29 | res.redirect(302, '/wiki');
30 | });
31 |
32 | router.get('/about', function(req, res) {
33 | res.redirect(301, '/map');
34 | });
35 |
36 | app.use(router);
37 | };
38 |
--------------------------------------------------------------------------------
/server/utils/bad-id-map.js:
--------------------------------------------------------------------------------
1 | export default {
2 | bg9997c9c79feddfaeb9bdef: '56bbb991ad1ed5201cd392ca',
3 | bg9995c9c69feddfaeb9bdef: '56bbb991ad1ed5201cd392cb',
4 | bg9994c9c69feddfaeb9bdef: '56bbb991ad1ed5201cd392cc',
5 | bg9996c9c69feddfaeb9bdef: '56bbb991ad1ed5201cd392cd',
6 | bg9997c9c69feddfaeb9bdef: '56bbb991ad1ed5201cd392ce',
7 | bg9997c9c89feddfaeb9bdef: '56bbb991ad1ed5201cd392cf',
8 | bg9998c9c99feddfaeb9bdef: '56bbb991ad1ed5201cd392d0',
9 | bg9999c9c99feddfaeb9bdef: '56bbb991ad1ed5201cd392d1',
10 | bg9999c9c99feedfaeb9bdef: '56bbb991ad1ed5201cd392d2',
11 | bg9999c9c99fdddfaeb9bdef: '56bbb991ad1ed5201cd392d3',
12 | bb000000000000000000001: '56bbb991ad1ed5201cd392d4',
13 | bc000000000000000000001: '56bbb991ad1ed5201cd392d5',
14 | bb000000000000000000002: '56bbb991ad1ed5201cd392d6',
15 | bb000000000000000000003: '56bbb991ad1ed5201cd392d7',
16 | bb000000000000000000004: '56bbb991ad1ed5201cd392d8',
17 | bb000000000000000000005: '56bbb991ad1ed5201cd392d9',
18 | bb000000000000000000006: '56bbb991ad1ed5201cd392da'
19 | };
20 |
--------------------------------------------------------------------------------
/server/views/partials/react-stylesheets.jade:
--------------------------------------------------------------------------------
1 | link(rel='stylesheet', type='text/css' href='/css/lato.css')
2 | link(rel='stylesheet', href='/bower_components/font-awesome/css/font-awesome.min.css')
3 | link(rel='stylesheet', href=rev('/css', 'main.css'))
4 | link(rel='stylesheet', href='/css/Vimeo.css')
5 |
6 | include meta
7 | meta(charset='utf-8')
8 | meta(http-equiv='X-UA-Compatible', content='IE=edge')
9 | meta(name='viewport', content='width=device-width, initial-scale=1.0')
10 | meta(name='csrf-token', content=_csrf)
11 | script.
12 | var _vds = _vds || [];
13 | window._vds = _vds;
14 | (function(){
15 | _vds.push(['setAccountId', 'b350d488f8e3e5f1']);
16 | (function() {
17 | var vds = document.createElement('script');
18 | vds.type='text/javascript';
19 | vds.async = true;
20 | vds.src = ('https:' == document.location.protocol ? 'https://' : 'http://') + 'dn-growing.qbox.me/vds.js';
21 | var s = document.getElementsByTagName('script')[0];
22 | s.parentNode.insertBefore(vds, s);
23 | })();
24 | })();
25 |
--------------------------------------------------------------------------------
/client/commonFramework/run-tests-stream.js:
--------------------------------------------------------------------------------
1 | window.common = (function(global) {
2 | const {
3 | Rx: { Observable },
4 | chai,
5 | common = { init: [] }
6 | } = global;
7 |
8 | common.runTests$ = function runTests$({
9 | code,
10 | originalCode,
11 | userTests,
12 | ...rest
13 | }) {
14 |
15 | return Observable.from(userTests)
16 | .map(function(test) {
17 |
18 | /* eslint-disable no-unused-vars */
19 | const assert = chai.assert;
20 | const editor = { getValue() { return originalCode; }};
21 | /* eslint-enable no-unused-vars */
22 |
23 | try {
24 | if (test) {
25 | /* eslint-disable no-eval */
26 | eval(common.reassembleTest(code, test));
27 | /* eslint-enable no-eval */
28 | }
29 | } catch (e) {
30 | test.err = e.message;
31 | }
32 |
33 | return test;
34 | })
35 | .toArray()
36 | .map(tests => ({ ...rest, tests }));
37 | };
38 |
39 | return common;
40 | }(window));
41 |
--------------------------------------------------------------------------------
/client/less/lib/bootstrap/utilities.less:
--------------------------------------------------------------------------------
1 | //
2 | // Utility classes
3 | // --------------------------------------------------
4 |
5 |
6 | // Floats
7 | // -------------------------
8 |
9 | .clearfix {
10 | .clearfix();
11 | }
12 | .center-block {
13 | .center-block();
14 | }
15 | .pull-right {
16 | float: right !important;
17 | }
18 | .pull-left {
19 | float: left !important;
20 | }
21 |
22 |
23 | // Toggling content
24 | // -------------------------
25 |
26 | // Note: Deprecated .hide in favor of .hidden or .sr-only (as appropriate) in v3.0.1
27 | .hide {
28 | display: none !important;
29 | }
30 | .show {
31 | display: block !important;
32 | }
33 | .invisible {
34 | visibility: hidden;
35 | }
36 | .text-hide {
37 | .text-hide();
38 | }
39 |
40 |
41 | // Hide from screenreaders and browsers
42 | //
43 | // Credit: HTML5 Boilerplate
44 |
45 | .hidden {
46 | display: none !important;
47 | visibility: hidden !important;
48 | }
49 |
50 |
51 | // For Affix plugin
52 | // -------------------------
53 |
54 | .affix {
55 | position: fixed;
56 | }
57 |
--------------------------------------------------------------------------------
/common/app/utils/Professor-Context.js:
--------------------------------------------------------------------------------
1 | import React, { Children, PropTypes } from 'react';
2 |
3 | class ProfessorContext extends React.Component {
4 | constructor(props) {
5 | super(props);
6 | this.professor = props.professor;
7 | }
8 | static displayName = 'ProfessorContext';
9 |
10 | static propTypes = {
11 | professor: PropTypes.object,
12 | children: PropTypes.element.isRequired
13 | };
14 |
15 | static childContextTypes = {
16 | professor: PropTypes.object
17 | };
18 |
19 | getChildContext() {
20 | return { professor: this.professor };
21 | }
22 |
23 | render() {
24 | return Children.only(this.props.children);
25 | }
26 | }
27 |
28 | /* eslint-disable react/display-name, react/prop-types */
29 | ProfessorContext.wrap = function wrap(Component, professor) {
30 | const props = {};
31 | if (professor) {
32 | props.professor = professor;
33 | }
34 |
35 | return React.createElement(
36 | ProfessorContext,
37 | props,
38 | Component
39 | );
40 | };
41 |
42 | export default ProfessorContext;
43 |
--------------------------------------------------------------------------------
/server/utils/rx.js:
--------------------------------------------------------------------------------
1 | import Rx from 'rx';
2 | import debugFactory from 'debug';
3 |
4 | const debug = debugFactory('fcc:rxUtils');
5 |
6 | export function saveInstance(instance) {
7 | return new Rx.Observable.create(function(observer) {
8 | if (!instance || typeof instance.save !== 'function') {
9 | debug('no instance or save method');
10 | observer.onNext();
11 | return observer.onCompleted();
12 | }
13 | return instance.save(function(err, savedInstance) {
14 | if (err) {
15 | return observer.onError(err);
16 | }
17 | debug('instance saved');
18 | observer.onNext(savedInstance);
19 | return observer.onCompleted();
20 | });
21 | });
22 | }
23 |
24 | // alias saveInstance
25 | export const saveUser = saveInstance;
26 |
27 | export function observeQuery(Model, method, query) {
28 | return Rx.Observable.fromNodeCallback(Model[method], Model)(query);
29 | }
30 |
31 | export function observeMethod(context, methodName) {
32 | return Rx.Observable.fromNodeCallback(context[methodName], context);
33 | }
34 |
--------------------------------------------------------------------------------
/server/views/account/email-signup.jade:
--------------------------------------------------------------------------------
1 | extends ../layout
2 | block content
3 | script.
4 | var challengeName = 'Email Signup'
5 | h2.text-center 账户注册:
6 | form.form-horizontal(method='POST', action='/api/users', name="signupForm")
7 | .row
8 | .col-sm-6.col-sm-offset-3
9 | input(type='hidden', name='_csrf', value=_csrf)
10 | .form-group
11 | input.input-lg.form-control(type='email', name='email', id='email', placeholder='邮箱', autofocus, required, autocomplete="off")
12 | .form-group
13 | input.input-lg.form-control(type='password', name='password', id='password', placeholder='密码', required, pattern=".{8,50}", title="密码长度为8-50之间")
14 | .form-group
15 | button.btn.btn-lg.btn-primary.btn-block(type='submit')
16 | span.ion-person-add
17 | | 注册
18 | br
19 | br
20 | br
21 | br
22 | br
23 | br
24 | br
25 | br
26 |
--------------------------------------------------------------------------------
/common/app/redux/fetch-user-saga.js:
--------------------------------------------------------------------------------
1 | import { Observable } from 'rx';
2 | import { handleError, setUser, fetchUser } from './types';
3 |
4 | export default ({ services }) => ({ dispatch }) => next => {
5 | return function getUserSaga(action) {
6 | if (action.type !== fetchUser) {
7 | return next(action);
8 | }
9 |
10 | return services.readService$({ service: 'user' })
11 | .map(({
12 | username,
13 | picture,
14 | progressTimestamps = [],
15 | isFrontEndCert,
16 | isBackEndCert,
17 | isFullStackCert
18 | }) => {
19 | return {
20 | type: setUser,
21 | payload: {
22 | username,
23 | picture,
24 | points: progressTimestamps.length,
25 | isFrontEndCert,
26 | isBackEndCert,
27 | isFullStackCert,
28 | isSignedIn: true
29 | }
30 | };
31 | })
32 | .catch(error => Observable.just({
33 | type: handleError,
34 | error
35 | }))
36 | .doOnNext(dispatch);
37 | };
38 | };
39 |
40 |
--------------------------------------------------------------------------------
/server/middlewares/add-return-to.js:
--------------------------------------------------------------------------------
1 | const pathsOfNoReturn = [
2 | 'link',
3 | 'bower_components',
4 | 'auth',
5 | 'login',
6 | 'logout',
7 | 'signin',
8 | 'signup',
9 | 'fonts',
10 | 'favicon',
11 | 'js',
12 | 'css'
13 | ];
14 |
15 | const pathsWhiteList = [
16 | 'news',
17 | 'challenges',
18 | 'map',
19 | 'news',
20 | 'commit'
21 | ];
22 |
23 | const pathsOfNoReturnRegex = new RegExp(pathsOfNoReturn.join('|'), 'i');
24 | const whiteListRegex = new RegExp(pathsWhiteList.join('|'), 'i');
25 |
26 | export default function addReturnToUrl() {
27 | return function(req, res, next) {
28 | // Remember original destination before login.
29 | var path = req.path.split('/')[1];
30 |
31 | if (
32 | req.method !== 'GET' ||
33 | pathsOfNoReturnRegex.test(path) ||
34 | !whiteListRegex.test(path) ||
35 | (/news/i).test(path) && (/hot/i).test(req.path)
36 | ) {
37 | return next();
38 | }
39 | req.session.returnTo = req.originalUrl === '/map-aside' ?
40 | '/map' :
41 | req.originalUrl;
42 | return next();
43 | };
44 | }
45 |
--------------------------------------------------------------------------------
/server/services/job.js:
--------------------------------------------------------------------------------
1 | const whereFilt = {
2 | where: {
3 | isFilled: false,
4 | isPaid: true,
5 | isApproved: true
6 | },
7 | order: 'postedOn DESC'
8 | };
9 |
10 | export default function getJobServices(app) {
11 | const { Job } = app.models;
12 |
13 | return {
14 | name: 'jobs',
15 | create(req, resource, { job } = {}, body, config, cb) {
16 | if (!job) {
17 | return cb(new Error('job creation should get a job object'));
18 | }
19 |
20 | Object.assign(job, {
21 | isPaid: false,
22 | isApproved: false
23 | });
24 |
25 | return Job.create(job, (err, savedJob) => {
26 | cb(err, savedJob.toJSON());
27 | });
28 | },
29 | read(req, resource, params, config, cb) {
30 | const id = params ? params.id : null;
31 | if (id) {
32 | return Job.findById(id)
33 | .then(job => cb(null, job.toJSON()))
34 | .catch(cb);
35 | }
36 | return Job.find(whereFilt)
37 | .then(jobs => cb(null, jobs.map(job => job.toJSON())))
38 | .catch(cb);
39 | }
40 | };
41 | }
42 |
--------------------------------------------------------------------------------
/client/less/lib/bootstrap/pager.less:
--------------------------------------------------------------------------------
1 | //
2 | // Pager pagination
3 | // --------------------------------------------------
4 |
5 |
6 | .pager {
7 | padding-left: 0;
8 | margin: @line-height-computed 0;
9 | list-style: none;
10 | text-align: center;
11 | &:extend(.clearfix all);
12 | li {
13 | display: inline;
14 | > a,
15 | > span {
16 | display: inline-block;
17 | padding: 5px 14px;
18 | background-color: @pager-bg;
19 | border: 1px solid @pager-border;
20 | border-radius: @pager-border-radius;
21 | }
22 |
23 | > a:hover,
24 | > a:focus {
25 | text-decoration: none;
26 | background-color: @pager-hover-bg;
27 | }
28 | }
29 |
30 | .next {
31 | > a,
32 | > span {
33 | float: right;
34 | }
35 | }
36 |
37 | .previous {
38 | > a,
39 | > span {
40 | float: left;
41 | }
42 | }
43 |
44 | .disabled {
45 | > a,
46 | > a:hover,
47 | > a:focus,
48 | > span {
49 | color: @pager-disabled-color;
50 | background-color: @pager-bg;
51 | cursor: @cursor-disabled;
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/common/app/routes/Jobs/redux/apply-promo-saga.js:
--------------------------------------------------------------------------------
1 | import { Observable } from 'rx';
2 |
3 | import { applyPromo } from './types';
4 | import { applyPromoCompleted } from './actions';
5 | import { postJSON$ } from '../../../../utils/ajax-stream';
6 |
7 | export default () => ({ dispatch }) => next => {
8 | return function applyPromoSaga(action) {
9 | if (action.type !== applyPromo) {
10 | return next(action);
11 | }
12 |
13 | const { id, code = '', type = null } = action.payload;
14 |
15 | const body = {
16 | id,
17 | code: code.replace(/[^\d\w\s]/, '')
18 | };
19 |
20 | if (type) {
21 | body.type = type;
22 | }
23 |
24 | return postJSON$('/api/promos/getButton', body)
25 | .retry(3)
26 | .map(({ promo }) => {
27 | if (!promo || !promo.buttonId) {
28 | throw new Error('No promo returned by server');
29 | }
30 |
31 | return applyPromoCompleted(promo);
32 | })
33 | .catch(error => Observable.just({
34 | type: 'app.handleError',
35 | error
36 | }))
37 | .doOnNext(dispatch);
38 | };
39 | };
40 |
--------------------------------------------------------------------------------
/client/less/lib/font-awesome-4.3.0/less/mixins.less:
--------------------------------------------------------------------------------
1 | // Mixins
2 | // --------------------------
3 |
4 | .fa-icon() {
5 | display: inline-block;
6 | font: normal normal normal @fa-font-size-base/1 FontAwesome; // shortening font declaration
7 | font-size: inherit; // can't have font-size inherit on line above, so need to override
8 | text-rendering: auto; // optimizelegibility throws things off #1094
9 | -webkit-font-smoothing: antialiased;
10 | -moz-osx-font-smoothing: grayscale;
11 | transform: translate(0, 0); // ensures no half-pixel rendering in firefox
12 |
13 | }
14 |
15 | .fa-icon-rotate(@degrees, @rotation) {
16 | filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=@rotation);
17 | -webkit-transform: rotate(@degrees);
18 | -ms-transform: rotate(@degrees);
19 | transform: rotate(@degrees);
20 | }
21 |
22 | .fa-icon-flip(@horiz, @vert, @rotation) {
23 | filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=@rotation, mirror=1);
24 | -webkit-transform: scale(@horiz, @vert);
25 | -ms-transform: scale(@horiz, @vert);
26 | transform: scale(@horiz, @vert);
27 | }
28 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | var webpack = require('webpack');
2 | var path = require('path');
3 | var webpack = require('webpack');
4 |
5 | var __DEV__ = process.env.NODE_ENV !== 'production';
6 |
7 | module.exports = {
8 | entry: './client',
9 | output: {
10 | filename: 'bundle.js',
11 | path: path.join(__dirname, '/public/js'),
12 | publicPath: 'public/'
13 | },
14 | module: {
15 | loaders: [
16 | {
17 | test: /\.jsx?$/,
18 | include: [
19 | path.join(__dirname, 'client/'),
20 | path.join(__dirname, 'common/')
21 | ],
22 | loaders: [
23 | 'babel-loader'
24 | ]
25 | },
26 | {
27 | test: /\.json$/,
28 | loaders: [
29 | 'json-loader'
30 | ]
31 | }
32 | ]
33 | },
34 | plugins: [
35 | new webpack.optimize.DedupePlugin(),
36 | new webpack.optimize.OccurenceOrderPlugin(true),
37 | new webpack.DefinePlugin({
38 | 'process.env': {
39 | 'NODE_ENV': JSON.stringify(__DEV__ ? 'development' : 'production')
40 | },
41 | '__DEVTOOLS__': !__DEV__
42 | })
43 | ]
44 | };
45 |
--------------------------------------------------------------------------------
/server/views/resources/shop.jade:
--------------------------------------------------------------------------------
1 | extends ../layout
2 | block content
3 | h1.text-center Shop
4 | hr
5 | .row
6 | .col-xs-12.col-sm-8.col-sm-offset-2.col-md-6.col-md-offset-3.text-center
7 | img.img-responsive.img-center(src='//i.imgur.com/MH1CvwY.jpg')
8 | h3 Free Code Camp laptop stickers are here!
9 | h4 Get two for only $5, with free shipping anywhere!
10 | p These durable 2" (5 cm) stickers sport a matte finish, and look great anywhere - especially on your laptop.
11 | html.
12 |
18 |
--------------------------------------------------------------------------------
/client/less/lib/font-awesome-4.3.0/scss/_mixins.scss:
--------------------------------------------------------------------------------
1 | // Mixins
2 | // --------------------------
3 |
4 | @mixin fa-icon() {
5 | display: inline-block;
6 | font: normal normal normal #{$fa-font-size-base}/1 FontAwesome; // shortening font declaration
7 | font-size: inherit; // can't have font-size inherit on line above, so need to override
8 | text-rendering: auto; // optimizelegibility throws things off #1094
9 | -webkit-font-smoothing: antialiased;
10 | -moz-osx-font-smoothing: grayscale;
11 | transform: translate(0, 0); // ensures no half-pixel rendering in firefox
12 |
13 | }
14 |
15 | @mixin fa-icon-rotate($degrees, $rotation) {
16 | filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation});
17 | -webkit-transform: rotate($degrees);
18 | -ms-transform: rotate($degrees);
19 | transform: rotate($degrees);
20 | }
21 |
22 | @mixin fa-icon-flip($horiz, $vert, $rotation) {
23 | filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation});
24 | -webkit-transform: scale($horiz, $vert);
25 | -ms-transform: scale($horiz, $vert);
26 | transform: scale($horiz, $vert);
27 | }
28 |
--------------------------------------------------------------------------------
/server/boot/redirectHttps.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 | var loopback = require('loopback');
3 | var express = require('express');
4 |
5 | var port = 1337;
6 |
7 | // this will listen to traffic on port 1337
8 | // The purpose is to redirect any user who is direct to https
9 | // instead of http by mistake. Our nginx proxy server will listen
10 | // for https traffic and serve from this port on this server.
11 | // the view being send will have a short timeout and a redirect
12 | module.exports = function(loopbackApp) {
13 | var app = express();
14 | app.set('view engine', 'jade');
15 | // views in ../views'
16 | app.set('views', path.join(__dirname, '..'));
17 |
18 | // server static files
19 | app.use(loopback.static(path.join(
20 | __dirname,
21 | '../',
22 | '../public'
23 | )));
24 |
25 | // all traffic will be redirected on page load;
26 | app.use(function(req, res) {
27 | return res.render('views/redirect-https');
28 | });
29 |
30 | loopbackApp.once('started', function() {
31 | app.listen(port, function() {
32 | console.log('https redirect listening on port %s', port);
33 | });
34 | });
35 | };
36 |
--------------------------------------------------------------------------------
/server/views/resources/dashboard.jade:
--------------------------------------------------------------------------------
1 | extends ../layout
2 | block content
3 | style.
4 | table,th,td{
5 | padding-left: 5px;
6 | text-align:center;
7 | }
8 | tr:nth-child(even){
9 | background-color: #FAEBD7;
10 | }
11 | tr:nth-child(odd){
12 | background-color: white;
13 | }
14 | th, tr{
15 | padding:10px;
16 | }
17 | table{margin: 0 auto;}
18 | .row(ng-app="app")
19 | .col-md-12
20 | h2.text-center FCC同城学习小组
21 | if user
22 | table(ng-controller="dashboard")
23 | thead
24 | tr
25 | th id
26 | th 姓名
27 | th 邮箱
28 | th 手机号
29 | th 微信号
30 | th 地点
31 | th 背景
32 | tbody
33 | tr(ng-repeat="item in items")
34 | th {{item.username}}
35 | th {{item.fullname}}
36 | th {{item.email}}
37 | th {{item.telphone}}
38 | th {{item.wechat}}
39 | th {{item.location}}
40 | th {{item.background}}
41 | script(src="/js/angular.min.js")
42 | script(src="/js/dashboard.js")
43 |
--------------------------------------------------------------------------------
/public/js/lib/loop-protect/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 JS Bin Ltd
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/server/middlewares/revision-helpers.js:
--------------------------------------------------------------------------------
1 | import manifest from '../rev-manifest.json';
2 |
3 | const __DEV__ = process.env.NODE_ENV === 'development';
4 | const manifestPath = '../rev-manifest.json';
5 |
6 | export default function({ globalPrepend = '' } = {}) {
7 |
8 | function rev(manifest, scopedPrepend, asset) {
9 | return `${globalPrepend}${scopedPrepend}/${ manifest[asset] || asset }`;
10 | }
11 | const boundRev = rev.bind(null, manifest);
12 |
13 | return function(req, res, next) {
14 | // in dev environment, we reread the manifest on every call
15 | // this means we do not need to restart server on every change to
16 | // client code
17 | if (__DEV__) {
18 | // we first need to remove the manifest from require cache
19 | delete require.cache[require.resolve(manifestPath)];
20 | // and re-require
21 | const manifest = require(manifestPath);
22 | res.locals.rev = rev.bind(null, manifest);
23 | return next();
24 | }
25 |
26 | // in production we take use the initially loaded manifest
27 | // since this should not change in production
28 | res.locals.rev = boundRev;
29 | return next();
30 | };
31 | }
32 |
--------------------------------------------------------------------------------
/server/views/account/email-signin.jade:
--------------------------------------------------------------------------------
1 | extends ../layout
2 | block content
3 | .row
4 | .col-xs-12
5 | h2.text-center 账户登录:
6 | .col-sm-6.col-sm-offset-3
7 | form(method='POST', action='/api/users/login')
8 | input(type='hidden', name='_csrf', value=_csrf)
9 | .form-group
10 | input.input-lg.form-control(type='email', name='email', id='email', placeholder='邮箱', autofocus=true, autocomplete=false)
11 | .form-group
12 | input.input-lg.form-control(type='password', name='password', id='password', placeholder='密码', autocomplete=false)
13 | button.btn.btn-primary.btn-lg.btn-block(type='submit')
14 | span.ion-android-hand
15 | | 登录
16 | .button-spacer
17 | .button-spacer
18 | a.btn.btn-info.btn-lg.btn-block(href='/forgot') 忘记密码?
19 | br
20 | br
21 | br
22 | br
23 | br
24 | br
25 | br
26 | br
27 |
--------------------------------------------------------------------------------
/client/less/lib/bootstrap/jumbotron.less:
--------------------------------------------------------------------------------
1 | //
2 | // Jumbotron
3 | // --------------------------------------------------
4 |
5 |
6 | .jumbotron {
7 | padding: @jumbotron-padding (@jumbotron-padding / 2);
8 | margin-bottom: @jumbotron-padding;
9 | color: @jumbotron-color;
10 | background-color: @jumbotron-bg;
11 |
12 | h1,
13 | .h1 {
14 | color: @jumbotron-heading-color;
15 | }
16 | p {
17 | margin-bottom: (@jumbotron-padding / 2);
18 | font-size: @jumbotron-font-size;
19 | font-weight: 200;
20 | }
21 |
22 | > hr {
23 | border-top-color: darken(@jumbotron-bg, 10%);
24 | }
25 |
26 | .container &,
27 | .container-fluid & {
28 | border-radius: @border-radius-large; // Only round corners at higher resolutions if contained in a container
29 | }
30 |
31 | .container {
32 | max-width: 100%;
33 | }
34 |
35 | @media screen and (min-width: @screen-sm-min) {
36 | padding: (@jumbotron-padding * 1.6) 0;
37 |
38 | .container & {
39 | padding-left: (@jumbotron-padding * 2);
40 | padding-right: (@jumbotron-padding * 2);
41 | }
42 |
43 | h1,
44 | .h1 {
45 | font-size: (@font-size-base * 4.5);
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/common/app/components/Footer/links.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "className": "ion-speakerphone",
4 | "content": " Blog ",
5 | "href": "http://medium.freecodecamp.com",
6 | "target": "_blank"
7 | },
8 | {
9 | "className": "ion-social-twitch-outline",
10 | "content": " Twitch ",
11 | "href": "http://www.twitch.tv/freecodecamp",
12 | "target": "_blank"
13 | },
14 | {
15 | "className": "ion-social-github",
16 | "content": " Github ",
17 | "href": "http://github.com/freecodecamp",
18 | "target": "_blank"
19 | },
20 | {
21 | "className": "ion-social-twitter",
22 | "content": " Twitter ",
23 | "href": "http://twitter.com/freecodecamp",
24 | "target": "_blank"
25 | },
26 | {
27 | "className": "ion-social-facebook",
28 | "content": " Facebook ",
29 | "href": "http://facebook.com/freecodecamp",
30 | "target": "_blank"
31 | },
32 | {
33 | "className": "ion-information-circled",
34 | "content": " About ",
35 | "href": "/learn-to-code",
36 | "target": "_self"
37 | },
38 | {
39 | "className": "ion-locked",
40 | "content": " Privacy ",
41 | "href": "/privacy'",
42 | "target": "_self"
43 | }
44 | ]
45 |
--------------------------------------------------------------------------------
/common/app/routes/Jobs/redux/actions.js:
--------------------------------------------------------------------------------
1 | import { createAction } from 'redux-actions';
2 |
3 | import types from './types';
4 |
5 | export const fetchJobs = createAction(types.fetchJobs);
6 | export const fetchJobsCompleted = createAction(
7 | types.fetchJobsCompleted,
8 | (currentJob, jobs) => ({ currentJob, jobs })
9 | );
10 |
11 | export const findJob = createAction(types.findJob);
12 |
13 | // saves to database
14 | export const saveJob = createAction(types.saveJob);
15 | // saves to localStorage
16 | export const saveForm = createAction(types.saveForm);
17 |
18 | export const saveCompleted = createAction(types.saveCompleted);
19 |
20 | export const clearForm = createAction(types.clearForm);
21 |
22 | export const loadSavedForm = createAction(types.loadSavedForm);
23 | export const loadSavedFormCompleted = createAction(
24 | types.loadSavedFormCompleted
25 | );
26 |
27 | export const clearPromo = createAction(types.clearPromo);
28 | export const updatePromo = createAction(
29 | types.updatePromo,
30 | ({ target: { value = '' } = {} } = {}) => value
31 | );
32 |
33 | export const applyPromo = createAction(types.applyPromo);
34 | export const applyPromoCompleted = createAction(types.applyPromoCompleted);
35 |
--------------------------------------------------------------------------------
/common/app/routes/Jobs/components/NewJobCompleted.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { LinkContainer } from 'react-router-bootstrap';
3 | import { Button, Col, Row } from 'react-bootstrap';
4 |
5 | export default class extends React.createClass {
6 | static displayName = 'NewJobCompleted';
7 |
8 | render() {
9 | return (
10 |
11 |
12 |
13 |
14 | Your Position has Been Submitted
15 |
16 |
17 |
18 |
21 | We’ll review your listing and email you when it’s live.
22 |
23 | Thank you for listing this job with Free Code Camp.
24 |
25 |
26 |
27 |
28 |
32 | Go to the job board
33 |
34 |
35 |
36 |
37 | );
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/client/less/lib/bootstrap/mixins/image.less:
--------------------------------------------------------------------------------
1 | // Image Mixins
2 | // - Responsive image
3 | // - Retina image
4 |
5 |
6 | // Responsive image
7 | //
8 | // Keep images from scaling beyond the width of their parents.
9 | .img-responsive(@display: block) {
10 | display: @display;
11 | max-width: 100%; // Part 1: Set a maximum relative to the parent
12 | height: auto; // Part 2: Scale the height according to the width, otherwise you get stretching
13 | }
14 |
15 |
16 | // Retina image
17 | //
18 | // Short retina mixin for setting background-image and -size. Note that the
19 | // spelling of `min--moz-device-pixel-ratio` is intentional.
20 | .img-retina(@file-1x; @file-2x; @width-1x; @height-1x) {
21 | background-image: url("@{file-1x}");
22 |
23 | @media
24 | only screen and (-webkit-min-device-pixel-ratio: 2),
25 | only screen and ( min--moz-device-pixel-ratio: 2),
26 | only screen and ( -o-min-device-pixel-ratio: 2/1),
27 | only screen and ( min-device-pixel-ratio: 2),
28 | only screen and ( min-resolution: 192dpi),
29 | only screen and ( min-resolution: 2dppx) {
30 | background-image: url("@{file-2x}");
31 | background-size: @width-1x @height-1x;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/server/boot/about.js:
--------------------------------------------------------------------------------
1 | import dedent from 'dedent';
2 | import moment from 'moment';
3 |
4 | import { observeMethod } from '../utils/rx';
5 |
6 | function numberWithCommas(x) {
7 | return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
8 | }
9 |
10 | export default function about(app) {
11 | const router = app.loopback.Router();
12 | const User = app.models.User;
13 | const userCount$ = observeMethod(User, 'count');
14 |
15 | function showAbout(req, res, next) {
16 | const daysRunning = moment().diff(new Date('5/5/2016'), 'days');
17 |
18 | userCount$()
19 | .map(camperCount => numberWithCommas(camperCount))
20 | .doOnNext(camperCount => {
21 | res.render('resources/about', {
22 | camperCount,
23 | daysRunning,
24 | title: dedent`
25 | About our Open Source Community, our social media presence,
26 | and how to contact us`.split('\n').join(' '),
27 | globalCompletedCount: numberWithCommas(
28 | 12952 + (Math.floor((Date.now() - 1463557575258) / 18000))
29 | )
30 | });
31 | })
32 | .subscribe(() => {}, next);
33 | }
34 |
35 | router.get('/about', showAbout);
36 | app.use(router);
37 | }
38 |
--------------------------------------------------------------------------------
/common/models/pledge.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pledge",
3 | "base": "PersistedModel",
4 | "idInjection": true,
5 | "trackChanges": false,
6 | "properties": {
7 | "nonprofit": {
8 | "type": "string",
9 | "index": true
10 | },
11 | "amount": {
12 | "type": "number"
13 | },
14 | "dateStarted": {
15 | "type": "date",
16 | "defaultFn": "now"
17 | },
18 | "dateEnded": {
19 | "type": "date"
20 | },
21 | "formerUserId": {
22 | "type": "string"
23 | },
24 | "isOrphaned": {
25 | "type": "boolean"
26 | },
27 | "isCompleted": {
28 | "type": "boolean",
29 | "default": "false"
30 | }
31 | },
32 | "validations": [],
33 | "relations": {
34 | "user": {
35 | "type": "hasMany",
36 | "model": "user",
37 | "foreignKey": "userId"
38 | }
39 | },
40 | "acls": [
41 | {
42 | "accessType": "*",
43 | "principalType": "ROLE",
44 | "principalId": "$everyone",
45 | "permission": "DENY"
46 | },
47 | {
48 | "accessType": "READ",
49 | "principalType": "ROLE",
50 | "principalId": "$everyone",
51 | "permission": "ALLOW"
52 | }
53 | ],
54 | "methods": []
55 | }
56 |
--------------------------------------------------------------------------------
/client/less/lib/bootstrap/mixins.less:
--------------------------------------------------------------------------------
1 | // Mixins
2 | // --------------------------------------------------
3 |
4 | // Utilities
5 | @import "mixins/hide-text.less";
6 | @import "mixins/opacity.less";
7 | @import "mixins/image.less";
8 | @import "mixins/labels.less";
9 | @import "mixins/reset-filter.less";
10 | @import "mixins/resize.less";
11 | @import "mixins/responsive-visibility.less";
12 | @import "mixins/size.less";
13 | @import "mixins/tab-focus.less";
14 | @import "mixins/text-emphasis.less";
15 | @import "mixins/text-overflow.less";
16 | @import "mixins/vendor-prefixes.less";
17 |
18 | // Components
19 | @import "mixins/alerts.less";
20 | @import "mixins/buttons.less";
21 | @import "mixins/panels.less";
22 | @import "mixins/pagination.less";
23 | @import "mixins/list-group.less";
24 | @import "mixins/nav-divider.less";
25 | @import "mixins/forms.less";
26 | @import "mixins/progress-bar.less";
27 | @import "mixins/table-row.less";
28 |
29 | // Skins
30 | @import "mixins/background-variant.less";
31 | @import "mixins/border-radius.less";
32 | @import "mixins/gradients.less";
33 |
34 | // Layout
35 | @import "mixins/clearfix.less";
36 | @import "mixins/center-block.less";
37 | @import "mixins/nav-vertical-align.less";
38 | @import "mixins/grid-framework.less";
39 | @import "mixins/grid.less";
40 |
--------------------------------------------------------------------------------
/leanTest.js:
--------------------------------------------------------------------------------
1 | //Setup
2 | var contacts = [
3 | {
4 | "firstName": "Akira",
5 | "lastName": "Laine",
6 | "number": "0543236543",
7 | "likes": ["Pizza", "Coding", "Brownie Points"]
8 | },
9 | {
10 | "firstName": "Harry",
11 | "lastName": "Potter",
12 | "number": "0994372684",
13 | "likes": ["Hogwarts", "Magic", "Hagrid"]
14 | },
15 | {
16 | "firstName": "Sherlock",
17 | "lastName": "Holmes",
18 | "number": "0487345643",
19 | "likes": ["Intriguing Cases", "Violin"]
20 | },
21 | {
22 | "firstName": "Kristian",
23 | "lastName": "Vos",
24 | "number": "unknown",
25 | "likes": ["Javascript", "Gaming", "Foxes"]
26 | }
27 | ];
28 |
29 |
30 | function lookUp(firstName, prop){
31 | // Only change code below this line
32 | for(var i in contacts){
33 | if(contacts[i].firstName == firstName){
34 | if(contacts[i].hasOwnProperty(prop)){
35 | return contacts[i][prop];
36 | }else{
37 | return "No such property";
38 | }
39 | }else{
40 | return "No such contact";
41 | }
42 | }
43 | // Only change code above this line
44 | }
45 |
46 | // Change these values to test your function
47 | lookUp("Akira", "likes");
48 |
--------------------------------------------------------------------------------
/common/utils/services-creator.js:
--------------------------------------------------------------------------------
1 | import { Observable, Disposable } from 'rx';
2 | import Fetchr from 'fetchr';
3 | import stampit from 'stampit';
4 |
5 | function callbackObserver(observer) {
6 | return (err, res) => {
7 | if (err) {
8 | return observer.onError(err);
9 | }
10 |
11 | observer.onNext(res);
12 | return observer.onCompleted();
13 | };
14 | }
15 |
16 |
17 | export default stampit({
18 | init({ args: [ options ] }) {
19 | this.services = new Fetchr(options);
20 | },
21 | methods: {
22 | readService$({ service: resource, params, config }) {
23 | return Observable.create(observer => {
24 | this.services.read(
25 | resource,
26 | params,
27 | config,
28 | callbackObserver(observer)
29 | );
30 |
31 | return Disposable.create(() => observer.dispose());
32 | });
33 | },
34 | createService$({ service: resource, params, body, config }) {
35 | return Observable.create(observer => {
36 | this.services.create(
37 | resource,
38 | params,
39 | body,
40 | config,
41 | callbackObserver(observer)
42 | );
43 |
44 | return Disposable.create(() => observer.dispose());
45 | });
46 | }
47 | }
48 | });
49 |
--------------------------------------------------------------------------------
/common/app/routes/Jobs/redux/jobs-form-normalizer.js:
--------------------------------------------------------------------------------
1 | import normalizeUrl from 'normalize-url';
2 | import {
3 | inHTMLData,
4 | uriInSingleQuotedAttr
5 | } from 'xss-filters';
6 |
7 | const normalizeOptions = {
8 | stripWWW: false
9 | };
10 |
11 | function ifDefinedNormalize(normalizer) {
12 | return value => value ? normalizer(value) : value;
13 | }
14 |
15 | function formatUrl(url) {
16 | if (
17 | typeof url === 'string' &&
18 | url.length > 4 &&
19 | url.indexOf('.') !== -1
20 | ) {
21 | // prevent trailing / from being stripped during typing
22 | let lastChar = '';
23 | if (url.substring(url.length - 1) === '/') {
24 | lastChar = '/';
25 | }
26 | return normalizeUrl(url, normalizeOptions) + lastChar;
27 | }
28 | return url;
29 | }
30 |
31 | export default {
32 | NewJob: {
33 | position: ifDefinedNormalize(inHTMLData),
34 | locale: ifDefinedNormalize(inHTMLData),
35 | description: ifDefinedNormalize(inHTMLData),
36 | email: ifDefinedNormalize(inHTMLData),
37 | url: ifDefinedNormalize(value => formatUrl(uriInSingleQuotedAttr(value))),
38 | logo: ifDefinedNormalize(value => formatUrl(uriInSingleQuotedAttr(value))),
39 | company: ifDefinedNormalize(inHTMLData),
40 | howToApply: ifDefinedNormalize(inHTMLData)
41 | }
42 | };
43 |
--------------------------------------------------------------------------------
/common/app/components/Footer/Footer.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Col, Row, Grid } from 'react-bootstrap';
3 |
4 | import links from './links.json';
5 |
6 | export default class extends React.Component {
7 | static displayName = 'Footer';
8 | renderLinks(mobile) {
9 | return links.map(link => {
10 | return (
11 |
16 | { this.renderContent(mobile, link.content) }
17 |
18 | );
19 | });
20 | }
21 |
22 | renderContent(mobile, content) {
23 | if (mobile) {
24 | return (
25 |
26 | content;
27 |
28 | );
29 | }
30 | return content;
31 | }
32 |
33 | render() {
34 | return (
35 |
36 |
37 |
40 | { this.renderLinks() }
41 |
42 |
45 | { this.renderLinks(true) }
46 |
47 |
48 |
49 | );
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/public/favicons.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/client/less/lib/bootstrap/badges.less:
--------------------------------------------------------------------------------
1 | //
2 | // Badges
3 | // --------------------------------------------------
4 |
5 |
6 | // Base class
7 | .badge {
8 | display: inline-block;
9 | min-width: 10px;
10 | padding: 3px 7px;
11 | font-size: @font-size-small;
12 | font-weight: @badge-font-weight;
13 | color: @badge-color;
14 | line-height: @badge-line-height;
15 | vertical-align: baseline;
16 | white-space: nowrap;
17 | text-align: center;
18 | background-color: @badge-bg;
19 | border-radius: @badge-border-radius;
20 |
21 | // Empty badges collapse automatically (not available in IE8)
22 | &:empty {
23 | display: none;
24 | }
25 |
26 | // Quick fix for badges in buttons
27 | .btn & {
28 | position: relative;
29 | top: -1px;
30 | }
31 | .btn-xs & {
32 | top: 0;
33 | padding: 1px 5px;
34 | }
35 |
36 | // Hover state, but only for links
37 | a& {
38 | &:hover,
39 | &:focus {
40 | color: @badge-link-hover-color;
41 | text-decoration: none;
42 | cursor: pointer;
43 | }
44 | }
45 |
46 | // Account for badges in navs
47 | a.list-group-item.active > &,
48 | .nav-pills > .active > a > & {
49 | color: @badge-active-color;
50 | background-color: @badge-active-bg;
51 | }
52 | .nav-pills > li > a > & {
53 | margin-left: 3px;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/client/less/lib/bootstrap/mixins/buttons.less:
--------------------------------------------------------------------------------
1 | // Button variants
2 | //
3 | // Easily pump out default styles, as well as :hover, :focus, :active,
4 | // and disabled options for all buttons
5 |
6 | .button-variant(@color; @background; @border) {
7 | color: @color;
8 | background-color: @background;
9 | border-color: @border;
10 |
11 | &:hover,
12 | &:focus,
13 | &.focus,
14 | &:active,
15 | &.active,
16 | .open > .dropdown-toggle& {
17 | color: @gray-lighter;
18 | background-color: @background;
19 | border-color: darken(@border, 12%);
20 | }
21 | &:active,
22 | &.active,
23 | .open > .dropdown-toggle& {
24 | background-image: none;
25 | }
26 | &.disabled,
27 | &[disabled],
28 | fieldset[disabled] & {
29 | &,
30 | &:hover,
31 | &:focus,
32 | &.focus,
33 | &:active,
34 | &.active {
35 | background-color: @background;
36 | border-color: @border;
37 | }
38 | }
39 |
40 | .badge {
41 | color: @background;
42 | background-color: @color;
43 | }
44 | }
45 |
46 | // Button sizes
47 | .button-size(@padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) {
48 | padding: @padding-vertical @padding-horizontal;
49 | font-size: @font-size;
50 | line-height: @line-height;
51 | border-radius: @border-radius;
52 | }
53 |
--------------------------------------------------------------------------------
/webpack.config.node.js:
--------------------------------------------------------------------------------
1 | var fs = require('fs');
2 | var path = require('path');
3 | var webpack = require('webpack');
4 |
5 | var nodeModules = fs.readdirSync('node_modules')
6 | .filter(function(x) {
7 | return ['.bin'].indexOf(x) === -1;
8 | })
9 | .reduce(function(nodeModules, module) {
10 | nodeModules[module] = 'commonjs ' + module;
11 | return nodeModules;
12 | }, {});
13 |
14 | module.exports = {
15 | devtool: 'sourcemap',
16 | target: 'node',
17 | entry: './common/app',
18 | // keeps webpack from bundling modules
19 | externals: nodeModules,
20 | output: {
21 | filename: 'app-stream.bundle.js',
22 | path: path.join(__dirname, '/server'),
23 | publicPath: 'public/'
24 | },
25 | module: {
26 | loaders: [
27 | {
28 | test: /\.jsx?$/,
29 | include: [
30 | path.join(__dirname, 'client/'),
31 | path.join(__dirname, 'common/')
32 | ],
33 | loaders: [
34 | 'babel-loader'
35 | ]
36 | },
37 | {
38 | test: /\.json$/,
39 | loaders: [
40 | 'json-loader'
41 | ]
42 | }
43 | ]
44 | },
45 | plugins: [
46 | new webpack.BannerPlugin(
47 | 'require("source-map-support").install();',
48 | {
49 | raw: true,
50 | entryOnly: false
51 | }
52 | )
53 | ]
54 | };
55 |
--------------------------------------------------------------------------------
/client/less/lib/bootstrap/bootstrap.less:
--------------------------------------------------------------------------------
1 | // Core variables and mixins
2 | @import "variables.less";
3 | @import "mixins.less";
4 |
5 | // Reset and dependencies
6 | @import "normalize.less";
7 | @import "print.less";
8 | @import "glyphicons.less";
9 |
10 | // Core CSS
11 | @import "scaffolding.less";
12 | @import "type.less";
13 | @import "code.less";
14 | @import "grid.less";
15 | @import "tables.less";
16 | @import "forms.less";
17 | @import "buttons.less";
18 |
19 | // Components
20 | @import "component-animations.less";
21 | @import "dropdowns.less";
22 | @import "button-groups.less";
23 | @import "input-groups.less";
24 | @import "navs.less";
25 | @import "navbar.less";
26 | @import "breadcrumbs.less";
27 | @import "pagination.less";
28 | @import "pager.less";
29 | @import "labels.less";
30 | @import "badges.less";
31 | @import "jumbotron.less";
32 | @import "thumbnails.less";
33 | @import "alerts.less";
34 | @import "progress-bars.less";
35 | @import "media.less";
36 | @import "list-group.less";
37 | @import "panels.less";
38 | @import "responsive-embed.less";
39 | @import "wells.less";
40 | @import "close.less";
41 |
42 | // Components w/ JavaScript
43 | @import "modals.less";
44 | @import "tooltip.less";
45 | @import "popovers.less";
46 | @import "carousel.less";
47 |
48 | // Utility classes
49 | @import "utilities.less";
50 | @import "responsive-utilities.less";
51 |
--------------------------------------------------------------------------------
/server/views/partials/scripts.jade:
--------------------------------------------------------------------------------
1 |
2 | script.
3 | var _vds = _vds || [];
4 | window._vds = _vds;
5 | (function(){
6 | _vds.push(['setAccountId', 'b350d488f8e3e5f1']);
7 | (function() {
8 | var vds = document.createElement('script');
9 | vds.type='text/javascript';
10 | vds.async = true;
11 | vds.src = ('https:' == document.location.protocol ? 'https://' : 'http://') + 'dn-growing.qbox.me/vds.js';
12 | var s = document.getElementsByTagName('script')[0];
13 | s.parentNode.insertBefore(vds, s);
14 | })();
15 | })();
16 | (function(i,s,o,g,r,a,m){ i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
17 | (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
18 | m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
19 | })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
20 | ga('create', 'UA-76000773-1', 'auto');
21 | ga('require', 'displayfeatures');
22 | ga('send', 'pageview');
23 | // Leave the below lines alone!
24 | script.
25 | (function(global) {
26 | global.main = global.main || {};
27 | global.main.isLoggedIn = !{JSON.stringify(!!user)};
28 | global.main.userId = !{JSON.stringify(user && user.id || false)};
29 | }(window))
30 | script(src=rev('/js', 'vendor-main.js'))
31 | script(src=rev('/js', 'main.js'))
32 |
--------------------------------------------------------------------------------
/client/less/lib/bootstrap/labels.less:
--------------------------------------------------------------------------------
1 | //
2 | // Labels
3 | // --------------------------------------------------
4 |
5 | .label {
6 | display: inline;
7 | padding: .2em .6em .3em;
8 | font-size: 75%;
9 | font-weight: bold;
10 | line-height: 1;
11 | color: @label-color;
12 | text-align: center;
13 | white-space: nowrap;
14 | vertical-align: baseline;
15 | border-radius: .25em;
16 |
17 | // Add hover effects, but only for links
18 | a& {
19 | &:hover,
20 | &:focus {
21 | color: @label-link-hover-color;
22 | text-decoration: none;
23 | cursor: pointer;
24 | }
25 | }
26 |
27 | // Empty labels collapse automatically (not available in IE8)
28 | &:empty {
29 | display: none;
30 | }
31 |
32 | // Quick fix for labels in buttons
33 | .btn & {
34 | position: relative;
35 | top: -1px;
36 | }
37 | }
38 |
39 | // Colors
40 | // Contextual variations (linked labels get darker on :hover)
41 |
42 | .label-default {
43 | .label-variant(@label-default-bg);
44 | }
45 |
46 | .label-primary {
47 | .label-variant(@label-primary-bg);
48 | }
49 |
50 | .label-success {
51 | .label-variant(@label-success-bg);
52 | }
53 |
54 | .label-info {
55 | .label-variant(@label-info-bg);
56 | }
57 |
58 | .label-warning {
59 | .label-variant(@label-warning-bg);
60 | }
61 |
62 | .label-danger {
63 | .label-variant(@label-danger-bg);
64 | }
65 |
--------------------------------------------------------------------------------
/common/app/routes/Jobs/redux/fetch-jobs-saga.js:
--------------------------------------------------------------------------------
1 | import { Observable } from 'rx';
2 | import { normalize, Schema, arrayOf } from 'normalizr';
3 |
4 | import { fetchJobsCompleted } from './actions';
5 | import { fetchJobs } from './types';
6 | import { handleError } from '../../../redux/types';
7 |
8 | const job = new Schema('job', { idAttribute: 'id' });
9 |
10 | export default ({ services }) => ({ dispatch }) => next => {
11 | return function fetchJobsSaga(action) {
12 | if (action.type !== fetchJobs) {
13 | return next(action);
14 | }
15 |
16 | const { payload: id } = action;
17 | const data = { service: 'jobs' };
18 | if (id) {
19 | data.params = { id };
20 | }
21 |
22 | return services.readService$(data)
23 | .map(jobs => {
24 | if (!Array.isArray(jobs)) {
25 | jobs = [jobs];
26 | }
27 |
28 | const { entities, result } = normalize(
29 | { jobs },
30 | { jobs: arrayOf(job) }
31 | );
32 |
33 |
34 | return fetchJobsCompleted(
35 | result.jobs[0],
36 | {
37 | entities: entities.job,
38 | results: result.jobs
39 | }
40 | );
41 | })
42 | .catch(error => {
43 | return Observable.just({
44 | type: handleError,
45 | error
46 | });
47 | })
48 | .doOnNext(dispatch);
49 | };
50 | };
51 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ## FreeCodeCamp Pull Request template
2 | Please, go through these steps before you submit a PR.
3 |
4 | 1. Make sure that your PR is not a duplicate.
5 | 2. If not, then make sure that:
6 |
7 | 2.1. You have done your changes in a separate branch. Branches MUST have descriptive names that start with either the `fix/` or `feature/` prefixes. Good examples are: `fix/signin-issue` or `feature/issue-templates`.
8 |
9 | 2.2. You have a descriptive commit message with a short title (first line).
10 |
11 | 2.3. You have only one commit (if not, [squash](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/git-rebase#squashing-multiple-commits-into-one) them into one commit).
12 |
13 | 2.4. `npm test` doesn't throw any error. If it does, fix them first and amend your commit (`git commit --amend`).
14 |
15 | 3. **After** these steps, you're ready to open a pull request.
16 |
17 | 3.1. Your pull request MUST NOT target the `master` branch on FreeCodeCamp's repository. You probably want to target `staging` instead.
18 |
19 | 3.2. Give a descriptive title to your PR.
20 |
21 | 3.3. Provide a description of your changes.
22 |
23 | 3.4. Put `closes #XXXX` in your comment to auto-close the issue that your PR fixes (if such).
24 |
25 | IMPORTANT: Please review the [CONTRIBUTING.md](../CONTRIBUTING.md) file for detailed contributing guidelines.
26 |
27 | **PLEASE REMOVE THIS TEMPLATE BEFORE SUBMITTING**
28 |
--------------------------------------------------------------------------------
/common/app/routes/Hikes/redux/fetch-hikes-saga.js:
--------------------------------------------------------------------------------
1 | import { Observable } from 'rx';
2 | import { normalize, Schema, arrayOf } from 'normalizr';
3 | // import debug from 'debug';
4 |
5 | import types from './types';
6 | import { fetchHikesCompleted } from './actions';
7 | import { handleError } from '../../../redux/types';
8 |
9 | import { findCurrentHike } from './utils';
10 |
11 | // const log = debug('fcc:fetch-hikes-saga');
12 | const hike = new Schema('hike', { idAttribute: 'dashedName' });
13 |
14 | export default ({ services }) => ({ dispatch }) => next => {
15 | return function fetchHikesSaga(action) {
16 | if (action.type !== types.fetchHikes) {
17 | return next(action);
18 | }
19 |
20 | const dashedName = action.payload;
21 | return services.readService$({ service: 'hikes' })
22 | .map(hikes => {
23 | const { entities, result } = normalize(
24 | { hikes },
25 | { hikes: arrayOf(hike) }
26 | );
27 |
28 | hikes = {
29 | entities: entities.hike,
30 | results: result.hikes
31 | };
32 |
33 | const currentHike = findCurrentHike(hikes, dashedName);
34 |
35 | return fetchHikesCompleted(hikes, currentHike);
36 | })
37 | .catch(error => {
38 | return Observable.just({
39 | type: handleError,
40 | error
41 | });
42 | })
43 | .doOnNext(dispatch);
44 | };
45 | };
46 |
--------------------------------------------------------------------------------
/server/middlewares/error-handlers.js:
--------------------------------------------------------------------------------
1 | import errorHanlder from 'errorhandler';
2 | import accepts from 'accepts';
3 |
4 | export default function prodErrorHandler() {
5 | if (process.env.NODE_ENV === 'development') {
6 | return errorHanlder({ log: true });
7 | }
8 | // error handling in production.
9 | // disabling eslint due to express parity rules for error handlers
10 | return function(err, req, res, next) { // eslint-disable-line
11 | // respect err.status
12 | if (err.status) {
13 | res.statusCode = err.status;
14 | }
15 |
16 | // default status code to 500
17 | if (res.statusCode < 400) {
18 | res.statusCode = 500;
19 | }
20 |
21 | // parse res type
22 | var accept = accepts(req);
23 | var type = accept.type('html', 'json', 'text');
24 |
25 | var message = 'Oops! Something went wrong. Please try again later';
26 | if (type === 'html') {
27 | if (typeof req.flash === 'function') {
28 | req.flash('errors', {
29 | msg: message
30 | });
31 | }
32 | return res.redirect('/map');
33 | // json
34 | } else if (type === 'json') {
35 | res.setHeader('Content-Type', 'application/json');
36 | return res.send({
37 | message: message
38 | });
39 | // plain text
40 | } else {
41 | res.setHeader('Content-Type', 'text/plain');
42 | return res.send(message);
43 | }
44 | };
45 | }
46 |
--------------------------------------------------------------------------------
/server/model-config.json:
--------------------------------------------------------------------------------
1 | {
2 | "_meta": {
3 | "sources": [
4 | "loopback/common/models",
5 | "loopback/server/models",
6 | "../common/models",
7 | "./models"
8 | ]
9 | },
10 | "User": {
11 | "dataSource": "db",
12 | "public": false
13 | },
14 | "AccessToken": {
15 | "dataSource": "db",
16 | "public": false
17 | },
18 | "ACL": {
19 | "dataSource": "db",
20 | "public": false
21 | },
22 | "RoleMapping": {
23 | "dataSource": "db",
24 | "public": false
25 | },
26 | "Role": {
27 | "dataSource": "db",
28 | "public": false
29 | },
30 | "Email": {
31 | "dataSource": "mail",
32 | "public": false
33 | },
34 | "challenge": {
35 | "dataSource": "db",
36 | "public": true
37 | },
38 | "job": {
39 | "dataSource": "db",
40 | "public": true
41 | },
42 | "nonprofit": {
43 | "dataSource": "db",
44 | "public": true
45 | },
46 | "story": {
47 | "dataSource": "db",
48 | "public": true
49 | },
50 | "pledge": {
51 | "dataSource": "db",
52 | "public": true
53 | },
54 | "promo": {
55 | "dataSource": "db",
56 | "public": true
57 | },
58 | "user": {
59 | "dataSource": "db",
60 | "public": true
61 | },
62 | "userCredential": {
63 | "dataSource": "db",
64 | "public": true
65 | },
66 | "userIdentity": {
67 | "dataSource": "db",
68 | "public": true
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/server/views/redirect-https.jade:
--------------------------------------------------------------------------------
1 | doctype html
2 | html(lang='en')
3 | script(src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js")
4 | script(src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.4/js/bootstrap.min.js")
5 | link(rel='stylesheet', href='/bower_components/font-awesome/css/font-awesome.min.css')
6 | link(rel='stylesheet', href='/css/main.css')
7 | link(rel='stylesheet', href='/css/Vimeo.css')
8 |
9 | include partials/meta
10 | meta(charset='utf-8')
11 | meta(http-equiv='X-UA-Compatible', content='IE=edge')
12 | meta(name='viewport', content='width=device-width, initial-scale=1.0')
13 | meta(name='csrf-token', content=_csrf)
14 | script.
15 | var _vds = _vds || [];
16 | window._vds = _vds;
17 | (function(){
18 | _vds.push(['setAccountId', 'b350d488f8e3e5f1']);
19 | (function() {
20 | var vds = document.createElement('script');
21 | vds.type='text/javascript';
22 | vds.async = true;
23 | vds.src = ('https:' == document.location.protocol ? 'https://' : 'http://') + 'dn-growing.qbox.me/vds.js';
24 | var s = document.getElementsByTagName('script')[0];
25 | s.parentNode.insertBefore(vds, s);
26 | })();
27 | })();
28 | body.top-and-bottom-margins
29 | include partials/navbar
30 | .container
31 | .row
32 | .panel.panel-info
33 | p redirecting you... please wait...
34 | script.
35 | setTimeout(function() {
36 | window.location = 'http://freecodecamp.cn'
37 | }, 500);
38 |
--------------------------------------------------------------------------------
/server/utils/commit.js:
--------------------------------------------------------------------------------
1 | import dedent from 'dedent';
2 | import debugFactory from 'debug';
3 | import { Observable } from 'rx';
4 |
5 | import commitGoals from './commit-goals.json';
6 | const debug = debugFactory('fcc:utils/commit');
7 |
8 | export { commitGoals };
9 |
10 | export function completeCommitment$(user) {
11 | const {
12 | isFrontEndCert,
13 | isDataVisCert,
14 | isBackEndCert,
15 | isFullStackCert
16 | } = user;
17 |
18 | return Observable.fromNodeCallback(user.pledge, user)()
19 | .flatMap(pledge => {
20 | if (!pledge) {
21 | return Observable.just('No pledge found');
22 | }
23 |
24 | const { goal } = pledge;
25 |
26 | if (
27 | (isFrontEndCert && goal === commitGoals.frontEndCert) ||
28 | (isDataVisCert && goal === commitGoals.dataVisCert) ||
29 | (isBackEndCert && goal === commitGoals.backEndCert) ||
30 | (isFullStackCert && goal === commitGoals.fullStackCert)
31 | ) {
32 | debug('marking goal complete');
33 | pledge.isCompleted = true;
34 | pledge.dateEnded = new Date();
35 | pledge.formerUserId = pledge.userId;
36 | pledge.userId = null;
37 | return Observable.fromNodeCallback(pledge.save, pledge)();
38 | }
39 | return Observable.just(dedent`
40 | You have not yet reached your goal of completing the ${goal}
41 | Please retry when you have met the requirements.
42 | `);
43 | });
44 | }
45 |
--------------------------------------------------------------------------------
/client/commonFramework/output-display.js:
--------------------------------------------------------------------------------
1 | window.common = (function(global) {
2 | const {
3 | CodeMirror,
4 | document: doc,
5 | common = { init: [] }
6 | } = global;
7 |
8 | const { challengeTypes, challengeType = '0' } = common;
9 |
10 | if (
11 | !CodeMirror ||
12 | challengeType !== challengeTypes.JS &&
13 | challengeType !== challengeTypes.BONFIRE
14 | ) {
15 | common.updateOutputDisplay = () => {};
16 | common.appendToOutputDisplay = () => {};
17 | return common;
18 | }
19 |
20 | var codeOutput = CodeMirror.fromTextArea(
21 | doc.getElementById('codeOutput'),
22 | {
23 | lineNumbers: false,
24 | mode: 'text',
25 | theme: 'monokai',
26 | readOnly: 'nocursor',
27 | lineWrapping: true
28 | }
29 | );
30 |
31 | codeOutput.setValue(`/**
32 | * Your output will go here.
33 | * Any console.log() -type
34 | * statements will appear in
35 | * your browser\'s DevTools
36 | * JavaScript console.
37 | */`);
38 |
39 | codeOutput.setSize('100%', '100%');
40 |
41 | common.updateOutputDisplay = function updateOutputDisplay(str = '') {
42 | if (typeof str !== 'string') {
43 | str = JSON.stringify(str);
44 | }
45 | codeOutput.setValue(str);
46 | return str;
47 | };
48 |
49 | common.appendToOutputDisplay = function appendToOutputDisplay(str = '') {
50 | codeOutput.setValue(codeOutput.getValue() + str);
51 | return str;
52 | };
53 |
54 | return common;
55 | }(window));
56 |
--------------------------------------------------------------------------------
/server/views/resources/stories.jade:
--------------------------------------------------------------------------------
1 | extends ../layout
2 | block content
3 | h1.text-center 学员感受
4 | hr
5 | .row
6 | .col-xs-12.col-sm-10.col-sm-offset-1
7 | .row
8 | for story in stories
9 | .col-xs-12.col-sm-6.col-md-4
10 | .height-500
11 | a(href=story.linkedin target='_blank')
12 | img.testimonial-image.img-responsive.img-center(src=story.image)
13 | h3.text-center= story.camper
14 | |
15 | if story.linkedin
16 | a.fa.fa-linkedin-square.text-primary(alt="#{story.camper}'s LinkedIn Profile", href=story.linkedin, target='_blank')
17 | else
18 | a.fa.fa-github-square.text-primary(alt="#{story.camper}'s GitHub Profile", href=story.github, target='_blank')
19 | p.small-p.text-justify= story.quote
20 | .col-xs-12.col-sm-10.col-sm-offset-1
21 | if moreStories
22 | .text-center
23 | a.btn.btn-lg.btn-primary.btn-primary-ghost.btn-block(href="/all-stories") 查看更多
24 | .spacer
25 |
26 | if !user
27 | .text-center
28 | a.btn.btn-cta.signup-btn.btn-block(href="/login") 准备好了,Go!
29 |
--------------------------------------------------------------------------------
/server/utils/auth.js:
--------------------------------------------------------------------------------
1 | import assign from 'object.assign';
2 |
3 | const providerHash = {
4 | facebook: ({ id }) => id,
5 | twitter: ({ username }) => username,
6 | linkedin({ _json }) {
7 | return _json && _json.publicProfileUrl || null;
8 | },
9 | google: ({ id }) => id
10 | };
11 |
12 | export function getUsernameFromProvider(provider, profile) {
13 | return typeof providerHash[provider] === 'function' ?
14 | providerHash[provider](profile) :
15 | null;
16 | }
17 |
18 | // using es6 argument destructing
19 | export function setProfileFromGithub(
20 | user,
21 | {
22 | profileUrl: githubURL,
23 | username
24 | },
25 | {
26 | id: githubId,
27 | 'avatar_url': picture,
28 | email: githubEmail,
29 | 'created_at': joinedGithubOn,
30 | blog: website,
31 | location,
32 | name
33 | }
34 | ) {
35 | return assign(
36 | user,
37 | { isGithubCool: true, isMigrationGrandfathered: false },
38 | {
39 | name,
40 | username: username.toLowerCase(),
41 | location,
42 | joinedGithubOn,
43 | website,
44 | picture,
45 | githubId,
46 | githubURL,
47 | githubEmail,
48 | githubProfile: githubURL
49 | }
50 | );
51 | }
52 |
53 | export function getFirstImageFromProfile(profile) {
54 | return profile && profile.photos && profile.photos[0] ?
55 | profile.photos[0].value :
56 | null;
57 | }
58 |
59 | export function getSocialProvider(provider) {
60 | return provider.split('-')[0];
61 | }
62 |
--------------------------------------------------------------------------------
/server/views/partials/challenge-modals.jade:
--------------------------------------------------------------------------------
1 | #issue-modal.modal(tabindex='-1')
2 | .modal-dialog.animated.fadeIn.fast-animation
3 | .modal-content
4 | .modal-header.challenge-list-header 你发现了一个bug吗?
5 | a.close.closing-x(href='#', data-dismiss='modal', aria-hidden='true') ×
6 | .modal-body.text-center
7 | h3 在你提交一个新的问题之前,请先阅读“求助,我发现了一个bug”,然后浏览这个挑战的其他问题。
8 | a.btn.btn-lg.btn-primary.btn-block#help-ive-found-a-bug-wiki-article(name='_csrf', value=_csrf) 求助,我发现了一个bug
9 | a.btn.btn-lg.btn-primary.btn-block#search-issue(name='_csrf', value=_csrf) 浏览这个挑战的其他问题
10 | a.btn.btn-lg.btn-primary.btn-block#report-issue(name='_csrf', value=_csrf) 创建一个新问题
11 | a.btn.btn-lg.btn-primary.btn-block(href='#', data-dismiss='modal', aria-hidden='true') 取消
12 |
13 | #reset-modal.modal(tabindex='-1')
14 | .modal-dialog.animated.fadeInUp.fast-animation
15 | .modal-content
16 | .modal-header.challenge-list-header 重置你的代码吗?
17 | a.close.closing-x(href='#', data-dismiss='modal', aria-hidden='true') ×
18 | .modal-body
19 | h4.text-center 重置将会让你的代码编辑器回到初始状态
20 | h4.text-center 当代码一直无法通过测试时,可以尝试重置,然后重写一遍,这招非常有效。
21 | a.btn.btn-lg.btn-warning.btn-block#reset-button(href='#', data-dismiss='modal', aria-hidden='true') 重置
22 | a.btn.btn-lg.btn-primary.btn-block(href='#', data-dismiss='modal', aria-hidden='true') 取消
23 |
--------------------------------------------------------------------------------