feat(challenges): Added math challenge stubs

This commit is contained in:
Quincy Larson
2017-08-30 17:35:35 -07:00
parent 9556cede00
commit fb36c052ee
356 changed files with 85679 additions and 0 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,108 @@
{
"name": "Claim Your Responsive Web Design Certificate",
"order": 13,
"time": "5 minutes",
"challenges": [
{
"id": "587d78aa367417b2b2512aee",
"title": "Claim Your Responsive Web Design Certificate",
"description": [
[
"//i.imgur.com/k8btNUB.jpg",
"An image of our Responsive Web Design Certificate",
"This challenge will give you your verified Responsive Web Design Certificate. Before we issue your certificate, we must verify that you have completed all of our basic and intermediate algorithm scripting challenges, and all our basic, intermediate, and advanced front end development projects. You must also accept our Academic Honesty Pledge. Click the button below to start this process.",
""
],
[
"//i.imgur.com/uLPsUko.jpg",
"The definition of plagiarism: Plagiarism (noun) - copying someone elses work and presenting it as your own without crediting them",
"By clicking below, you pledge that all of your submitted code A) is code you or your pair personally wrote, or B) comes from open source libraries like jQuery, or C) has been clearly attributed to its original authors. You also give us permission to audit your challenge solutions and revoke your certificate if we discover evidence of plagiarism.",
"#"
],
[
"//i.imgur.com/UedoV2G.jpg",
"An image of the text \"Front End Development Certificate requirements\"",
"Let's confirm that you have completed all of our basic and intermediate algorithm scripting challenges, and all our basic, intermediate, and advanced front end development projects. Click the button below to verify this.",
"#"
],
[
"//i.imgur.com/Q5Za9U6.jpg",
"An image of the word \"Congratulations\"",
"Congratulations! We've added your Responsive Web Design Certificate to your portfolio page. Unless you choose to hide your solutions, this certificate will remain publicly visible and verifiable.",
""
]
],
"challengeSeed": [
{
"properties": [
"isHonest",
"isFrontEndCert"
],
"apis": [
"/certificate/honest",
"/certificate/verify/front-end"
],
"stepIndex": [
1,
2
]
}
],
"tests": [
{
"id": "587d78af367417b2b2512b03",
"title": "Build a Survey Form"
},
{
"id": "bd7158d8c442eddfaeb5bd18",
"title": "Build a Tribute Page"
},
{
"id": "587d78af367417b2b2512b04",
"title": "Build a Product Landing Page"
},
{
"id": "587d78b0367417b2b2512b05",
"title": "Build a Technical Documentation Page"
},
{
"id": "bd7158d8c242eddfaeb5bd13",
"title": "Build a Personal Portfolio Webpage"
}
],
"type": "Waypoint",
"challengeType": 7,
"translations": {
"es": {
"title": "Reclama tu certificado de Desarrollo de interfaces",
"description": [
[
"//i.imgur.com/k8btNUB.jpg",
"Una imagen que muestra nuestro certificado de Desarrollo de interfaces",
"Este desafío te otorga tu certificado autenticado de Desarrollo de interfaces. Antes de que podamos emitir tu certificado, debemos verificar que has completado todos los desafíos básicos e intermedios de diseño de algoritmos, y todos los proyectos básicos e intermedios de desarrollo de interfaces. También debes aceptar nuestro Juramento de honestidad académica. Pulsa el botón siguiente para iniciar este proceso.",
""
],
[
"//i.imgur.com/HArFfMN.jpg",
"Plagio (nombre): acción y efecto de plagiar. Plagiar (verbo) - copiar en lo sustancial obras ajenas, dándolas como propias.",
"Al pulsar el botón siguiente, juras que todo el código en tus soluciones a los desafíos A) es código que tú o tu compañero escribieron personalmente, o B) proviene de librerías de código abierto como jQuery, o C) ha sido claramente atribuido a sus autores originales. También nos otorgas el permiso para auditar tus soluciones a los desafíos y revocar tu certificado si encontramos evidencia de plagio.",
"#"
],
[
"//i.imgur.com/14F2Van.jpg",
"Una imagen del texto \"Front End Development Certificate requirements\"",
"Confirmemos que has completado todos nuestros desafíos básicos e intermedios de diseño de algoritmos, y todos nuestros proyectos básicos e intermedios de desarrollo de interfaces. Pulsa el botón siguiente para hacer la verificación.",
"#"
],
[
"//i.imgur.com/16SIhHO.jpg",
"Una imagen de la palabra \"Congratulations\"",
"¡Felicitaciones! Hemos agregado tu certificado de Desarrollo de interfaces a tu portafolio. A menos que elijas no mostrar tus soluciones, este certificado será públicamente visible y verificable.",
""
]
]
}
}
}
]
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,319 @@
{
"name": "Applied Responsive Web Design Projects",
"order": 6,
"time": "150 hours",
"helpRoom": "Help",
"challenges": [
{
"id": "587d78af367417b2b2512b02",
"title": "Get Set for our Responsive Web Design Projects",
"description": [
[
"//i.imgur.com/OAD6SJz.png",
"An image of a Simon game, one our front end projects.",
"Our front end development projects will give you a chance to apply the front end skills you've developed up to this point. We'll use a popular browser-based code editor called CodePen.",
""
],
[
"//i.imgur.com/WBetuBa.jpg",
"A programmer punching through his laptop screen in frustration.",
"These projects are hard. It takes most campers several days to build each project. You will get frustrated. But don't quit. This gets easier with practice.",
""
],
[
"//i.imgur.com/p2TpOQd.jpg",
"A cute dog jumping over a hurdle and winking and pointing his paw at you.",
"When you get stuck, just use the Read-Search-Ask methodology. Don't worry - you've got this.",
""
],
[
"//i.imgur.com/G1saeDt.gif",
"A gif showing how to create a Codepen account.",
"For our front end project challenges, we'll use a popular browser-based code editor called CodePen. Click the \"Open link in new tab\" button below to open CodePen's signup page. Fill out the form and click \"Sign up\". <br><div class=\"small\">Note: If you already have a CodePen account, you can skip this step by clicking \"Open link in new tab\", closing the new tab that opens, then clicking \"go to my next step\". We removed our \"skip step\" button because many people would just click it repeatedly without doing these important steps.</div>",
"https://codepen.io/accounts/signup/user/free"
],
[
"//i.imgur.com/U4y9RJ1.gif",
"A gif showing that you can type \"hello world\" will output \"hello world\" in the preview window. You can also drag windows to resize them, and change their orientation.",
"In the HTML box, create an <code>h1</code> element with the text \"Hello World\". You can drag the frames around to resize them. You can also click the \"Change View\" button and change the orientation of the frames.",
""
],
[
"//i.imgur.com/xHoCEt2.gif",
"A gif showing the process of adding Bootstrap to your pen.",
"Click the gear in the upper left hand corner of the CSS box, then copy this link <code>https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css</code> inside the text box. Now give your <code>h1</code> element the class of <code>text-primary</code> to change its color and prove that Bootstrap is now available. Note that by using the dropdown menu and selecting \"Bootstrap\", the Alpha v.4 will be added instead.",
""
],
[
"//i.imgur.com/m0pWik2.gif",
"A gif showing the process of turning off auto update preview",
"When using CodePen and Ajax, it is a good idea to turn off automatic preview updating so API calls are not made too often. Too many API calls can sometimes lead to temporary blockages, and may require waiting periods before they can be used again. <br> <div class=\"small\"> To disable automatic preview updating click the \"Settings\" button at the top of the page, then click the \"Behavior\" tab. At the bottom of the page, un-check \"AUTO UPDATE PREVIEW\". Now press \"Run\" at the top of the page to update the preview, and click \"Save\".</div>",
""
]
],
"challengeSeed": [],
"tests": [],
"type": "Waypoint",
"isRequired": false,
"challengeType": 7,
"translations": {
"es": {
"title": "Prepárate para los Proyectos de Desarrollo de Interfaces",
"description": [
[
"//i.imgur.com/OAD6SJz.png",
"Una imagen del juego Simón, uno de nuestros proyectos de interfaz.",
"Nuestros proyectos de desarrollo de interfaces te darán oportunidad de aplicar las habilidades con interfaces que has desarrollado hasta este momento. Usaremos un editor de código basado en el navegador llamado CodePen.",
""
],
[
"//i.imgur.com/WBetuBa.jpg",
"Un programador frustado golpeando la pantalla de su computador.",
"Nuestros desafíos sobre algoritmos son difíciles. Algunos pueden requerir muchas horas para resolverse. Podrás frustarte, pero no te rindas. Se vuelve fácil con práctica.",
""
],
[
"//i.imgur.com/p2TpOQd.jpg",
"Un tierno perro que salta sobre un obstáculo, pica el ojo y te apunta con su pata.",
"Cuando te atasques, usa la metodología Leer-Buscar-Preguntar. No te preocupes - lo tienes resuelto.",
""
],
[
"//i.imgur.com/G1saeDt.gif",
"Un gif que muestra cómo crear una cuenta en Codepen.",
"Para nuestros desafíos de interfaces, usaremos un editor de código basado en el navegador que es muy famoso llamado Codepen. Pulsa en el botón de abajo \"Open link in new tab\" para abrir la página de registro de CodePen. Rellena el formulario y pulsa \"Sign up\". <br><div class=\"small\">Nota: Si ya tienes una cuenta de CodePen, puedes omitir este paso pulsando \"Open link in new tab\", cierra la nueva pestaña que se abre, entonces pulsa \"go to my next step\". Eliminamos nuestro botón \"skip step\" porque mucha gente solamente pulsa el botón sin realizar estos importantes pasos.</div>",
"https://codepen.io/accounts/signup/user/free"
],
[
"//i.imgur.com/U4y9RJ1.gif",
"Un gif que muestra que puedes escribir \"hello world\" en el editor, lo cual escribirá \"hello world\" en la ventana de vista previa. También puedes mover las ventanas para cambiar su tamaño, y cambiar su orientación.",
"En la ventana de HTML, crea un elemento h1 con el texto \"Hola mundo\". Puedes arrastrar los bordes de las ventanas para cambiar su tamaño. También puedes pulsar el botón de \"Change View\" para cambiar la orientación de las ventanas.",
""
],
[
"//i.imgur.com/G9KFQDL.gif",
"Un gif que muestra el proceso de agregar Bootstrap a tu proyecto.",
"Pulsa el engrane en la esquina superior izquierda de la ventana de CSS, luego ve hacia abajo hasta donde dice \"Quick add\" y elige Bootstrap. Ahora dale a tu elemento h1 la clase \"text-primary\" para cambiar su color y verificar que Bootstrap está activado.",
""
]
]
},
"pt-br": {
"title": "Prepare-se para nossos Projetos de Desenvolvimento Front End",
"description": [
[
"//i.imgur.com/OAD6SJz.png",
"A imagem de um jogo Simon, um de nossos projetos front end.",
"Nossos projetos de Desenvolvimento front end vão dar a você a chance de aplicar as habilidades front end que você desenvolveu até esse ponto. Nós vamos usar um editor popular chamado CodePen que funciona direto no navegador.",
""
],
[
"//i.imgur.com/WBetuBa.jpg",
"Um programador atravessando a tela de seu laptop com um soco em frustração.",
"Esses projetos são difíceis. A maioria dos campistas leva alguns dias para contruir cada projeto. Você vai ficar frustrado. Mas não desista. Isso fica mais fácil com a prática.",
""
],
[
"//i.imgur.com/p2TpOQd.jpg",
"Um cachorro fofo pulando sobre um obstáculo, piscando e apontando sua pata a você.",
"Quando ficar travado, use a metodologia Ler-Buscar-Perguntar. Não se preocupe - você consegue.",
""
],
[
"//i.imgur.com/G1saeDt.gif",
"Um gif mostrando com criar uma conta CodePen.",
"Para nossos projetos front end, usaremos um popular editor de código baseado em navegador chamado CodePen. Clique no botão \"Open link in new tab\" abaixo para abrir a página de resgistro do CodePen. Preencha o formulário e clique em \"Sign up\". <br><div class=\"small\">Nota: Se você já tem uma conta CodePen, você pode pular esse passo clicando em \"Open link in new tab\", fechando a nova aba que abrir, e clicando em \"go to my next step\". Nós removemos nosso botão \"skip step\" pois muitas pessoas iam simplesmente clicar nele repetidamente sem passar por esses passos importantes.</div>",
"https://codepen.io/accounts/signup/user/free"
],
[
"//i.imgur.com/U4y9RJ1.gif",
"Um gif mostrando que você pode digitar \"hello world\" e será mostrado \"hello world\" na janela de visualização. Você também pode arrastar janelas para redimensioná-las e mudar a orientação das mesmas.",
"Na caixa do HTML, crie um elemento <code>h1</code> com o texto \"Hello World\". Você pode arrastar as bordas para redimensioná-las. Você pode também clicar no botão \"Change View\" e mudar a orientação das janelas.",
""
],
[
"//i.imgur.com/G9KFQDL.gif",
"Um gif mostrando como adicionar o Bootstrap à sua pen.",
"Clique na engrenagem no canto superior esquerdo da caixa do CSS, então role para baixo até \"Quick add\" e escolha Bootstrap. Agora adicione ao seu elemento <code>h1</code> a classe <code>text-primary</code> para mudar sua cor e provar que o Bootstrap agora está disponível.",
""
],
[
"//i.imgur.com/m0pWik2.gif",
"Um gif mostrando o processo de desativar o update automático da janela de visualização",
"Ao usar CodePen e Ajax, é uma boa idea desativar o update automático da janela de visualização para que as chamadas para as APIs não sejam feitas a todo momento. Muitas chamadas para API pode levar à bloqueios temporários e podem requerer períodos de esperar para que possam ser usadas novamente. <br> <div class=\"small\"> Para desativar o update automático da janela de visualização clique no botão \"Settings\" no topo da página, então clique na aba \"Behavior\". No final da página, desmarque \"AUTO UPDATE PREVIEW\". Agora clique em \"Run\" no topo da página para atualizar a janela de visualização e clique \"Save\".</div>",
""
]
]
},
"ru": {
"title": "Приготовьтесь к разработке фронтенд проектов",
"description": [
[
"//i.imgur.com/OAD6SJz.png",
"Игра Саймона - один из фронтенд проектов.",
"Наши фронтенд проекты дадут вам шанс применить полученные к этому моменту знания по фронтенд разработке. Мы будем использовать популярный браузерный редактор кода - CodePen.",
""
],
[
"//i.imgur.com/WBetuBa.jpg",
"Программист от отчаяния кулаком пробивает экран своего ноутбука.",
"Это трудные проекты. Разработка каждого занимает у большинства кэмперов несколько дней. У вас может возникнуть чувство отчаяния. Несмотря на это не сдавайтесь. С практикой этот процесс станет проще.",
""
],
[
"//i.imgur.com/p2TpOQd.jpg",
"Милый пес, прыгающий через препятствие, указывает на вас лапой и подмигивает.",
"Если что-то не получается, воспользуйтесь Read-Search-Ask. Не волнуйтесь - вы сможете это сделать.",
""
],
[
"//i.imgur.com/G1saeDt.gif",
"Гифка показывающая как зарегистрироваться на CodePen.",
"Для заданий по фронтенд разработке, мы будем использовать популярный браузерный редактор кода под названием CodePen. Откройте страницу регистрации на сайте CodePen, нажав на расположенную чуть ниже кнопку \"Open link in new tab\". Заполните форму и нажмите \"Sign up\". <br><div class=\"small\">Замечание: Если у вас уже есть аккаунт CodePen, то этот шаг можно пропустить: нажмите на кнопку \"Open link in new tab\", закройте появившуюся вкладку и затем кликните \"go to my next step\". Мы убрали кнопку \"skip step\", ввиду того что большинство людей просто нажимали бы ее несколько раз подряд и пропускали бы эти важные инструкции.</div>",
"https://codepen.io/accounts/signup/user/free"
],
[
"//i.imgur.com/U4y9RJ1.gif",
"Гифка показывающая набор в редакторе заголовка с текстом \"hello world\", который затем отображается в окошке предпросмотра. А также указывающая как изменить размер окон редактора или поменять их расположение.",
"В окошке HTML создайте элемент h1 с текстом \"Hello World\". Ухватив края окон можно изменить их размер. А нажав на кнопку \"Change View\" поменять их расположение.",
""
],
[
"//i.imgur.com/G9KFQDL.gif",
"Гифка показывающая как в CodePen добавить к проекту Bootstrap.",
"Нажмите на звездочку в левом верхнем углу окошка CSS, найдите внизу поле \"Quick add\" и выберите в нем Bootstrap. Добавьте к элементу h1 класс \"text-primary\", чтобы изменить его цвет и удостовериться, что Bootstrap подключен.",
""
]
]
}
}
},
{
"id": "bd7158d8c442eddfaeb5bd18",
"title": "Build a Tribute Page",
"description": [
"Fulfill the user stories by getting all of the tests to pass. Use whichever libraries you need. Give it your own personal style.",
"Here's a <a href='http://codepen.io/freeCodeCamp/full/zNqgVx' target='_blank'>working example</a>. Try not to look at its code.",
"You can build your project by forking <a href='http://codepen.io/freeCodeCamp/pen/MJjpwO' target='_blank'>this CodePen pen</a>. Or you can use this CDN link to run the tests in any environment you like: <code>https://gitcdn.link/repo/freeCodeCamp/testable-projects-fcc/master/build/bundle.js</code>.",
"Once you're done, submit the URL to your working project with all its tests passing.",
"Remember to use the <a href='https://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> method if you get stuck."
],
"releasedOn": "January 1, 2016",
"challengeSeed": [
"Nk0DzQi"
],
"tests": [],
"type": "zipline",
"isRequired": true,
"challengeType": 3,
"translations": {
"es": {
"title": "Construye una página Tributo",
"description": []
},
"pt-br": {
"title": "Construa uma Página Tributo",
"description": []
},
"ru": {
"title": "Создайте страницу посвященную тому что вас вдохновляет",
"description": []
}
}
},
{
"id": "587d78af367417b2b2512b03",
"title": "Build a Survey Form",
"description": [
"Fulfill the user stories by getting all of the tests to pass. Use whichever libraries you need. Give it your own personal style.",
"Here's a <a href='http://codepen.io/freeCodeCamp/full/VPaoNP' target='_blank'>working example</a>. Try not to look at its code.",
"You can build your project by forking <a href='http://codepen.io/freeCodeCamp/pen/MJjpwO' target='_blank'>this CodePen pen</a>. Or you can use this CDN link to run the tests in any environment you like: <code>https://gitcdn.link/repo/freeCodeCamp/testable-projects-fcc/master/build/bundle.js</code>",
"Once you're done, submit the URL to your working project with all its tests passing.",
"Remember to use the <a href='https://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> method if you get stuck."
],
"releasedOn": "January 15, 2017",
"challengeSeed": [
"A7Pn5zw"
],
"tests": [],
"type": "zipline",
"isRequired": true,
"challengeType": 3,
"translations": {}
},
{
"id": "587d78af367417b2b2512b04",
"title": "Build a Product Landing Page",
"description": [
"Fulfill the user stories by getting all of the tests to pass. Use whichever libraries you need. Give it your own personal style.",
"Here's a <a href='http://codepen.io/freeCodeCamp/full/RKRbwL' target='_blank'>working example</a>. Try not to look at its code.",
"You can build your project by forking <a href='http://codepen.io/freeCodeCamp/full/MJjpwO' target='_blank'>this CodePen pen</a>. Or you can use this CDN link to run the tests in any environment you like: <code>https://gitcdn.link/repo/freeCodeCamp/testable-projects-fcc/master/build/bundle.js</code>",
"Once you're done, submit the URL to your working project with all its tests passing.",
"Remember to use the <a href='https://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> method if you get stuck."
],
"releasedOn": "January 15, 2017",
"challengeSeed": [
"ExCJjAT"
],
"tests": [],
"type": "zipline",
"isRequired": true,
"challengeType": 3,
"translations": {}
},
{
"id": "587d78b0367417b2b2512b05",
"title": "Build a Technical Documentation Page",
"description": [
"Fulfill the user stories by getting all of the tests to pass. Use whichever libraries you need. Give it your own personal style.",
"Here's a <a href='http://codepen.io/freeCodeCamp/full/NdrKKL' target='_blank'>working example</a>. Try not to look at its code.",
"You can build your project by forking <a href='http://codepen.io/freeCodeCamp/pen/MJjpwO' target='_blank'>this CodePen pen</a>. Or you can use this CDN link to run the tests in any environment you like: <code>https://gitcdn.link/repo/freeCodeCamp/testable-projects-fcc/master/build/bundle.js</code>",
"Once you're done, submit the URL to your working project with all its tests passing.",
"Remember to use the <a href='https://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> method if you get stuck."
],
"releasedOn": "January 15, 2017",
"challengeSeed": [
"cDIfODs"
],
"tests": [],
"type": "zipline",
"isRequired": true,
"challengeType": 3,
"translations": {}
},
{
"id": "587d78b0367417b2b2512b06",
"title": "Build a Personal Portfolio Webpage",
"description": [
"Fulfill the user stories by getting all of the tests to pass. Use whichever libraries you need. Give it your own personal style.",
"Here's a <a href='http://codepen.io/freeCodeCamp/full/zNBOYG' target='_blank'>working example</a>. Try not to look at its code.",
"You can build your project by forking <a href='http://codepen.io/freeCodeCamp/pen/MJjpwO' target='_blank'>this CodePen pen</a>. Or you can use this CDN link to run the tests in any environment you like: <code>https://gitcdn.link/repo/freeCodeCamp/testable-projects-fcc/master/build/bundle.js</code>",
"Once you're done, submit the URL to your working project with all its tests passing.",
"Remember to use the <a href='https://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> method if you get stuck."
],
"challengeSeed": [
"Uw6sYKY"
],
"tests": [],
"type": "zipline",
"isRequired": true,
"challengeType": 3,
"translations": {
"es": {
"title": "Construye una página web para tu portafolio",
"description": []
},
"pt-br": {
"title": "Construa uma Página de Portfólio Pessoal",
"description": [
]
},
"ru": {
"title": "Создайте сайт-портфолио",
"description": [
]
}
}
}
]
}

View File

@ -0,0 +1,247 @@
{
"name": "Responsive Web Design Principles",
"order": 4,
"time": "5 hours",
"helpRoom": "Help",
"challenges": [
{
"id": "587d78b0367417b2b2512b07",
"title": "Introduction to the Responsive Web Design Challenges",
"description": [
[
"",
"",
"Today, there are many types of devices that can access the web. They range from large desktop computers to small mobile phones. These devices have different screen sizes, resolutions, and processing power.",
""
],
[
"",
"",
"Responsive Web Design is an approach to designing web content that responds to the constraints of different devices. The page structure and CSS rules should be flexible to accommodate these differences.",
""
],
[
"",
"",
"In general, design the page's CSS to your target audience. If you expect most of your traffic to be from mobile users, take a 'mobile-first' approach. Then add conditional rules for larger screen sizes. If your visitors are desktop users, then design for larger screens with conditional rules for smaller sizes.",
""
],
[
"",
"",
"CSS gives you the tools to write different style rules, then apply them depending on the device displaying the page. This section will cover the basic ways to use CSS for Responsive Web Design.",
""
]
],
"releasedOn": "Feb 17, 2017",
"challengeSeed": [],
"tests": [],
"type": "waypoint",
"challengeType": 7,
"isRequired": false,
"translations": {
"pt-br": {
"title": "Introdução aos Desafios de Web Design Responsivo",
"description": [
[
"",
"",
"Hoje em dia há muitos dispositivos que podem acessar a web. Eles vão de computadores grandes de mesa até os pequenos celulares. Estes dispositivos tem diferentes tamanhos de tela, resoluções e capacidade de processamento.",
""
],
[
"",
"",
"O Web Design Responsivo é uma abordagem para o design the conteúdo para a web que responde às limitações dos diferentes dispositivos. A estrutura das páginas e as regras CSS devem ser flexíveis para acomodar estas diferenças.",
""
],
[
"",
"",
"Em geral, foque o design do CSS de sua página em seu público alvo. Se você espera que a maior parte dos seus usuários utilizem seus celulares, use uma abordagem 'mobile-first.' E então adicione regras condicionais para as telas maiores. Se seus usuários utilizam computadores de mesa, foque o design em telas maiores e utilize regras condicionais para tamanhos menores.",
""
],
[
"",
"",
"CSS lhe dá as ferramentas para escrever regras de estilo diversas, e então aplicá-las dependendo do dispositivo que estiver acessando a página. Esta seção cobrirá as maneiras básicas de utilizar CSS para o Web Design Responsivo.",
""
]
]
}
}
},
{
"id": "587d78b0367417b2b2512b08",
"title": "Create a Media Query",
"description": [
"Media Queries are a new technique introduced in CSS3 that change the presentation of content based on different viewport sizes. The viewport is a user's visible area of a web page, and is different depending on the device used to access the site.",
"Media Queries consist of a media type, and if that media type matches the type of device the document is displayed on, the styles are applied. You can have as many selectors and styles inside your media query as you want.",
"Here's an example of a media query that returns the content when the device's width is less than or equal to 100px:",
"<code>@media (max-width: 100px) { /* CSS Rules */ }</code>",
"Remember, the CSS inside the media query is applied only if the media type matches that of the device being used.",
"<hr>",
"Add a media query, so that the <code>p</code> tag has a <code>font-size</code> of 10px when the device's height is less than or equal to 800px."
],
"challengeSeed": [
"<style>",
" p {",
" font-size: 20px;",
" }",
" ",
" /* Add media query below */",
" ",
"</style>",
" ",
"<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus quis tempus massa. Aenean erat nisl, gravida vel vestibulum cursus, interdum sit amet lectus. Sed sit amet quam nibh. Suspendisse quis tincidunt nulla. In hac habitasse platea dictumst. Ut sit amet pretium nisl. Vivamus vel mi sem. Aenean sit amet consectetur sem. Suspendisse pretium, purus et gravida consequat, nunc ligula ultricies diam, at aliquet velit libero a dui.</p>"
],
"tests": [
"assert(code.match(/p\\s*\\{\\s*font-size:\\s*10px;\\s*\\}/g), 'message: Your <code>p</code> element should have the <code>font-size</code> of 10px when the device <code>height</code> is less than or equal to 800px.');",
"assert(code.match(/@media \\(max-height:\\s*?800px\\)/g), 'message: Declare a <code>@media</code> query for devices with a <code>height</code> less than or equal to 800px.');"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"solution": [],
"hints": [],
"challengeType": 0,
"translations": {
"pt-br": {
"title": "Criando uma Media Query",
"description": [
"Media Queries são uma nova técnica introduzida no CSS3 que mudam a apresentação do conteúdo de acordo com os diferentes tamanhos de janela de exibição. A janela de exibição é a área visível de uma página da web, e é diferente dependendo do dispositivo utilizado para acessar o site.",
"Media Queries consistem em um tipo de mídia, e se o tipo de mídia corresponder com o dispositivo no qual o documento está sendo exibido, os estilos são aplicados. Você pode colocar quantos seletores e estilos quanto desejar dentro de suas media queries.",
"Segue um exemplo de media query que retorna seu conteúdo quando a largura do dispositivo é menor que 100px:",
"<code>@media (max-width: 100px) { /* Regras do CSS */ }</code>",
"Lembre-se, o CSS dentro da media query só é aplicado se o tipo de mídia corresponder ao dispositivo em uso.",
"<hr>",
"Adicione uma media query para que o tag <code>p</code> tenha um <code>font-size</code> de 10px quando a altura do dispositivo for menor ou igual a 800px."
]
}
}
},
{
"id": "587d78b1367417b2b2512b09",
"title": "Make an Image Responsive",
"description": [
"Making images responsive with CSS is actually very simple. Instead of applying an absolute width to an element:",
"<code>img { width: 720px; }</code>",
"You can use:",
"<blockquote>img {<br> max-width: 100%;<br> display: block;<br> height: auto;<br>}</blockquote>",
"The <code>max-width</code> property of 100% scales the image to fit the width of its container, but the image won't stretch wider than its original width. Setting the <code>display</code> property to block changes the image from an inline element (its default), to a block element on its own line. The <code>height</code> property of auto keeps the original aspect ratio of the image.",
"<hr>",
"Add style rules for the <code>img</code> tag to make it responsive to the size of its container. It should display as a block-level element, it should fit the full width of its container without stretching, and it should keep its original aspect ratio."
],
"challengeSeed": [
"<style>",
" ",
"</style>",
"",
"<img src=\"https://s3.amazonaws.com/freecodecamp/FCCStickerPack.jpg\" alt=\"freeCodeCamp stickers set\">"
],
"tests": [
"assert(code.match(/max-width:\\s*?100%;/g), 'message: Your <code>img</code> tag should have a <code>max-width</code> set to 100%.');",
"assert($('img').css('display') == 'block', 'message: Your <code>img</code> tag should have a <code>display</code> set to block.');",
"assert(code.match(/height:\\s*?auto;/g), 'message: Your <code>img</code> tag should have a <code>height</code> set to auto.');"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"solutions": [],
"hints": [],
"translations": {
"pt-br": {
"title": "Torne uma Imagem Responsiva",
"description": [
"Fazer com que imagens sejam responsivas é muito simples com CSS. Ao invés de aplicar uma largura absoluta a um elemento:",
"<code>img { width: 720px; }</code>",
"Você pode usar:",
"<blockquote>img {<br> max-width: 100%;<br> display: block;<br> height: auto;<br>}</blockquote>",
"A propriedade <code>max-width</code> em 100% ajusta o tamanho da imagem para preencher a largura de seu container, mas a imagem não irá esticar mais que sua largura original. Ajustando a propriedade <code>display</code> como block muda imagem de elemento inline (o padrão) para um elemento block com uma linha própria. A propriedade <code>height</code> na configuração auto mantem a proporção original da imagem.",
"<hr>",
"Adicione regras de estilo para a tag <code>img</code> para torná-la responsiva com relação ao tamanho do seu container. Ela deve ser exibida como um elemento de nível block, e deve preencher toda a largura de seu container sem esticar, mantendo as proporções originais."
]
}
}
},
{
"id": "587d78b1367417b2b2512b0a",
"title": "Use a Retina Image for Higher Resolution Displays",
"description": [
"The simplest way to make your images appear \"retina\" (and optimize them for retina displays) is to define their <code>width</code> and <code>height</code> values as only half of what the original file is.",
"Here is an example of an image that is only using half of the original height and width:",
"<blockquote>&lt;style&gt;<br> img { height: 250px; width: 250px; }<br>&lt;/style&gt;<br>&lt;img src=&quot;coolPic500x500&quot; alt=&quot;A most excellent picture&quot;&gt;</blockquote>",
"<hr>",
"Set the <code>width</code> and <code>height</code> of the <code>img</code> tag to half of their original values. In this case, both the original <code>height</code> and the original <code>width</code> are 200px."
],
"challengeSeed": [
"<style>",
" ",
"</style>",
"",
"<img src=\"https://s3.amazonaws.com/freecodecamp/FCCStickers-CamperBot200x200.jpg\" alt=\"freeCodeCamp sticker that says 'Because CamperBot Cares'\">"
],
"tests": [
"assert($('img').css('width') == '100px', 'message: Your <code>img</code> tag should have a <code>width</code> of 100 pixels.');",
"assert($('img').css('height') == '100px', 'message: Your <code>img</code> tag should have a <code>height</code> of 100 pixels.');"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"solutions": [],
"hints": [],
"translations": {
"pt-br": {
"title": "Use uma Imagem Retina para Telas de Alta Resolução",
"description": [
"A maneira mais simples de fazer com que suas imagens tenham uma aparência \"retina\" (e otimizadas para telas retina) é definindo seus valores de <code>width</code> e <code>height</code> como somente metade do tamanho original dos arquivos.",
"Segue um exemplo de imagem que possui somente metade dos valores originais de altura e largura:",
"<blockquote>&lt;style&gt;<br> img { height: 250px; width: 250px; }<br>&lt;/style&gt;<br>&lt;img src=&quot;coolPic500x500&quot; alt=&quot;A most excellent picture&quot;&gt;</blockquote>",
"<hr>",
"Configure os valores de <code>width</code> e <code>height</code> da tag <code>img</code> como metade do seu tamanho original. Nesse caso, o valor original de <code>height</code> e o valor original de <code>width</code> são de 200px."
]
}
}
},
{
"id": "587d78b1367417b2b2512b0c",
"title": "Make Typography Responsive",
"description": [
"Instead of using <code>em</code> or <code>px</code> to size text, you can use viewport units for responsive typography. Viewport units, like percentages, are relative units, but they are based off different items. Viewport units are relative to the viewport dimensions (width or height) of a device, and percentages are relative to the size of the parent container element.",
"The four different viewport units are:",
"<ul><li><code>vw: 10vw</code> would be 10% of the viewport's width.</li><li><code>vh: 3vh</code> would be 3% of the viewport's height.</li><li><code>vmin: 70vmin</code> would be 70% of the viewport's smaller dimension (height vs. width).</li><li><code>vmax: 100vmax</code> would be 100% of the viewport's bigger dimension (height vs. width).</li></ul>",
"<hr>",
"Set the <code>width</code> of the <code>h2</code> tag to 80% of the viewport's width and the <code>width</code> of the paragraph as 75% of the viewport's smaller dimension."
],
"challengeSeed": [
"<style>",
" ",
"</style>",
"",
"<h2>Importantus Ipsum</h2>",
"<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus quis tempus massa. Aenean erat nisl, gravida vel vestibulum cursus, interdum sit amet lectus. Sed sit amet quam nibh. Suspendisse quis tincidunt nulla. In hac habitasse platea dictumst. Ut sit amet pretium nisl. Vivamus vel mi sem. Aenean sit amet consectetur sem. Suspendisse pretium, purus et gravida consequat, nunc ligula ultricies diam, at aliquet velit libero a dui.</p>"
],
"tests": [
"assert(code.match(/h2\\s*?{\\s*?width:\\s*?80vw;\\s*?}/g), 'message: Your <code>h2</code> tag should have a <code>width</code> of 80vw.');",
"assert(code.match(/p\\s*?{\\s*?width:\\s*?75vmin;\\s*?}/g), 'message: Your <code>p</code> tag should have a <code>width</code> of 75vmin.');"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"solutions": [],
"hints": [],
"challengeType": 0,
"translations": {
"pt-br": {
"title": "Torne a Tipografia Responsiva",
"description": [
"Ao invés de utilizar <code>em</code> ou <code>px</code> para alterar o tamanho do texto, você pode usar unidades da janela de exibição para obter tipografia responsiva. Unidades da janela de exibição, assim como porcentagens, são unidades relativas, mas que são baseadas em ítens diferentes. Unidades da janela de exibição são relativas às dimensões da janela de exibição (largura ou altura) de um dispositivo, enquanto que porcentagens são relativas ao tamanho do container do elemento pai.",
"As quatro unidades da janela de exibição são",
"<ul><li><code>vw: 10vw</code> seria 10% da largura da janela de exibição.</li><li><code>vh: 3vh</code> seria 3% da altura da janela de exibição.</li><li><code>vmin: 70vmin</code> seria 70% da menor dimensão da janela de exibição (largura ou altura).</li><li><code>vmax: 100vmax</code> seria 100% da maior dimensão da janela de exibição (largura ou altura).</li></ul>",
"<hr>",
"Ajuste o <code>width</code> da tag <code>h2</code> para 80% da largura da janela de exibição e a <code>width</code> do parágrafo para 75% da menor dimensão da janela de exibição."
]
}
}
}
]
}

View File

@ -0,0 +1,971 @@
{
"name": "Basic Algorithm Scripting",
"order": 5,
"time": "50 hours",
"helpRoom": "HelpJavaScript",
"challenges": [
{
"id": "bd7158d2c442eddfbeb5bd1f",
"title": "Get Set for our Algorithm Challenges",
"description": [
[
"//i.imgur.com/sJkp30a.png",
"An image of a algorithm challenge showing directions, tests, and the code editor.",
"Our algorithm challenges will teach you how to think like a programmer.",
""
],
[
"//i.imgur.com/d8LuRNh.png",
"A mother bird kicks a baby bird out of her nest.",
"Our previous challenges introduced you to programming concepts. But for these algorithm challenges, you'll now need to apply what you learned to solve open-ended problems.",
""
],
[
"//i.imgur.com/WBetuBa.jpg",
"A programmer punching through his laptop screen in frustration.",
"Our algorithm challenges are hard. Some of them may take you several hours to solve. You will get frustrated. But don't quit.",
""
],
[
"//i.imgur.com/p2TpOQd.jpg",
"A cute dog jumping over a hurdle and winking and pointing his paw at you.",
"When you get stuck, just use the Read-Search-Ask methodology.<br>Don't worry - you've got this.",
""
]
],
"challengeSeed": [],
"tests": [],
"type": "Waypoint",
"challengeType": 7,
"isRequired": false,
"translations": {
"es": {
"title": "Prepárate para nuestros Desafíos sobre Algoritmos",
"description": [
[
"//i.imgur.com/sJkp30a.png",
"Una imagen de un desafio sobre algoritmos que presenta instrucciones, pruebas y el editor de código.",
"Nuestros desafios sobre algoritmos te enseñarán como pensar como un programador.",
""
],
[
"//i.imgur.com/d8LuRNh.png",
"Una mamá pájaro saca un bebé pájaro fuer de su nido.",
"Nuestros desafios anteriores te introdujeron a los conceptos de programación. Pero para estos desafios sobre algoritmos, ahora necesitarás aplicar lo que has aprendido y resolver problemas de respuesta abierta",
""
],
[
"//i.imgur.com/WBetuBa.jpg",
"Un programador frustado golpeando la pantalla de su computador.",
"Nuestros desafíos sobre algortimos son difíciles. Algunos pueden requerir muchas horas para resolverse. Podrás frustarte, pero no te rindas.",
""
],
[
"//i.imgur.com/p2TpOQd.jpg",
"Un tierno perro que salta sobre un obstáculo, pica el ojo y te apunta con su pata.",
"Cuando te atasques, usa la metodología Leer-Buscar-Preguntar.<br>No te preocupes - ya lo has entendido.",
""
]
]
},
"pt-br": {
"title": "Prepare-se para nossos desafios de algoritmos",
"description": [
[
"//i.imgur.com/sJkp30a.png",
"Uma imagem de um desafio de algoritmo mostrando instruções, testes e o editor de código.",
"Nossos desafios de algoritmos vão te ensinar a pensar como um programador.",
""
],
[
"//i.imgur.com/d8LuRNh.png",
"Uma mãe pássaro expulsa seu filhote do ninho.",
"Os desafios anteriores te apresentaram os conceitos de programação. Mas para esses desafios de algoritmos, você terá que aplicar o que aprendeu para resolver problemas abertos.",
""
],
[
"//i.imgur.com/WBetuBa.jpg",
"Um programador frustrado atravessando a tela de seu laptop com um soco.",
"Os desafios de algoritmos são difíceis. Você pode levar várias horas para resolver alguns deles. Você vai ficar frustado. Mas não desista.",
""
],
[
"//i.imgur.com/p2TpOQd.jpg",
"Um cachorro fofo pulando sobre um obstáculo, piscando e apontando a pata na sua direção.",
"Quando ficar travado, use a metodologia Ler-Pesquisar-Perguntar.<br>Não se preocupe - você consegue.",
""
]
]
}
}
},
{
"id": "56533eb9ac21ba0edf2244b3",
"title": "Convert Celsius to Fahrenheit",
"description": [
"The algorithm to convert from Celsius to Fahrenheit is the temperature in Celsius times <code>9/5</code>, plus <code>32</code>.",
"You are given a variable <code>celsius</code> representing a temperature in Celsius. Use the variable <code>fahrenheit</code> already defined and assign it the Fahrenheit temperature equivalent to the given Celsius temperature. Use the algorithm mentioned above to help convert the Celsius temperature to Fahrenheit.",
"Don't worry too much about the function and return statements as they will be covered in future challenges. For now, only use operators that you have already learned."
],
"releasedOn": "January 1, 2016",
"challengeSeed": [
"function convertToF(celsius) {",
" var fahrenheit;",
" return fahrenheit;",
"}",
"",
"convertToF(30);"
],
"solutions": [
"function convertToF(celsius) {\n var fahrenheit = celsius * 9/5 + 32;\n if ( typeof fahrenheit !== 'undefined' ) {\n return fahrenheit;\n } else {\n return 'fahrenheit not defined';\n }\n}"
],
"tests": [
"assert(typeof convertToF(0) === 'number', 'message: <code>convertToF(0)</code> should return a number');",
"assert(convertToF(-30) === -22, 'message: <code>convertToF(-30)</code> should return a value of <code>-22</code>');",
"assert(convertToF(-10) === 14, 'message: <code>convertToF(-10)</code> should return a value of <code>14</code>');",
"assert(convertToF(0) === 32, 'message: <code>convertToF(0)</code> should return a value of <code>32</code>');",
"assert(convertToF(20) === 68, 'message: <code>convertToF(20)</code> should return a value of <code>68</code>');",
"assert(convertToF(30) === 86, 'message: <code>convertToF(30)</code> should return a value of <code>86</code>');"
],
"type": "checkpoint",
"challengeType": 1,
"isRequired": true,
"translations": {
"es": {
"title": "Convierte celsius a fahrenheit",
"description": [
"Para probar tu aprendizaje, crearás una solucion \"desde cero\". Coloca tu código entre las líneas indicadas y este será probado contra multiples casos de prueba.",
"El algoritmo para convertir de Celsius a Fahrenheit consiste en multiplicar la temperatura en grados Celsius por 9/5 y al resultado agregarle 32.",
"Se te da una variable <code>celsius</code> representando una temperatura en Celsius. Crea una variable <code>fahrenheit</code> y aplica el algoritmo para asignar la correspondiente temperatura en Fahrenheit."
]
},
"pt-br": {
"title": "Converta Celsius para Fahrenheit",
"description": [
"O algoritmo para converter de Celsius para Fahrenheit é a temperatura em Celsius vezes <code>9/5</code> mais <code>32</code>.",
"Você recebe uma variável <code>celsius</code> representando uma temperatura em Celsius. Use a variável <code>fahrenheit</code> já definida e aplique o algoritmo para atribuir a ela a temperatura correspondente em Fahrenheit."
]
}
}
},
{
"id": "a202eed8fc186c8434cb6d61",
"title": "Reverse a String",
"description": [
"Reverse the provided string.",
"You may need to turn the string into an array before you can reverse it.",
"Your result must be a string.",
"Remember to use <a href=\"http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514\" target=\"_blank\">Read-Search-Ask</a> if you get stuck. Write your own code."
],
"challengeSeed": [
"function reverseString(str) {",
" return str;",
"}",
"",
"reverseString(\"hello\");"
],
"tests": [
"assert(typeof reverseString(\"hello\") === \"string\", 'message: <code>reverseString(\"hello\")</code> should return a string.');",
"assert(reverseString(\"hello\") === \"olleh\", 'message: <code>reverseString(\"hello\")</code> should become <code>\"olleh\"</code>.');",
"assert(reverseString(\"Howdy\") === \"ydwoH\", 'message: <code>reverseString(\"Howdy\")</code> should become <code>\"ydwoH\"</code>.');",
"assert(reverseString(\"Greetings from Earth\") === \"htraE morf sgniteerG\", 'message: <code>reverseString(\"Greetings from Earth\")</code> should return <code>\"htraE morf sgniteerG\"</code>.');"
],
"type": "bonfire",
"isRequired": true,
"solutions": [
"function reverseString(str) {\n return str.split('').reverse().join(\"\");\n}\n\nreverseString('hello');\n"
],
"MDNlinks": [
"Global String Object",
"String.prototype.split()",
"Array.prototype.reverse()",
"Array.prototype.join()"
],
"challengeType": 5,
"translations": {
"es": {
"title": "Invierte el texto",
"description": [
"Invierte la cadena de texto que se te provee",
"Puede que necesites convertir la cadena de texto en un arreglo antes de que puedas invertirla",
"El resultado debe ser una cadena de texto",
"Recuerda utilizar <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Leer-Buscar-Preguntar</a> si te sientes atascado. Intenta programar en pareja. Escribe tu propio código."
]
},
"pt-br": {
"title": "Inverta uma string",
"description": [
"Inverta a string fornecida.",
"Talvez você tenha que transformar a string num array antes de invertê-la.",
"Seu resultado deve ser uma string.",
"Lembre-se de <a href=\"http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514\" target=\"_blank\">Ler-Pesquisar-Perguntar</a> se ficar travado. Escreva seu próprio código."
]
}
}
},
{
"id": "a302f7aae1aa3152a5b413bc",
"title": "Factorialize a Number",
"description": [
"Return the factorial of the provided integer.",
"If the integer is represented with the letter n, a factorial is the product of all positive integers less than or equal to n.",
"Factorials are often represented with the shorthand notation <code>n!</code>",
"For example: <code>5! = 1 * 2 * 3 * 4 * 5 = 120</code>",
"Only integers greater than or equal to zero will be supplied to the function.",
"Remember to use <a href=\"http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514\" target=\"_blank\">Read-Search-Ask</a> if you get stuck. Write your own code."
],
"challengeSeed": [
"function factorialize(num) {",
" return num;",
"}",
"",
"factorialize(5);"
],
"tests": [
"assert(typeof factorialize(5) === 'number', 'message: <code>factorialize(5)</code> should return a number.');",
"assert(factorialize(5) === 120, 'message: <code>factorialize(5)</code> should return 120.');",
"assert(factorialize(10) === 3628800, 'message: <code>factorialize(10)</code> should return 3628800.');",
"assert(factorialize(20) === 2432902008176640000, 'message: <code>factorialize(20)</code> should return 2432902008176640000.');",
"assert(factorialize(0) === 1, 'message: <code>factorialize(0)</code> should return 1.');"
],
"type": "bonfire",
"isRequired": true,
"solutions": [
"function factorialize(num) {\n return num < 1 ? 1 : num * factorialize(num-1);\n}\n\nfactorialize(5);\n"
],
"MDNlinks": [
"Arithmetic Operators"
],
"challengeType": 5,
"translations": {
"es": {
"title": "Factoriza un número",
"description": [
"Crea una función que devuelva el factorial del número entero que se te provee",
"El factorial de un número entero positivo n es la multiplicación de todos los enteros positivos menores o iguales a n",
"Los factoriales son comúnmente representados con la notación <code>n!</code>",
"Por ejemplo: <code>5! = 1 * 2 * 3 * 4 * 5 = 120</code>",
"Recuerda utilizar <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Leer-Buscar-Preguntar</a> si te sientes atascado. Intenta programar en pareja. Escribe tu propio código."
]
},
"pt-br": {
"title": "Determine o fatorial de um número",
"description": [
"Retorne o fatorial do inteiro fornecido.",
"Se o inteiro é representado pela letra n, o seu fatorial é o produto de todos os inteiros positivos menores ou iguais a n.",
"Por exemplo: <code>5! = 1 * 2 * 3 * 4 * 5 = 120</code>",
"Apenas inteiros maiores ou iguais a zero serão fornecidos à função.",
"Lembre-se de <a href=\"http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514\" target=\"_blank\">Ler-Pesquisar-Perguntar</a> se ficar travado. Escreva seu próprio código."
]
}
}
},
{
"id": "a26cbbe9ad8655a977e1ceb5",
"title": "Find the Longest Word in a String",
"description": [
"Return the length of the longest word in the provided sentence.",
"Your response should be a number.",
"Remember to use <a href=\"http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514\" target=\"_blank\">Read-Search-Ask</a> if you get stuck. Write your own code."
],
"challengeSeed": [
"function findLongestWordLength(str) {",
" return str.length;",
"}",
"",
"findLongestWordLength(\"The quick brown fox jumped over the lazy dog\");"
],
"tests": [
"assert(typeof findLongestWordLength(\"The quick brown fox jumped over the lazy dog\") === \"number\", 'message: <code>findLongestWordLength(\"The quick brown fox jumped over the lazy dog\")</code> should return a number.');",
"assert(findLongestWordLength(\"The quick brown fox jumped over the lazy dog\") === 6, 'message: <code>findLongestWordLength(\"The quick brown fox jumped over the lazy dog\")</code> should return 6.');",
"assert(findLongestWordLength(\"May the force be with you\") === 5, 'message: <code>findLongestWordLength(\"May the force be with you\")</code> should return 5.');",
"assert(findLongestWordLength(\"Google do a barrel roll\") === 6, 'message: <code>findLongestWordLength(\"Google do a barrel roll\")</code> should return 6.');",
"assert(findLongestWordLength(\"What is the average airspeed velocity of an unladen swallow\") === 8, 'message: <code>findLongestWordLength(\"What is the average airspeed velocity of an unladen swallow\")</code> should return 8.');",
"assert(findLongestWordLength(\"What if we try a super-long word such as otorhinolaryngology\") === 19, 'message: <code>findLongestWordLength(\"What if we try a super-long word such as otorhinolaryngology\")</code> should return 19.');"
],
"type": "bonfire",
"isRequired": true,
"solutions": [
"function findLongestWordLength(str) {\n return str.split(' ').sort(function(a, b) { return b.length - a.length;})[0].length;\n}\n\nfindLongestWordLength('The quick brown fox jumped over the lazy dog');\n"
],
"MDNlinks": [
"String.prototype.split()",
"String.length"
],
"challengeType": 5,
"translations": {
"es": {
"title": "Encuentra la palabra más larga",
"description": [
"Crea una función que devuelva la longitud de la palabra más larga en una frase dada",
"El resultado debe ser un número",
"Recuerda utilizar <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Leer-Buscar-Preguntar</a> si te sientes atascado. Intenta programar en pareja. Escribe tu propio código."
]
},
"pt-br": {
"title": "Encontre a palavra mais longa de uma string",
"description": [
"Retorne o tamanho da palavra mais longa da frase fornecida.",
"Sua resposta deve ser um número.",
"Lembre-se de <a href=\"http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514\" target=\"_blank\">Ler-Pesquisar-Perguntar</a> se ficar travado. Escreva seu próprio código."
]
}
}
},
{
"id": "a789b3483989747d63b0e427",
"title": "Return Largest Numbers in Arrays",
"description": [
"Return an array consisting of the largest number from each provided sub-array. For simplicity, the provided array will contain exactly 4 sub-arrays.",
"Remember, you can iterate through an array with a simple for loop, and access each member with array syntax <code>arr[i]</code>.",
"Remember to use <a href=\"http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514\" target=\"_blank\">Read-Search-Ask</a> if you get stuck. Write your own code."
],
"challengeSeed": [
"function largestOfFour(arr) {",
" // You can do this!",
" return arr;",
"}",
"",
"largestOfFour([[4, 5, 1, 3], [13, 27, 18, 26], [32, 35, 37, 39], [1000, 1001, 857, 1]]);"
],
"tests": [
"assert(largestOfFour([[4, 5, 1, 3], [13, 27, 18, 26], [32, 35, 37, 39], [1000, 1001, 857, 1]]).constructor === Array, 'message: <code>largestOfFour([[4, 5, 1, 3], [13, 27, 18, 26], [32, 35, 37, 39], [1000, 1001, 857, 1]])</code> should return an array.');",
"assert.deepEqual(largestOfFour([[13, 27, 18, 26], [4, 5, 1, 3], [32, 35, 37, 39], [1000, 1001, 857, 1]]), [27, 5, 39, 1001], 'message: <code>largestOfFour([[13, 27, 18, 26], [4, 5, 1, 3], [32, 35, 37, 39], [1000, 1001, 857, 1]])</code> should return <code>[27, 5, 39, 1001]</code>.');",
"assert.deepEqual(largestOfFour([[4, 9, 1, 3], [13, 35, 18, 26], [32, 35, 97, 39], [1000000, 1001, 857, 1]]), [9, 35, 97, 1000000], 'message: <code>largestOfFour([[4, 9, 1, 3], [13, 35, 18, 26], [32, 35, 97, 39], [1000000, 1001, 857, 1]])</code> should return <code>[9, 35, 97, 1000000]</code>.');",
"assert.deepEqual(largestOfFour([[17, 23, 25, 12], [25, 7, 34, 48], [4, -10, 18, 21], [-72, -3, -17, -10]]), [25, 48, 21, -3], 'message: <code>largestOfFour([[17, 23, 25, 12], [25, 7, 34, 48], [4, -10, 18, 21], [-72, -3, -17, -10]])</code> should return <code>[25, 48, 21, -3]</code>.');"
],
"type": "bonfire",
"isRequired": true,
"solutions": [
"function largestOfFour(arr) {\n return arr.map(function(subArr) {\n return Math.max.apply(null, subArr);\n });\n}\n\nlargestOfFour([[4, 5, 1, 3], [13, 27, 18, 26], [32, 35, 37, 39], [1000, 1001, 857, 1]]);\n"
],
"MDNlinks": [
"Comparison Operators"
],
"challengeType": 5,
"translations": {
"es": {
"title": "Devuelve el mayor entero de cada arreglo",
"description": [
"Crea una función que devuelva un arreglo que contenga el mayor de los números de cada sub-arreglo que recibe. Para simplificar las cosas, el arreglo que recibirá tendrá exactamente 4 sub-arreglos",
"Recuerda que puedes iterar a través de un arreglo con un búcle simple, y acceder a cada miembro utilizando la sintaxis arr[i].",
"Si escribes tu propio test con Chai.js, asegúrate de utilizar un operador de igualdad estricto en lugar de un operador de igualdad cuando compares arreglos. ",
"Recuerda utilizar <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Leer-Buscar-Preguntar</a> si te sientes atascado. Intenta programar en pareja. Escribe tu propio código."
]
},
"pt-br": {
"title": "Retorne os maiores números de arrays",
"description": [
"Retorne um array contendo o maior número de cada sub-array fornecido. Para simplificar, o array fornecido conterá exatamente 4 sub-arrays.",
"Lembre-se, você pode iterar por um array com um simples <code>for</code> e acessar cada membro do array com a sintaxe <code>arr[i]</code>.",
"Lembre-se de <a href=\"http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514\" target=\"_blank\">Ler-Pesquisar-Perguntar</a> se ficar travado. Escreva seu próprio código."
]
}
}
},
{
"id": "acda2fb1324d9b0fa741e6b5",
"title": "Confirm the Ending",
"description": [
"Check if a string (first argument, <code>str</code>) ends with the given target string (second argument, <code>target</code>).",
"This challenge <em>can</em> be solved with the <code>.endsWith()</code> method, which was introduced in ES2015. But for the purpose of this challenge, we would like you to use one of the JavaScript substring methods instead.",
"Remember to use <a href=\"http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514\" target=\"_blank\">Read-Search-Ask</a> if you get stuck. Write your own code."
],
"challengeSeed": [
"function confirmEnding(str, target) {",
" // \"Never give up and good luck will find you.\"",
" // -- Falcor",
" return str;",
"}",
"",
"confirmEnding(\"Bastian\", \"n\");"
],
"tests": [
"assert(confirmEnding(\"Bastian\", \"n\") === true, 'message: <code>confirmEnding(\"Bastian\", \"n\")</code> should return true.');",
"assert(confirmEnding(\"Congratulation\", \"on\") === true, 'message: <code>confirmEnding(\"Congratulation\", \"on\")</code> should return true.');",
"assert(confirmEnding(\"Connor\", \"n\") === false, 'message: <code>confirmEnding(\"Connor\", \"n\")</code> should return false.');",
"assert(confirmEnding(\"Walking on water and developing software from a specification are easy if both are frozen\", \"specification\") === false, 'message: <code>confirmEnding(\"Walking on water and developing software from a specification are easy if both are frozen\"&#44; \"specification\"&#41;</code> should return false.');",
"assert(confirmEnding(\"He has to give me a new name\", \"name\") === true, 'message: <code>confirmEnding(\"He has to give me a new name\", \"name\")</code> should return true.');",
"assert(confirmEnding(\"Open sesame\", \"same\") === true, 'message: <code>confirmEnding(\"Open sesame\", \"same\")</code> should return true.');",
"assert(confirmEnding(\"Open sesame\", \"pen\") === false, 'message: <code>confirmEnding(\"Open sesame\", \"pen\")</code> should return false.');",
"assert(confirmEnding(\"Open sesame\", \"game\") === false, 'message: <code>confirmEnding(\"Open sesame\", \"game\")</code> should return false.');",
"assert(confirmEnding(\"If you want to save our world, you must hurry. We dont know how much longer we can withstand the nothing\", \"mountain\") === false, 'message: <code>confirmEnding(\"If you want to save our world, you must hurry. We dont know how much longer we can withstand the nothing\", \"mountain\")</code> should return false.');",
"assert(confirmEnding(\"Abstraction\", \"action\") === true, 'message: <code>confirmEnding(\"Abstraction\", \"action\")</code> should return true.');",
"assert(!/\\.endsWith\\(.*?\\)\\s*?;?/.test(code), 'message: Do not use the built-in method <code>.endsWith()</code> to solve the challenge.');"
],
"type": "bonfire",
"isRequired": true,
"solutions": [
"function confirmEnding(str, target) {\n return str.substring(str.length-target.length) === target;\n};\n"
],
"MDNlinks": [
"String.prototype.substr()",
"String.prototype.substring()"
],
"challengeType": 5,
"translations": {
"es": {
"title": "Confirma la terminación",
"description": [
"Verifica si una cadena de texto (primer argumento) termina con otra cadena de texto (segundo argumento).",
"Recuerda utilizar <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Leer-Buscar-Preguntar</a> si te sientes atascado. Intenta programar en pareja. Escribe tu propio código."
]
},
"pt-br": {
"title": "Confirme o final",
"description": [
"Verifique se uma string (primeiro argumento, <code>str</code>) termina com a string alvo fornecida (segundo argumento, <code>target</code>).",
"Esse desafio <em>pode</em> ser resolvido com o método <code>.endsWith()</code>, que foi introduzido na ES2015. Mas para o propósito desse desafio, nós gostaríamos que, ao invés dele, você usasse algum dos métodos de substring do JavaScript.",
"Lembre-se de <a href=\"http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514\" target=\"_blank\">Ler-Pesquisar-Perguntar</a> se ficar travado. Escreva seu próprio código."
]
}
}
},
{
"id": "afcc8d540bea9ea2669306b6",
"title": "Repeat a String Repeat a String",
"description": [
"Repeat a given string <code>str</code> (first argument) for <code>num</code> times (second argument). Return an empty string if <code>num</code> is not a positive number.",
"Remember to use <a href=\"http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514\" target=\"_blank\">Read-Search-Ask</a> if you get stuck. Write your own code."
],
"challengeSeed": [
"function repeatStringNumTimes(str, num) {",
" // repeat after me",
" return str;",
"}",
"",
"repeatStringNumTimes(\"abc\", 3);"
],
"tests": [
"assert(repeatStringNumTimes(\"*\", 3) === \"***\", 'message: <code>repeatStringNumTimes(\"*\", 3)</code> should return <code>\"***\"</code>.');",
"assert(repeatStringNumTimes(\"abc\", 3) === \"abcabcabc\", 'message: <code>repeatStringNumTimes(\"abc\", 3)</code> should return <code>\"abcabcabc\"</code>.');",
"assert(repeatStringNumTimes(\"abc\", 4) === \"abcabcabcabc\", 'message: <code>repeatStringNumTimes(\"abc\", 4)</code> should return <code>\"abcabcabcabc\"</code>.');",
"assert(repeatStringNumTimes(\"abc\", 1) === \"abc\", 'message: <code>repeatStringNumTimes(\"abc\", 1)</code> should return <code>\"abc\"</code>.');",
"assert(repeatStringNumTimes(\"*\", 8) === \"********\", 'message: <code>repeatStringNumTimes(\"*\", 8)</code> should return <code>\"********\"</code>.');",
"assert(repeatStringNumTimes(\"abc\", -2) === \"\", 'message: <code>repeatStringNumTimes(\"abc\", -2)</code> should return <code>\"\"</code>.');",
"assert(!/\\.repeat/g.test(code), 'message: The built-in <code>repeat()</code>-method should not be used');"
],
"type": "bonfire",
"isRequired": true,
"solutions": [
"function repeatStringNumTimes(str, num) {\n if (num < 0) return '';\n return num === 1 ? str : str + repeatStringNumTimes(str, num-1);\n}\n\nrepeatStringNumTimes('abc', 3);\n"
],
"MDNlinks": [
"Global String Object"
],
"challengeType": 5,
"translations": {
"es": {
"title": "Repite el Texto Repite el Texto",
"description": [
"Repite una cadena de texto dada (primer argumento) <code>num</code> veces (segundo argumento). Retorna una cadena de texto vacía si <code>num</code> es un número negativo.",
"Recuerda utilizar <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Leer-Buscar-Preguntar</a> si te sientes atascado. Intenta programar en pareja. Escribe tu propio código."
]
},
"pt-br": {
"title": "Repita uma string Repita uma string",
"description": [
"Repita uma string <code>str</code> dada (primeiro argumento) <code>num</code> vezes (segundo argumento). Retorne uma string vazia se <code>num</code> não for um número positivo.",
"Lembre-se de <a href=\"http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514\" target=\"_blank\">Ler-Pesquisar-Perguntar</a> se ficar travado. Escreva seu próprio código."
]
}
}
},
{
"id": "ac6993d51946422351508a41",
"title": "Truncate a String",
"description": [
"Truncate a string (first argument) if it is longer than the given maximum string length (second argument). Return the truncated string with a <code>...</code> ending.",
"Remember to use <a href=\"http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514\" target=\"_blank\">Read-Search-Ask</a> if you get stuck. Write your own code."
],
"challengeSeed": [
"function truncateString(str, num) {",
" // Clear out that junk in your trunk",
" return str;",
"}",
"",
"truncateString(\"A-tisket a-tasket A green and yellow basket\", 8);"
],
"tests": [
"assert(truncateString(\"A-tisket a-tasket A green and yellow basket\", 8) === \"A-tisket...\", 'message: <code>truncateString(\"A-tisket a-tasket A green and yellow basket\", 8)</code> should return \"A-tisket...\".');",
"assert(truncateString(\"Peter Piper picked a peck of pickled peppers\", 11) === \"Peter Piper...\", 'message: <code>truncateString(\"Peter Piper picked a peck of pickled peppers\", 11)</code> should return \"Peter Piper...\".');",
"assert(truncateString(\"A-tisket a-tasket A green and yellow basket\", \"A-tisket a-tasket A green and yellow basket\".length) === \"A-tisket a-tasket A green and yellow basket\", 'message: <code>truncateString(\"A-tisket a-tasket A green and yellow basket\", \"A-tisket a-tasket A green and yellow basket\".length)</code> should return \"A-tisket a-tasket A green and yellow basket\".');",
"assert(truncateString('A-tisket a-tasket A green and yellow basket', 'A-tisket a-tasket A green and yellow basket'.length + 2) === 'A-tisket a-tasket A green and yellow basket', 'message: <code>truncateString(\"A-tisket a-tasket A green and yellow basket\", \"A-tisket a-tasket A green and yellow basket\".length + 2)</code> should return \"A-tisket a-tasket A green and yellow basket\".');",
"assert(truncateString(\"A-\", 1) === \"A...\", 'message: <code>truncateString(\"A-\", 1)</code> should return \"A...\".');",
"assert(truncateString(\"Absolutely Longer\", 2) === \"Ab...\", 'message: <code>truncateString(\"Absolutely Longer\", 2)</code> should return \"Ab...\".');"
],
"type": "bonfire",
"isRequired": true,
"solutions": [
"function truncateString(str, num) {\n if (num >= str.length) {\n return str;\n }\n return str.slice(0, num) + '...';\n}"
],
"MDNlinks": [
"String.prototype.slice()"
],
"challengeType": 5,
"translations": {
"es": {
"title": "Trunca una Cadena de Texto",
"description": [
"Trunca una cadena de texto (primer argumento) si su longitud es mayor que un máximo de caracteres dado (segundo argumento). Devuelve la cadena de texto truncada con una terminación \"...\".",
"Recuerda utilizar <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Leer-Buscar-Preguntar</a> si te sientes atascado. Intenta programar en pareja. Escribe tu propio código."
]
},
"pt-br": {
"title": "Trunque uma string",
"description": [
"Trunque uma string (primeiro argumento) se ela for mais longa do que o comprimento máximo dado (segundo argumento). Retorne a string truncada com um <code>...</code> no final.",
"Lembre-se de <a href=\"http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514\" target=\"_blank\">Ler-Pesquisar-Perguntar</a> se ficar travado. Escreva seu próprio código."
]
}
}
},
{
"id": "a6e40f1041b06c996f7b2406",
"title": "Finders Keepers",
"description": [
"Create a function that looks through an array (first argument) and returns the first element in the array that passes a truth test (second argument). If no element passes the test, return undefined.",
"Remember to use <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> if you get stuck. Try to pair program. Write your own code."
],
"challengeSeed": [
"function findElement(arr, func) {",
" var num = 0;",
" return num;",
"}",
"",
"findElement([1, 2, 3, 4], function(num){ return num % 2 === 0; });"
],
"solutions": [
"function findElement(arr, func) {\n var num;\n arr.some(function(e) {\n if (func(e)) {\n num = e;\n return true;\n }\n });\n return num;\n}"
],
"tests": [
"assert.strictEqual(findElement([1, 3, 5, 8, 9, 10], function(num) { return num % 2 === 0; }), 8, 'message: <code>findElement([1, 3, 5, 8, 9, 10], function(num) { return num % 2 === 0; })</code> should return 8.');",
"assert.strictEqual(findElement([1, 3, 5, 9], function(num) { return num % 2 === 0; }), undefined, 'message: <code>findElement([1, 3, 5, 9], function(num) { return num % 2 === 0; })</code> should return undefined.');"
],
"type": "bonfire",
"MDNlinks": [
"Array.prototype.filter()"
],
"isRequired": true,
"challengeType": 5,
"translations": {
"es": {
"title": "Buscando la verdad",
"description": [
"Crea una función que busque dentro de un vector (primer argumento) y que devuelva el primer elemento que pase una prueba de verdad (segundo argumento).",
"Recuerda utilizar <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Leer-Buscar-Preguntar</a> si te sientes atascado. Intenta programar en pareja. Escribe tu propio código."
]
},
"pt-br": {
"title": "Achado não é roubado",
"description": [
"Crie uma função que itera sobre um array (primeiro argumento) e retorna o primeiro elemento do array que retornar <code>true</code> para uma função de teste (segundo argumento). Se nenhum elemento passar no teste, retorne <code>undefined</code>.",
"Lembre-se de <a href=\"http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514\" target=\"_blank\">Ler-Pesquisar-Perguntar</a> se ficar travado. Escreva seu próprio código."
]
},
"fr": {
"title": "Détecteur de mensonges",
"description": [
"Crée une fonction qui parcourt un tableau (premier argument) et renvoie le premier élément du tableau qui passe le test (second argument).",
"N'oublie pas d'utiliser <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Lire-Chercher-Demander</a> si tu es bloqué. Essaye de trouver un partenaire. Écris ton propre code."
]
}
}
},
{
"id": "a77dbc43c33f39daa4429b4f",
"title": "Boo who",
"description": [
"Check if a value is classified as a boolean primitive. Return true or false.",
"Boolean primitives are true and false.",
"Remember to use <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> if you get stuck. Try to pair program. Write your own code."
],
"challengeSeed": [
"function booWho(bool) {",
" // What is the new fad diet for ghost developers? The Boolean.",
" return bool;",
"}",
"",
"booWho(null);"
],
"solutions": [
"function booWho(bool) {\n // What is the new fad diet for ghost developers? The Boolean.\n return typeof bool === \"boolean\";\n}\n\nbooWho(null);"
],
"tests": [
"assert.strictEqual(booWho(true), true, 'message: <code>booWho(true)</code> should return true.');",
"assert.strictEqual(booWho(false), true, 'message: <code>booWho(false)</code> should return true.');",
"assert.strictEqual(booWho([1, 2, 3]), false, 'message: <code>booWho([1, 2, 3])</code> should return false.');",
"assert.strictEqual(booWho([].slice), false, 'message: <code>booWho([].slice)</code> should return false.');",
"assert.strictEqual(booWho({ \"a\": 1 }), false, 'message: <code>booWho({ \"a\": 1 })</code> should return false.');",
"assert.strictEqual(booWho(1), false, 'message: <code>booWho(1)</code> should return false.');",
"assert.strictEqual(booWho(NaN), false, 'message: <code>booWho(NaN)</code> should return false.');",
"assert.strictEqual(booWho(\"a\"), false, 'message: <code>booWho(\"a\")</code> should return false.');",
"assert.strictEqual(booWho(\"true\"), false, 'message: <code>booWho(\"true\")</code> should return false.');",
"assert.strictEqual(booWho(\"false\"), false, 'message: <code>booWho(\"false\")</code> should return false.');"
],
"type": "bonfire",
"MDNlinks": [
"Boolean Objects"
],
"isRequired": true,
"challengeType": 5,
"translations": {
"es": {
"title": "¡Bu!",
"description": [
"Crea una función que verifique si el valor que se le pasa es de tipo booleano. Haz que la función devuelva true o false según corresponda.",
"Los primitivos booleanos primitivos son: true y false",
"Recuerda utilizar <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Leer-Buscar-Preguntar</a> si te sientes atascado. Intenta programar en pareja. Escribe tu propio código."
]
},
"pt-br": {
"title": "Bu!",
"description": [
"Verifique se um valor é classificado como um primitivo booleano. Retorne <code>true</code> ou <code>false</code>.",
"Primitivos booleanos são <code>true</code> e <code>false</code>.",
"Lembre-se de <a href=\"http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514\" target=\"_blank\">Ler-Pesquisar-Perguntar</a> se ficar travado. Tente programar em par. Escreva seu próprio código."
]
},
"fr": {
"title": "Boo !",
"description": [
"Crée une fonction qui vérifie qu'une valeur est de type booléen. Renvoie true ou false.",
"Les primitives booléennes sont true ou false.",
"N'oublie pas d'utiliser <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Lire-Chercher-Demander</a> si tu es bloqué. Essaye de trouver un partenaire. Écris ton propre code."
]
}
}
},
{
"id": "ab6137d4e35944e21037b769",
"title": "Title Case a Sentence",
"description": [
"Return the provided string with the first letter of each word capitalized. Make sure the rest of the word is in lower case.",
"For the purpose of this exercise, you should also capitalize connecting words like \"the\" and \"of\".",
"Remember to use <a href=\"http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514\" target=\"_blank\">Read-Search-Ask</a> if you get stuck. Write your own code."
],
"challengeSeed": [
"function titleCase(str) {",
" return str;",
"}",
"",
"titleCase(\"I'm a little tea pot\");"
],
"tests": [
"assert(typeof titleCase(\"I'm a little tea pot\") === \"string\", 'message: <code>titleCase(\"I&#39;m a little tea pot\")</code> should return a string.');",
"assert(titleCase(\"I'm a little tea pot\") === \"I'm A Little Tea Pot\", 'message: <code>titleCase(\"I&#39;m a little tea pot\")</code> should return <code>I&#39;m A Little Tea Pot</code>.');",
"assert(titleCase(\"sHoRt AnD sToUt\") === \"Short And Stout\", 'message: <code>titleCase(\"sHoRt AnD sToUt\")</code> should return <code>Short And Stout</code>.');",
"assert(titleCase(\"HERE IS MY HANDLE HERE IS MY SPOUT\") === \"Here Is My Handle Here Is My Spout\", 'message: <code>titleCase(\"HERE IS MY HANDLE HERE IS MY SPOUT\")</code> should return <code>Here Is My Handle Here Is My Spout</code>.');"
],
"type": "bonfire",
"isRequired": true,
"solutions": [
"function titleCase(str) {\n return str.split(' ').map(function(word) {\n return word.charAt(0).toUpperCase() + word.substring(1).toLowerCase();\n }).join(' ');\n}\n\ntitleCase(\"I'm a little tea pot\");\n"
],
"MDNlinks": [
"String.prototype.split()"
],
"challengeType": 5,
"translations": {
"es": {
"title": "Aplica formato de título",
"description": [
"Crea una función que devuelva la cadena de texto que recibe con la primera letra de cada palabra en mayúscula. Asegúrate de que el resto de las letras sean minúsculas",
"Para este ejercicio, también debes poner en mayúscula conectores como \"the\" y \"of\".",
"Recuerda utilizar <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Leer-Buscar-Preguntar</a> si te sientes atascado. Intenta programar en pareja. Escribe tu propio código."
]
},
"pt-br": {
"title": "Transforme Uma String Num Título",
"description": [
"Retorne a string fornecida com a primeira letra de cada palavra em maiúsculo. Certifique-se de que o resto da palavra esteja minúsculo.",
"Para o propósito desse exercício, você também deve deixar maiúscula a primeira letra das palavras de ligação como \"the\" e \"of\".",
"Lembre-se de <a href=\"http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514\" target=\"_blank\">Ler-Pesquisar-Perguntar</a> se ficar travado. Escreva seu próprio código."
]
}
}
},
{
"id": "579e2a2c335b9d72dd32e05c",
"title": "Slice and Splice",
"description": [
"You are given two arrays and an index.",
"Use the array methods <code>slice</code> and <code>splice</code> to copy each element of the first array into the second array, in order.",
"Begin inserting elements at index <code>n</code> of the second array.",
"Return the resulting array. The input arrays should remain the same after the function runs.",
"Remember to use <a href=\"http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514\" target=\"_blank\">Read-Search-Ask</a> if you get stuck. Write your own code."
],
"challengeSeed": [
"function frankenSplice(arr1, arr2, n) {",
" // It's alive. It's alive!",
" return arr2;",
"}",
"",
"frankenSplice([1, 2, 3], [4, 5, 6], 1);"
],
"tail": [
"var testArr1 = [1, 2];",
"var testArr2 = ['a', 'b'];"
],
"tests": [
"assert.deepEqual(frankenSplice([1, 2, 3], [4, 5], 1), [4, 1, 2, 3, 5], 'message: <code>frankenSplice([1, 2, 3], [4, 5], 1)</code> should return <code>[4, 1, 2, 3, 5]</code>.');",
"assert.deepEqual(frankenSplice(testArr1, testArr2, 1), ['a', 1, 2, 'b'], 'message: <code>frankenSplice([1, 2], [\"a\", \"b\"], 1)</code> should return <code>[\"a\", 1, 2, \"b\"]</code>.');",
"assert.deepEqual(frankenSplice(['claw', 'tentacle'], ['head', 'shoulders', 'knees', 'toes'], 2), ['head', 'shoulders', 'claw', 'tentacle', 'knees', 'toes'], 'message: <code>frankenSplice([\"claw\", \"tentacle\"], [\"head\", \"shoulders\", \"knees\", \"toes\"], 2)</code> should return <code>[\"head\", \"shoulders\", \"claw\", \"tentacle\", \"knees\", \"toes\"]</code>.');",
"assert.deepEqual(frankenSplice([1, 2, 3, 4], [], 0), [1, 2, 3, 4], 'message: All elements from the first array should be added to the second array in their original order.');",
"assert(testArr1[0] === 1 && testArr1[1] === 2, 'message: The first array should remain the same after the function runs.');",
"assert(testArr2[0] === 'a' && testArr2[1] === 'b', 'message: The second array should remain the same after the function runs.');"
],
"type": "bonfire",
"isRequired": true,
"isBeta": true,
"solutions": [
"function frankenSplice(arr1, arr2, n) {\n // It's alive. It's alive!\n var result = arr2.slice();\n for(var i = 0; i < arr1.length; i++) {\n result.splice(n+i, 0, arr1[i]);\n }\n return result;\n}\n\nfrankenSplice([1, 2, 3], [4, 5], 1);\n"
],
"MDNlinks": [
"Array.prototype.slice()",
"Array.prototype.splice()"
],
"challengeType": 5,
"translations": {
"pt-br": {
"title": "Slice e splice",
"description": [
"Você recebe dois arrays e um índice.",
"Use os métodos de array <code>slice</code> e <code>splice</code> para copiar cada elemento do primeiro array para o segundo array, em ordem.",
"Comece a inserir elementos no índice <code>n</code> do segundo array.",
"Lembre-se de <a href=\"http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514\" target=\"_blank\">Ler-Pesquisar-Perguntar</a> se ficar travado. Escreva seu próprio código."
]
}
}
},
{
"id": "adf08ec01beb4f99fc7a68f2",
"title": "Falsy Bouncer",
"description": [
"Remove all falsy values from an array.",
"Falsy values in JavaScript are <code>false</code>, <code>null</code>, <code>0</code>, <code>\"\"</code>, <code>undefined</code>, and <code>NaN</code>.",
"Hint: Try converting each value to a Boolean.",
"Remember to use <a href=\"http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514\" target=\"_blank\">Read-Search-Ask</a> if you get stuck. Write your own code."
],
"challengeSeed": [
"function bouncer(arr) {",
" // Don't show a false ID to this bouncer.",
" return arr;",
"}",
"",
"bouncer([7, \"ate\", \"\", false, 9]);"
],
"tests": [
"assert.deepEqual(bouncer([7, \"ate\", \"\", false, 9]), [7, \"ate\", 9], 'message: <code>bouncer([7, \"ate\", \"\", false, 9])</code> should return <code>[7, \"ate\", 9]</code>.');",
"assert.deepEqual(bouncer([\"a\", \"b\", \"c\"]), [\"a\", \"b\", \"c\"], 'message: <code>bouncer([\"a\", \"b\", \"c\"])</code> should return <code>[\"a\", \"b\", \"c\"]</code>.');",
"assert.deepEqual(bouncer([false, null, 0, NaN, undefined, \"\"]), [], 'message: <code>bouncer([false, null, 0, NaN, undefined, \"\"])</code> should return <code>[]</code>.');",
"assert.deepEqual(bouncer([1, null, NaN, 2, undefined]), [1, 2], 'message: <code>bouncer([1, null, NaN, 2, undefined])</code> should return <code>[1, 2]</code>.');"
],
"type": "bonfire",
"isRequired": true,
"solutions": [
"function bouncer(arr) {\n // Don't show a false ID to this bouncer.\n return arr.filter(function(e) {return e;});\n}\n\nbouncer([7, 'ate', '', false, 9]);\n"
],
"MDNlinks": [
"Boolean Objects",
"Array.prototype.filter()"
],
"challengeType": 5,
"translations": {
"es": {
"title": "Detector de Mentiras",
"description": [
"Remueve todos los valores falsy de un arreglo dado",
"En javascript, los valores falsy son los siguientes: <code>false</code>, <code>null</code>, <code>0</code>, <code>\"\"</code>, <code>undefined</code>, y <code>NaN</code>.",
"Recuerda utilizar <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Leer-Buscar-Preguntar</a> si te sientes atascado. Intenta programar en pareja. Escribe tu propio código."
]
},
"pt-br": {
"title": "Detector de mentiras",
"description": [
"Remova todos os valores falsos de um array.",
"Valores falsos em JavaScript são <code>false</code>, <code>null</code>, <code>0</code>, <code>\"\"</code>, <code>undefined</code> e <code>NaN</code>.",
"Dica: Tente converter cada valor para um booleano.",
"Lembre-se de <a href=\"http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514\" target=\"_blank\">Ler-Pesquisar-Perguntar</a> se ficar travado. Escreva seu próprio código."
]
}
}
},
{
"id": "a24c1a4622e3c05097f71d67",
"title": "Where do I Belong",
"description": [
"Return the lowest index at which a value (second argument) should be inserted into an array (first argument) once it has been sorted. The returned value should be a number.",
"For example, <code>getIndexToIns([1,2,3,4], 1.5)</code> should return <code>1</code> because it is greater than <code>1</code> (index 0), but less than <code>2</code> (index 1).",
"Likewise, <code>getIndexToIns([20,3,5], 19)</code> should return <code>2</code> because once the array has been sorted it will look like <code>[3,5,20]</code> and <code>19</code> is less than <code>20</code> (index 2) and greater than <code>5</code> (index 1).",
"Remember to use <a href=\"http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514\" target=\"_blank\">Read-Search-Ask</a> if you get stuck. Write your own code."
],
"challengeSeed": [
"function getIndexToIns(arr, num) {",
" // Find my place in this sorted array.",
" return num;",
"}",
"",
"getIndexToIns([40, 60], 50);"
],
"tests": [
"assert(getIndexToIns([10, 20, 30, 40, 50], 35) === 3, 'message: <code>getIndexToIns([10, 20, 30, 40, 50], 35)</code> should return <code>3</code>.');",
"assert(typeof(getIndexToIns([10, 20, 30, 40, 50], 35)) === \"number\", 'message: <code>getIndexToIns([10, 20, 30, 40, 50], 35)</code> should return a number.');",
"assert(getIndexToIns([10, 20, 30, 40, 50], 30) === 2, 'message: <code>getIndexToIns([10, 20, 30, 40, 50], 30)</code> should return <code>2</code>.');",
"assert(typeof(getIndexToIns([10, 20, 30, 40, 50], 30)) === \"number\", 'message: <code>getIndexToIns([10, 20, 30, 40, 50], 30)</code> should return a number.');",
"assert(getIndexToIns([40, 60], 50) === 1, 'message: <code>getIndexToIns([40, 60], 50)</code> should return <code>1</code>.');",
"assert(typeof(getIndexToIns([40, 60], 50)) === \"number\", 'message: <code>getIndexToIns([40, 60], 50)</code> should return a number.');",
"assert(getIndexToIns([3, 10, 5], 3) === 0, 'message: <code>getIndexToIns([3, 10, 5], 3)</code> should return <code>0</code>.');",
"assert(typeof(getIndexToIns([3, 10, 5], 3)) === \"number\", 'message: <code>getIndexToIns([3, 10, 5], 3)</code> should return a number.');",
"assert(getIndexToIns([5, 3, 20, 3], 5) === 2, 'message: <code>getIndexToIns([5, 3, 20, 3], 5)</code> should return <code>2</code>.');",
"assert(typeof(getIndexToIns([5, 3, 20, 3], 5)) === \"number\", 'message: <code>getIndexToIns([5, 3, 20, 3], 5)</code> should return a number.');",
"assert(getIndexToIns([2, 20, 10], 19) === 2, 'message: <code>getIndexToIns([2, 20, 10], 19)</code> should return <code>2</code>.');",
"assert(typeof(getIndexToIns([2, 20, 10], 19)) === \"number\", 'message: <code>getIndexToIns([2, 20, 10], 19)</code> should return a number.');",
"assert(getIndexToIns([2, 5, 10], 15) === 3, 'message: <code>getIndexToIns([2, 5, 10], 15)</code> should return <code>3</code>.');",
"assert(typeof(getIndexToIns([2, 5, 10], 15)) === \"number\", 'message: <code>getIndexToIns([2, 5, 10], 15)</code> should return a number.');",
"assert(getIndexToIns([], 1) === 0, 'message: <code>getIndexToIns([], 1)</code> should return <code>0</code>.');",
"assert(typeof(getIndexToIns([], 1)) === \"number\", 'message: <code>getIndexToIns([], 1)</code> should return a number.');"
],
"type": "bonfire",
"isRequired": true,
"solutions": [
"function getIndexToIns(arr, num) {\n arr = arr.sort(function(a, b){return a-b;});\n for (var i = 0; i < arr.length; i++) {\n if (arr[i] >= num)\n {\n return i;\n }\n }\n return arr.length;\n}"
],
"MDNlinks": [
"Array.prototype.sort()"
],
"challengeType": 5,
"translations": {
"es": {
"title": "¿Cuál es mi Asiento?",
"description": [
"Devuelve el menor índice en el que un valor (segundo argumento) debe ser insertado en un arreglo (primer argumento) una vez ha sido ordenado.",
"Por ejemplo, where([1,2,3,4], 1.5) debe devolver 1 porque el segundo argumento de la función (1.5) es mayor que 1 (con índice 0 en el arreglo), pero menor que 2 (con índice 1).",
"Mientras que <code>where([20,3,5], 19)</code> debe devolver <code>2</code> porque una vez ordenado el arreglo se verá com <code>[3,5,20]</code> y <code>19</code> es menor que <code>20</code> (índice 2) y mayor que <code>5</code> (índice 1).",
"Recuerda utilizar <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Leer-Buscar-Preguntar</a> si te sientes atascado. Intenta programar en pareja. Escribe tu propio código."
]
},
"pt-br": {
"title": "Onde é meu lugar?",
"description": [
"Retorne o menor índice no qual um valor (segundo argumento) deve ser inserido num array (primeiro argumento) depois que ele foi ordenado. O valor retornado deve ser um número.",
"Por exemplo, <code>getIndexToIns([1,2,3,4], 1.5)</code> deve retornar <code>1</code> porque <code>1.5</code> é maior que <code>1</code> (índice 0), mas menor que <code>2</code> (índice 1).",
"Da mesma forma, <code>getIndexToIns([20,3,5], 19)</code> deve retornar <code>2</code> porque, depois de ordenado, o array será <code>[3,5,20]</code> e <code>19</code> é menor que <code>20</code> (índice 2) e maior que <code>5</code> (index 1).",
"Lembre-se de <a href=\"http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514\" target=\"_blank\">Ler-Pesquisar-Perguntar</a> se ficar travado. Escreva seu próprio código."
]
}
}
},
{
"id": "af2170cad53daa0770fabdea",
"title": "Mutations",
"description": [
"Return true if the string in the first element of the array contains all of the letters of the string in the second element of the array.",
"For example, <code>[\"hello\", \"Hello\"]</code>, should return true because all of the letters in the second string are present in the first, ignoring case.",
"The arguments <code>[\"hello\", \"hey\"]</code> should return false because the string \"hello\" does not contain a \"y\".",
"Lastly, <code>[\"Alien\", \"line\"]</code>, should return true because all of the letters in \"line\" are present in \"Alien\".",
"Remember to use <a href=\"http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514\" target=\"_blank\">Read-Search-Ask</a> if you get stuck. Write your own code."
],
"challengeSeed": [
"function mutation(arr) {",
" return arr;",
"}",
"",
"mutation([\"hello\", \"hey\"]);"
],
"tests": [
"assert(mutation([\"hello\", \"hey\"]) === false, 'message: <code>mutation([\"hello\", \"hey\"])</code> should return false.');",
"assert(mutation([\"hello\", \"Hello\"]) === true, 'message: <code>mutation([\"hello\", \"Hello\"])</code> should return true.');",
"assert(mutation([\"zyxwvutsrqponmlkjihgfedcba\", \"qrstu\"]) === true, 'message: <code>mutation([\"zyxwvutsrqponmlkjihgfedcba\", \"qrstu\"])</code> should return true.');",
"assert(mutation([\"Mary\", \"Army\"]) === true, 'message: <code>mutation([\"Mary\", \"Army\"])</code> should return true.');",
"assert(mutation([\"Mary\", \"Aarmy\"]) === true, 'message: <code>mutation([\"Mary\", \"Aarmy\"])</code> should return true.');",
"assert(mutation([\"Alien\", \"line\"]) === true, 'message: <code>mutation([\"Alien\", \"line\"])</code> should return true.');",
"assert(mutation([\"floor\", \"for\"]) === true, 'message: <code>mutation([\"floor\", \"for\"])</code> should return true.');",
"assert(mutation([\"hello\", \"neo\"]) === false, 'message: <code>mutation([\"hello\", \"neo\"])</code> should return false.');",
"assert(mutation([\"voodoo\", \"no\"]) === false, 'message: <code>mutation([\"voodoo\", \"no\"])</code> should return false.');"
],
"type": "bonfire",
"isRequired": true,
"solutions": [
"function mutation(arr) {\n var hash = Object.create(null);\n arr[0].toLowerCase().split('').forEach(function(c) {\n hash[c] = true;\n });\n return !arr[1].toLowerCase().split('').filter(function(c) {\n return !hash[c];\n }).length;\n}\n\nmutation(['hello', 'hey']);\n"
],
"MDNlinks": [
"String.prototype.indexOf()"
],
"challengeType": 5,
"translations": {
"es": {
"title": "Mutaciones",
"description": [
"Crea una función que devuelva <code>true</code> si la cadena de texto del primer elemento de un arreglo contiene todas las letras de la cadena de texto del segundo elemento del arreglo.",
"Por ejemplo, <code>[\"hello\", \"Hello\"]</code>, debe devolver <code>true</code> porque todas las letras en la segunda cadena de texto están presentes en la primera, sin distinguir entre mayúsculas y minúsculas.",
"En el caso de <code>[\"hello\", \"hey\"]</code> la función debe devolver false porque la cadena de texto \"hello\" no contiene una \"y\".",
"Finalmente, <code>[\"Alien\", \"line\"]</code>, la función debe devolver <code>true</code> porque todas las letras en \"line\" están presentes en \"Alien\".",
"Recuerda utilizar <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Leer-Buscar-Preguntar</a> si te sientes atascado. Intenta programar en pareja. Escribe tu propio código."
]
},
"pt-br": {
"title": "Mutações",
"description": [
"Retorne <code>true</code> se a string no primeiro elemento do array contiver todas as letras da string no segundo elemento do array.",
"Por exemplo, para os argumentos <code>[\"hello\", \"Hello\"]</code>, sua função deve retornar <code>true</code>, porque todas as letras da segunda string estão presentes na primeira, ignorando maiúsculas e minúsculas.",
"Para os argumentos <code>[\"hello\", \"hey\"]</code>, sua função deve retornar <code>false</code> porque a string \"hello\" não contém um \"y\".",
"Finalmente, para <code>[\"Alien\", \"line\"]</code>, sua função deve retornar <code>true</code> porque todas as letras em \"line\" estão presentes em \"Alien\".",
"Lembre-se de <a href=\"http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514\" target=\"_blank\">Ler-Pesquisar-Perguntar</a> se ficar travado. Escreva seu próprio código."
]
}
}
},
{
"id": "a9bd25c716030ec90084d8a1",
"title": "Chunky Monkey",
"description": [
"Write a function that splits an array (first argument) into groups the length of <code>size</code> (second argument) and returns them as a two-dimensional array.",
"Remember to use <a href=\"http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514\" target=\"_blank\">Read-Search-Ask</a> if you get stuck. Write your own code."
],
"challengeSeed": [
"function chunkArrayInGroups(arr, size) {",
" // Break it up.",
" return arr;",
"}",
"",
"chunkArrayInGroups([\"a\", \"b\", \"c\", \"d\"], 2);"
],
"tests": [
"assert.deepEqual(chunkArrayInGroups([\"a\", \"b\", \"c\", \"d\"], 2), [[\"a\", \"b\"], [\"c\", \"d\"]], 'message: <code>chunkArrayInGroups([\"a\", \"b\", \"c\", \"d\"], 2)</code> should return <code>[[\"a\", \"b\"], [\"c\", \"d\"]]</code>.');",
"assert.deepEqual(chunkArrayInGroups([0, 1, 2, 3, 4, 5], 3), [[0, 1, 2], [3, 4, 5]], 'message: <code>chunkArrayInGroups([0, 1, 2, 3, 4, 5], 3)</code> should return <code>[[0, 1, 2], [3, 4, 5]]</code>.');",
"assert.deepEqual(chunkArrayInGroups([0, 1, 2, 3, 4, 5], 2), [[0, 1], [2, 3], [4, 5]], 'message: <code>chunkArrayInGroups([0, 1, 2, 3, 4, 5], 2)</code> should return <code>[[0, 1], [2, 3], [4, 5]]</code>.');",
"assert.deepEqual(chunkArrayInGroups([0, 1, 2, 3, 4, 5], 4), [[0, 1, 2, 3], [4, 5]], 'message: <code>chunkArrayInGroups([0, 1, 2, 3, 4, 5], 4)</code> should return <code>[[0, 1, 2, 3], [4, 5]]</code>.');",
"assert.deepEqual(chunkArrayInGroups([0, 1, 2, 3, 4, 5, 6], 3), [[0, 1, 2], [3, 4, 5], [6]], 'message: <code>chunkArrayInGroups([0, 1, 2, 3, 4, 5, 6], 3)</code> should return <code>[[0, 1, 2], [3, 4, 5], [6]]</code>.');",
"assert.deepEqual(chunkArrayInGroups([0, 1, 2, 3, 4, 5, 6, 7, 8], 4), [[0, 1, 2, 3], [4, 5, 6, 7], [8]], 'message: <code>chunkArrayInGroups([0, 1, 2, 3, 4, 5, 6, 7, 8], 4)</code> should return <code>[[0, 1, 2, 3], [4, 5, 6, 7], [8]]</code>.');",
"assert.deepEqual(chunkArrayInGroups([0, 1, 2, 3, 4, 5, 6, 7, 8], 2), [[0, 1], [2, 3], [4, 5], [6, 7], [8]], 'message: <code>chunkArrayInGroups([0, 1, 2, 3, 4, 5, 6, 7, 8], 2)</code> should return <code>[[0, 1], [2, 3], [4, 5], [6, 7], [8]]</code>.');"
],
"type": "bonfire",
"isRequired": true,
"solutions": [
"function chunkArrayInGroups(arr, size) {\n var out = [];\n for (var i = 0; i < arr.length; i+=size) {\n out.push(arr.slice(i,i+size));\n }\n return out;\n}\n\nchunkArrayInGroups(['a', 'b', 'c', 'd'], 2);\n"
],
"MDNlinks": [
"Array.prototype.push()",
"Array.prototype.slice()"
],
"challengeType": 5,
"translations": {
"es": {
"title": "En mil Pedazos",
"description": [
"Escribe una función que parta un arreglo (primer argumento) en fragmentos de una longitud dada (segundo argumento) y los devuelva en forma de un arreglo bidimensional.",
"Recuerda utilizar <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Leer-Buscar-Preguntar</a> si te sientes atascado. Intenta programar en pareja. Escribe tu propio código."
]
},
"pt-br": {
"title": "Em pedaços",
"description": [
"Escreva uma função que divide um array (primeiro argumento) em grupos de comprimento <code>size</code> (segundo argumento) e retorna esses grupos num array bidimensional.",
"Lembre-se de <a href=\"http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514\" target=\"_blank\">Ler-Pesquisar-Perguntar</a> se ficar travado. Escreva seu próprio código."
]
}
}
}
]
}

View File

@ -0,0 +1,825 @@
{
"name": "Basic Data Structures",
"order": 4,
"time": "1 hour",
"helpRoom": "Help",
"challenges": [
{
"id": "587d7dac367417b2b2516zx5",
"title": "Introduction to Arrays",
"description": [
[
"",
"",
"<dfn>Arrays</dfn> are one of JavaScript's most fundamental built-in data structures, and probably the data structure that you will work with most often throughout the course of the freeCodeCamp curriculum. The array is by no means unique to JavaScript, however &mdash; in fact, its probably safe to say that arrays are utilized by almost every complex program... ever.<br><br>In computer science, an array is a linear collection of elements characterized by the fact that each element has a unique <dfn>index</dfn>, or address, that can be computed and used to look up an element's position at run-time.",
""
],
[
"",
"",
"In Javascript, arrays are written as comma-separated lists and are enclosed in brackets <code>[element1, element2, element3]</code>. They can be any length, and store any type of data supported by JavaScript.<br><br>Arrays can sometimes be simple and serve very basic functionalities, but they can also be complex and very powerful - all of which depends on how the programmer chooses to utilize them<br><br>From this point forward, whenever we refer to the term <dfn>array</dfn>, it will be strictly within the context of JavaScript.",
""
],
[
"",
"",
"JavaScript offers many array <dfn>methods</dfn>, which are a sort of built in function, that allow us to access, traverse, and mutate arrays as needed, depending on our purpose.<br><br>In the coming challenges, we will discuss several of the most common and useful methods, and a few other key techniques, that will help you to better understand and utilize arrays as data structures in JavaScript.",
""
]
],
"releasedOn": "Feb 17, 2017",
"challengeSeed": [],
"tests": [],
"type": "waypoint",
"challengeType": 7,
"isRequired": false,
"translations": {}
},
{
"id": "587d7b7e367417b2b2512b20",
"title": "Use an Array to Store a Collection of Data",
"description": [
"The below is an example of the simplest implementation of an array data structure. This is known as a <dfn>one-dimensional array</dfn>, meaning it only has one level, or that it does not have any other arrays nested within it. Notice it contains <dfn>booleans</dfn>, <dfn>strings</dfn>, and <dfn>numbers</dfn>, among other valid JavaScript data types:",
"<blockquote>let simpleArray = ['one', 2, 'three, true, false, undefined, null];<br>console.log(simpleArray.length);<br>// logs 7</blockquote>",
"All array's have a length property, which as shown above, can be very easily accessed with the syntax <code>Array.length</code>.",
"A more complex implementation of an array can be seen below. This is known as a <dfn>multi-dimensional array</dfn>, or an array that contains other arrays. Notice that this array also contains JavaScript <dfn>objects</dfn>, which we will examine very closely in our next section, but for now, all you need to know is that arrays are also capable of storing complex objects.",
"<blockquote>let complexArray = [<br> [<br> {<br> one: 1,<br> two: 2<br> },<br> {<br> three: 3,<br> four: 4<br> }<br> ],<br> [<br> {<br> a: \"a\",<br> b: \"b\"<br> },<br> {<br> c: \"c\",<br> d: “d”<br> }<br> ]<br>];</blockquote>",
"<hr>",
"We have defined a variable called <code>yourArray</code>. Complete the statement by assigning an array of at least 5 elements in length to the <code>yourArray</code> variable. Your array should contain at least one <dfn>string</dfn>, one <dfn>number</dfn>, and one <dfn>boolean</dfn>."
],
"challengeSeed": [
"let yourArray; // change this line"
],
"tests": [
"assert.strictEqual(Array.isArray(yourArray), true, 'message: yourArray is an array');",
"assert.isAtLeast(yourArray.length, 5, 'message: <code>yourArray</code> is at least 5 elements long');",
"assert(yourArray.filter( el => typeof el === 'boolean').length >= 1, 'message: <code>yourArray</code> contains at least one <code>boolean</code>');",
"assert(yourArray.filter( el => typeof el === 'number').length >= 1, 'message: <code>yourArray</code> contains at least one <code>number</code>');",
"assert(yourArray.filter( el => typeof el === 'string').length >= 1, 'message: <code>yourArray</code> contains at least one <code>string</code>');"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"solutions": [],
"challengeType": 1,
"translations": {}
},
{
"id": "587d78b2366415b2v2512be3",
"title": "Access an Array's Contents Using Bracket Notation",
"description": [
"The fundamental feature of any data structure is, of course, the ability to not only store data, but to be able to retrieve that data on command. So, now that we've learned how to create an array, let's begin to think about how we can access that array's information.",
"When we define a simple array as seen below, there are 3 items in it:",
"<blockquote>let ourArray = [\"a\", \"b\", \"c\"];</blockquote>",
"In an array, each array item has an <dfn>index</dfn>. This index doubles as the position of that item in the array, and how you reference it. However, it is important to note, that JavaScript arrays are <dfn>zero-indexed</dfn>, meaning that the first element of an array is actually at the <em><strong>zeroth</strong></em> position, not the first.",
"In order to retrieve an element from an array we can enclose an index in brackets and append it to the end of an array, or more commonly, to a variable which references an array object. This is known as <dfn>bracket notation</dfn>.",
"For example, if we want to retrieve the <code>\"a\"</code> from <code>ourArray</code> and assign it to a variable, we can do so with the following code:",
"<blockquote>let ourVariable = ourArray[0];<br>// ourVariable equals \"a\"</blockquote>",
"In addition to accessing the value associated with an index, you can also <em>set</em> an index to a value using the same notation:",
"<blockquote>ourArray[1] = \"not b anymore\";<br>// ourArray now equals [\"a\", \"not b anymore\", \"c\"];</blockquote>",
"Using bracket notation, we have now reset the item at index 1 from <code>\"b\"</code>, to <code>\"not b anymore\"</code>.",
"<hr>",
"In order to complete this challenge, set the 2nd position (index <code>1</code>) of <code>myArray</code> to anything you want, besides <code>\"b\"</code>."
],
"challengeSeed": [
"let myArray = [\"a\", \"b\", \"c\", \"d\"];",
"// change code below this line",
"",
"//change code above this line",
"console.log(myArray);"
],
"tests": [
"assert.strictEqual(myArray[0], \"a\", 'message: <code>myArray[0]</code> is equal to <code>\"a\"</code>');",
"assert.notStrictEqual(myArray[1], \"b\", 'message: <code>myArray[1]</code> is no longer set to <code>\"b\"</code>');",
"assert.strictEqual(myArray[2], \"c\", 'message: <code>myArray[2]</code> is equal to <code>\"c\"</code>');",
"assert.strictEqual(myArray[3], \"d\", 'message: <code>myArray[3]</code> is equal to <code>\"d\"</code>');"
],
"type": "waypoint",
"solutions": [],
"challengeType": 1,
"translations": {}
},
{
"id": "587d78b2367417b2b2512b0e",
"title": "Add Items to an Array with push() and unshift()",
"description": [
"An array's length, like the data types it can contain, is not fixed. Arrays can be defined with a length of any number of elements, and elements can be added or removed over time; in other words, arrays are <dfn>mutable</dfn>. In this challenge, we will look at two methods with which we can programmatically modify an array: <code>Array.push()</code> and <code>Array.unshift()</code>. ",
"Both methods take one or more elements as parameters and add those elements to the array the method is being called on; the <code>push()</code> method adds elements to the end of an array, and <code>unshift()</code> adds elements to the beginning. Consider the following:",
"<blockquote>let twentyThree = 'XXIII';<br>let romanNumerals = ['XXI', 'XXII'];<br><br>romanNumerals.unshift('XIX', 'XX');<br>// now equals ['XIX', 'XX', 'XXI', 'XXII']<br><br>romanNumerals.push(twentyThree);<br>// now equals ['XIX', 'XX', 'XXI', 'XXII', 'XXIII']",
"Notice that we can also pass variables, which allows us even greater flexibility in dynamically modifying our array's data.",
"<hr>",
"We have defined a function, <code>mixedNumbers</code>, which we are passing an array as an argument. Modify the function by using <code>push()</code> and <code>unshift()</code> to add <code>'I', 2, 'three'</code> to the beginning of the array and <code>7, 'VIII', 9</code> to the end so that the returned array contains representations of the numbers 1-9 in order."
],
"challengeSeed": [
"function mixedNumbers(arr) {",
" // change code below this line",
"",
" // change code above this line",
" return arr;",
"}",
"",
"// do not change code below this line",
"console.log(mixedNumbers(['IV', 5, 'six']));"
],
"tests": [
"assert.deepEqual(mixedNumbers(['IV', 5, 'six']), ['I', 2, 'three', 'IV', 5, 'six', 7, 'VIII', 9], 'message: <code>mixedNumbers([\"IV\", 5, \"six\"])</code> should now return <code>[\"I\", 2, \"three\", \"IV\", 5, \"six\", 7, \"VIII\", 9]</code>');",
"assert.notStrictEqual(mixedNumbers.toString().search(/\\.push\\(/), -1, 'message: The <code>mixedNumbers</code> function should utilize the <code>push()</code> method');",
"assert.notStrictEqual(mixedNumbers.toString().search(/\\.unshift\\(/), -1, 'message: The <code>mixedNumbers</code> function should utilize the <code>unshift()</code> method');"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"solutions": [],
"challengeType": 1,
"translations": {}
},
{
"id": "587d78b2367417b2b2512b0f",
"title": "Remove Items from an Array with pop() and shift()",
"description": [
"Both <code>push()</code> and <code>unshift()</code> have corresponding methods that are nearly functional opposites: <code>pop()</code> and <code>shift()</code>. As you may have guessed by now, instead of adding, <code>pop()</code> <em>removes</em> an element from the end of an array, while <code>shift()</code> removes an element from the beginning. The key difference between <code>pop()</code> and <code>shift()</code> and their cousins <code>push()</code> and <code>unshift()</code>, is that neither method takes parameters, and each only allows an array to be modified by a single element at a time.",
"Let's take a look:",
"<blockquote>let greetings = ['whats up?', 'hello', 'see ya!'];<br><br>greetings.pop();<br>// now equals ['whats up?', 'hello']<br><br>greetings.shift();<br>// now equals ['hello']</blockquote>",
"We can also return the value of the removed element with either method like this:",
"<blockquote>let popped = greetings.pop();<br>// returns 'hello'<br>// greetings now equals []</blockquote>",
"<hr>",
"We have defined a function, <code>popShift</code>, which takes an array as an argument and returns a new array. Modify the function, using <code>pop()</code> and <code>shift()</code>, to remove the first and last elements of the argument array, and assign the removed elements to their corresponding variables, so that the returned array contains their values."
],
"challengeSeed": [
"function popShift(arr) {",
" let popped; // change this line",
" let shifted; // change this line",
" return [shifted, popped];",
"}",
"",
"// do not change code below this line",
"console.log(popShift(['challenge', 'is', 'not', 'complete']));"
],
"tests": [
"assert.deepEqual(popShift(['challenge', 'is', 'not', 'complete']), [\"challenge\", \"complete\"], 'message: <code>popShift([\"challenge\", \"is\", \"not\", \"complete\"])</code> should return <code>[\"challenge\", \"complete\"]</code>');",
"assert.notStrictEqual(popShift.toString().search(/\\.pop\\(/), -1, 'message: The <code>popShift</code> function should utilize the <code>pop()</code> method');",
"assert.notStrictEqual(popShift.toString().search(/\\.shift\\(/), -1, 'message: The <code>popShift</code> function should utilize the <code>shift()</code> method');"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"solutions": [],
"challengeType": 1,
"translations": {}
},
{
"id": "587d78b2367417b2b2512b10",
"title": "Remove Items Using splice()",
"description": [
"Ok, so we've learned how to remove elements from the beginning and end of arrays using <code>shift()</code> and <code>pop()</code>, but what if we want to remove an element from somewhere in the middle? Or remove more than one element at once? Well, that's where <code>splice()</code> comes in. <code>splice()</code> allows us to do just that: <strong>remove any number of consecutive elements</strong> from anywhere in an array.",
"<code>splice()</code> can take up to 3 parameters, but for now, we'll focus on just the first 2. The first two parameters of <code>splice()</code> are integers which represent indexes, or positions, of the array that <code>splice()</code> is being called upon. And remember, arrays are <em>zero-indexed</em>, so to indicate the first element of an array, we would use <code>0</code>. <code>splice()</code>'s first parameter represents the index on the array from which to begin removing elements, while the second parameter indicates the number of elements to delete. For example:",
"<blockquote>let array = ['today', 'was', 'not', 'so', 'great'];<br><br>array.splice(2, 2);<br>// remove 2 elements beginning with the 3rd element<br>// array now equals ['today', 'was', 'great']</blockquote>",
"<code>splice()</code> not only modifies the array it's being called on, but it also returns a new array containing the value of the removed elements:",
"<blockquote>let array = ['I', 'am', 'feeling', 'really', 'happy'];<br><br>let newArray = array.splice(3, 2);<br>// newArray equals ['really', 'happy']</blockquote>",
"<hr>",
"We've defined a function, <code>sumOfTen</code>, which takes an array as an argument and returns the sum of that array's elements. Modify the function, using <code>splice()</code>, so that it returns a value of <code>10</code>."
],
"challengeSeed": [
"function sumOfTen(arr) {",
" // change code below this line",
" ",
" // change code above this line",
" return arr.reduce((a, b) => a + b);",
"}",
"",
"// do not change code below this line",
"console.log(sumOfTen([2, 5, 1, 5, 2, 1]));"
],
"tests": [
"assert.strictEqual(sumOfTen([2, 5, 1, 5, 2, 1]), 10, 'message: <code>sumOfTen</code> should return 10');",
"assert.notStrictEqual(sumOfTen.toString().search(/\\.splice\\(/), -1, 'message: The <code>sumOfTen</code> function should utilize the <code>splice()</code> method');"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"solutions": [],
"challengeType": 1,
"translations": {}
},
{
"id": "587d78b3367417b2b2512b11",
"title": "Add Items Using splice()",
"description": [
"Remember in the last challenge we mentioned that <code>splice()</code> can take up to three parameters? Well, we can go one step further with <code>splice()</code> &mdash; in addition to removing elements, we can use that third parameter, which represents one or more elements, to <em>add</em> them as well. This can be incredibly useful for quickly switching out an element, or a set of elements, for another. For instance, let's say you're storing a color scheme for a set of DOM elements in an array, and want to dynamically change a color based on some action:",
"<blockquote>function colorChange(arr, index, newColor) {<br>&nbsp;&nbsp;arr.splice(index, 1, newColor);<br>&nbsp;&nbsp;return arr;<br>}<br><br>let colorScheme = ['#878787', '#a08794', '#bb7e8c', '#c9b6be', '#d1becf'];<br><br>colorScheme = colorChange(colorScheme, 2, '#332327');<br>// we have removed '#bb7e8c' and added '#332327' in its place<br>// colorScheme now equals ['#878787', '#a08794', '#332327', '#c9b6be', '#d1becf']</blockquote>",
"This function takes an array of hex values, an index at which to remove an element, and the new color to replace the removed element with. The return value is an array containing a newly modified color scheme! While this example is a bit oversimplified, we can see the value that utilizing <code>splice()</code> to its maximum potential can have.",
"<hr>",
"We have defined a function, <code>htmlColorNames</code>, which takes an array of HTML colors as an argument. Modify the function using <code>splice()</code> to remove the first two elements of the array and add <code>'DarkSalmon'</code> and <code>'BlanchedAlmond'</code> in their respective places."
],
"challengeSeed": [
"function htmlColorNames(arr) {",
" // change code below this line",
" ",
" // change code above this line",
" return arr;",
"} ",
" ",
"// do not change code below this line",
"console.log(htmlColorNames(['DarkGoldenRod', 'WhiteSmoke', 'LavenderBlush', 'PaleTurqoise', 'FireBrick']));"
],
"tests": [
"assert.deepEqual(htmlColorNames(['DarkGoldenRod', 'WhiteSmoke', 'LavenderBlush', 'PaleTurqoise', 'FireBrick']), ['DarkSalmon', 'BlanchedAlmond', 'LavenderBlush', 'PaleTurqoise', 'FireBrick'], 'message: <code>htmlColorNames</code> should return <code>[\"DarkSalmon\", \"BlanchedAlmond\", \"LavenderBlush\", \"PaleTurqoise\", \"FireBrick\"]</code>');",
"assert(/.splice/.test(code), 'message: The <code>htmlColorNames</code> function should utilize the <code>splice()</code> method');",
"assert(!/shift|unshift/.test(code), 'message: You should not use <code>shift()</code> or <code>unshift()</code>.');",
"assert(!/\\[\\d\\]\\s*=/.test(code), 'message: You should not use array bracket notation.');"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"solutions": [],
"challengeType": 1,
"translations": {}
},
{
"id": "587d7b7a367417b2b2512b12",
"title": "Copy Array Items Using slice()",
"description": [
"The next method we will cover is <code>slice()</code>. <code>slice()</code>, rather than modifying an array, copies, or <em>extracts</em>, a given number of elements to a new array, leaving the array it is called upon untouched. <code>slice()</code> takes only 2 parameters &mdash; the first is the index at which to begin extraction, and the second is the index at which to stop extraction (extraction will occur up to, but not including the element at this index). Consider this:",
"<blockquote>let weatherConditions = ['rain', 'snow', 'sleet', 'hail', 'clear'];<br><br>let todaysWeather = weatherConditions.slice(1, 3);<br>// todaysWeather equals ['snow', 'sleet'];<br>// weatherConditions still equals ['rain', 'snow', 'sleet', 'hail', 'clear']<br></blockquote>",
"In effect, we have created a new array by extracting elements from an existing array.",
"<hr>",
"We have defined a function, <code>forecast</code>, that takes an array as an argument. Modify the function using <code>slice()</code> to extract information from the argument array and return a new array that contains the elements <code>'warm'</code> and <code>'sunny'</code>."
],
"challengeSeed": [
"function forecast(arr) {",
" // change code below this line",
" ",
" return arr;",
"}",
"",
"// do not change code below this line",
"console.log(forecast(['cold', 'rainy', 'warm', 'sunny', 'cool', 'thunderstorms']));"
],
"tests": [
"assert.deepEqual(forecast(['cold', 'rainy', 'warm', 'sunny', 'cool', 'thunderstorms']), ['warm', 'sunny'], 'message: <code>forecast</code> should return <code>[\"warm\", \"sunny\"]');",
"assert(/\\.slice\\(/.test(code), 'message: The <code>forecast</code> function should utilize the <code>slice()</code> method');"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"solutions": [],
"challengeType": 1,
"translations": {}
},
{
"id": "587d7b7b367417b2b2512b13",
"title": "Copy an Array with the Spread Operator",
"description": [
"While <code>slice()</code> allows us to be selective about what elements of an array to copy, among several other useful tasks, ES6's new <dfn>spread operator</dfn> allows us to easily copy <em>all</em> of an array's elements, in order, with a simple and highly readable syntax. The spread syntax simply looks like this: <code>...</code>",
"In practice, we can use the spread operator to copy an array like so:",
"<blockquote>let thisArray = [true, true, undefined, false, null];<br>let thatArray = [...thisArray];<br>// thatArray equals [true, true, undefined, false, null]<br>// thisArray remains unchanged, and is identical to thatArray</blockquote>",
"<hr>",
"We have defined a function, <code>copyMachine</code> which takes <code>arr</code> (an array) and <code>num</code> (a number) as arguments. The function is supposed to return a new array made up of <code>num</code> copies of <code>arr</code>. We have done most of the work for you, but it doesn't work quite right yet. Modify the function using spread syntax so that it works correctly (hint: another method we have already covered might come in handy here!)."
],
"challengeSeed": [
"function copyMachine(arr, num) {",
" let newArr = [];",
" while (num >= 1) {",
" // change code below this line",
"",
" // change code above this line",
" num--;",
" }",
" return newArr;",
"}",
"",
"// change code here to test different cases:",
"console.log(copyMachine([true, false, true], 2));"
],
"tests": [
"assert.deepEqual(copyMachine([true, false, true], 2), [[true, false, true], [true, false, true]], 'message: <code>copyMachine([true, false, true], 2)</code> should return <code>[[true, false, true], [true, false, true]]</code>');",
"assert.deepEqual(copyMachine([1, 2, 3], 5), [[1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3]], 'message: <code>copyMachine([1, 2, 3], 5)</code> should return <code>[[1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3]]</code>');",
"assert.deepEqual(copyMachine([true, true, null], 1), [[true, true, null]], 'message: <code>copyMachine([true, true, null], 1)</code> should return <code>[[true, true, null]]</code>');",
"assert.deepEqual(copyMachine(['it works'], 3), [['it works'], ['it works'], ['it works']], 'message: <code>copyMachine([\"it works\"], 3)</code> should return <code>[[\"it works\"], [\"it works\"], [\"it works\"]]</code>');",
"assert.notStrictEqual(copyMachine.toString().indexOf('.concat(_toConsumableArray(arr))'), -1, 'message: The <code>copyMachine</code> function should utilize the <code>spread operator</code> with array <code>arr</code>');"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"solutions": [],
"challengeType": 1,
"translations": {}
},
{
"id": "587d7b7b367417b2b2512b17",
"title": "Combine Arrays with the Spread Operator",
"description": [
"Another huge advantage of the <dfn>spread</dfn> operator, is the ability to combine arrays, or to insert all the elements of one array into another, at any index. With more traditional syntaxes, we can concatenate arrays, but this only allows us to combine arrays at the end of one, and at the start of another. Spread syntax makes the following operation extremely simple:",
"<blockquote>let thisArray = ['sage', 'rosemary', 'parsley', 'thyme'];<br><br>let thatArray = ['basil', 'cilantro', ...thisArray, 'coriander'];<br>// thatArray now equals ['basil', 'cilantro', 'sage', 'rosemary', 'parsley', 'thyme', 'coriander']</blockquote>",
"Using spread syntax, we have just achieved an operation that would have been more more complex and more verbose had we used traditional methods.",
"<hr>",
"We have defined a function <code>spreadOut</code> that returns the variable <code>sentence</code>, modify the function using the <dfn>spread</dfn> operator so that it returns the array <code>['learning', 'to', 'code', 'is', 'fun']</code>."
],
"challengeSeed": [
"function spreadOut() {",
" let fragment = ['to', 'code'];",
" let sentence; // change this line",
" return sentence;",
"}",
"",
"// do not change code below this line",
"console.log(spreadOut());"
],
"tests": [
"assert.deepEqual(spreadOut(), ['learning', 'to', 'code', 'is', 'fun'], 'message: <code>spreadOut</code> should return <code>[\"learning\", \"to\", \"code\", \"is\", \"fun\"]</code>');",
"assert.notStrictEqual(spreadOut.toString().search(/[...]/), -1, 'message: The <code>spreadOut</code> function should utilize spread syntax');"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"solutions": [],
"challengeType": 1,
"translations": {}
},
{
"id": "587d7b7b367417b2b2512b14",
"title": "Check For The Presence of an Element With indexOf()",
"description": [
"Since arrays can be changed, or <em>mutated</em>, at any time, there's no guarantee about where a particular piece of data will be on a given array, or if that element even still exists. Luckily, JavaScript provides us with another built-in method, <code>indexOf()</code>, that allows us to quickly and easily check for the presence of an element on an array. <code>indexOf()</code> takes an element as a parameter, and when called, it returns the position, or index, of that element, or <code>-1</code> if the element does not exist on the array.",
"For example:",
"<blockquote>let fruits = ['apples', 'pears', 'oranges', 'peaches', 'pears'];<br><br>fruits.indexOf('dates') // returns -1<br>fruits.indexOf('oranges') // returns 2<br>fruits.indexOf('pears') // returns 1, the first index at which the element exists</blockquote>",
"<hr>",
"<code>indexOf()</code> can be incredibly useful for quickly checking for the presence of an element on an array. We have defined a function, <code>quickCheck</code>, that takes an array and an element as arguments. Modify the function using <code>indexOf()</code> so that it returns <code>true</code> if the passed element exists on the array, and <code>false</code> if it does not."
],
"challengeSeed": [
"function quickCheck(arr, elem) {",
" // change code below this line",
"",
" // change code above this line",
"}",
"",
"// change code here to test different cases:",
"console.log(quickCheck(['squash', 'onions', 'shallots'], 'mushrooms'));"
],
"tests": [
"assert.strictEqual(quickCheck(['squash', 'onions', 'shallots'], 'mushrooms'), false, 'message: <code>quickCheck([\"squash\", \"onions\", \"shallots\"], \"mushrooms\")</code> should return <code>false</code>');",
"assert.strictEqual(quickCheck(['squash', 'onions', 'shallots'], 'onions'), true, 'message: <code>quickCheck([\"squash\", \"onions\", \"shallots\"], \"onions\")</code> should return <code>true</code>');",
"assert.strictEqual(quickCheck([3, 5, 9, 125, 45, 2], 125), true, 'message: <code>quickCheck([3, 5, 9, 125, 45, 2], 125)</code> should return <code>true</code>');",
"assert.strictEqual(quickCheck([true, false, false], undefined), false, 'message: <code>quickCheck([true, false, false], undefined)</code> should return <code>false</code>');",
"assert.notStrictEqual(quickCheck.toString().search(/\\.indexOf\\(/), -1, 'message: The <code>quickCheck</code> function should utilize the <code>indexOf()</code> method');"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"solutions": [],
"challengeType": 1,
"translations": {}
},
{
"id": "587d7b7b367417b2b2512b15",
"title": "Iterate Through All an Array's Items Using For Loops",
"description": [
"Sometimes when working with arrays, it is very handy to be able to iterate through each item to find one or more elements that we might need, or to manipulate an array based on which data items meet a certain set of criteria. JavaScript offers several built in methods that each iterate over arrays in slightly different ways to achieve different results (such as <code>every()</code>, <code>forEach()</code>, <code>map()</code>, etc.), however the technique which is most flexible and offers us the greatest amount of control is a simple <code>for</code> loop.",
"Consider the following:",
"<blockquote>function greaterThanTen(arr) {<br>&nbsp;&nbsp;let newArr = [];<br>&nbsp;&nbsp;for (let i = 0; i < arr.length; i++) {<br>&nbsp;&nbsp;&nbsp;&nbsp;if (arr[i] > 10) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;newArr.push(arr[i]);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;}<br>&nbsp;&nbsp;return newArr;<br>}<br><br>greaterThanTen([2, 12, 8, 14, 80, 0, 1]);<br>// returns [12, 14, 80]</blockquote>",
"Using a <code>for</code> loop, this function iterates through and accesses each element of the array, and subjects it to a simple test that we have created. In this way, we have easily and programmatically determined which data items are greater than <code>10</code>, and returned a new array containing those items.",
"<hr>",
"We have defined a function, <code>filteredArray</code>, which takes <code>arr</code>, a nested array, and <code>elem</code> as arguments, and returns a new array. <code>elem</code> represents an element that may or may not be present on one or more of the arrays nested within <code>arr</code>. Modify the function, using a <code>for</code> loop, to return a filtered version of the passed array such that any array nested within <code>arr</code> containing <code>elem</code> has been removed."
],
"challengeSeed": [
"function filteredArray(arr, elem) {",
" let newArr = [];",
" // change code below this line",
"",
" // change code above this line",
" return newArr;",
"}",
"",
"// change code here to test different cases:",
"console.log(filteredArray([[3, 2, 3], [1, 6, 3], [3, 13, 26], [19, 3, 9]], 3));"
],
"tests": [
"assert.deepEqual(filteredArray([ [10, 8, 3], [14, 6, 23], [3, 18, 6] ], 18), [[10, 8, 3], [14, 6, 23]], 'message: <code>filteredArray([[10, 8, 3], [14, 6, 23], [3, 18, 6]], 18)</code> should return <code>[ [10, 8, 3], [14, 6, 23] ]</code>');",
"assert.deepEqual(filteredArray([ ['trumpets', 2], ['flutes', 4], ['saxophones', 2] ], 2), [['flutes', 4]], 'message: <code>filteredArray([ [\"trumpets\", 2], [\"flutes\", 4], [\"saxophones\", 2] ], 2)</code> should return <code>[ [\"flutes\", 4] ]</code>');",
"assert.deepEqual(filteredArray([['amy', 'beth', 'sam'], ['dave', 'sean', 'peter']], 'peter'), [['amy', 'beth', 'sam']], 'message: <code>filteredArray([ [\"amy\", \"beth\", \"sam\"], [\"dave\", \"sean\", \"peter\"] ], \"peter\")</code> should return <code>[ [\"amy\", \"beth\", \"sam\"] ]</code>');",
"assert.deepEqual(filteredArray([[3, 2, 3], [1, 6, 3], [3, 13, 26], [19, 3, 9]], 3), [], 'message: <code>filteredArray([[3, 2, 3], [1, 6, 3], [3, 13, 26], [19, 3, 9]], 3)</code> should return <code>[ ]</code>');",
"assert.notStrictEqual(filteredArray.toString().search(/for/), -1, 'message: The <code>filteredArray</code> function should utilize a <code>for</code> loop');"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"solutions": [],
"challengeType": 1,
"translations": {}
},
{
"id": "587d7b7b367417b2b2512b16",
"title": "Create complex multi-dimensional arrays",
"description": [
"Awesome! You have just learned a ton about arrays! This has been a fairly high level overview, and there is plenty more to learn about working with arrays, much of which you will see in later sections. But before moving on to looking at <dfn>Objects</dfn>, lets take one more look, and see how arrays can become a bit more complex than what we have seen in previous challenges.",
"One of the most powerful features when thinking of arrays as data structures, is that arrays can contain, or even be completely made up of other arrays. We have seen arrays that contain arrays in previous challenges, but fairly simple ones. However, arrays can contain an infinite depth of arrays that can contain other arrays, each with their own arbitrary levels of depth, and so on. In this way, an array can very quickly become very complex data structure, known as a <dfn>multi-dimensional</dfn>, or nested array. Consider the following example:",
"<blockquote>let nestedArray = [ // top, or first level - the outer most array<br>&nbsp;&nbsp;['deep'], // an array within an array, 2 levels of depth<br>&nbsp;&nbsp;[<br>&nbsp;&nbsp;&nbsp;&nbsp;['deeper'], ['deeper'] // 2 arrays nested 3 levels deep<br>&nbsp;&nbsp;],<br>&nbsp;&nbsp;[<br>&nbsp;&nbsp;&nbsp;&nbsp;[<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;['deepest'], ['deepest'] // 2 arrays nested 4 levels deep<br>&nbsp;&nbsp;&nbsp;&nbsp;],<br>&nbsp;&nbsp;&nbsp;&nbsp;[<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;['deepest-est?'] // an array nested 5 levels deep<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;]<br>&nbsp;&nbsp;&nbsp;&nbsp;]<br>&nbsp;&nbsp;]<br>];</blockquote>",
"While this example may seem convoluted, this level of complexity is not unheard of, or even unusual, when dealing with large amounts of data.",
"However, we can still very easily access the deepest levels of an array this complex with bracket notation:",
"<blockquote>console.log(nestedArray[2][1][0][0][0]);<br>// logs: deepest-est?</blockquote>",
"And now that we know where that piece of data is, we can reset it if we need to:",
"<blockquote>nestedArray[2][1][0][0][0] = 'deeper still';<br><br>console.log(nestedArray[2][1][0][0][0]);<br>// now logs: deeper still</blockquote>",
"<hr>",
"We have defined a variable, <code>myNestedArray</code>, set equal to an array. Modify <code>myNestedArray</code>, using any combination of <dfn>strings</dfn>, <dfn>numbers</dfn>, and <dfn>booleans</dfn> for data elements, so that it has exactly five levels of depth (remember, the outer-most array is level 1). Somewhere on the third level, include the string <code>'deep'</code>, on the fourth level, include the string <code>'deeper'</code>, and on the fifth level, include the string <code>'deepest'</code>."
],
"challengeSeed": [
"let myNestedArray = [",
" // change code below this line",
" ['unshift', false, 1, 2, 3, 'complex', 'nested'],",
" ['loop', 'shift', 6, 7, 1000, 'method'],",
" ['concat', false, true, 'spread', 'array'],",
" ['mutate', 1327.98, 'splice', 'slice', 'push'],",
" ['iterate', 1.3849, 7, '8.4876', 'arbitrary', 'depth']",
" // change code above this line",
"];"
],
"tests": [
"assert.strictEqual((function(arr) { let flattened = (function flatten(arr) { const flat = [].concat(...arr); return flat.some (Array.isArray) ? flatten(flat) : flat; })(arr); for (let i = 0; i < flattened.length; i++) { if ( typeof flattened[i] !== 'number' && typeof flattened[i] !== 'string' && typeof flattened[i] !== 'boolean') { return false } } return true })(myNestedArray), true, 'message: <code>myNestedArray</code> should contain only numbers, booleans, and strings as data elements');",
"assert.strictEqual((function(arr) {let depth = 0;function arrayDepth(array, i, d) { if (Array.isArray(array[i])) { arrayDepth(array[i], 0, d + 1);} else { depth = (d > depth) ? d : depth;}if (i < array.length) { arrayDepth(array, i + 1, d);} }arrayDepth(arr, 0, 0);return depth;})(myNestedArray), 4, 'message: <code>myNestedArray</code> should have exactly 5 levels of depth');",
"assert((function howDeep(array, target, depth = 0) {return array.reduce((combined, current) => {if (Array.isArray(current)) { return combined.concat(howDeep(current, target, depth + 1));} else if (current === target) { return combined.concat(depth);} else { return combined;}}, []);})(myNestedArray, 'deep').length === 1 && (function howDeep(array, target, depth = 0) {return array.reduce((combined, current) => {if (Array.isArray(current)) { return combined.concat(howDeep(current, target, depth + 1));} else if (current === target) { return combined.concat(depth);} else { return combined;}}, []);})(myNestedArray, 'deep')[0] === 2, 'message: <code>myNestedArray</code> should contain exactly one occurrence of the string <code>\"deep\"</code> on an array nested 3 levels deep');",
"assert((function howDeep(array, target, depth = 0) {return array.reduce((combined, current) => {if (Array.isArray(current)) { return combined.concat(howDeep(current, target, depth + 1));} else if (current === target) { return combined.concat(depth);} else { return combined;}}, []);})(myNestedArray, 'deeper').length === 1 && (function howDeep(array, target, depth = 0) {return array.reduce((combined, current) => {if (Array.isArray(current)) { return combined.concat(howDeep(current, target, depth + 1));} else if (current === target) { return combined.concat(depth);} else { return combined;}}, []);})(myNestedArray, 'deeper')[0] === 3, 'message: <code>myNestedArray</code> should contain exactly one occurrence of the string <code>\"deeper\"</code> on an array nested 4 levels deep');",
"assert((function howDeep(array, target, depth = 0) {return array.reduce((combined, current) => {if (Array.isArray(current)) { return combined.concat(howDeep(current, target, depth + 1));} else if (current === target) { return combined.concat(depth);} else { return combined;}}, []);})(myNestedArray, 'deepest').length === 1 && (function howDeep(array, target, depth = 0) {return array.reduce((combined, current) => {if (Array.isArray(current)) { return combined.concat(howDeep(current, target, depth + 1));} else if (current === target) { return combined.concat(depth);} else { return combined;}}, []);})(myNestedArray, 'deepest')[0] === 4, 'message: <code>myNestedArray</code> should contain exactly one occurrence of the string <code>\"deepest\"</code> on an array nested 5 levels deep');"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"solutions": [],
"challengeType": 1,
"translations": {}
},
{
"id": "587d7dac367417b2b25184d3",
"title": "Introduction to Objects",
"description": [
[
"",
"",
"The next data structure we will discuss is the JavaScript <dfn>object</dfn>. Like arrays, objects are a fundamental part of JavaScript. However, it is probably safe to say that objects surpass arrays in flexibility, usefulness and in their overall importance to the language &mdash; in fact, you may have heard this line before: 'In JavaScript, everything is an object.'<br><br>While an understanding of objects is important to understand the inner workings of JavaScript functions or JavaScript's object-oriented capabilities, JavaScript objects at a basic level are actually just <dfn>key-value pair</dfn> stores, a commonly used data structure across almost all programming languages. Here, we will confine our discussion to JavaScript objects in this capacity.",
""
],
[
"",
"",
"Key-value pair data structures go by different names depending on the language and the specific details of the data structure. The terms <dfn>dictionary</dfn>, <dfn>map</dfn>, and <dfn>hash table</dfn> all refer to the notion of a data structure in which specific keys, or properties, are mapped to specific values.<br><br>Objects, and other similar key-value pair data structures, offer some very useful benefits. One clear benefit is that they allow us to structure our data in an intuitive way; properties can be nested to an arbitrary depth, and values can be anything, including arrays and even other objects.<br><br>Largely due to this flexibility, objects are also the foundation for <dfn>JavaScript Object Notation</dfn>, or <dfn>JSON</dfn>, which is a widely used method of sending data across the web.",
""
],
[
"",
"",
"Another powerful advantage of key-value pair data structures is <dfn>constant lookup time</dfn>. What this means, is that when you request the value of a specific property, you will get the value back in the same amount of time (theoretically) regardless of the number of entries in the object. If you had an object with 5 entries or one that held a collection of 1,000,000, you could still retrieve property values or check if a key exists in the same amount of time.<br><br>The reason for this fast lookup time, is that internally, the object is storing properties using a hashing mechanism which allows it to know exactly where it has stored different property values. If you want to learn more about this please take a look at the optional Advanced Data Structures challenges. All you should remember for now is that <strong>performant access to flexibly structured data make key-value stores very attractive data structures useful in a wide variety of settings</strong>.",
""
],
[
"",
"",
"<br><br>In JavaScript, objects are written as comma-separated lists of key-value pairs, wrapped in curly brackets, with each key and its assigned value separated by a colon:<br> <code>{ key1: 'val-1', key2: 'val-2' }</code><br><br>In the next few challenges, we will examine JavaScript objects more closely, and take a look at <dfn>methods</dfn> and techniques that allow us to access, store, and manipulate an object's data.<br><br>Note that throughout the scope of this discussion, and in general when considering JavaScript objects, the terms <dfn>key</dfn> and <dfn>property</dfn> will be used interchangeably.",
""
]
],
"releasedOn": "Feb 17, 2017",
"challengeSeed": [],
"tests": [],
"type": "waypoint",
"challengeType": 7,
"isRequired": false,
"translations": {}
},
{
"id": "587d7b7c367417b2b2512b18",
"title": "Add Key-Value Pairs to JavaScript Objects",
"description": [
"At their most basic, objects are just collections of <dfn>key-value pairs</dfn>, or in other words, pieces of data mapped to unique identifiers that we call <dfn>properties</dfn> or <dfn>keys</dfn>. Let's take a look at a very simple example:",
"<blockquote>let FCC_User = {<br> username: 'awesome_coder',<br> followers: 572,<br> points: 1741,<br> completedProjects: 15<br>};</blockquote>",
"The above code defines an object called <code>FCC_User</code> that has four <dfn>properties</dfn>, each of which map to a specific value. If we wanted to know the number of <code>followers</code> <code>FCC_User</code> has, we can access that property by writing:",
"<blockquote>let userData = FCC_User.followers;<br>// userData equals 572</blockquote>",
"This is called <dfn>dot notation</dfn>. Alternatively, we can also access the property with brackets, like so:",
"<blockquote>let userData = FCC_User['followers']<br>// userData equals 572</blockquote>",
"Notice that with <dfn>bracket notation</dfn>, we enclosed <code>followers</code> in quotes. This is because the brackets actually allow us to pass a variable in to be evaluated as a property name (hint: keep this in mind for later!). Had we passed <code>followers</code> in without the quotes, the JavaScript engine would have attempted to evaluate it as a variable, and a <code>ReferenceError: followers is not defined</code> would have been thrown.",
"<hr>",
"Using the same syntax, we can also <em><strong>add new</strong></em> key-value pairs to objects. We've created a <code>foods</code> object with three entries. Add three more entries: <code>bananas</code> with a value of <code>13</code>, <code>grapes</code> with a value of <code>35</code>, and <code>strawberries</code> with a value of <code>27</code>."
],
"challengeSeed": [
"let foods = {",
" apples: 25,",
" oranges: 32,",
" plums: 28",
"};",
"",
"// change code below this line",
"",
"// change code above this line",
"",
"console.log(foods);"
],
"tests": [
"assert(typeof foods === 'object', 'message: <code>foods</code> is an object');",
"assert(foods.bananas === 13, 'message: The <code>foods</code> object has a key <code>\"bananas\"</code> with a value of <code>13</code>');",
"assert(foods.grapes === 35, 'message: The <code>foods</code> object has a key <code>\"grapes\"</code> with a value of <code>35</code>');",
"assert(foods.strawberries === 27, 'message: The <code>foods</code> object has a key <code>\"strawberries\"</code> with a value of <code>27</code>');",
"assert(code.search(/bananas:/) === -1 && code.search(/grapes:/) === -1 && code.search(/strawberries:/) === -1, 'message: The key-value pairs should be set using dot or bracket notation');"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"solutions": [],
"challengeType": 1,
"translations": {}
},
{
"id": "587d7b7c367417b2b2512b19",
"title": "Modify an Object Nested Within an Object",
"description": [
"Now let's take a look at a slightly more complex object. Object properties can be nested to an arbitrary depth, and their values can be any type of data supported by JavaScript, including arrays and even other objects. Consider the following:",
"<blockquote>let nestedObject = {<br> id: 28802695164,<br> date: 'December 31, 2016',<br> data: {<br> totalUsers: 99,<br> online: 80,<br> onlineStatus: {<br> active: 67,<br> away: 13<br> }<br> }<br>};</blockquote>",
"<code>nestedObject</code> has three unique keys: <code>id</code>, whose value is a number, <code>date</code> whose value is a string, and <code>data</code>, whose value is an object which has yet another object nested within it. While structures can quickly become complex, we can still use the same notations to access the information we need.",
"<hr>",
"Here we've defined an object, <code>userActivity</code>, which includes another object nested within it. You can modify properties on this nested object in the same way you modified properties in the last challenge. Set the value of the <code>online</code> key to <code>45</code>."
],
"challengeSeed": [
"let userActivity = {",
" id: 23894201352,",
" date: 'January 1, 2017',",
" data: {",
" totalUsers: 51,",
" online: 42",
" }",
"};",
"",
"// change code below this line",
"",
"// change code above this line",
"",
"console.log(userActivity);"
],
"tests": [
"assert('id' in userActivity && 'date' in userActivity && 'data' in userActivity, 'message: <code>userActivity</code> has <code>id</code>, <code>date</code> and <code>data</code> properties');",
"assert('totalUsers' in userActivity.data && 'online' in userActivity.data, 'message: <code>userActivity</code> has a <code>data</code> key set to an object with keys <code>totalUsers</code> and <code>online</code>');",
"assert(userActivity.data.online === 45, 'message: The <code>online</code> property nested in the <code>data</code> key of <code>userActivity</code> should be set to <code>45</code>');",
"assert.strictEqual(code.search(/online: 45/), -1, 'message: The <code>online</code> property is set using dot or bracket notation');"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"solutions": [],
"challengeType": 1,
"translations": {}
},
{
"id": "587d7b7c367417b2b2512b1a",
"title": "Access Property Names with Bracket Notation",
"description": [
"In the first object challenge we mentioned the use of bracket notation as a way to access property values using the evaluation of a variable. For instance, imagine that our <code>foods</code> object is being used in a program for a supermarket cash register. We have some function that sets the <code>selectedFood</code> and we want to check our <code>foods</code> object for the presence of that food. This might look like:",
"<blockquote>let selectedFood = getCurrentFood(scannedItem);<br>let inventory = foods[selectedFood];</blockquote>",
"This code will evaluate the value stored in the <code>selectedFood</code> variable and return the value of that key in the <code>foods</code> object, or <code>undefined</code> if it is not present. Bracket notation is very useful because sometimes object properties are not known before runtime or we need to access them in a more dynamic way.",
"<hr>",
"We've defined a function, <code>checkInventory</code>, which receives a scanned item as an argument. Return the current value of the <code>scannedItem</code> key in the <code>foods</code> object. You can assume that only valid keys will be provided as an argument to <code>checkInventory</code>."
],
"challengeSeed": [
"let foods = {",
" apples: 25,",
" oranges: 32,",
" plums: 28,",
" bananas: 13,",
" grapes: 35,",
" strawberries: 27",
"};",
"// do not change code above this line",
"",
"function checkInventory(scannedItem) {",
" // change code below this line",
"",
"}",
"",
"// change code below this line to test different cases:",
"console.log(checkInventory(\"apples\"));"
],
"tests": [
"assert.strictEqual(typeof checkInventory, 'function', 'message: <code>checkInventory</code> is a function');",
"assert.deepEqual(foods, {apples: 25, oranges: 32, plums: 28, bananas: 13, grapes: 35, strawberries: 27}, 'message: The <code>foods</code> object should have only the following key-value pairs: <code>apples: 25</code>, <code>oranges: 32</code>, <code>plums: 28</code>, <code>bananas: 13</code>, <code>grapes: 35</code>, <code>strawberries: 27</code>');",
"assert.strictEqual(checkInventory('apples'), 25, 'message: <code>checkInventory(\"apples\")</code> should return <code>25</code>');",
"assert.strictEqual(checkInventory('bananas'), 13, 'message: <code>checkInventory(\"bananas\")</code> should return <code>13</code>');",
"assert.strictEqual(checkInventory('strawberries'), 27, 'message: <code>checkInventory(\"strawberries\")</code> should return <code>27</code>');"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"solutions": [],
"challengeType": 1,
"translations": {}
},
{
"id": "587d7b7c367417b2b2512b1b",
"title": "Use the delete Keyword to Remove Object Properties",
"description": [
"Now you know what objects are and their basic features and advantages. In short, they are key-value stores which provide a flexible, intuitive way to structure data, <strong><em>and</em></strong>, they provide very fast lookup time. Throughout the rest of these challenges, we will describe several common operations you can perform on objects so you can become comfortable applying these useful data structures in your programs.",
"In earlier challenges, we have both added to and modified an object's key-value pairs. Here we will see how we can <em>remove</em> a key-value pair from an object.",
"Let's revisit our <code>foods</code> object example one last time. If we wanted to remove the <code>apples</code> key, we can remove it by using the <code>delete</code> keyword like this:",
"<blockquote>delete foods.apples;</blockquote>",
"<hr>",
"Use the delete keyword to remove the <code>oranges</code>, <code>plums</code>, and <code>strawberries</code> keys from the <code>foods</code> object."
],
"challengeSeed": [
"let foods = {",
" apples: 25,",
" oranges: 32,",
" plums: 28,",
" bananas: 13,",
" grapes: 35,",
" strawberries: 27",
"};",
"",
"// change code below this line",
"",
"// change code above this line",
"",
"console.log(foods);"
],
"tests": [
"assert(!foods.hasOwnProperty('oranges') && !foods.hasOwnProperty('plums') && !foods.hasOwnProperty('strawberries') && Object.keys(foods).length === 3, 'message: The <code>foods</code> object only has three keys: <code>apples</code>, <code>grapes</code>, and <code>bananas</code>');",
"assert(code.search(/oranges:/) !== -1 && code.search(/plums:/) !== -1 && code.search(/strawberries:/) !== -1, 'message: The <code>oranges</code>, <code>plums</code>, and <code>strawberries</code> keys are removed using <code>delete</code>');"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"solutions": [],
"challengeType": 1,
"translations": {}
},
{
"id": "587d7b7d367417b2b2512b1c",
"title": "Check if an Object has a Property",
"description": [
"Now we can add, modify, and remove keys from objects. But what if we just wanted to know if an object has a specific property? JavaScript provides us with two different ways to do this. One uses the <code>hasOwnProperty()</code> method and the other uses the <code>in</code> keyword. If we have an object <code>users</code> with a property of <code>Alan</code>, we could check for its presence in either of the following ways:",
"<blockquote>users.hasOwnProperty('Alan');<br>'Alan' in users;<br>// both return true</blockquote>",
"<hr>",
"We've created an object, <code>users</code>, with some users in it and a function <code>isEveryoneHere</code>, which we pass the <code>users</code> object to as an argument. Finish writing this function so that it returns <code>true</code> only if the <code>users</code> object contains all four names, <code>Alan</code>, <code>Jeff</code>, <code>Sarah</code>, and <code>Ryan</code>, as keys, and <code>false</code> otherwise."
],
"challengeSeed": [
"let users = {",
" Alan: {",
" age: 27,",
" online: true",
" },",
" Jeff: {",
" age: 32,",
" online: true",
" },",
" Sarah: {",
" age: 48,",
" online: true",
" },",
" Ryan: {",
" age: 19,",
" online: true",
" }",
"};",
"",
"function isEveryoneHere(obj) {",
" // change code below this line",
"",
" // change code above this line",
"}",
"",
"console.log(isEveryoneHere(users));"
],
"tests": [
"assert('Alan' in users && 'Jeff' in users && 'Sarah' in users && 'Ryan' in users && Object.keys(users).length === 4, 'message: The <code>users</code> object only contains the keys <code>Alan</code>, <code>Jeff</code>, <code>Sarah</code>, and <code>Ryan</code>');",
"assert(isEveryoneHere(users) === true, 'message: The function <code>isEveryoneHere</code> returns <code>true</code> if <code>Alan</code>, <code>Jeff</code>, <code>Sarah</code>, and <code>Ryan</code> are properties on the <code>users</code> object');",
"assert((function() { delete users.Alan; delete users.Jeff; delete users.Sarah; delete users.Ryan; return isEveryoneHere(users) })() === false, 'message: The function <code>isEveryoneHere</code> returns <code>false</code> if <code>Alan</code>, <code>Jeff</code>, <code>Sarah</code>, and <code>Ryan</code> are not properties on the <code>users</code> object');"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"solutions": [],
"challengeType": 1,
"translations": {}
},
{
"id": "587d7b7d367417b2b2512b1d",
"title": " Iterate Through the Keys of an Object with a for...in Statement",
"description": [
"Sometimes you may need to iterate through all the keys within an object. This requires a specific syntax in JavaScript called a <dfn>for...in</dfn> statement. For our <code>users</code> object, this could look like:",
"<blockquote>for (let user in users) {<br> console.log(user);<br>};<br><br>// logs:<br>Alan<br>Jeff<br>Sarah<br>Ryan</blockquote>",
"In this statement, we defined a variable <code>user</code>, and as you can see, this variable was reset during each iteration to each of the object's keys as the statement looped through the object, resulting in each user's name being printed to the console.",
"<strong>NOTE:</strong><br>Objects do not maintain an ordering to stored keys like arrays do; thus a keys position on an object, or the relative order in which it appears, is irrelevant when referencing or accessing that key.",
"<hr>",
"We've defined a function, <code>countOnline</code>; use a <dfn>for...in</dfn> statement within this function to loop through the users in the <code>users</code> object and return the number of users whose <code>online</code> property is set to <code>true</code>."
],
"challengeSeed": [
"let users = {",
" Alan: {",
" age: 27,",
" online: false",
" },",
" Jeff: {",
" age: 32,",
" online: true",
" },",
" Sarah: {",
" age: 48,",
" online: false",
" },",
" Ryan: {",
" age: 19,",
" online: true",
" }",
"};",
"",
"function countOnline(obj) {",
" // change code below this line",
"",
" // change code above this line",
"}",
"",
"console.log(countOnline(users));"
],
"tests": [
"assert(users.Alan.online === false && users.Jeff.online === true && users.Sarah.online === false && users.Ryan.online === true, 'message: The <code>users</code> object contains users <code>Jeff</code> and <code>Ryan</code> with <code>online</code> set to <code>true</code> and users <code>Alan</code> and <code>Sarah</code> with <code>online</code> set to <code>false</code>');",
"assert((function() { users.Harry = {online: true}; users.Sam = {online: true}; users.Carl = {online: true}; return countOnline(users) })() === 5, 'message: The function <code>countOnline</code> returns the number of users with the <code>online</code> property set to <code>true</code>');"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"solutions": [],
"challengeType": 1,
"translations": {}
},
{
"id": "587d7b7d367417b2b2512b1e",
"title": "Generate an Array of All Object Keys with Object.keys()",
"description": [
"We can also generate an array which contains all the keys stored in an object using the <code>Object.keys()</code> method and passing in an object as the argument. This will return an array with strings representing each property in the object. Again, there will be no specific order to the entries in the array.",
"<hr>",
"Finish writing the <code>getArrayOfUsers</code> function so that it returns an array containing all the properties in the object it receives as an argument."
],
"challengeSeed": [
"let users = {",
" Alan: {",
" age: 27,",
" online: false",
" },",
" Jeff: {",
" age: 32,",
" online: true",
" },",
" Sarah: {",
" age: 48,",
" online: false",
" },",
" Ryan: {",
" age: 19,",
" online: true",
" }",
"};",
"",
"function getArrayOfUsers(obj) {",
" // change code below this line",
"",
" // change code above this line",
"}",
"",
"console.log(getArrayOfUsers(users));"
],
"tests": [
"assert('Alan' in users && 'Jeff' in users && 'Sarah' in users && 'Ryan' in users && Object.keys(users).length === 4, 'message: The <code>users</code> object only contains the keys <code>Alan</code>, <code>Jeff</code>, <code>Sarah</code>, and <code>Ryan</code>');",
"assert((function() { users.Sam = {}; users.Lewis = {}; let R = getArrayOfUsers(users); return (R.indexOf('Alan') !== -1 && R.indexOf('Jeff') !== -1 && R.indexOf('Sarah') !== -1 && R.indexOf('Ryan') !== -1 && R.indexOf('Sam') !== -1 && R.indexOf('Lewis') !== -1); })() === true, 'message: The <code>getArrayOfUsers</code> function returns an array which contains all the keys in the <code>users</code> object');"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"solutions": [],
"challengeType": 1,
"translations": {}
},
{
"id": "587d7b7d367417b2b2512b1f",
"title": "Modify an Array Stored in an Object",
"description": [
"Now you've seen all the basic operations for JavaScript objects. You can add, modify, and remove key-value pairs, check if keys exist, and iterate over all the keys in an object. As you continue learning JavaScript you will see even more versatile applications of objects. Additionally, the optional Advanced Data Structures lessons later in the curriculum also cover the ES6 <dfn>Map</dfn> and <dfn>Set</dfn> objects, both of which are similar to ordinary objects but provide some additional features. Now that you've learned the basics of arrays and objects, you're fully prepared to begin tackling more complex problems using JavaScript!",
"<hr>",
"Take a look at the object we've provided in the code editor. The <code>user</code> object contains three keys. The <code>data</code> key contains four keys, one of which contains an array of <code>friends</code>. From this, you can see how flexible objects are as data structures. We've started writing a function <code>addFriend</code>. Finish writing it so that it takes a <code>user</code> object and adds the name of the <code>friend</code> argument to the array stored in <code>user.data.friends</code> and returns that array."
],
"challengeSeed": [
"let user = {",
" name: 'Kenneth',",
" age: 28,",
" data: {",
" username: 'kennethCodesAllDay',",
" joinDate: 'March 26, 2016',",
" organization: 'freeCodeCamp',",
" friends: [",
" 'Sam',",
" 'Kira',",
" 'Tomo'",
" ],",
" location: {",
" city: 'San Francisco',",
" state: 'CA',",
" country: 'USA'",
" }",
" }",
"};",
"",
"function addFriend(userObj, friend) {",
" // change code below this line ",
"",
" // change code above this line",
"}",
"",
"console.log(addFriend(user, 'Pete'));"
],
"tests": [
"assert('name' in user && 'age' in user && 'data' in user, 'message: The <code>user</code> object has <code>name</code>, <code>age</code>, and <code>data</code> keys');",
"assert((function() { let L1 = user.data.friends.length; addFriend(user, 'Sean'); let L2 = user.data.friends.length; return (L2 === L1 + 1); })(), 'message: The <code>addFriend</code> function accepts a <code>user</code> object and a <code>friend</code> string as arguments and adds the friend to the array of <code>friends</code> in the <code>user</code> object');",
"assert.deepEqual((function() { delete user.data.friends; user.data.friends = ['Sam', 'Kira', 'Tomo']; return addFriend(user, 'Pete') })(), ['Sam', 'Kira', 'Tomo', 'Pete'], 'message: <code>addFriend(user, \"Pete\")</code> should return <code>[\"Sam\", \"Kira\", \"Tomo\", \"Pete\"]</code>');"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"solutions": [],
"challengeType": 1,
"translations": {}
}
]
}

View File

@ -0,0 +1,240 @@
{
"name": "Claim Your JavaScript Algorithms and Data Structures Certificate",
"order": 13,
"time": "5 minutes",
"challenges": [
{
"id": "587d7b7f367417b2b2512b25",
"title": "Claim Your JavaScript Algorithms and Data Structures Certificate",
"description": [
[
"//i.imgur.com/k8btNUB.jpg",
"An image of our Front End Development Certificate",
"This challenge will give you your verified Front End Development Certificate. Before we issue your certificate, we must verify that you have completed all of our basic and intermediate algorithm scripting challenges, and all our basic, intermediate, and advanced front end development projects. You must also accept our Academic Honesty Pledge. Click the button below to start this process.",
""
],
[
"//i.imgur.com/uLPsUko.jpg",
"The definition of plagiarism: Plagiarism (noun) - copying someone elses work and presenting it as your own without crediting them",
"By clicking below, you pledge that all of your submitted code A) is code you or your pair personally wrote, or B) comes from open source libraries like jQuery, or C) has been clearly attributed to its original authors. You also give us permission to audit your challenge solutions and revoke your certificate if we discover evidence of plagiarism.",
"#"
],
[
"//i.imgur.com/UedoV2G.jpg",
"An image of the text \"Front End Development Certificate requirements\"",
"Let's confirm that you have completed all of our basic and intermediate algorithm scripting challenges, and all our basic, intermediate, and advanced front end development projects. Click the button below to verify this.",
"#"
],
[
"//i.imgur.com/Q5Za9U6.jpg",
"An image of the word \"Congratulations\"",
"Congratulations! We've added your Front End Development Certificate to your portfolio page. Unless you choose to hide your solutions, this certificate will remain publicly visible and verifiable.",
""
]
],
"challengeSeed": [
{
"properties": [
"isHonest",
"isFrontEndCert"
],
"apis": [
"/certificate/honest",
"/certificate/verify/front-end"
],
"stepIndex": [
1,
2
]
}
],
"tests": [
{
"id": "a202eed8fc186c8434cb6d61",
"title": "Reverse a String"
},
{
"id": "a302f7aae1aa3152a5b413bc",
"title": "Factorialize a Number"
},
{
"id": "aaa48de84e1ecc7c742e1124",
"title": "Check for Palindromes"
},
{
"id": "a26cbbe9ad8655a977e1ceb5",
"title": "Find the Longest Word in a String"
},
{
"id": "ab6137d4e35944e21037b769",
"title": "Title Case a Sentence"
},
{
"id": "a789b3483989747d63b0e427",
"title": "Return Largest Numbers in Arrays"
},
{
"id": "acda2fb1324d9b0fa741e6b5",
"title": "Confirm the Ending"
},
{
"id": "afcc8d540bea9ea2669306b6",
"title": "Repeat a string repeat a string"
},
{
"id": "ac6993d51946422351508a41",
"title": "Truncate a string"
},
{
"id": "a9bd25c716030ec90084d8a1",
"title": "Chunky Monkey"
},
{
"id": "579e2a2c335b9d72dd32e05c",
"title": "Splice and Slice"
},
{
"id": "af2170cad53daa0770fabdea",
"title": "Mutations"
},
{
"id": "adf08ec01beb4f99fc7a68f2",
"title": "Falsy Bouncer"
},
{
"id": "a39963a4c10bc8b4d4f06d7e",
"title": "Seek and Destroy"
},
{
"id": "a24c1a4622e3c05097f71d67",
"title": "Where do I belong"
},
{
"id": "a3566b1109230028080c9345",
"title": "Sum All Numbers in a Range"
},
{
"id": "a5de63ebea8dbee56860f4f2",
"title": "Diff Two Arrays"
},
{
"id": "a7f4d8f2483413a6ce226cac",
"title": "Roman Numeral Converter"
},
{
"id": "a8e512fbe388ac2f9198f0fa",
"title": "Wherefore art thou"
},
{
"id": "a0b5010f579e69b815e7c5d6",
"title": "Search and Replace"
},
{
"id": "aa7697ea2477d1316795783b",
"title": "Pig Latin"
},
{
"id": "afd15382cdfb22c9efe8b7de",
"title": "DNA Pairing"
},
{
"id": "af7588ade1100bde429baf20",
"title": "Missing letters"
},
{
"id": "a77dbc43c33f39daa4429b4f",
"title": "Boo who"
},
{
"id": "a105e963526e7de52b219be9",
"title": "Sorted Union"
},
{
"id": "a6b0bb188d873cb2c8729495",
"title": "Convert HTML Entities"
},
{
"id": "a103376db3ba46b2d50db289",
"title": "Spinal Tap Case"
},
{
"id": "a5229172f011153519423690",
"title": "Sum All Odd Fibonacci Numbers"
},
{
"id": "a3bfc1673c0526e06d3ac698",
"title": "Sum All Primes"
},
{
"id": "ae9defd7acaf69703ab432ea",
"title": "Smallest Common Multiple"
},
{
"id": "a6e40f1041b06c996f7b2406",
"title": "Finders Keepers"
},
{
"id": "a5deed1811a43193f9f1c841",
"title": "Drop it"
},
{
"id": "ab306dbdcc907c7ddfc30830",
"title": "Steamroller"
},
{
"id": "a8d97bd4c764e91f9d2bda01",
"title": "Binary Agents"
},
{
"id": "a10d2431ad0c6a099a4b8b52",
"title": "Everything Be True"
},
{
"id": "a97fd23d9b809dac9921074f",
"title": "Arguments Optional"
},
{
"id": "56533eb9ac21ba0edf2244e2",
"title": "Caesars Cipher"
},
{
"id": "a2f1d72d9b908d0bd72bb9f6",
"title": "Make a Person"
},
{
"id": "af4afb223120f7348cdfc9fd",
"title": "Map the Debris"
}
],
"type": "Waypoint",
"challengeType": 7,
"descriptionEs": [
[
"//i.imgur.com/k8btNUB.jpg",
"Una imagen que muestra nuestro certificado de Desarrollo de interfaces",
"Este desafío te otorga tu certificado autenticado de Desarrollo de interfaces. Antes de que podamos emitir tu certificado, debemos verificar que has completado todos los desafíos básicos e intermedios de diseño de algoritmos, y todos los proyectos básicos e intermedios de desarrollo de interfaces. También debes aceptar nuestro Juramento de honestidad académica. Pulsa el botón siguiente para iniciar este proceso.",
""
],
[
"//i.imgur.com/HArFfMN.jpg",
"Plagio (nombre): acción y efecto de plagiar. Plagiar (verbo) - copiar en lo sustancial obras ajenas, dándolas como propias.",
"Al pulsar el botón siguiente, juras que todo el código en tus soluciones a los desafíos A) es código que tú o tu compañero escribieron personalmente, o B) proviene de librerías de código abierto como jQuery, o C) ha sido claramente atribuido a sus autores originales. También nos otorgas el permiso para auditar tus soluciones a los desafíos y revocar tu certificado si encontramos evidencia de plagio.",
"#"
],
[
"//i.imgur.com/14F2Van.jpg",
"Una imagen del texto \"Front End Development Certificate requirements\"",
"Confirmemos que has completado todos nuestros desafíos básicos e intermedios de diseño de algoritmos, y todos nuestros proyectos básicos e intermedios de desarrollo de interfaces. Pulsa el botón siguiente para hacer la verificación.",
"#"
],
[
"//i.imgur.com/16SIhHO.jpg",
"Una imagen de la palabra \"Congratulations\"",
"¡Felicitaciones! Hemos agregado tu certificado de Desarrollo de interfaces a tu portafolio. A menos que elijas no mostrar tus soluciones, este certificado será públicamente visible y verificable.",
""
]
],
"titleEs": "Reclama tu certificado de Desarrollo de interfaces"
}
]
}

View File

@ -0,0 +1,386 @@
{
"name": "Debugging",
"order": 4,
"time": "1 hour",
"helpRoom": "Help",
"challenges": [
{
"id": "587d7b83367417b2b2512b32",
"title": "Introduction to the Debugging Challenges",
"description": [
[
"http://imgs.xkcd.com/comics/debugging.png",
"XKCD web comic walking through the convoluted process of debugging. The programmer moves from a browser problem, to a keyboard driver issue, receives a cryptic system utility error message, and ends by finding the sword of Martin the Warrior.",
"Debugging is a valuable and (unfortunately) necessary tool for programmers. It follows the testing phase of checking if your code works as intended, and discovering it does not. Debugging is the process of finding exactly what isn't working and fixing it.",
""
],
[
"",
"",
"After spending time creating a brilliant block of code, it is tough realizing it may have errors. These issues generally come in three forms: 1) syntax errors that prevent a program from running, 2) runtime errors when code fails to execute or has unexpected behavior, and 3) semantic (or logical) errors when code doesn't do what it's meant to.<br><br>Modern code editors (and experience) can help identify syntax errors. Semantic and runtime errors are harder to find. They may cause your program to crash, make it run forever, or give incorrect output. Think of debugging as trying to understand why your code is behaving the way it is.<br><br>Example of a syntax error - often detected by the code editor:<br><br><blockquote>funtion willNotWork( {<br>&nbsp;&nbsp;console.log(\"Yuck\");<br>}<br>// \"function\" keyword is misspelled and there's a missing parenthesis</blockquote><br><br>Here's an example of a runtime error - often detected while the program executes:<br><br><blockquote>function loopy() {<br>&nbsp;&nbsp;while(true) {<br>&nbsp;&nbsp;&nbsp;&nbsp;console.log(\"Hello, world!\");<br>&nbsp;&nbsp;}<br>}<br>// Calling loopy starts an infinite loop, which may crash your browser</blockquote><br><br>Example of a semantic error - often detected after testing code output:<br><br><blockquote>function calcAreaOfRect(w, h) {<br>&nbsp;&nbsp;return w + h; // This should be w * h<br>}<br>let myRectArea = calcAreaOfRect(2, 3);<br>// Correct syntax and the program executes, but this gives the wrong answer</blockquote>",
""
],
[
"",
"",
"Debugging is frustrating, but it helps to develop (and follow) a step-by-step approach to review your code. This means checking the intermediate values and types of variables to see if they are what they should be. You can start with a simple process of elimination.<br><br>For example, if function A works and returns what it's supposed to, then function B may have the issue. Or start checking values in a block of code from the middle to try to cut the search space in half. A problem in one spot indicates a bug in the first half of the code. If not, it's likely in the second.<br><br>This section will cover a couple helpful tools to find bugs, and some of the common forms they take. Fortunately, debugging is a learnable skill that just requires a little patience and practice to master.",
""
]
],
"releasedOn": "Feb 17, 2017",
"challengeSeed": [],
"tests": [],
"type": "waypoint",
"challengeType": 7,
"isRequired": false,
"translations": {}
},
{
"id": "587d7b83367417b2b2512b33",
"title": "Use the JavaScript Console to Check the Value of a Variable",
"description": [
"Both Chrome and Firefox have excellent JavaScript consoles, also known as DevTools, for debugging your JavaScript.",
"You can find Developer tools in your Chrome's menu or Web Console in FireFox's menu. If you're using a different browser, or a mobile phone, we strongly recommend switching to desktop Firefox or Chrome.",
"The <code>console.log()</code> method, which \"prints\" the output of what's within its parentheses to the console, will likely be the most helpful debugging tool. Placing it at strategic points in your code can show you the intermediate values of variables. It's good practice to have an idea of what the output should be before looking at what it is. Having check points to see the status of your calculations throughout your code will help narrow down where the problem is.",
"Here's an example to print 'Hello world!' to the console:",
"<code>console.log('Hello world!');</code>",
"<hr>",
"Use the <code>console.log()</code> method to print the value of the variable <code>a</code> where noted in the code."
],
"challengeSeed": [
"let a = 5;",
"let b = 1;",
"a++;",
"// Add your code below this line",
"",
"",
"let sumAB = a + b;",
"console.log(sumAB);"
],
"tests": [
"assert(code.match(/console\\.log\\(a\\)/g), 'message: Your code should use <code>console.log()</code> to check the value of the variable <code>a</code>.');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7b84367417b2b2512b34",
"title": "Use typeof to Check the Type of a Variable",
"description": [
"You can use <code>typeof</code> to check the data structure, or type, of a variable. This is useful in debugging when working with multiple data types. If you think you're adding two numbers, but one is actually a string, the results can be unexpected. Type errors can lurk in calculations or function calls. Especially take care when you're accessing and working with external data in the form of a JavaScript object (JSON).",
"Here are some examples using <code>typeof</code>:",
"<blockquote>console.log(typeof \"\"); // outputs \"string\"<br>console.log(typeof 0); // outputs \"number\"<br>console.log(typeof []); // outputs \"object\"<br>console.log(typeof {}); // outputs \"object\"</blockquote>",
"JavaScript recognizes six primitive (immutable) data types: <code>Boolean</code>, <code>Null</code>, <code>Undefined</code>, <code>Number</code>, <code>String</code>, and <code>Symbol</code> (new with ES6) and one type for mutable items: <code>Object</code>. Note that in JavaScript, arrays are technically a type of object.",
"<hr>",
"Add two <code>console.log()</code> statements to check the <code>typeof</code> each of the two variables <code>seven</code> and <code>three</code> in the code."
],
"challengeSeed": [
"let seven = 7;",
"let three = \"3\";",
"console.log(seven + three);",
"// Add your code below this line",
""
],
"tests": [
"assert(code.match(/console\\.log\\(typeof[\\( ].*\\)?\\);/g).length == 2, 'message: Your code should use <code>typeof</code> in two <code>console.log()</code> statements to check the type of the variables.');",
"assert(code.match(/typeof[\\( ]seven\\)?/g), 'message: Your code should use <code>typeof</code> to check the type of the variable <code>seven</code>.');",
"assert(code.match(/typeof[\\( ]three\\)?/g), 'message: Your code should use <code>typeof</code> to check the type of the variable <code>three</code>.');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7b84367417b2b2512b35",
"title": "Catch Misspelled Variable and Function Names",
"description": [
"The <code>console.log()</code> and <code>typeof</code> methods are the two primary ways to check intermediate values and types of program output. Now it's time to get into the common forms that bugs take. One syntax-level issue that fast typers can commiserate with is the humble spelling error.",
"Transposed, missing, or mis-capitalized characters in a variable or function name will have the browser looking for an object that doesn't exist - and complain in the form of a reference error. JavaScript variable and function names are case-sensitive.",
"<hr>",
"Fix the two spelling errors in the code so the <code>netWorkingCapital</code> calculation works."
],
"challengeSeed": [
"let receivables = 10;",
"let payables = 8;",
"let netWorkingCapital = recievables - payable;",
"console.log(`Net working capital is: ${netWorkingCapital}`);"
],
"tests": [
"assert(netWorkingCapital === 2, 'message: Check the spelling of the two variables used in the netWorkingCapital calculation, the console output should show that \"Net working capital is: 2\".');",
"assert(!code.match(/recievables/g), 'message: There should be no instances of mis-spelled variables in the code.');",
"assert(code.match(/receivables/g).length == 2, 'message: The <code>receivables</code> variable should be declared and used properly in the code.');",
"assert(!code.match(/payable;/g), 'message: There should be no instances of mis-spelled variables in the code.');",
"assert(code.match(/payables/g).length == 2, 'message: The <code>payables</code> variable should be declared and used properly in the code.');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7b84367417b2b2512b36",
"title": "Catch Unclosed Parentheses, Brackets, Braces and Quotes",
"description": [
"Another syntax error to be aware of is that all opening parentheses, brackets, curly braces, and quotes have a closing pair. Forgetting a piece tends to happen when you're editing existing code and inserting items with one of the pair types. Also, take care when nesting code blocks into others, such as adding a callback function as an argument to a method.",
"One way to avoid this mistake is as soon as the opening character is typed, immediately include the closing match, then move the cursor back between them and continue coding. Fortunately, most modern code editors generate the second half of the pair automatically.",
"<hr>",
"Fix the two pair errors in the code."
],
"challengeSeed": [
"let myArray = [1, 2, 3;",
"let arraySum = myArray.reduce((previous, current => previous + current);",
"console.log(`Sum of array values is: ${arraySum}`);"
],
"tests": [
"assert(code.match(/myArray\\s*?=\\s*?\\[\\s*?1\\s*?,\\s*?2\\s*?,\\s*?3\\s*?\\];/g), 'message: Your code should fix the missing piece of the array.');",
"assert(arraySum === 6, 'message: Your code should fix the missing piece of the <code>.reduce()</code> method. The console output should show that \"Sum of array values is: 6\".');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7b84367417b2b2512b37",
"title": "Catch Mixed Usage of Single and Double Quotes",
"description": [
"JavaScript allows the use of both single ('') and double (\"\") quotes to declare a string. Deciding which one to use generally comes down to personal preference, with some exceptions.",
"Having two choices is great when a string has contractions or another piece of text that's in quotes. Just be careful that you don't close the string too early, which causes a syntax error.",
"Here are some examples of mixing quotes:",
"<blockquote>// These are correct:<br>const grouchoContraction = \"I've had a perfectly wonderful evening, but this wasn't it.\";<br>const quoteInString = \"Groucho Marx once said 'Quote me as saying I was mis-quoted.'\";<br>// This is incorrect:<br>const uhOhGroucho = 'I've had a perfectly wonderful evening, but this wasn't it.';</blockquote>",
"Of course, it is okay to use only one style of quotes. You can escape the quotes inside the string by using the backslash (\\) escape character:",
"<blockquote>// Correct use of same quotes:<br>const allSameQuotes = 'I\\'ve had a perfectly wonderful evening, but this wasn\\'t it.';</blockquote>",
"<hr>",
"Fix the string so it either uses different quotes for the <code>href</code> value, or escape the existing ones. Keep the double quote marks around the entire string."
],
"challengeSeed": [
"let innerHtml = \"<p>Click here to <a href=\"#Home\">return home</a></p>\";",
"console.log(innerHtml);"
],
"tests": [
"assert(code.match(/<a href=\\s*?('|\\\\\")#Home\\1\\s*?>/g), 'message: Your code should fix the quotes around the <code>href</code> value \"#Home\" by either changing or escaping them.');",
"assert(code.match(/\"<p>.*?<\\/p>\";/g), 'message: Your code should keep the double quotes around the entire string.');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7b85367417b2b2512b38",
"title": "Catch Use of Assignment Operator Instead of Equality Operator",
"description": [
"Branching programs, i.e. ones that do different things if certain conditions are met, rely on <code>if</code>, <code>else if</code>, and <code>else</code> statements in JavaScript. The condition sometimes takes the form of testing whether a result is equal to a value.",
"This logic is spoken (in English, at least) as \"if x equals y, then ...\" which can literally translate into code using the <code>=</code>, or assignment operator. This leads to unexpected control flow in your program.",
"As covered in previous challenges, the assignment operator (<code>=</code>) in JavaScript assigns a value to a variable name. And the <code>==</code> and <code>===</code> operators check for equality (the triple <code>===</code> tests for strict equality, meaning both value and type are the same).",
"The code below assigns <code>x</code> to be 2, which evaluates as <code>true</code>. Almost every value on its own in JavaScript evaluates to <code>true</code>, except what are known as the \"falsy\" values: <code>false</code>, <code>0</code>, <code>\"\"</code> (an empty string), <code>NaN</code>, <code>undefined</code>, and <code>null</code>.",
"<blockquote>let x = 1;<br>let y = 2;<br>if (x = y) {<br>&nbsp;&nbsp;// this code block will run for any value of y (unless y were originally set as a falsy)<br>} else {<br>&nbsp;&nbsp;// this code block is what should run (but won't) in this example<br>}</blockquote>",
"<hr>",
"Fix the condition so the program runs the right branch, and the appropriate value is assigned to <code>result</code>."
],
"challengeSeed": [
"let x = 7;",
"let y = 9;",
"let result = \"to come\";",
"",
"if(x = y) {",
" result = \"Equal!\";",
"} else {",
" result = \"Not equal!\";",
"}",
"",
"console.log(result);"
],
"tests": [
"assert(result == \"Not equal!\", 'message: Your code should fix the condition so it checks for equality, instead of using assignment.');",
"assert(code.match(/x\\s*?===?\\s*?y/g), 'message: The condition can use either <code>==</code> or <code>===</code> to test for equality.');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7b85367417b2b2512b39",
"title": "Catch Missing Open and Closing Parenthesis After a Function Call",
"description": [
"When a function or method doesn't take any arguments, you may forget to include the (empty) opening and closing parentheses when calling it. Often times the result of a function call is saved in a variable for other use in your code. This error can be detected by logging variable values (or their types) to the console and seeing that one is set to a function reference, instead of the expected value the function returns.",
"The variables in the following example are different:",
"<blockquote>function myFunction() {<br>&nbsp;&nbsp;return \"You rock!\";<br>}<br>let varOne = myFunction; // set to equal a function<br>let varTwo = myFunction(); // set to equal the string \"You rock!\"</blockquote>",
"<hr>",
"Fix the code so the variable <code>result</code> is set to the value returned from calling the function <code>getNine</code>."
],
"challengeSeed": [
"function getNine() {",
" let x = 6;",
" let y = 3;",
" return x + y;",
"}",
"",
"let result = getNine;",
"console.log(result);"
],
"tests": [
"assert(result == 9, 'message: Your code should fix the variable <code>result</code> so it is set to the number that the function <code>getNine</code> returns.');",
"assert(code.match(/getNine\\(\\)/g).length == 2, 'message: Your code should call the <code>getNine</code> function.');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7b85367417b2b2512b3a",
"title": "Catch Arguments Passed in the Wrong Order When Calling a Function",
"description": [
"Continuing the discussion on calling functions, the next bug to watch out for is when a function's arguments are supplied in the incorrect order. If the arguments are different types, such as a function expecting an array and an integer, this will likely throw a runtime error. If the arguments are the same type (all integers, for example), then the logic of the code won't make sense. Make sure to supply all required arguments, in the proper order to avoid these issues.",
"<hr>",
"The function <code>raiseToPower</code> raises a base to an exponent. Unfortunately, it's not called properly - fix the code so the value of <code>power</code> is the expected 8."
],
"challengeSeed": [
"function raiseToPower(b, e) {",
" return Math.pow(b, e);",
"}",
"",
"let base = 2;",
"let exp = 3;",
"let power = raiseToPower(exp, base);",
"console.log(power);"
],
"tests": [
"assert(power == 8, 'message: Your code should fix the variable <code>power</code> so it equals 2 raised to the 3rd power, not 3 raised to the 2nd power.');",
"assert(code.match(/raiseToPower\\(\\s*?base\\s*?,\\s*?exp\\s*?\\);/g), 'message: Your code should use the correct order of the arguments for the <code>raiseToPower</code> function call.');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7b86367417b2b2512b3b",
"title": "Catch Off By One Errors When Using Indexing",
"description": [
"<code>Off by one errors</code> (sometimes called OBOE) crop up when you're trying to target a specific index of a string or array (to slice or access a segment), or when looping over the indices of them. JavaScript indexing starts at zero, not one, which means the last index is always one less than the length of the item. If you try to access an index equal to the length, the program may throw an \"index out of range\" reference error or print <code>undefined</code>.",
"When you use string or array methods that take index ranges as arguments, it helps to read the documentation and understand if they are inclusive (the item at the given index is part of what's returned) or not. Here are some examples of off by one errors:",
"<blockquote>let alphabet = \"abcdefghijklmnopqrstuvwxyz\";<br>let len = alphabet.length;<br>for (let i = 0; i <= len; i++) {<br>&nbsp;&nbsp;// loops one too many times at the end<br>&nbsp;&nbsp;console.log(alphabet[i]);<br>}<br>for (let j = 1; j < len; j++) {<br>&nbsp;&nbsp;// loops one too few times and misses the first character at index 0<br>&nbsp;&nbsp;console.log(alphabet[j]);<br>}<br>for (let k = 0; k < len; k++) {<br>&nbsp;&nbsp;// Goldilocks approves - this is just right<br>&nbsp;&nbsp;console.log(alphabet[k]);<br>}</blockquote>",
"<hr>",
"Fix the two indexing errors in the following function so all the numbers 1 through 5 are printed to the console."
],
"challengeSeed": [
"function countToFive() {",
" let firstFive = \"12345\";",
" let len = firstFive.length;",
" // Fix the line below",
" for (let i = 1; i <= len; i++) {",
" // Do not alter code below this line",
" console.log(firstFive[i]);",
" }",
"}",
"",
"countToFive();"
],
"tests": [
"assert(code.match(/i\\s*?=\\s*?0\\s*?;/g).length == 1, 'message: Your code should set the initial condition of the loop so it starts at the first index.');",
"assert(!code.match(/i\\s?=\\s*?1\\s*?;/g), 'message: Your code should fix the initial condition of the loop so that the index starts at 0.');",
"assert(code.match(/i\\s*?<\\s*?len\\s*?;/g).length == 1, 'message: Your code should set the terminal condition of the loop so it stops at the last index.');",
"assert(!code.match(/i\\s*?<=\\s*?len;/g), 'message: Your code should fix the terminal condition of the loop so that it stops at 1 before the length.');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7b86367417b2b2512b3c",
"title": "Use Caution When Reinitializing Variables Inside a Loop",
"description": [
"Sometimes it's necessary to save information, increment counters, or re-set variables within a loop. A potential issue is when variables either should be reinitialized, and aren't, or vice versa. This is particularly dangerous if you accidentally reset the variable being used for the terminal condition, causing an infinite loop.",
"Printing variable values with each cycle of your loop by using <code>console.log()</code> can uncover buggy behavior related to resetting, or failing to reset a variable.",
"<hr>",
"The following function is supposed to create a two-dimensional array with <code>m</code> rows and <code>n</code> columns of zeroes. Unfortunately, it's not producing the expected output because the <code>row</code> variable isn't being reinitialized (set back to an empty array) in the outer loop. Fix the code so it returns a correct 3x2 array of zeroes, which looks like <code>[[0, 0], [0, 0], [0, 0]]</code>."
],
"challengeSeed": [
"function zeroArray(m, n) {",
" // Creates a 2-D array with m rows and n columns of zeroes",
" let newArray = [];",
" let row = [];",
" for (let i = 0; i < m; i++) {",
" // Adds the m-th row into newArray",
" ",
" for (let j = 0; j < n; j++) {",
" // Pushes n zeroes into the current row to create the columns",
" row.push(0);",
" }",
" // Pushes the current row, which now has n zeroes in it, to the array",
" newArray.push(row);",
" }",
" return newArray;",
"}",
"",
"let matrix = zeroArray(3, 2);",
"console.log(matrix);"
],
"tests": [
"assert(JSON.stringify(matrix) == \"[[0,0],[0,0],[0,0]]\", 'message: Your code should set the <code>matrix</code> variable to an array holding 3 rows of 2 columns of zeroes each.');",
"assert(matrix.length == 3, 'message: The <code>matrix</code> variable should have 3 rows.');",
"assert(matrix[0].length == 2 && matrix[1].length === 2 && matrix[2].length === 2, 'message: The <code>matrix</code> variable should have 2 columns in each row.');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7b86367417b2b2512b3d",
"title": "Prevent Infinite Loops with a Valid Terminal Condition",
"description": [
"The final topic is the dreaded infinite loop. Loops are great tools when you need your program to run a code block a certain number of times or until a condition is met, but they need a terminal condition that ends the looping. Infinite loops are likely to freeze or crash the browser, and cause general program execution mayhem, which no one wants.",
"There was an example of an infinite loop in the introduction to this section - it had no terminal condition to break out of the <code>while</code> loop inside <code>loopy()</code>. Do NOT call this function!",
"<blockquote>function loopy() {<br>&nbsp;&nbsp;while(true) {<br>&nbsp;&nbsp;&nbsp;&nbsp;console.log(\"Hello, world!\");<br>&nbsp;&nbsp;}<br>}</blockquote>",
"It's the programmer's job to ensure that the terminal condition, which tells the program when to break out of the loop code, is eventually reached. One error is incrementing or decrementing a counter variable in the wrong direction from the terminal condition. Another one is accidentally resetting a counter or index variable within the loop code, instead of incrementing or decrementing it.",
"<hr>",
"The <code>myFunc()</code> function contains an infinite loop because the terminal condition <code>i != 4</code> will never evaluate to <code>false</code> (and break the looping) - <code>i</code> will increment by 2 each pass, and jump right over 4 since <code>i</code> is odd to start. Fix the comparison operator in the terminal condition so the loop only runs for <code>i</code> less than or equal to 4."
],
"challengeSeed": [
"function myFunc() {",
" for (let i = 1; i != 4; i += 2) {",
" console.log(\"Still going!\");",
" }",
"}"
],
"tests": [
"assert(code.match(/i\\s*?<=\\s*?4;/g).length == 1, 'message: Your code should change the comparison operator in the terminal condition (the middle part) of the <code>for</code> loop.');",
"assert(!code.match(/i\\s*?!=\\s*?4;/g), 'message: Your code should fix the comparison operator in the terminal condition of the loop.');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
}
]
}

View File

@ -0,0 +1,841 @@
{
"name": "ES6",
"order": 2,
"time": "5 hours",
"helpRoom": "Help",
"challenges": [
{
"id": "587d7b86367417b2b2512b3e",
"title": "Introduction to the ES6 Challenges",
"description": [
[
"",
"",
"ECMAScript is a standardized version of JavaScript with the goal of unifying the language's specifications and features. As all major browsers and JavaScript-runtimes follow this specification, the term <i>ECMAScript</i> is interchangeable with the term <i>JavaScript</i>.<br><br>Most of the challenges on freeCodeCamp use the ECMAScript 5 (ES5) specification of the language, finalized in 2009. But JavaScript is an evolving programming language. As features are added and revisions are made, new versions of the language are released for use by developers.<br><br>The most recent standardized version is called ECMAScript 6 (ES6), released in 2015. This new version of the language adds some powerful features that will be covered in this section of challenges, including:<br><br><ul><li>Arrow functions</li><li>Classes</li><li>Modules</li><li>Promises</li><li>Generators</li><li><code>let</code> and <code>const</code></li></ul><br><br><strong>Note</strong><br>Not all browsers support ES6 features. If you use ES6 in your own projects, you may need to use a program (transpiler) to convert your ES6 code into ES5 until browsers support ES6.",
""
]
],
"releasedOn": "Feb 17, 2017",
"challengeSeed": [],
"tests": [],
"type": "waypoint",
"challengeType": 7,
"isRequired": false,
"translations": {}
},
{
"id": "587d7b87367417b2b2512b3f",
"title": "Explore Problems with the var Keyword",
"description": [
"One of the biggest problems with declaring variables with the <code>var</code> keyword is that you can overwrite variable declarations without an error.",
"<blockquote>var camper = 'James';<br>var camper = 'David';<br>console.log(camper);<br>// logs 'David'</blockquote>",
"In a small application, you might not run into this type of problem, but when your code becomes larger, you might accidently overwrite a variable that you did not intend to overwrite. Because this behaviour does not throw an error, searching and fixing bugs becomes more difficult.",
"Another problem with the <code>var</code> keyword is that it is hoisted to the top of your code when it compiles. This means that you can use a variable before you declare it.",
"<blockquote>console.log(camper);<br>var camper = 'David';<br>// logs undefined</blockquote>",
"The code runs in the following order:",
"<ol><li>The variable <code>camper</code> is declared as undefined.</li><li>The value of <code>camper</code> is logged.</li><li>David is assigned to <code>camper</code>.</li></ol>",
"This code will run without an error.",
"A new keyword called <code>let</code> was introduced in ES6 to solve the problems with the <code>var</code> keyword. With the <code>let</code> keyword, all the examples we just saw will cause an error to appear. We can no longer overwrite variables or use a variable before we declare it. Some modern browsers require you to add <code>\"use strict\";</code> to the top of your code before you can use the new features of ES6.",
"Let's try using the <code>let</code> keyword.",
"<hr>",
"Fix the code so that it only uses the <code>let</code> keyword and makes the errors go away.",
"<strong>Note</strong><br>Remember to add <code>\"use strict\";</code> to the top of your code."
],
"challengeSeed": [
"var favorite = redNosedReindeer + \" is Santa's favorite reindeer.\";",
"var redNosedReindeer = \"Rudolph\";",
"var redNosedReindeer = \"Comet\";"
],
"tests": [
"assert(redNosedReindeer === \"Rudolph\", 'message: <code>redNosedReindeer</code> should be Rudolph.');",
"assert(favorite === \"Rudolph is Santa's favorite reindeer.\", \"message: <code>favorite</code> should return Santa's favorite reindeer.\");"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7b87367417b2b2512b40",
"title": "Compare Scopes of the var and let Keywords",
"description": [
"When you declare a variable with the <code>var</code> keyword, it is declared globally, or locally if declared inside a function.",
"The <code>let</code> keyword behaves similarly, but with some extra features. When you declare a variable with the <code>let</code> keyword inside a block, statement, or expression, its scope is limited to that block, statement, or expression.",
"For example:",
"<blockquote>var numArray = [];<br>for (var i = 0; i < 3; i++) {<br> numArray.push(i);<br>}<br>console.log(numArray);<br>// returns [0, 1, 2]<br>console.log(i);<br>// returns 3</blockquote>",
"With the <code>var</code> keyword, <code>i</code> is declared globally. So when <code>i++</code> is executed, it updates the global variable. This code is similiar to the following:",
"<blockquote>var numArray = [];<br>var i;<br>for (i = 0; i < 3; i++) {<br> numArray.push(i);<br>}<br>console.log(numArray);<br>// returns [0, 1, 2]<br>console.log(i);<br>// returns 3</blockquote>",
"This behavior will cause problems if you were to create a function and store it for later use inside a for loop that uses the <code>i</code> variable. This is because the stored function will always refer to the value of the updated global <code>i</code> variable.",
"<blockquote>var printNumTwo;<br>for (var i = 0; i < 3; i++) {<br> if(i === 2){<br> printNumTwo = function() {<br> return i;<br> };<br> }<br>}<br>console.log(printNumTwo());<br>// returns 3</blockquote>",
"As you can see, <code>printNumTwo()</code> prints 3 and not 2. This is because the value assigned to <code>i</code> was updated and the <code>printNumTwo()</code> returns the global <code>i</code> and not the value <code>i</code> had when the function was created in the for loop. The <code>let</code> keyword does not follow this behavior:",
"<blockquote>'use strict';<br>let printNumTwo;<br>for (let i = 0; i < 3; i++) {<br> if (i === 2) {<br> printNumTwo = function() {<br> return i;<br> };<br> }<br>}<br>console.log(printNumTwo());<br>// returns 2<br>console.log(i);<br>// returns \"i is not defined\"</blockquote>",
"<code>i</code> is not defined because it was not declared in the global scope. It is only declared within the for loop statement. <code>printNumTwo()</code> returned the correct value because three different <code>i</code> variables with unique values (0, 1, and 2) were created by the <code>let</code> keyword within the loop statement.",
"<hr>",
"Fix the code so that <code>i</code> declared in the if statement is a separate variable than <code>i</code> declared in the first line of the function. Be certain not to use the <code>var</code> keyword anywhere in your code.",
"<strong>Note</strong><br>Remember to add <code>\"use strict\";</code> to the top of your code.",
"This exercise is designed to illustrate the difference between how <code>var</code> and <code>let</code> keywords assign scope to the declared variable. When programming a function similar to the one used in this exercise, it is often better to use different variable names to avoid confusion."
],
"challengeSeed": [
"function checkScope() {",
" var i = \"function scope\";",
" if (true) {",
" i = \"block scope\";",
" console.log(\"Block scope i is: \", i);",
" }",
" console.log(\"Function scope i is: \", i);",
" return i;",
"}",
"// only change the code above this line",
"checkScope();"
],
"tests": [
"// TEMPORARILY COMMENTED OUT: assert(!/var/g.test(code) && /let/g.test(code), 'message: The <code>var</code> keyword should be replaced with <code>let</code>. (This test is temporarily disabled)');",
"assert(code.match(/(i\\s*=\\s*).*\\s*.*\\s*.*\\1('|\")block\\s*scope\\2/g), 'message: The variable <code>i</code> declared in the if statement should equal \"block scope\".');",
"assert(checkScope() === \"function scope\", 'message: <code>checkScope()</code> should return \"function scope\"');"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7b87367417b2b2512b41",
"title": "Declare a Read-Only Variable with the const Keyword",
"description": [
"<code>let</code> is not the only new way to declare variables. In ES6, you can also declare variables using the <code>const</code> keyword.",
"<code>const</code> has all the awesome features that <code>let</code> has, with the added bonus that variables declared using <code>const</code> are read-only. They are a constant value, which means that once a variable is assigned with <code>const</code>, it cannot be reassigned.",
"<blockquote>\"use strict\"<br>const FAV_PET = \"Cats\";<br>FAV_PET = \"Dogs\"; // returns error</blockquote>",
"As you can see, trying to reassign a variable declared with <code>const</code> will throw an error. You should always name variables you don't want to reassign using the <code>const</code> keyword. This helps when you accidentally attempt to reassign a variable that is meant to stay constant. A common practice is to name your constants in all upper-cases and with an underscore to separate words (e.g. <code>EXAMPLE_VARIABLE</code>).",
"<hr>",
"Change the code so that all variables are declared using <code>let</code> or <code>const</code>. Use <code>let</code> when you want the variable to change, and <code>const</code> when you want the variable to remain constant. Also, rename variables declared with <code>const</code> to conform to common practices.",
"<strong>Note</strong><br>Don't forget to add <code>\"use strict\";</code> to the top of your code."
],
"challengeSeed": [
"// change 'var' to 'let' or 'const'",
"// rename constant variables",
"var pi = 3.14;",
"var radius = 10;",
"var calculateCircumference = function(r) {",
" var diameter = 2 * r;",
" var result = pi * diameter;",
" return result;",
"};",
"// Test your code",
"console.log(calculateCircumference(radius));"
],
"tests": [
"// Test user replaced all var keyword",
"// Test PI is const",
"// Test calculateCircumference is const",
"// Test pi and calculateCircumference has been renamed"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7b87367417b2b2512b42",
"title": "Mutate an Array Declared with const",
"description": [
"The <code>const</code> declaration has many use cases in modern JavaScript.",
"Some developers prefer to assign all their variables using <code>const</code> by default, unless they know they will need to reassign the value. Only in that case, they use <code>let</code>.",
"However, it is important to understand that objects (including arrays and functions) assigned to a variable using <code>const</code> are still mutable. Using the <code>const</code> declaration only prevents reassignment of the variable identifier.",
"<blockquote>\"use strict\";<br>const s = [5, 6, 7];<br>s = [1, 2, 3]; // throws error, trying to assign a const<br>s[2] = 45; // works just as it would with an array declared with var or let<br>console.log(s); // returns [5, 6, 45]</blockquote>",
"As you can see, you can mutate the object <code>[5, 6, 7]</code> itself and the variable <code>s</code> will still point to the altered array <code>[5, 6, 45]</code>. Like all arrays, the array elements in <code>s</code> are mutable, but because <code>const</code> was used, you cannot use the variable identifier <code>s</code> to point to a different array using the assignment operator.",
"<hr>",
"An array is declared as <code>const s = [5, 7, 2]</code>. Change the array to <code>[2, 5, 7]</code> using various element assignment.",
"<strong>Note</strong><br>Don't forget to add <code>\"use strict\";</code> to the top of your code."
],
"challengeSeed": [
"const s = [5, 7, 2];",
"// change code below this line",
"",
"s = [2, 5, 7];",
"",
"// change code above this line",
"// Test your code",
"console.log(s);"
],
"tests": [
"assert(code.match(/const/g), 'message: Do not replace <code>const</code> keyword.');",
"assert(code.match(/const\\s+s/g), 'message: <code>s</code> is declared with <code>const</code>.');",
"assert(code.match(/const\\s+s\\s*?=\\s*?\\[\\s*?2\\s*?,\\s*?5\\s*?,\\s*?7\\s*?\\]\\s*?;/g), 'message: Do not change the original array declaration.');",
"assert.deepEqual(s, [2, 5, 7], 'message: <code>s</code> should be equal to <code>[2, 5, 7]</code>.');"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7b87367417b2b2512b43",
"title": "Use Arrow Functions to Write Concise Anonymous Functions",
"description": [
"In JavaScript, we often don't need to name our functions, especially when passing a function as an argument to another function. Instead, we create inline functions. We don't need to name these functions because we do not reuse them anywhere else.",
"To achieve this, we often use the following syntax:",
"<blockquote>const myFunc = function() {<br> const myVar = \"value\";<br> return myVar;<br>}</blockquote>",
"ES6 provides us with the syntactic sugar to not have to write anonymous functions this way. Instead, you can use <strong>arrow function syntax</strong>:",
"<blockquote>const myFunc = () => {<br> const myVar = \"value\";<br> return myVar;<br>}</blockquote>",
"When there is no function body, and only a return value, arrow function syntax allows you to omit the keyword <code>return</code> as well as the brackets surrounding the code. This helps simplify smaller functions into one-line statements:",
"<blockquote>const myFunc= () => \"value\"</blockquote>",
"This code will still return <code>value</code> by default.",
"<hr>",
"Rewrite the function assigned to the variable <code>magic</code> which returns a new <code>Date()</code> to use arrow function syntax. Also make sure nothing is defined using the keyword <code>var</code>.",
"Note",
"Don't forget to use strict mode."
],
"challengeSeed": [
"// change code below this line",
"var magic = function() {",
" return new Date();",
"}",
"// change code above this line",
"// test your code",
"console.log(magic());"
],
"tests": [
"// Test user did replace var keyword",
"// Test magic is const",
"// Test magic is a function",
"// Test magic() returns the correct date",
"// Test function keyword was not used",
"// Test arrow => was used"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7b88367417b2b2512b44",
"title": "Write Arrow Functions with Parameters",
"description": [
"Just like a normal function, you can pass arguments into arrow functions.",
"<blockquote>// doubles input value and returns it<br>const doubler = (item) => item * 2;</blockquote>",
"You can pass more than one argument into arrow functions as well.",
"<hr>",
"Rewrite the <code>myConcat</code> function which appends contents of <code>arr2</code> to <code>arr1</code> so that the function uses arrow function syntax.",
"Note",
"Don't forget to use strict mode."
],
"challengeSeed": [
"// change code below this line",
"var myConcat = function(arr1, arr2) {",
" return arr1.concat(arr2);",
"}",
"// change code above this line",
"// test your code",
"console.log(myConcat([1, 2], [3, 4, 5]));"
],
"tests": [
"// Test user did replace var keyword",
"// Test myConcat is const",
"assert(typeof myConcat === \"function\", 'message: <code>myConcat</code> should be a function');",
"// Test myConcat() returns the correct array",
"// Test function keyword was not used",
"// Test arrow => was used"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7b88367417b2b2512b45",
"title": "Write Higher Order Arrow Functions",
"description": [
"It's time we see how powerful arrow functions are when processing data.",
"Arrow functions work really well with higher order functions, such as <code>map()</code>, <code>filter()</code>, and <code>reduce()</code>, that take other functions as arguments for processing collections of data.",
"Read the following code:",
"<blockquote>FBPosts.filter(function(post) {<br> return post.thumbnail !== null && post.shares > 100 && post.likes > 500;<br>})</blockquote>",
"We have written this with <code>filter()</code> to at least make it somewhat readable. Now compare it to the following code which uses arrow function syntax instead:",
"<blockquote>FBPosts.filter((post) => post.thumbnail !== null && post.shares > 100 && post.likes > 500)</blockquote>",
"This code is more succinct and accomplishes the same task with fewer lines of code.",
"<hr>",
"Use arrow function syntax to compute the square of only the positive integers (fractions are not integers) in the array <code>realNumberArray</code> and store the new array in the variable <code>squaredIntegers</code>.",
"Note",
"Don't forget to use strict mode."
],
"challengeSeed": [
"const realNumberArray = [4, 5.6, -9.8, 3.14, 42, 6, 8.34];",
"// change code below this line",
"var squaredIntegers = realNumberArray;",
"// change code above this line",
"// test your code",
"console.log(squaredIntegers);"
],
"tests": [
"// Test user did replace <code>var</code> keyword",
"// Test <code>squaredIntegers</code> is <code>const</code>",
"assert(Array.isArray(squaredIntegers), 'message: <code>squaredIntegers</code> should be an array');",
"assert(squaredIntegers[0] === 16 && squaredIntegers[1] === 1764 && squaredIntegers[2] === 36, 'message: <code>squaredIntegers</code> should be <code>[16, 1764, 36]</code>');",
"// Test <code>function</code> keyword was not used",
"// Test arrow <code>=></code> was used",
"assert(!code.match(/(for)|(while)/g), 'message: loop should not be used');",
"assert(code.match(/map/g) && code.match(/filter/g), 'message: <code>map</code> and <code>filter</code> should be used');"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7b88367417b2b2512b46",
"title": "Set Default Parameters for Your Functions",
"description": [
"In order to help us create more flexible functions, ES6 introduces <dfn>default parameters</dfn> for functions.",
"Check out this code:",
"<blockquote>function greeting(name = \"Anonymous\") {<br> return \"Hello \" + name;<br>}<br>console.log(greeting(\"John\")); // Hello John<br>console.log(greeting()); // Hello Anonymous</blockquote>",
"The default parameter kicks in when the argument is not specified (it is undefined). As you can see in the example above, the parameter <code>name</code> will receive its default value <code>\"Anonymous\"</code> when you do not provide a value for the parameter. You can add default values for as many parameters as you want.",
"<hr>",
"Modify the function <code>increment</code> by adding default parameters so that it will add 1 to <code>number</code> if <code>value</code> is not specified.",
"<strong>Note</strong><br>Don't forget to use strict mode."
],
"challengeSeed": [
"function increment(number, value) {",
" return number + value;",
"}",
"console.log(increment(5, 2)); // returns 7",
"console.log(increment(5)); // returns NaN"
],
"tests": [
"assert(increment(5, 2) === 7, \"The result of increment(5, 2) should be 7\");",
"assert(increment(5) === 6, \"The result of increment(5) should be 6\");",
"// Test default parameter was used for 'value'"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7b88367417b2b2512b47",
"title": "Use the Rest Operator with Function Parameters",
"description": [
"In order to help us create more flexible functions, ES6 introduces the <dfn>rest operator</dfn> for function parameters. With the rest operator, you can create functions that take a variable number of arguments. These arguments are stored in an array that can be accessed later from inside the function.",
"Check out this code:",
"<blockquote>function howMany(...args) {<br> return \"You have passed \" + args.length + \" arguments.\";<br>}<br>console.log(howMany(0, 1, 2)); // You have passed 3 arguments<br>console.log(howMany(\"string\", null, [1, 2, 3], { })); // You have passed 4 arguments.</blockquote>",
"The rest operator eliminates the need to check the <code>args</code> array and allows us to apply <code>map()</code>, <code>filter()</code> and <code>reduce()</code> on the parameters array.",
"<hr>",
"Modify the function <code>sum</code> so that is uses the rest operator and it works in the same way with any number of parameters.",
"<strong>Note</strong><br>Don't forget to use strict mode."
],
"challengeSeed": [
"function sum(x, y, z) {",
" const array = [ x, y, z ];",
" return array.reduce((a, b) => a + b, 0);",
"}",
"console.log(sum(1, 2, 3)); // 6"
],
"tests": [
"assert(sum(0,1,2) === 3, 'The result of sum(0,1,2) should be 3');",
"assert(sum(1,2,3,4) === 10, 'The result of sum(1,2,3,4) should be 10');",
"assert(sum(5) === 5, 'The result of sum(5) should be 5');",
"assert(sum() === 0, 'The result of sum() should be 0');"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7b89367417b2b2512b48",
"title": "Use the Spread Operator to Evaluate Arrays In-Place",
"description": [
"ES6 introduces the <dfn>spread operator</dfn>, which allows us to expand arrays and other expressions in places where multiple parameters or elements are expected.",
"The ES5 code below uses <code>apply()</code> to compute the maximum value in an array:",
"<blockquote>var arr = [6, 89, 3, 45];<br>var maximus = Math.max.apply(null, arr); // returns 89</blockquote>",
"We had to use <code>Math.max.apply(null, arr)</code> because <code>Math.max(arr)</code> returns <code>NaN</code>. <code>Math.max()</code> expects comma-separated arguments, but not an array.",
"The spread operator makes this syntax much better to read and maintain.",
"<blockquote>const arr = [6, 89, 3, 45];<br>const maximus = Math.max(...arr); // returns 89</blockquote>",
"<code>...arr</code> returns an unpacked array. In other words, it <em>spreads</em> the array.",
"However, the spread operator only works in-place, like in an argument to a function or in an array literal. The following code will not work:",
"<blockquote>const spreaded = ...arr; // will throw a syntax error</blockquote>",
"<hr>",
"Copy all contents of <code>arr1</code> into another array <code>arr2</code> using the spread operator."
],
"challengeSeed": [
"const arr1 = ['JAN', 'FEB', 'MAR', 'APR', 'MAY'];",
"const arr2 = []; // change this line",
"arr1.push('JUN');",
"console.log(arr2); // arr2 should not be affected"
],
"tests": [
"// Test arr2 is correct copy of arr1",
"// Test arr1 has changed",
"// Test spread operator was used"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7b89367417b2b2512b49",
"title": "Use Destructuring Assignment to Assign Variables from Objects",
"description": [
"We earlier saw how spread operator can effectively spread, or unpack, the contents of the array.",
"We can do something similar with objects as well. <dfn>Destructuring assignment</dfn> is special syntax for neatly assigning values taken directly from an object to variables.",
"Consider the following ES5 code:",
"<blockquote>var voxel = {x: 3.6, y: 7.4, z: 6.54 };<br>var x = voxel.x; // x = 3.6<br>var y = voxel.y; // y = 7.4<br>var z = voxel.z; // z = 6.54</blockquote>",
"Here's the same assignment statement with ES6 destructuring syntax:",
"<blockquote>const { x, y, z } = voxel; // x = 3.6, y = 7.4, z = 6.54</blockquote>",
"If instead you want to store the values of <code>voxel.x</code> into <code>a</code>, <code>voxel.y</code> into <code>b</code>, and <code>voxel.z</code> into <code>c</code>, you have that freedom as well.",
"<blockquote>const { x : a, y : b, z : c } = voxel // a = 3.6, b = 7.4, c = 6.54</blockquote>",
"You may read it as \"get the field <code>x</code> and copy the value into <code>a</code>,\" and so on.",
"<hr>",
"Use destructuring to obtain the length of the string <code>greeting</code>"
],
"challengeSeed": [
"const greeting = 'itadakimasu';",
"// change code below this line",
"const length = 0; // change this",
"// change code above this line",
"console.log(length); // should be using destructuring"
],
"tests": [
"// Test len is 11",
"// Test destructuring was used"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7b89367417b2b2512b4a",
"title": "Use Destructuring Assignment to Assign Variables from Nested Objects",
"description": [
"We can similarly destructure <em>nested</em> objects into variables.",
"Consider the following code:",
"<blockquote>const a = {<br> start: { x: 5, y: 6},<br> end: { x: 6, y: -9 }<br>};<br>const { start : { x: startX, y: startY }} = a;<br>console.log(startX, startY); // 5, 6</blockquote>",
"In the example above, the variable <code>start</code> is assigned the value of <code>a.start</code>, which is also an object.",
"<hr>",
"Use destructuring assignment to obtain <code>max</code> of <code>forecast.tomorrow</code> and assign it to <code>maxOfTomorrow</code>."
],
"challengeSeed": [
"const forecast = {",
" today: { min: 72, max: 83 },",
" tomorrow: { min: 73.3, max: 84.6 }",
"};",
"// change code below this line",
"const maxOfTomorrow = undefined; // change this line",
"// change code above this line",
"console.log(maxOfTomorrow); // should be 84.6"
],
"tests": [
"// Test maxOfTomorrow to be 84.6",
"// Test destructuring was used"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7b89367417b2b2512b4b",
"title": "Use Destructuring Assignment to Assign Variables from Arrays",
"description": [
"ES6 makes destructuring arrays as easy as destructuring objects.",
"One key difference between the spread operator and array destructuring is that the spread operator unpacks all contents of an array into a comma-separated list. Consequently, you cannot pick or choose which elements you want to assign to variables.",
"Destructuring an array lets us do exactly that:",
"<blockquote>const [a, b] = [1, 2, 3, 4, 5, 6];<br>console.log(a, b); // 1, 2</blockquote>",
"The variable <code>a</code> is assigned the first value of the array, and <code>b</code> is assigned the second value of the array.",
"We can also access the value at any index in an array with destructuring by using commas to reach the desired index:",
"<blockquote>const [a, b,,, c] = [1, 2, 3, 4, 5, 6];<br>console.log(a, b, c); // 1, 2, 5 </blockquote>",
"<hr>",
"Use destructuring assignment to swap the values of <code>a</code> and <code>b</code> so that <code>a</code> receives the value stored in <code>b</code>, and <code>b</code> receives the value stored in <code>a</code>."
],
"challengeSeed": [
"let a = 8, b = 6;",
"// change code below this line",
"",
"// change code above this line",
"console.log(a); // should be 6",
"console.log(b); // should be 8"
],
"tests": [
"assert(a === 6, 'message: Value of <code>a</code> should be 6, after swapping.');",
"assert(b === 8, 'message: Value of <code>b</code> should be 8, after swapping.');",
"// assert(/\\[\\s*(\\w)\\s*,\\s*(\\w)\\s*\\]\\s*=\\s*\\[\\s*\\2\\s*,\\s*\\1\\s*\\]/g.test(code), 'message: Use array destructuring to swap a and b.');"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7b8a367417b2b2512b4c",
"title": "Use Destructuring Assignment with the Rest Operator to Reassign Array Elements",
"description": [
"In some situations involving array destructuring, we might want to collect the rest of the elements into a separate array.",
"The result is similar to <code>Array.prototype.slice()</code>, as shown below:",
"<blockquote>const [a, b, ...arr] = [1, 2, 3, 4, 5, 7];<br>console.log(a, b); // 1, 2<br>console.log(arr); // [3, 4, 5, 7]</blockquote>",
"Variables <code>a</code> and <code>b</code> take the first and second values from the array. After that, because of rest operator's presence, <code>arr</code> gets rest of the values in the form of an array.",
"The rest element only works correctly as the last variable in the list. As in, you cannot use the rest operator to catch a subarray that leaves out last element of the original array.",
"<hr>",
"Use destructuring assignment with the rest operator to perform an effective <code>Array.prototype.slice()</code> so that <code>arr</code> is a sub-array of the original array <code>source</code> with the first two elements ommitted."
],
"challengeSeed": [
"const source = [1,2,3,4,5,6,7,8,9,10];",
"// change code below this line",
"const arr = source; // change this",
"// change code below this line",
"console.log(arr); // should be [3,4,5,6,7,8,9,10]",
"console.log(source); // should be [1,2,3,4,5,6,7,8,9,10];"
],
"tests": [
"// Test arr is [3,4,5,6,7,8,9,10];",
"// Test source is [1,2,3,4,5,6,7,8,9,10];",
"// Test destructuring was used",
"// Test slice was not used"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7b8a367417b2b2512b4d",
"title": "Use Destructuring Assignment to Pass an Object as a Function's Parameters",
"description": [
"In some cases, you can destructure the object in a function argument itself.",
"Consider the code below:",
"<blockquote>const profileUpdate = (profileData) => {<br> const { name, age, nationality, location } = profileData;<br> // do something with these variables<br>}</blockquote>",
"This effectively destructures the object sent into the function. This can also be done in-place:",
"<blockquote>const profileUpdate = ({ name, age, nationality, location }) => {<br> /* do something with these fields */<br>}</blockquote>",
"This removes some extra lines and makes our code look neat.",
"This has the added benefit of not having to manipulate an entire object in a function; only the fields that are needed are copied inside the function.",
"<hr>",
"Use destructuring assignment within the argument to the function <code>half</code> to send only <code>max</code> and <code>min</code> inside the function."
],
"challengeSeed": [
"const stats = {",
" max: 56.78,",
" standard_deviation: 4.34,",
" median: 34.54,",
" mode: 23.87,",
" min: -0.75,",
" average: 35.85",
"};",
"// change code below this line",
"const half = (stats) => ((stats.max + stats.min) / 2.0); // use function argument destructurung",
"// change code above this line",
"console.log(stats); // should be object",
"console.log(half(stats)); // should be 28.015"
],
"tests": [
"// Test stats is an object",
"// Test half is 28.015",
"// Test destructuring was used"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7b8a367417b2b2512b4e",
"title": "Create Strings using Template Literals",
"description": [
"A new feature of ES6 is the <dfn>template literal</dfn>. This is a special type of string that allows you to use string interpolation features to create strings.",
"Consider the code below:",
"<blockquote>const person = {<br> name: \"Zodiac Hasbro\",<br> age: 56<br>};<br><br>// string interpolation<br>const greeting = `Hello, my name is ${person.name}!<br>I am ${person.age} years old.`;<br><br>console.log(greeting); // prints<br>// Hello, my name is Zodiac Hasbro!<br>// I am 56 years old.<br></blockquote>",
"A lot of things happened there.",
"Firstly, the <code>${variable}</code> syntax used above is a place holder. Basically, you won't have to use concatenation with the <code>+</code> operator anymore. To add variables to strings, you just drop the variable in a template string and wrap it with <code>${</code> and <code>}</code>.",
"Secondly, the example uses backticks (<code>`</code>), not quotes (<code>'</code> or <code>\"</code>), to wrap the string. Notice that the string is multi-line.",
"This new way of creating strings gives you more flexibility to create robust strings.",
"<hr>",
"Use template literal syntax with backticks to display each entry of the <code>result</code> object's <code>failure</code> array. Each entry should be wrapped inside an <code>li</code> element with the class attribute <code>text-warning</code>."
],
"challengeSeed": [
"const result = {",
" success: [\"max-length\", \"no-amd\", \"prefer-arrow-functions\"],",
" failure: [\"no-var\", \"var-on-top\", \"linebreak\"],",
" skipped: [\"id-blacklist\", \"no-dup-keys\"]",
"};",
"// change code below this line",
"const resultDisplay = null;",
"// change code above this line",
"console.log(resultDisplay);",
"/**",
" * should look like this",
" * <li class=\"text-warning\">no-var</li>",
" * <li class=\"text-warning\">var-on-top</li>",
" * <li class=\"text-warning\">linebreak</li>",
" **/"
],
"tests": [
"// Test resultDisplay is a string",
"// Test resultDisplay is the desired output",
"// Test template strings were used"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7b8a367417b2b2512b4f",
"title": "Write Concise Object Literal Declarations Using Simple Fields",
"description": [
"ES6 adds some nice support for easily definining object literals.",
"Consider the following code:",
"<blockquote>const getMousePosition = (x, y) => ({<br> x: x,<br> y: y<br>});</blockquote>",
"<code>getMousePosition</code> is a simple function that returns an object containing two fields.",
"ES6 provides the syntactic sugar to eliminate the redundancy of having to write <code>x: x</code>. You can simply write <code>x</code> once, and it will be converted to<code>x: x</code> (or something equivalent) under the hood.",
"Here is the same function from above rewritten to use this new syntax:",
"<blockquote>const getMousePosition = (x, y) => ({ x, y });</blockquote>",
"<hr>",
"Use simple fields with object literals to create and return a <code>Person</code> object."
],
"challengeSeed": [
"// change code below this line",
"const createPerson = (name, age, gender) => {",
" return {",
" name: name,",
" age: age,",
" gender: gender",
" };",
"};",
"// change code above this line",
"console.log(createPerson(\"Zodiac Hasbro\", 56, \"male\")); // returns a proper object"
],
"tests": [
"// Test the output is {name: \"Zodiac Hasbro\", age: 56, gender: \"male\"}",
"// Test no : was present"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7b8b367417b2b2512b50",
"title": "Write Concise Declarative Functions with ES6",
"description": [
"When defining functions within objects in ES5, we have to use the keyword <code>function</code> as follows:",
"<blockquote>const person = {<br> name: \"Taylor\",<br> sayHello: function() {<br> return `Hello! My name is ${this.name}.`;<br> }<br>};</blockquote>",
"With ES6, You can remove the <code>function</code> keyword and colon altogether when defining functions in objects. Here's an example of this syntax:",
"<blockquote>const person = {<br> name: \"Taylor\",<br> sayHello() {<br> return `Hello! My name is ${this.name}.`;<br> }<br>};</blockquote>",
"<hr>",
"Refactor the function <code>setGear</code> inside the object <code>bicycle</code> to use the shorthand syntax described above."
],
"challengeSeed": [
"// change code below this line",
"const bicycle = {",
" gear: 2,",
" setGear: function(newGear) {",
" this.gear = newGear;",
" }",
"};",
"// change code above this line",
"bicycle.setGear(3);",
"console.log(bicycle.gear);"
],
"tests": [
"// Test the output is Sending request to Yanoshi Mimoto",
"// Test no : was present"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7b8b367417b2b2512b53",
"title": "Use class Syntax to Define a Constructor Function",
"description": [
"ES6 provides a new syntax to help create objects, using the keyword <dfn>class</dfn>.",
"This is to be noted, that the <code>class</code> syntax is just a syntax, and not a full-fledged class based implementation of object oriented paradigm, unlike in languages like Java, or Python, or Ruby etc.",
"In ES5, we usually define a constructor function, and use the <code>new</code> keyword to instantiate an object.",
"<blockquote>var SpaceShuttle = function(targetPlanet){<br> this.targetPlanet = targetPlanet;<br>}<br>var zeus = new spaceShuttle('Jupiter');</blockquote>",
"The class syntax simply replaces the constructor function creation:",
"<blockquote>class SpaceShuttle {<br> constructor(targetPlanet){<br> this.targetPlanet = targetPlanet;<br> }<br>}<br>const zeus = new spaceShuttle('Jupiter');</blockquote>",
"Notice that the <code>class</code> keyword declares a new function, and a constructor was added, which would be invoked when <code>new</code> is called - to create a new object.",
"<hr>",
"Use <code>class</code> keyword and write a proper constructor to create the <code>Vegetable</code> class.",
"The <code>Vegetable</code> lets you create a vegetable object, with a property <code>name</code>, to be passed to constructor."
],
"challengeSeed": [
"/* Alter code below this line */",
"const Vegetable = undefined;",
"/* Alter code above this line */",
"const carrot = new Vegetable('carrot');",
"console.log(carrot.name); // => should be 'carrot'"
],
"tests": [
"// Test the Vegetable is a class",
"// Test that class keyword was used",
"// Test that other objects could be created with the class"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7b8c367417b2b2512b54",
"title": "Use getters and setters to Control Access to an Object",
"description": [
"You can obtain values from an object, and set a value of a property within an object.",
"These are classically called <dfn>getters</dfn> and <dfn>setters</dfn>.",
"Getter functions are meant to simply return (get) the value of an object's private variable to the user without the user directly accessing the private variable.",
"Setter functions are meant to modify (set) the value of an object's private variable based on the value passed into the setter function. This change could involve calculations, or even overwriting the previous value completely.",
"<blockquote>class Book {<br> constructor(author) {<br> this._author = author;<br> }<br> // getter<br> get writer(){<br> return this._author;<br> }<br> // setter<br> set writer(updatedAuthor){<br> this._author = updatedAuthor;<br> }<br>}<br>const lol = new Book('anonymous');<br>console.log(lol.writer);<br>lol.writer = 'wut';<br>console.log(lol.writer);</blockquote>",
"Notice the syntax we are using to invoke the getter and setter - as if they are not even functions.",
"Getters and setters are important, because they hide internal implementation details.",
"<hr>",
"Use <code>class</code> keyword to create a Thermostat class. The constructor accepts Farenheit temperature.",
"Now create <code>getter</code> and <code>setter</code> in the class, to obtain the temperature in Celsius scale.",
"Remember that <code>F = C * 9.0 / 5 + 32</code>, where F is the value of temperature in Fahrenheit scale, and C is the value of the same temperature in Celsius scale",
"Note",
"When you implement this, you would be tracking the temperature inside the class in one scale - either Fahrenheit or Celsius.",
"This is the power of getter or setter - you are creating an API for another user, who would get the correct result, no matter which one you track.",
"In other words, you are abstracting implementation details from the consumer."
],
"challengeSeed": [
"/* Alter code below this line */",
"const Thermostat = undefined;",
"/* Alter code above this line */",
"const thermos = new Thermostat(76); // setting in Farenheit scale",
"let temp = thermos.temperature; // 24.44 in C",
"thermos.temperature = 26;",
"temp = thermos.temperature; // 26 in C"
],
"tests": [
"// Test the Thermostat is a class",
"// Test that class keyword was used",
"// Test that other objects could be created with the class"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7b8c367417b2b2512b55",
"title": "Understand the Differences Between import and require",
"description": [
"In the past, the function <code>require()</code> would be used to import the functions and code in external files and modules. While handy, this presents a problem: some files and modules are rather large, and you may only need certain code from those external resources.",
"ES6 gives us a very handy tool known as <dfn>import</dfn>. With it, we can choose which parts of a module or file to load into a given file, saving time and memory.",
"Consider the following example. Imagine that <code>math_array_functions</code> has about 20 functions, but I only need one, <code>countItems</code>, in my current file. The old <code>require()</code> approach would force me to bring in all 20 functions. With this new <code>import</code> syntax, I can bring in just the desired function, like so:",
"<blockquote>import { countItems } from \"math_array_functions\"</blockquote>",
"A description of the above code:",
"<blockquote>import { function } from \"file_path_goes_here\"<br>// We can also import variables the same way!</blockquote>",
"There are a few ways to write an <code>import</code> statement, but the above is a very common use-case.",
"<strong>Note</strong><br>the whitespace surrounding the function inside the curly braces is a best practice - it makes it easier to read the <code>import</code> statement.",
"<strong>Note</strong><br>The lessons in this section handle non-browser features. <code>import</code>, and the statements we introduce in the rest of these lessons, won't work on a browser directly, However, we can use various tools to create code out of this to make it work in browser.",
"<hr>",
"Add the appropriate <code>import</code> statement that will allow the current file to use the <code>capitalizeString</code> function. The file where this function lives is called <code>\"string_functions\"</code>, and it is in the same directory as the current file."
],
"challengeSeed": [
"capitalizeString(\"hello!\");"
],
"tests": [
"assert(code.match(/import\\s+\\{\\s?capitalizeString\\s?\\}\\s+from\\s+\"string_functions\"/ig)"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7b8c367417b2b2512b56",
"title": "Use export to Reuse a Code Block",
"description": [
"In the previous challenge, you learned about <code>import</code> and how it can be leveraged to import small amounts of code from large files. In order for this to work, though, we must utilize one of the statements that goes with <code>import</code>, known as <dfn>export</dfn>. When we want some code - a function, or a variable - to be usable in another file, we must export it in order to import it into another file. Like <code>import</code>, <code>export</code> is a non-browser feature.",
"The following is what we refer to as a <dfn>named export</dfn>. With this, we can import any code we export into another file with the <code>import</code> syntax you learned in the last lesson. Here's an example:",
"<blockquote>const capitalizeString = (string) => {<br> return string.charAt(0).toUpperCase() + string.slice(1);<br>}<br>export { capitalizeString } //How to export functions.<br>export const foo = \"bar\"; //How to export variables.</blockquote>",
"Alternatively, if you would like to compact all your <code>export</code> statements into one line, you can take this approach:",
"<blockquote>const capitalizeString = (string) => {<br> return string.charAt(0).toUpperCase() + string.slice(1);<br>}<br>const foo = \"bar\";<br>export { capitalizeString, foo }</blockquote>",
"Either approach is perfectly acceptable.",
"<hr>",
"Below are two variables that I want to make available for other files to use. Utilizing the first way I demonstrated <code>export</code>, export the two variables."
],
"challengeSeed": [
"const foo = \"bar\";",
"const boo = \"far\";"
],
"tests": [
"assert(code.match(/export\\s+const\\s+foo\\s+=+\\s\"bar\"/ig))",
"assert(code.match(/export\\s+const\\s+boo\\s+=+\\s\"far\"/ig))"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7b8c367417b2b2512b57",
"title": "Use * to Import Everything from a File",
"description": [
"Suppose you have a file that you wish to import all of its contents into the current file. This can be done with the <dfn>import *</dfn> syntax.",
"Here's an example where the contents of a file named <code>\"math_functions\"</code> are imported into a file in the same directory:",
"<blockquote>import * as myMathModule from \"math_functions\"<br>myMathModule.add(2,3);<br>myMathModule.subtract(5,3);</blockquote>",
"And breaking down that code:",
"<blockquote>import * as object_with_name_of_your_choice from \"file_path_goes_here\"<br>object_with_name_of_your_choice.imported_function</blockquote>",
"You may use any name following the <code>import *</code> as portion of the statement. In order to utilize this method, it requires an object that receives the imported values. From here, you will use the dot notation to call your imported values.",
"<hr>",
"The code below requires the contents of a file, <code>\"capitalize_strings\"</code>, found in the same directory as it, imported. Add the appropriate <code>import *</code> statement to the top of the file, using the object provided."
],
"challengeSeed": [
"myStringModule.capitalize(\"foo\");",
"myStringModule.lowercase(\"Foo\");"
],
"tests": [
"assert(code.match(/import\\s+\\*\\s+as\\s+myStringModule\\s+from\\s+\"capitalize_strings\"/ig))"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7b8c367417b2b2512b58",
"title": "Create an Export Fallback with export default",
"description": [
"In the <code>export</code> lesson, you learned about the syntax referred to as a <dfn>named export</dfn>. This allowed you to make multiple functions and variables available for use in other files.",
"There is another <code>export</code> syntax you need to know, known as <dfn>export default</dfn>. Usually you will use this syntax if only one value is being exported from a file. It is also used to create a fallback value for a file or module.",
"Here is a quick example of <code>export default</code>:",
"<blockquote>export default const add = (x,y) => {<br> return x + y;<br>}</blockquote>",
"There is a one major feature of <code>export default</code> you must never forget - since it is used to declare a fallback value for a module or file, you can only have one value be a default export in each module or file.",
"<hr>",
"The following function should be the fallback value for the module. Please add the necessary code to do so."
],
"challengeSeed": [
"const subtract = (x,y) => {return x - y;}"
],
"tests": [
"assert(code.match(/export\\s+default\\s+const\\s+subtract\\s+=\\s+\\(x,y\\)\\s+=>\\s+{return\\s+x\\s-\\s+y;}/ig))"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7b8d367417b2b2512b59",
"title": "Import a Default Export",
"description": [
"In the last challenge, you learned about <code>export default</code> and its uses. It is important to note that, to import a default export, you need to use a different <code>import</code> syntax.",
"In the following example, we have a function, <code>add</code>, that is the default export of a file, <code>\"math_functions\"</code>. Here is how to import it:",
"<blockquote>import add from \"math_functions\";<br>add(5,4); //Will return 9</blockquote>",
"The syntax differs in one key place - the imported value, <code>add</code>, is not surrounded by curly braces, <code>{}</code>. Unlike exported values, the primary method of importing a default export is to simply write the value's name after <code>import</code>.",
"<hr>",
"In the following code, please import the default export, <code>subtract</code>, from the file <code>\"math_functions\"</code>, found in the same directory as this file."
],
"challengeSeed": [
"subtract(7,4);"
],
"tests": [
"assert(code.match(/import\\s+subtract\\s+from\\s+\"math_functions\"/ig))"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
}
]
}

View File

@ -0,0 +1,998 @@
{
"name": "Regular Expressions",
"order": 3,
"time": "5 hours",
"helpRoom": "Help",
"challenges": [
{
"id": "587d7db3367417b2b2512b8d",
"title": "Introduction to the Regular Expression Challenges",
"description": [
[
"https://camo.githubusercontent.com/85ac1a6783961ce77add6b2e8630dbf6521d33b2/687474703a2f2f696d67732e786b63642e636f6d2f636f6d6963732f726567756c61725f65787072657373696f6e732e706e67",
"XKCD web comic showing how regular expressions can save the day",
"Regular expressions are special strings that represent a search pattern. Also known as \"regex\" or \"regexp\", they help programmers match, search, and replace text. Regular expressions can appear cryptic because a few characters have special meaning. The goal is to combine the symbols and text into a pattern that matches what you want, but only what you want. This section will cover the characters, a few shortcuts, and the common uses for writing regular expressions.",
""
]
],
"releasedOn": "Feb 17, 2017",
"challengeSeed": [],
"tests": [],
"type": "waypoint",
"challengeType": 7,
"isRequired": false,
"translations": {}
},
{
"id": "587d7db3367417b2b2512b8e",
"title": "Using the Test Method",
"description": [
"Regular expressions are used in programming languages to match parts of strings. You create patterns to help you do that matching.",
"If you want to find the word <code>\"the\"</code> in the string <code>\"The dog chased the cat\"</code>, you could use the following regular expression: <code>/the/</code>. Notice that quote marks are not required within the regular expression.",
"JavaScript has multiple ways to use regexes. One way to test a regex is using the <code>.test()</code> method. The <code>.test()</code> method takes the regex, applies it to a string (which is placed inside the parentheses), and returns <code>true</code> or <code>false</code> if your pattern finds something or not.",
"<blockquote>let testStr = \"freeCodeCamp\";<br>let testRegex = /Code/;<br>testRegex.test(testStr);<br>// Returns true</blockquote>",
"<hr>",
"Apply the regex <code>myRegex</code> on the string <code>myString</code> using the <code>.test()</code> method."
],
"challengeSeed": [
"let myString = \"Hello, World!\";",
"let myRegex = /Hello/;",
"let result = myRegex; // Change this line"
],
"tests": [
"assert(code.match(/myRegex.test\\(\\s*myString\\s*\\)/), 'message: You should use <code>.test()</code> to test the regex.');",
"assert(result === true, 'message: Your result should return <code>true</code>.');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7db3367417b2b2512b8f",
"title": "Match Literal Strings",
"description": [
"In the last challenge, you searched for the word <code>\"Hello\"</code> using the regular expression <code>/Hello/</code>. That regex searched for a literal match of the string <code>\"Hello\"</code>. Here's another example searching for a literal match of the string <code>\"Kevin\"</code>:",
"<blockquote>let testStr = \"Hello, my name is Kevin.\";<br>let testRegex = /Kevin/;<br>testRegex.test(testStr);<br>// Returns true</blockquote>",
"Any other forms of <code>\"Kevin\"</code> will not match. For example, the regex <code>/Kevin/</code> will not match <code>\"kevin\"</code> or <code>\"KEVIN\"</code>.",
"<blockquote>let wrongRegex = /kevin/;<br>wrongRegex.test(testStr);<br>// Returns false</blockquote>",
"A future challenge will show how to match those other forms as well.",
"<hr>",
"Complete the regex <code>waldoRegex</code> to find <code>\"Waldo\"</code> in the string <code>waldoIsHiding</code> with a literal match."
],
"challengeSeed": [
"let waldoIsHiding = \"Somewhere Waldo is hiding in this text.\";",
"let waldoRegex = /search/; // Change this line",
"let result = waldoRegex.test(waldoIsHiding);"
],
"tests": [
"assert(waldoRegex.test(waldoIsHiding), 'message: Your regex <code>waldoRegex</code> should find <code>\"Waldo\"</code>');",
"assert(!waldoRegex.test('Somewhere is hiding in this text.'), 'message: Your regex <code>waldoRegex</code> should not search for anything else.');",
"assert(!/\\/.*\\/i/.test(code), 'message: You should perform a literal string match with your regex.');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7db4367417b2b2512b90",
"title": "Match a Literal String with Different Possibilities",
"description": [
"Using regexes like <code>/coding/</code>, you can look for the pattern <code>\"coding\"</code> in another string.",
"This is powerful to search single strings, but it's limited to only one pattern. You can search for multiple patterns using the <code>alternation</code> or <code>OR</code> operator: <code>|</code>.",
"This operator matches patterns either before or after it. For example, if you wanted to match <code>\"yes\"</code> or <code>\"no\"</code>, the regex you want is <code>/yes|no/</code>.",
"You can also search for more than just two patterns. You can do this by adding more patterns with more <code>OR</code> operators separating them, like <code>/yes|no|maybe/</code>.",
"<hr>",
"Complete the regex <code>petRegex</code> to match the pets <code>\"dog\"</code>, <code>\"cat\"</code>, <code>\"bird\"</code>, or <code>\"fish\"</code>."
],
"challengeSeed": [
"let petString = \"James has a pet cat.\";",
"let petRegex = /change/; // Change this line",
"let result = petRegex.test(petString);"
],
"tests": [
"assert(petRegex.test('John has a pet dog.'), 'message: Your regex <code>petRegex</code> should return <code>true</code> for the string <code>\"John has a pet dog.\"</code>');",
"assert(!petRegex.test('Emma has a pet rock.'), 'message: Your regex <code>petRegex</code> should return <code>false</code> for the string <code>\"Emma has a pet rock.\"</code>');",
"assert(petRegex.test('Emma has a pet bird.'), 'message: Your regex <code>petRegex</code> should return <code>true</code> for the string <code>\"Emma has a pet bird.\"</code>');",
"assert(petRegex.test('Liz has a pet cat.'), 'message: Your regex <code>petRegex</code> should return <code>true</code> for the string <code>\"Liz has a pet cat.\"</code>');",
"assert(!petRegex.test('Kara has a pet dolphin.'), 'message: Your regex <code>petRegex</code> should return <code>false</code> for the string <code>\"Kara has a pet dolphin.\"</code>');",
"assert(petRegex.test('Alice has a pet fish.'), 'message: Your regex <code>petRegex</code> should return <code>true</code> for the string <code>\"Alice has a pet fish.\"</code>');",
"assert(!petRegex.test('Jimmy has a pet computer.'), 'message: Your regex <code>petRegex</code> should return <code>false</code> for the string <code>\"Jimmy has a pet computer.\"</code>');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7db4367417b2b2512b91",
"title": "Ignore Case While Matching",
"description": [
"Up until now, you've looked at regexes to do literal matches of strings. But sometimes, you might want to also match case differences.",
"Case (or sometimes letter case) is the difference between uppercase letters and lowercase letters. Examples of uppercase are <code>\"A\"</code>, <code>\"B\"</code>, and <code>\"C\"</code>. Examples of lowercase are <code>\"a\"</code>, <code>\"b\"</code>, and <code>\"c\"</code>.",
"You can match both cases using what is called a flag. There are other flags but here you'll focus on the flag that ignores case - the <code>i</code> flag. You can use it by appending it to the regex. An example of using this flag is <code>/ignorecase/i</code>. This regex can match the strings <code>\"ignorecase\"</code>, <code>\"igNoreCase\"</code>, and <code>\"IgnoreCase\"</code>.",
"<hr>",
"Write a regex <code>fccRegex</code> to match <code>\"freeCodeCamp\"</code>, no matter its case. Your regex should not match any abbreviations or variations with spaces."
],
"challengeSeed": [
"let myString = \"freeCodeCamp\";",
"let fccRegex = /change/; // Change this line",
"let result = fccRegex.test(myString);"
],
"tests": [
"assert(fccRegex.test('freeCodeCamp'), 'message: Your regex should match <code>freeCodeCamp</code>');",
"assert(fccRegex.test('FreeCodeCamp'), 'message: Your regex should match <code>FreeCodeCamp</code>');",
"assert(fccRegex.test('FreecodeCamp'), 'message: Your regex should match <code>FreecodeCamp</code>');",
"assert(fccRegex.test('FreeCodecamp'), 'message: Your regex should match <code>FreeCodecamp</code>');",
"assert(!fccRegex.test('Free Code Camp'), 'message: Your regex should not match <code>Free Code Camp</code>');",
"assert(fccRegex.test('FreeCOdeCamp'), 'message: Your regex should match <code>FreeCOdeCamp</code>');",
"assert(!fccRegex.test('FCC'), 'message: Your regex should not match <code>FCC</code>');",
"assert(fccRegex.test('FrEeCoDeCamp'), 'message: Your regex should match <code>FrEeCoDeCamp</code>');",
"assert(fccRegex.test('FrEeCodECamp'), 'message: Your regex should match <code>FrEeCodECamp</code>');",
"assert(fccRegex.test('FReeCodeCAmp'), 'message: Your regex should match <code>FReeCodeCAmp</code>');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7db4367417b2b2512b92",
"title": "Extract Matches",
"description": [
"So far, you have only been checking if a pattern exists or not within a string. You can also extract the actual matches you found with the <code>.match()</code> method.",
"To use the <code>.match()</code> method, apply the method on a string and pass in the regex inside the parentheses. Here's an example:",
"<blockquote>\"Hello, World!\".match(/Hello/);<br>// Returns [\"Hello\"]<br>let ourStr = \"Regular expressions\";<br>let ourRegex = /expressions/;<br>ourStr.match(ourRegex);<br>// Returns [\"expressions\"]</blockquote>",
"<hr>",
"Apply the <code>.match()</code> method to extract the word <code>coding</code>."
],
"challengeSeed": [
"let extractStr = \"Extract the word 'coding' from this string.\";",
"let codingRegex = /change/; // Change this line",
"let result = extractStr; // Change this line"
],
"tests": [
"assert(result.join() === \"coding\", 'message: The <code>result</code> should have the word <code>coding</code>');",
"assert(codingRegex.source === \"coding\", 'message: Your regex <code>codingRegex</code> should search for <code>coding</code>');",
"assert(code.match(/\\.match\\(.*\\)/), 'message: You should use the <code>.match()</code> method.');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7db4367417b2b2512b93",
"title": "Find More Than the First Match",
"description": [
"So far, you have only been able to extract or search a pattern once.",
"<blockquote>let testStr = \"Repeat, Repeat, Repeat\";<br>let ourRegex = /Repeat/;<br>testStr.match(ourRegex);<br>// Returns [\"Repeat\"]</blockquote>",
"To search or extract a pattern more than once, you can use the <code>g</code> flag.",
"<blockquote>let repeatRegex = /Repeat/g;<br>testStr.match(repeatRegex);<br>// Returns [\"Repeat\", \"Repeat\", \"Repeat\"]</blockquote>",
"<hr>",
"Using the regex <code>starRegex</code>, find and extract both <code>\"Twinkle\"</code> words from the string <code>twinkleStar</code>.",
"<strong>Note</strong><br>You can have multiple flags on your regex like <code>/search/gi</code>"
],
"challengeSeed": [
"let twinkleStar = \"Twinkle, twinkle, little star\";",
"let starRegex = /change/; // Change this line",
"let result = twinkleStar; // Change this line"
],
"tests": [
"assert(starRegex.flags.match(/g/).length == 1, 'message: Your regex <code>starRegex</code> should use the global flag <code>g</code>');",
"assert(starRegex.flags.match(/i/).length == 1, 'message: Your regex <code>starRegex</code> should use the case insensitive flag <code>i</code>');",
"assert(result.sort().join() == twinkleStar.match(/twinkle/gi).sort().join(), 'message: Your match should match both occurrences of the word <code>\"Twinkle\"</code>');",
"assert(result.length == 2, 'message: Your match <code>result</code> should have two elements in it.');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7db5367417b2b2512b94",
"title": "Match Anything with Wildcard Period",
"description": [
"Sometimes you won't (or don't need to) know the exact characters in your patterns. Thinking of all words that match, say, a misspelling would take a long time. Luckily, you can save time using the wildcard character: <code>.</code>",
"The wildcard character <code>.</code> will match any one character. The wildcard is also called <code>dot</code> and <code>period</code>. You can use the wildcard character just like any other character in the regex. For example, if you wanted to match <code>\"hug\"</code>, <code>\"huh\"</code>, <code>\"hut\"</code>, and <code>\"hum\"</code>, you can use the regex <code>/hu./</code> to match all four words.",
"<blockquote>let humStr = \"I'll hum a song\";<br>let hugStr = \"Bear hug\";<br>let huRegex = /hu./;<br>humStr.match(huRegex); // Returns [\"hum\"]<br>hugStr.match(huRegex); // Returns [\"hug\"]</blockquote>",
"<hr>",
"Complete the regex <code>unRegex</code> so that it matches the strings <code>\"run\"</code>, <code>\"sun\"</code>, <code>\"fun\"</code>, <code>\"pun\"</code>, <code>\"nun\"</code>, and <code>\"bun\"</code>. Your regex should use the wildcard character."
],
"challengeSeed": [
"let exampleStr = \"Let's have fun with regular expressions!\";",
"let unRegex = /change/; // Change this line",
"let result = unRegex.test(exampleStr);"
],
"tests": [
"assert(code.match(/\\.test\\(.*\\)/), 'message: You should use the <code>.test()</code> method.');",
"assert(/\\./.test(unRegex.source), 'message: You should use the wildcard character in your regex <code>unRegex</code>');",
"assert(unRegex.test(\"Let us go on a run.\"), 'message: Your regex <code>unRegex</code> should match <code>\"run\"</code> in <code>\"Let us go on a run.\"</code>');",
"assert(unRegex.test(\"The sun is out today.\"), 'message: Your regex <code>unRegex</code> should match <code>\"sun\"</code> in <code>\"The sun is out today.\"</code>');",
"assert(unRegex.test(\"Coding is a lot of fun.\"), 'message: Your regex <code>unRegex</code> should match <code>\"fun\"</code> in <code>\"Coding is a lot of fun.\"</code>');",
"assert(unRegex.test(\"Seven days without a pun makes one weak.\"), 'message: Your regex <code>unRegex</code> should match <code>\"pun\"</code> in <code>\"Seven days without a pun makes one weak.\"</code>');",
"assert(unRegex.test(\"One takes a vow to be a nun.\"), 'message: Your regex <code>unRegex</code> should match <code>\"nun\"</code> in <code>\"One takes a vow to be a nun.\"</code>');",
"assert(unRegex.test(\"She got fired from the hot dog stand for putting her hair in a bun.\"), 'message: Your regex <code>unRegex</code> should match <code>\"bun\"</code> in <code>\"She got fired from the hot dog stand for putting her hair in a bun.\"</code>');",
"assert(!unRegex.test(\"There is a bug in my code.\"), 'message: Your regex <code>unRegex</code> should not match <code>\"There is a bug in my code.\"</code>');",
"assert(!unRegex.test(\"Can me if you can.\"), 'message: Your regex <code>unRegex</code> should not match <code>\"Catch me if you can.\"</code>');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7db5367417b2b2512b95",
"title": "Match Single Character with Multiple Possibilities",
"description": [
"You learned how to match literal patterns (<code>/literal/</code>) and wildcard character (<code>/./</code>). Those are the extremes of regular expressions, where one finds exact matches and the other matches everything. There are options that are a balance between the two extremes.",
"You can search for a literal pattern with some flexibility with <code>character classes</code>. Character classes allow you to define a group of characters you wish to match by placing them inside square (<code>[</code> and <code>]</code>) brackets.",
"For example, you want to match <code>\"bag\"</code>, <code>\"big\"</code>, and <code>\"bug\"</code> but not <code>\"bog\"</code>. You can create the regex <code>/b[aiu]g/</code> to do this. The <code>[aiu]</code> is the character class that will only match the characters <code>\"a\"</code>, <code>\"i\"</code>, or <code>\"u\"</code>.",
"<blockquote>let bigStr = \"big\";<br>let bagStr = \"bag\";<br>let bugStr = \"bug\";<br>let bogStr = \"bog\";<br>let bgRegex = /b[aiu]g/;<br>bigStr.match(bgRegex); // Returns [\"big\"]<br>bagStr.match(bgRegex); // Returns [\"bag\"]<br>bugStr.match(bgRegex); // Returns [\"bug\"]<br>bogStr.match(bgRegex); // Returns null</blockquote>",
"<hr>",
"Use a character class with vowels (<code>a</code>, <code>e</code>, <code>i</code>, <code>o</code>, <code>u</code>) in your regex <code>vowelRegex</code> to find all the vowels in the string <code>quoteSample</code>.",
"<strong>Note</strong><br>Be sure to match both upper- and lowercase vowels."
],
"challengeSeed": [
"let quoteSample = \"Beware of bugs in the above code; I have only proved it correct, not tried it.\";",
"let vowelRegex = /change/; // Change this line",
"let result = vowelRegex; // Change this line"
],
"tests": [
"assert(result.length == 25, 'message: You should find all 25 vowels.');",
"assert(/\\[.*\\]/.test(vowelRegex.source), 'message: Your regex <code>vowelRegex</code> should use a character class.');",
"assert(vowelRegex.flags.match(/g/).length == 1, 'message: Your regex <code>vowelRegex</code> should use the global flag.');",
"assert(vowelRegex.flags.match(/i/).length == 1, 'message: Your regex <code>vowelRegex</code> should use the case insensitive flag.');",
"assert(!/[b-df-hj-np-tv-z]/gi.test(result.join()), 'message: Your regex should not match any consonants.');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7db5367417b2b2512b96",
"title": "Match Letters of the Alphabet",
"description": [
"You saw how you can use <code>character sets</code> to specify a group of characters to match, but that's a lot of typing when you need to match a large range of characters (for example, every letter in the alphabet). Fortunately, there is a built-in feature that makes this short and simple.",
"Inside a <code>character set</code>, you can define a range of characters to match using a <code>hyphen</code> character: <code>-</code>.",
"For example, to match lowercase letters <code>a</code> through <code>e</code> you would use <code>[a-e]</code>.",
"<blockquote>let catStr = \"cat\";<br>let batStr = \"bat\";<br>let matStr = \"mat\";<br>let bgRegex = /[a-e]at/;<br>catStr.match(bgRegex); // Returns [\"cat\"]<br>batStr.match(bgRegex); // Returns [\"bat\"]<br>matStr.match(bgRegex); // Returns null</blockquote>",
"<hr>",
"Match all the letters in the string <code>quoteSample</code>.",
"<strong>Note</strong><br>Be sure to match both upper- and lowercase vowels."
],
"challengeSeed": [
"let quoteSample = \"The quick brown fox jumps over the lazy dog.\";",
"let alphabetRegex = /change/; // Change this line",
"let result = alphabetRegex; // Change this line"
],
"tests": [
"assert(result.length == 35, 'message: Your regex <code>alphabetRegex</code> should match 35 items.');",
"assert(alphabetRegex.flags.match(/g/).length == 1, 'message: Your regex <code>alphabetRegex</code> should use the global flag.');",
"assert(alphabetRegex.flags.match(/i/).length == 1, 'message: Your regex <code>alphabetRegex</code> should use the case insensitive flag.');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7db5367417b2b2512b97",
"title": "Match Numbers and Letters of the Alphabet",
"description": [
"Using the hyphen (<code>-</code>) to match a range of characters is not limited to letters. It also works to match a range of numbers.",
"For example, <code>/[0-5]/</code> matches any number between <code>0</code> and <code>5</code>, including the <code>0</code> and <code>5</code>.",
"Also, it is possible to combine a range of letters and numbers in a single character set.",
"<blockquote>let jennyStr = \"Jenny8675309\";<br>let myRegex = /[a-z0-9]/ig;<br>// matches all letters and numbers in jennyStr<br>jennyStr.match(myRegex);</blockquote>",
"<hr>",
"Create a single regex that matches a range of letters between <code>h</code> and <code>s</code>, and a range of numbers between <code>2</code> and <code>6</code>. Remember to include the appropriate flags in the regex."
],
"challengeSeed": [
"let quoteSample = \"Blueberry 3.141592653s are delicious.\";",
"let myRegex = /change/; // Change this line",
"let result = myRegex; // Change this line"
],
"tests": [
"assert(result.length == 17, 'message: Your regex <code>myRegex</code> should match 17 items.');",
"assert(myRegex.flags.match(/g/).length == 1, 'message: Your regex <code>myRegex</code> should use the global flag.');",
"assert(myRegex.flags.match(/i/).length == 1, 'message: Your regex <code>myRegex</code> should use the case insensitive flag.');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7db6367417b2b2512b98",
"title": "Match Single Characters Not Specified",
"description": [
"So far, you have created a set of characters that you want to match, but you could also create a set of characters that you do not want to match. These types of character sets are called <code>negated character sets</code>.",
"To create a <code>negated character set</code>, you place a <code>caret</code> character (<code>^</code>) after the opening bracket and before the characters you do not want to match.",
"For example, <code>/[^aeiou]/gi</code> matches all characters that are not a vowel. Note that characters like <code>.</code>, <code>!</code>, <code>[</code>, <code>@</code>, <code>/</code> and white space are matched - the negated vowel character set only excludes the vowel characters.",
"<hr>",
"Create a single regex that matches all characters that are not a number or a vowel. Remember to include the appropriate flags in the regex."
],
"challengeSeed": [
"let quoteSample = \"3 blind mice.\";",
"let myRegex = /change/; // Change this line",
"let result = myRegex; // Change this line"
],
"tests": [
"assert(result.length == 9, 'message: Your regex <code>myRegex</code> should match 9 items.');",
"assert(myRegex.flags.match(/g/).length == 1, 'message: Your regex <code>myRegex</code> should use the global flag.');",
"assert(myRegex.flags.match(/i/).length == 1, 'message: Your regex <code>myRegex</code> should use the case insensitive flag.');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7db6367417b2b2512b99",
"title": "Match Characters that Occur One or More Times",
"description": [
"Sometimes, you need to match a character (or group of characters) that appears one or more times in a row. This means it occurs at least once, and may be repeated.",
"You can use the <code>+</code> character to check if that is the case. Remember, the character or pattern has to be present consecutively. That is, the character has to repeat one after the other.",
"For example, <code>/a+/g</code> would find one match in <code>\"abc\"</code> and return <code>[\"a\"]</code>. Because of the <code>+</code>, it would also find a single match in <code>\"aabc\"</code> and return <code>[\"aa\"]</code>.",
"If it were instead checking the string <code>\"abab\"</code>, it would find two matches and return <code>[\"a\", \"a\"]</code> because the <code>a</code> characters are not in a row - there is a <code>b</code> between them. Finally, since there is no <code>\"a\"</code> in the string <code>\"bcd\"</code>, it wouldn't find a match.",
"<hr>",
"You want to find matches when the letter <code>s</code> occurs one or more times in <code>\"Mississippi\"</code>. Write a regex that uses the <code>+</code> sign."
],
"challengeSeed": [
"let difficultSpelling = \"Mississippi\";",
"let myRegex = /change/; // Change this line",
"let result = difficultSpelling.match(myRegex);"
],
"tests": [
"assert(/\\+/.test(myRegex.source), 'message: Your regex <code>myRegex</code> should use the <code>+</code> sign to match one or more <code>s</code> characters.');",
"assert(result.length == 2, 'message: Your regex <code>myRegex</code> should match 2 items.');",
"assert(result[0] == 'ss' && result[1] == 'ss', 'message: The <code>result</code> variable should be an array with two matches of <code>\"ss\"</code>');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7db6367417b2b2512b9a",
"title": "Match Characters that Occur Zero or More Times",
"description": [
"The last challenge used the plus <code>+</code> sign to look for characters that occur one or more times. There's also an option that matches characters that occur zero or more times.",
"The character to do this is the <code>asterisk</code> or <code>star</code>: <code>*</code>.",
"<blockquote>let sWord1 = \"seed\";<br>let sWord2 = \"saw\";<br>let kWord = \"kite\";<br>let sRegex = /s.*/; // Searches for words starting with s<br>sRegex.test(sWord1); // Returns true<br>sRegex.test(sWord2); // Returns true<br>sRegex.test(kWord); // Returns false<br></blockquote>",
"<hr>",
"Create a regex <code>starWarsRegex</code> that uses the <code>*</code> character to match all the movie titles that start with <code>\"Star Wars\"</code>. Your regex does not need flags."
],
"challengeSeed": [
"let starWars = \"Star Wars\";",
"let starWarsRegex = /change/; // Change this line",
"let result = starWars.match(starWarsRegex);"
],
"tests": [
"assert(starWarsRegex.test(\"Star Wars: The Phantom Menace\"), 'message: Your regex should match <code>\"Star Wars: The Phantom Menace\"</code>.');",
"assert(starWarsRegex.test(\"Star Wars: Attack of the Clones\"), 'message: Your regex should match <code>\"Star Wars: Attack of the Clones\"</code>.');",
"assert(starWarsRegex.test(\"Star Wars: Revenge of the Sith\"), 'message: Your regex should match <code>\"Star Wars: Revenge of the Sith\"</code>.');",
"assert(starWarsRegex.test(\"Star Wars: A New Hope\"), 'message: Your regex should match <code>\"Star Wars: A New Hope\"</code>.');",
"assert(starWarsRegex.test(\"Star Wars: The Empire Strikes Back\"), 'message: Your regex should match <code>\"Star Wars: The Empire Strikes Back\"</code>.');",
"assert(starWarsRegex.test(\"Star Wars: Return of the Jedi\"), 'message: Your regex should match <code>\"Star Wars: Return of the Jedi\"</code>.');",
"assert(starWarsRegex.test(\"Star Wars: The Force Awakens\"), 'message: Your regex should match <code>\"Star Wars: The Force Awakens\"</code>.');",
"assert(!starWarsRegex.test(\"The Clone Wars\"), 'message: Your regex should not match <code>\"The Clone Wars\"</code>');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7db6367417b2b2512b9b",
"title": "Find Characters with Lazy Matching",
"description": [
"In regular expressions, a <code>greedy</code> match finds the longest possible part of a string that fits the regex pattern and returns it as a match. The alternative is called a <code>lazy</code> match, which finds the smallest possible part of the string that satisfies the regex pattern.",
"You can apply the regex <code>/t[a-z]*i/</code> to the string <code>\"titanic\"</code>. This regex is basically a pattern that starts with <code>t</code>, ends with <code>i</code>, and has some letters in between.",
"Regular expressions are by default <code>greedy</code>, so the match would return <code>[\"titani\"]</code>. It finds the largest sub-string possible to fit the pattern.",
"However, you can use the <code>?</code> character to change it to <code>lazy</code> matching. <code>\"titanic\"</code> matched against the adjusted regex of <code>/t[a-z]*?i/</code> returns <code>[\"ti\"]</code>.",
"<hr>",
"Fix the regex <code>/&lt;.*&gt;/</code> to return the HTML tag <code>&lt;h1&gt;</code> and not the text <code>\"&lt;h1&gt;Winter is coming&lt;/h1&gt;\"</code>. Remember the wildcard <code>.</code> in a regular expression matches any character."
],
"challengeSeed": [
"let text = \"<h1>Winter is coming</h1>\";",
"let myRegex = /<.*>/; // Change this line",
"let result = text.match(myRegex);"
],
"tests": [
"assert(result[0] == '<h1>', 'message: The <code>result</code> variable should be an array with <code>&lt;h1&gt;</code> in it');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7db7367417b2b2512b9c",
"title": "Find One or More Criminals in a Hunt",
"description": [
"Time to pause and test your new regex writing skills. A group of criminals escaped from jail and ran away, but you don't know how many. However, you do know that they stay close together when they are around other people. You are responsible for finding all of the criminals at once.",
"Here's an example to review how to do this:",
"The regex <code>/z+/</code> matches the letter <code>z</code> when it appears one or more times in a row. It would find matches in all of the following strings:",
"<blockquote>\"z\"<br>\"zzzzzz\"<br>\"ABCzzzz\"<br>\"zzzzABC\"<br>\"abczzzzzzzzzzzzzzzzzzzzzabc\"</blockquote>",
"But it does not find matches in the following strings since there are no letter <code>z</code> characters:",
"<blockquote>\"\"<br>\"ABC\"<br>\"abcabc\"</blockquote>",
"<hr>",
"Write a <code>greedy</code> regex that finds one or more criminals within a group of other people. A criminal is represented by the capital letter <code>C</code>."
],
"challengeSeed": [
"// example crowd gathering",
"let crowd = 'P1P2P3P4P5P6CCCP7P8P9';",
"",
"let reCriminals = /./; // Change this line",
"",
"let matchedCriminals = crowd.match(reCriminals);",
"console.log(matchedCriminals);"
],
"tests": [
"assert('C'.match(reCriminals) && 'C'.match(reCriminals)[0] == 'C', 'message: Your regex should match <em>one</em> criminal (\"<code>C</code>\") in <code>\"C\"</code>');",
"assert('CC'.match(reCriminals) && 'CC'.match(reCriminals)[0] == 'CC', 'message: Your regex should match <em>two</em> criminals (\"<code>CC</code>\") in <code>\"CC\"</code>');",
"assert('P1P5P4CCCP2P6P3'.match(reCriminals) && 'P1P5P4CCCP2P6P3'.match(reCriminals)[0] == 'CCC', 'message: Your regex should match <em>three</em> criminals (\"<code>CCC</code>\") in <code>\"P1P5P4CCCP2P6P3\"</code>');",
"assert('P6P2P7P4P5CCCCCP3P1'.match(reCriminals) && 'P6P2P7P4P5CCCCCP3P1'.match(reCriminals)[0] == 'CCCCC', 'message: Your regex should match <em>five</em> criminals (\"<code>CCCCC</code>\") in <code>\"P6P2P7P4P5CCCCCP3P1\"</code>');",
"assert(!reCriminals.test(''), 'message: Your regex should not match any criminals in <code>\"\"</code>');",
"assert(!reCriminals.test('P1P2P3'), 'message: Your regex should not match any criminals in <code>\"P1P2P3\"</code>');",
"assert('P2P1P5P4CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCP3'.match(reCriminals) && 'P2P1P5P4CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCP3'.match(reCriminals)[0] == \"CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\", 'message: Your regex should match <em>fifty</em> criminals (\"<code>CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC</code>\") in <code>\"P2P1P5P4CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCP3\"</code>.');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7db7367417b2b2512b9d",
"title": "Match Beginning String Patterns",
"description": [
"Prior challenges showed that regular expressions can be used to look for a number of matches. They are also used to search for patterns in specific positions in strings.",
"In an earlier challenge, you used the <code>caret</code> character (<code>^</code>) inside a <code>character set</code> to create a <code>negated character set</code> in the form <code>[^thingsThatWillNotBeMatched]</code>. Outside of a <code>character set</code>, the <code>caret</code> is used to search for patterns at the beginning of strings.",
"<blockquote>let firstString = \"Ricky is first and can be found.\";<br>let firstRegex = /^Ricky/;<br>firstRegex.test(firstString);<br>// Returns true<br>let notFirst = \"You can't find Ricky now.\";<br>firstRegex.test(notFirst);<br>// Returns false</blockquote>",
"<hr>",
"Use the <code>caret</code> character in a regex to find <code>\"Cal\"</code> only in the beginning of the string <code>rickyAndCal</code>."
],
"challengeSeed": [
"let rickyAndCal = \"Cal and Ricky both like racing.\";",
"let calRegex = /change/; // Change this line",
"let result = calRegex.test(rickyAndCal);"
],
"tests": [
"assert(calRegex.source == \"^Cal\", 'message: Your regex should search for <code>\"Cal\"</code> with a capital letter.');",
"assert(calRegex.flags == \"\", 'message: Your regex should not use any flags.');",
"assert(calRegex.test(\"Cal and Ricky both like racing.\"), 'message: Your regex should match <code>\"Cal\"</code> at the beginning of the string.');",
"assert(!calRegex.test(\"Ricky and Cal both like racing.\"), 'message: Your regex should not match <code>\"Cal\"</code> in the middle of a string.');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7db7367417b2b2512b9e",
"title": "Match Ending String Patterns",
"description": [
"In the last challenge, you learned to use the <code>caret</code> character to search for patterns at the beginning of strings. There is also a way to search for patterns at the end of strings.",
"You can search the end of strings using the <code>dollar sign</code> character <code>$</code> at the end of the regex.",
"<blockquote>let theEnding = \"This is a never ending story\";<br>let storyRegex = /story$/;<br>storyRegex.test(theEnding);<br>// Returns true<br>let noEnding = \"Sometimes a story will have to end\";<br>storyRegex.test(noEnding);<br>// Returns false<br></blockquote>",
"<hr>",
"Use the anchor character (<code>$</code>) to match the string <code>\"caboose\"</code> at the end of the string <code>caboose</code>."
],
"challengeSeed": [
"let caboose = \"The last car on a train is the caboose\";",
"let lastRegex = /change/; // Change this line",
"let result = lastRegex.test(caboose);"
],
"tests": [
"assert(lastRegex.source == \"caboose$\", 'message: You should search for <code>\"caboose\"</code> with the dollar sign <code>$</code> anchor in your regex.');",
"assert(lastRegex.flags == \"\", 'message: Your regex should not use any flags.');",
"assert(lastRegex.test(\"The last car on a train is the caboose\"), 'message: You should match <code>\"caboose\"</code> at the end of the string <code>\"The last car on a train is the caboose\"</code>');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7db7367417b2b2512b9f",
"title": "Match All Letters and Numbers",
"description": [
"Using character classes, you were able to search for all letters of the alphabet with <code>[a-z]</code>. This kind of character class is common enough that there is a shortcut for it, although it includes a few extra characters as well.",
"The closest character class in JavaScript to match the alphabet is <code>\\w</code>. This shortcut is equal to <code>[A-Za-z0-9_]</code>. This character class matches upper and lowercase letters plus numbers. Note, this character class also includes the underscore character (<code>_</code>).",
"<blockquote>let longHand = /[A-Za-z0-9_]+/;<br>let shortHand = /\\w+/;<br>let numbers = \"42\";<br>let varNames = \"important_var\";<br>longHand.test(numbers); // Returns true<br>shortHand.test(numbers); // Returns true<br>longHand.test(varNames); // Returns true<br>shortHand.test(varNames); // Returns true</blockquote>",
"These shortcut character classes are also known as <code>shorthand character classes</code>.",
"<hr>",
"Use the shorthand character class <code>\\w</code> to count the number of alphanumeric characters in various quotes and strings."
],
"challengeSeed": [
"let quoteSample = \"The five boxing wizards jump quickly.\";",
"let alphabetRegexV2 = /change/; // Change this line",
"let result = quoteSample.match(alphabetRegexV2).length;"
],
"tests": [
"assert(alphabetRegexV2.global, 'message: Your regex should use the global flag.');",
"assert(\"The five boxing wizards jump quickly.\".match(alphabetRegexV2).length === 31, 'message: Your regex should find 31 alphanumeric characters in <code>\"The five boxing wizards jump quickly.\"</code>');",
"assert(\"Pack my box with five dozen liquor jugs.\".match(alphabetRegexV2).length === 32, 'message: Your regex should find 32 alphanumeric characters in <code>\"Pack my box with five dozen liquor jugs.\"</code>');",
"assert(\"How vexingly quick daft zebras jump!\".match(alphabetRegexV2).length === 30, 'message: Your regex should find 30 alphanumeric characters in <code>\"How vexingly quick daft zebras jump!\"</code>');",
"assert(\"123 456 7890 ABC def GHI jkl MNO pqr STU vwx YZ.\".match(alphabetRegexV2).length === 36, 'message: Your regex should find 36 alphanumeric characters in <code>\"123 456 7890 ABC def GHI jkl MNO pqr STU vwx YZ.\"</code>');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7db8367417b2b2512ba0",
"title": "Match Everything But Letters and Numbers",
"description": [
"You've learned that you can use a shortcut to match alphanumerics <code>[A-Za-z0-9_]</code> using <code>\\w</code>. A natural pattern you might want to search for is the opposite of alphanumerics.",
"You can search for the opposite of the <code>\\w</code> with <code>\\W</code>. Note, the opposite pattern uses a capital letter. This shortcut is the same as <code>[^A-Za-z0-9_]</code>.",
"<blockquote>let shortHand = /\\W/;<br>let numbers = \"42%\";<br>let sentence = \"Coding!\";<br>numbers.match(shortHand); // Returns [\"%\"]<br>sentence.match(shortHand); // Returns [\"!\"]<br></blockquote>",
"<hr>",
"Use the shorthand character class <code>\\W</code> to count the number of non-alphanumeric characters in various quotes and strings."
],
"challengeSeed": [
"let quoteSample = \"The five boxing wizards jump quickly.\";",
"let nonAlphabetRegex = /change/; // Change this line",
"let result = quoteSample.match(nonAlphabetRegex).length;"
],
"tests": [
"assert(nonAlphabetRegex.global, 'message: Your regex should use the global flag.');",
"assert(\"The five boxing wizards jump quickly.\".match(nonAlphabetRegex).length == 6, 'message: Your regex should find 6 non-alphanumeric characters in <code>\"The five boxing wizards jump quickly.\"</code>.');",
"assert(\"Pack my box with five dozen liquor jugs.\".match(nonAlphabetRegex).length == 8, 'message: Your regex should find 8 non-alphanumeric characters in <code>\"Pack my box with five dozen liquor jugs.\"</code>');",
"assert(\"How vexingly quick daft zebras jump!\".match(nonAlphabetRegex).length == 6, 'message: Your regex should find 6 non-alphanumeric characters in <code>\"How vexingly quick daft zebras jump!\"</code>');",
"assert(\"123 456 7890 ABC def GHI jkl MNO pqr STU vwx YZ.\".match(nonAlphabetRegex).length == 12, 'message: Your regex should find 12 non-alphanumeric characters in <code>\"123 456 7890 ABC def GHI jkl MNO pqr STU vwx YZ.\"</code>');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "5d712346c441eddfaeb5bdef",
"title": "Match All Numbers",
"description": [
"You've learned shortcuts for common string patterns like alphanumerics. Another common pattern is looking for just digits or numbers.",
"The shortcut to look for digit characters is <code>\\d</code>, with a lowercase <code>d</code>. This is equal to the character class <code>[0-9]</code>, which looks for a single character of any number between zero and nine.",
"<hr>",
"Use the shorthand character class <code>\\d</code> to count how many digits are in movie titles. Written out numbers (\"six\" instead of 6) do not count."
],
"challengeSeed": [
"let numString = \"Your sandwich will be $5.00\";",
"let numRegex = /change/; // Change this line",
"let result = numString.match(numRegex).length;"
],
"tests": [
"assert(/\\\\d/.test(numRegex.source), 'message: Your regex should use the shortcut character to match digit characters');",
"assert(numRegex.global, 'message: Your regex should use the global flag.');",
"assert(\"9\".match(numRegex).length == 1, 'message: Your regex should find 1 digit in <code>\"9\"</code>.');",
"assert(\"Catch 22\".match(numRegex).length == 2, 'message: Your regex should find 2 digits in <code>\"Catch 22\"</code>.');",
"assert(\"101 Dalmatians\".match(numRegex).length == 3, 'message: Your regex should find 3 digits in <code>\"101 Dalmatians\"</code>.');",
"assert(\"One, Two, Three\".match(numRegex) == null, 'message: Your regex should find no digits in <code>\"One, Two, Three\"</code>.');",
"assert(\"21 Jump Street\".match(numRegex).length == 2, 'message: Your regex should find 2 digits in <code>\"21 Jump Street\"</code>.');",
"assert(\"2001: A Space Odyssey\".match(numRegex).length == 4, 'message: Your regex should find 4 digits in <code>\"2001: A Space Odyssey\"</code>.');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7db8367417b2b2512ba1",
"title": "Match All Non-Numbers",
"description": [
"The last challenge showed how to search for digits using the shortcut <code>\\d</code> with a lowercase <code>d</code>. You can also search for non-digits using a similar shortcut that uses an uppercase <code>D</code> instead.",
"The shortcut to look for non-digit characters is <code>\\D</code>. This is equal to the character class <code>[^0-9]</code>, which looks for a single character that is not a number between zero and nine.",
"<hr>",
"Use the shorthand character class for non-digits <code>\\D</code> to count how many non-digits are in movie titles."
],
"challengeSeed": [
"let numString = \"Your sandwich will be $5.00\";",
"let noNumRegex = /change/; // Change this line",
"let result = numString.match(noNumRegex).length;"
],
"tests": [
"assert(/\\\\D/.test(noNumRegex.source), 'message: Your regex should use the shortcut character to match non-digit characters');",
"assert(noNumRegex.global, 'message: Your regex should use the global flag.');",
"assert(\"9\".match(noNumRegex) == null, 'message: Your regex should find no non-digits in <code>\"9\"</code>.');",
"assert(\"Catch 22\".match(noNumRegex).length == 6, 'message: Your regex should find 6 non-digits in <code>\"Catch 22\"</code>.');",
"assert(\"101 Dalmatians\".match(noNumRegex).length == 11, 'message: Your regex should find 11 non-digits in <code>\"101 Dalmatians\"</code>.');",
"assert(\"One, Two, Three\".match(noNumRegex).length == 15, 'message: Your regex should find 15 non-digits in <code>\"One, Two, Three\"</code>.');",
"assert(\"21 Jump Street\".match(noNumRegex).length == 12, 'message: Your regex should find 12 non-digits in <code>\"21 Jump Street\"</code>.');",
"assert(\"2001: A Space Odyssey\".match(noNumRegex).length == 17, 'message: Your regex should find 17 non-digits in <code>\"2001: A Space Odyssey\"</code>.');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7db8367417b2b2512ba2",
"title": "Restrict Possible Usernames",
"description": [
"Usernames are used everywhere on the internet. They are what give users a unique identity on their favorite sites.",
"You need to check all the usernames in a database. Here are some simple rules that users have to follow when creating their username.",
"1) The only numbers in the username have to be at the end. There can be zero or more of them at the end.",
"2) Username letters can be lowercase and uppercase.",
"3) Usernames have to be at least two characters long. A two-letter username can only use alphabet letter characters.",
"<hr>",
"Change the regex <code>userCheck</code> to fit the constraints listed above."
],
"challengeSeed": [
"let username = \"JackOfAllTrades\";",
"let userCheck = /change/; // Change this line",
"let result = userCheck.test(username);"
],
"tests": [
"assert(userCheck.test(\"JACK\"), 'message: Your regex should match <code>JACK</code>');",
"assert(!userCheck.test(\"J\"), 'message: Your regex should not match <code>J</code>');",
"assert(userCheck.test(\"Oceans11\"), 'message: Your regex should match <code>Oceans11</code>');",
"assert(userCheck.test(\"RegexGuru\"), 'message: Your regex should match <code>RegexGuru</code>');",
"assert(!userCheck.test(\"007\"), 'message: Your regex should not match <code>007</code>');",
"assert(!userCheck.test(\"9\"), 'message: Your regex should not match <code>9</code>');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7db8367417b2b2512ba3",
"title": "Match Whitespace",
"description": [
"The challenges so far have covered matching letters of the alphabet and numbers. You can also match the whitespace or spaces between letters.",
"You can search for whitespace using <code>\\s</code>, which is a lowercase <code>s</code>. This pattern not only matches whitespace, but also carriage return, tab, form feed, and new line characters. You can think of it as similar to the character class <code>[ \\r\\t\\f\\n\\v]</code>.",
"<blockquote>let whiteSpace = \"Whitespace. Whitespace everywhere!\"<br>let spaceRegex = /\\s/g;<br>whiteSpace.match(spaceRegex);<br>// Returns [\" \", \" \"]<br></blockquote>",
"<hr>",
"Change the regex <code>countWhiteSpace</code> to look for multiple whitespace characters in a string."
],
"challengeSeed": [
"let sample = \"Whitespace is important in separating words\";",
"let countWhiteSpace = /change/; // Change this line",
"let result = sample.match(countWhiteSpace);"
],
"tests": [
"assert(countWhiteSpace.global, 'message: Your regex should use the global flag.');",
"assert(\"Men are from Mars and women are from Venus.\".match(countWhiteSpace).length == 8, 'message: Your regex should find eight spaces in <code>\"Men are from Mars and women are from Venus.\"</code>');",
"assert(\"Space: the final frontier.\".match(countWhiteSpace).length == 3, 'message: Your regex should find three spaces in <code>\"Space: the final frontier.\"</code>');",
"assert(\"MindYourPersonalSpace\".match(countWhiteSpace) == null, 'message: Your regex should find no spaces in <code>\"MindYourPersonalSpace\"</code>');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7db9367417b2b2512ba4",
"title": "Match Non-Whitespace Characters",
"description": [
"You learned about searching for whitespace using <code>\\s</code>, with a lowercase <code>s</code>. You can also search for everything except whitespace.",
"Search for non-whitespace using <code>\\S</code>, which is an uppercase <code>s</code>. This pattern will not match whitespace, carriage return, tab, form feed, and new line characters. You can think of it being similar to the character class <code>[^ \\r\\t\\f\\n\\v]</code>.",
"<blockquote>let whiteSpace = \"Whitespace. Whitespace everywhere!\"<br>let nonSpaceRegex = /\\S/g;<br>whiteSpace.match(nonSpaceRegex).length; // Returns 32</blockquote>",
"<hr>",
"Change the regex <code>countNonWhiteSpace</code> to look for multiple non-whitespace characters in a string."
],
"challengeSeed": [
"let sample = \"Whitespace is important in separating words\";",
"let countNonWhiteSpace = /change/; // Change this line",
"let result = sample.match(countNonWhiteSpace);"
],
"tests": [
"assert(countNonWhiteSpace.global, 'message: Your regex should use the global flag.');",
"assert(\"Men are from Mars and women are from Venus.\".match(countNonWhiteSpace).length == 35, 'message: Your regex should find 35 non-spaces in <code>\"Men are from Mars and women are from Venus.\"</code>');",
"assert(\"Space: the final frontier.\".match(countNonWhiteSpace).length == 23, 'message: Your regex should find 23 non-spaces in <code>\"Space: the final frontier.\"</code>');",
"assert(\"MindYourPersonalSpace\".match(countNonWhiteSpace).length == 21, 'message: Your regex should find 21 non-spaces in <code>\"MindYourPersonalSpace\"</code>');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7db9367417b2b2512ba5",
"title": "Specify Upper and Lower Number of Matches",
"description": [
"Recall that you use the plus sign <code>+</code> to look for one or more characters and the asterisk <code>*</code> to look for zero or more characters. These are convenient but sometimes you want to match a certain range of patterns.",
"You can specify the lower and upper number of patterns with <code>quantity specifiers</code>. Quantity specifiers are used with curly brackets (<code>{</code> and <code>}</code>). You put two numbers between the curly brackets - for the lower and upper number of patterns.",
"For example, to match only the letter <code>a</code> appearing between <code>3</code> and <code>5</code> times in the string <code>\"ah\"</code>, your regex would be <code>/a{3,5}h/</code>.",
"<blockquote>let A4 = \"aaaah\";<br>let A2 = \"aah\";<br>let multipleA = /a{3,5}h/;<br>multipleA.test(A4); // Returns true<br>multipleA.test(A2); // Returns false</blockquote>",
"<hr>",
"Change the regex <code>ohRegex</code> to match only <code>3</code> to <code>6</code> letter <code>h</code>'s in the word <code>\"Oh no\"</code>."
],
"challengeSeed": [
"let ohStr = \"Ohhh no\";",
"let ohRegex = /change/; // Change this line",
"let result = ohRegex.test(ohStr);"
],
"tests": [
"assert(ohRegex.source.match(/{.*?}/).length > 0, 'message: Your regex should use curly brackets.');",
"assert(!ohRegex.test(\"Ohh no\"), 'message: Your regex should not match <code>\"Ohh no\"</code>');",
"assert(ohRegex.test(\"Ohhh no\"), 'message: Your regex should match <code>\"Ohhh no\"</code>');",
"assert(ohRegex.test(\"Ohhhh no\"), 'message: Your regex should match <code>\"Ohhhh no\"</code>');",
"assert(ohRegex.test(\"Ohhhhh no\"), 'message: Your regex should match <code>\"Ohhhhh no\"</code>');",
"assert(ohRegex.test(\"Ohhhhhh no\"), 'message: Your regex should match <code>\"Ohhhhhh no\"</code>');",
"assert(!ohRegex.test(\"Ohhhhhhh no\"), 'message: Your regex should not match <code>\"Ohhhhhhh no\"</code>');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7db9367417b2b2512ba6",
"title": "Specify Only the Lower Number of Matches",
"description": [
"You can specify the lower and upper number of patterns with <code>quantity specifiers</code> using curly brackets. Sometimes you only want to specify the lower number of patterns with no upper limit.",
"To only specify the lower number of patterns, keep the first number followed by a comma.",
"For example, to match only the string <code>\"hah\"</code> with the letter <code>a</code> appearing at least <code>3</code> times, your regex would be <code>/ha{3,}h/</code>.",
"<blockquote>let A4 = \"haaaah\";<br>let A2 = \"haah\";<br>let A100 = \"h\" + \"a\".repeat(100) + \"h\";<br>let multipleA = /ha{3,}h/;<br>multipleA.test(A4); // Returns true<br>multipleA.test(A2); // Returns false<br>multipleA.test(A100); // Returns true</blockquote>",
"<hr>",
"Change the regex <code>haRegex</code> to match the word <code>\"Hazzah\"</code> only when it has four or more letter <code>z</code>'s."
],
"challengeSeed": [
"let haStr = \"Hazzzzah\";",
"let haRegex = /change/; // Change this line",
"let result = haRegex.test(haStr);"
],
"tests": [
"assert(haRegex.source.match(/{.*?}/).length > 0, 'message: Your regex should use curly brackets.');",
"assert(!haRegex.test(\"Hazzah\"), 'message: Your regex should not match <code>\"Hazzah\"</code>');",
"assert(!haRegex.test(\"Hazzzah\"), 'message: Your regex should not match <code>\"Hazzzah\"</code>');",
"assert(haRegex.test(\"Hazzzzah\"), 'message: Your regex should match <code>\"Hazzzzah\"</code>');",
"assert(haRegex.test(\"Hazzzzzah\"), 'message: Your regex should match <code>\"Hazzzzzah\"</code>');",
"assert(haRegex.test(\"Hazzzzzzah\"), 'message: Your regex should match <code>\"Hazzzzzzah\"</code>');",
"assert(haRegex.test(\"Ha\" + \"z\".repeat(30) + \"ah\"), 'message: Your regex should match <code>\"Hazzah\"</code> with 30 <code>z</code>\\'s in it.');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7db9367417b2b2512ba7",
"title": "Specify Exact Number of Matches",
"description": [
"You can specify the lower and upper number of patterns with <code>quantity specifiers</code> using curly brackets. Sometimes you only want a specific number of matches.",
"To specify a certain number of patterns, just have that one number between the curly brackets.",
"For example, to match only the word <code>\"hah\"</code> with the letter <code>a</code> <code>3</code> times, your regex would be <code>/ha{3}h/</code>.",
"<blockquote>let A4 = \"haaaah\";<br>let A3 = \"haaah\";<br>let A100 = \"h\" + \"a\".repeat(100) + \"h\";<br>let multipleHA = /a{3}h/;<br>multipleHA.test(A4); // Returns false<br>multipleHA.test(A3); // Returns true<br>multipleHA.test(A100); // Returns false</blockquote>",
"<hr>",
"Change the regex <code>timRegex</code> to match the word <code>\"Timber\"</code> only when it has four letter <code>m</code>'s."
],
"challengeSeed": [
"let timStr = \"Timmmmber\";",
"let timRegex = /change/; // Change this line",
"let result = timRegex.test(timStr);"
],
"tests": [
"assert(timRegex.source.match(/{.*?}/).length > 0, 'message: Your regex should use curly brackets.');",
"assert(!timRegex.test(\"Timber\"), 'message: Your regex should not match <code>\"Timber\"</code>');",
"assert(!timRegex.test(\"Timmber\"), 'message: Your regex should not match <code>\"Timmber\"</code>');",
"assert(!timRegex.test(\"Timmmber\"), 'message: Your regex should not match <code>\"Timmmber\"</code>');",
"assert(timRegex.test(\"Timmmmber\"), 'message: Your regex should match <code>\"Timmmmber\"</code>');",
"assert(!timRegex.test(\"Ti\" + \"m\".repeat(30) + \"ber\"), 'message: Your regex should not match <code>\"Timber\"</code> with 30 <code>m</code>\\'s in it.');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7dba367417b2b2512ba8",
"title": "Check for All or None",
"description": [
"Sometimes the patterns you want to search for may have parts of it that may or may not exist. However, it may be important to check for them nonetheless.",
"You can specify the possible existence of an element with a question mark, <code>?</code>. This checks for zero or one of the preceding element. You can think of this symbol as saying the previous element is optional.",
"For example, there are slight differences in American and British English and you can use the question mark to match both spellings.",
"<blockquote>let american = \"color\";<br>let british = \"colour\";<br>let rainbowRegex= /colou?r/;<br>rainbowRegex.test(american); // Returns true<br>rainbowRegex.test(british); // Returns true</blockquote>",
"<hr>",
"Change the regex <code>favRegex</code> to match both the American English (favorite) and the British English (favourite) version of the word."
],
"challengeSeed": [
"let favWord = \"favorite\";",
"let favRegex = /change/; // Change this line",
"let result = favRegex.test(favWord);"
],
"tests": [
"assert(favRegex.source.match(/\\?/).length > 0, 'message: Your regex should use the optional symbol, <code>?</code>.');",
"assert(favRegex.test(\"favorite\"), 'message: Your regex should match <code>\"favorite\"</code>');",
"assert(favRegex.test(\"favourite\"), 'message: Your regex should match <code>\"favourite\"</code>');",
"assert(!favRegex.test(\"fav\"), 'message: Your regex should not match <code>\"fav\"</code>');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7dba367417b2b2512ba9",
"title": "Positive and Negative Lookahead",
"description": [
"<code>Lookaheads</code> are patterns that tell JavaScript to look-ahead in your string to check for patterns further along. This can be useful when you want to search for multiple patterns over the same string.",
"There are two kinds of <code>lookaheads</code>: <code>positive lookahead</code> and <code>negative lookahead</code>.",
"A <code>positive lookahead</code> will look to make sure the element in the search pattern is there, but won't actually match it. A positive lookahead is used as <code>(?=...)</code> where the <code>...</code> is the required part that is not matched.",
"On the other hand, a <code>negative lookahead</code> will look to make sure the element in the search pattern is not there. A negative lookahead is used as <code>(?!...)</code> where the <code>...</code> is the pattern that you do not want to be there. The rest of the pattern is returned if the negative lookahead part is not present.",
"Lookaheads are a bit confusing but some examples will help.",
"<blockquote>let quit = \"qu\";<br>let noquit = \"qt\";<br>let quRegex= /q(?=u)/;<br>let qRegex = /q(?!u)/;<br>quit.match(quRegex); // Returns [\"q\"]<br>noquit.match(qRegex); // Returns [\"q\"]</blockquote>",
"A more practical use of <code>lookaheads</code> is to check two or more patterns in one string. Here is a (naively) simple password checker that looks for between 3 and 6 characters and at least one number:",
"<blockquote>let password = \"abc123\";<br>let checkPass = /(?=\\w{3,6})(?=\\D*\\d)/;<br>checkPass.test(password); // Returns true</blockquote>",
"<hr>",
"Use <code>lookaheads</code> in the <code>pwRegex</code> to match passwords that are greater than 5 characters long and have two consecutive digits."
],
"challengeSeed": [
"let sampleWord = \"astronaut\";",
"let pwRegex = /change/; // Change this line",
"let result = pwRegex.test(sampleWord);"
],
"tests": [
"assert(pwRegex.source.match(/\\(\\?=.*?\\)\\(\\?=.*?\\)/) !== null, 'message: Your regex should use two positive <code>lookaheads</code>.');",
"assert(!pwRegex.test(\"astronaut\"), 'message: Your regex should not match <code>\"astronaut\"</code>');",
"assert(!pwRegex.test(\"airplanes\"), 'message: Your regex should not match <code>\"airplanes\"</code>');",
"assert(pwRegex.test(\"bana12\"), 'message: Your regex should match <code>\"bana12\"</code>');",
"assert(pwRegex.test(\"abc123\"), 'message: Your regex should match <code>\"abc123\"</code>');",
"assert(!pwRegex.test(\"123\"), 'message: Your regex should not match <code>\"123\"</code>');",
"assert(!pwRegex.test(\"1234\"), 'message: Your regex should not match <code>\"1234\"</code>');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7dbb367417b2b2512baa",
"title": "Reuse Patterns Using Capture Groups",
"description": [
"Some patterns you search for will occur multiple times in a string. It is wasteful to manually repeat that regex. There is a better way to specify when you have multiple repeat substrings in your string.",
"You can search for repeat substrings using <code>capture groups</code>. Parentheses, <code>(</code> and <code>)</code>, are used to find repeat substrings. You put the regex of the pattern that will repeat in between the parentheses.",
"To specify where that repeat string will appear, you use a backslash (<code>\\</code>) and then a number. This number starts at 1 and increases with each additional capture group you use. An example would be <code>\\1</code> to match the first group.",
"The example below matches any word that occurs twice separated by a space:",
"<blockquote>let repeatStr = \"regex regex\";<br>let repeatRegex = /(\\w+)\\s\\1/;<br>repeatRegex.test(repeatStr); // Returns true<br>repeatStr.match(repeatRegex); // Returns [\"regex regex\", \"regex\"]</blockquote>",
"Using the <code>.match()</code> method on a string will return an array with the string it matches, along with its capture group.",
"<hr>",
"Use <code>capture groups</code> in <code>reRegex</code> to match numbers that are repeated only three times in a string, each separated by a space."
],
"challengeSeed": [
"let repeatNum = \"42 42 42\";",
"let reRegex = /change/; // Change this line",
"let result = reRegex.test(repeatNum);"
],
"tests": [
"assert(reRegex.source.match(/\\\\d/), 'message: Your regex should use the shorthand character class for digits.');",
"assert(reRegex.source.match(/\\\\\\d/g).length === 2, 'message: Your regex should reuse the capture group twice.');",
"assert(reRegex.source.match(/\\\\s/g).length === 2, 'message: Your regex should have two spaces separating the three numbers.');",
"assert(reRegex.test(\"42 42 42\"), 'message: Your regex should match <code>\"42 42 42\"</code>.');",
"assert(reRegex.test(\"100 100 100\"), 'message: Your regex should match <code>\"100 100 100\"</code>.');",
"assert.equal((\"42 42 42 42\").match(reRegex.source), null, 'message: Your regex should not match <code>\"42 42 42 42\"</code>.');",
"assert.equal((\"42 42\").match(reRegex.source), null, 'message: Your regex should not match <code>\"42 42\"</code>.');",
"assert(!reRegex.test(\"101 102 103\"), 'message: Your regex should not match <code>\"101 102 103\"</code>.');",
"assert(!reRegex.test(\"1 2 3\"), 'message: Your regex should not match <code>\"1 2 3\"</code>.');",
"assert(reRegex.test(\"10 10 10\"), 'message: Your regex should match <code>\"10 10 10\"</code>.');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7dbb367417b2b2512bab",
"title": "Use Capture Groups to Search and Replace",
"description": [
"Searching is useful. However, you can make searching even more powerful when it also changes (or replaces) the text you match.",
"You can search and replace text in a string using <code>.replace()</code> on a string. The inputs for <code>.replace()</code> is first the regex pattern you want to search for. The second parameter is the string to replace the match or a function to do something.",
"<blockquote>let wrongText = \"The sky is silver.\";<br>let silverRegex = /silver/;<br>wrongText.replace(silverRegex, \"blue\");<br>// Returns \"The sky is blue.\"</blockquote>",
"You can also access capture groups in the replacement string with dollar signs (<code>$</code>).",
"<blockquote>\"Code Camp\".replace(/(\\w+)\\s(\\w+)/, '$2 $1');<br>// Returns \"Camp Code\"</blockquote>",
"<hr>",
"Write a regex so that it will search for the string <code>\"good\"</code>. Then update the <code>replaceText</code> variable to replace <code>\"good\"</code> with <code>\"okey-dokey\"</code>."
],
"challengeSeed": [
"let huhText = \"This sandwich is good.\";",
"let fixRegex = /change/; // Change this line",
"let replaceText = \"\"; // Change this line",
"let result = huhText.replace(fixRegex, replaceText);"
],
"tests": [
"assert(code.match(/\\.replace\\(.*\\)/), 'message: You should use <code>.replace()</code> to search and replace.');",
"assert(result == \"This sandwich is okey-dokey.\" && replaceText === \"okey-dokey\", 'message: Your regex should change <code>\"This sandwich is good.\"</code> to <code>\"This sandwich is okey-dokey.\"</code>');",
"assert(code.match(/result\\s*=\\s*huhText\\.replace\\(.*?\\)/), 'message: You should not change the last line.');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d7dbb367417b2b2512bac",
"title": "Remove Whitespace from Start and End",
"description": [
"Sometimes whitespace characters around strings are not wanted but are there. Typical processing of strings is to remove the whitespace at the start and end of it.",
"<hr>",
"Write a regex and use the appropriate string methods to remove whitespace at the beginning and end of strings.",
"<strong>Note</strong><br>The <code>.trim()</code> method would work here, but you'll need to complete this challenge using regular expressions."
],
"challengeSeed": [
"let hello = \" Hello, World! \";",
"let wsRegex = /change/; // Change this line",
"let result = hello; // Change this line"
],
"tests": [
"assert(result == \"Hello, World!\", 'message: <code>result</code> should equal to <code>\"Hello, World!\"</code>');",
"assert(!code.match(/\\.trim\\(.*?\\)/), 'message: You should not use the <code>.trim()</code> method.');",
"assert(!code.match(/result\\s*=\\s*\".*?\"/), 'message: The <code>result</code> variable should not be set equal to a string.');"
],
"solutions": [],
"hints": [
"You can use .replace() to remove the matched items by replacing them with an empty string."
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
}
]
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,108 @@
{
"name": "Claim Your Front End Libraries Certificate",
"order": 13,
"time": "5 minutes",
"challenges": [
{
"id": "587d7dbb367417b2b2512bad",
"title": "Claim Your Front End Libraries Certificate",
"description": [
[
"//i.imgur.com/k8btNUB.jpg",
"An image of our Front End Libraries Certificate",
"This challenge will give you your verified Front End Libraries Certificate. Before we issue your certificate, we must verify that you have completed all of our basic and intermediate algorithm scripting challenges, and all our basic, intermediate, and advanced front end development projects. You must also accept our Academic Honesty Pledge. Click the button below to start this process.",
""
],
[
"//i.imgur.com/uLPsUko.jpg",
"The definition of plagiarism: Plagiarism (noun) - copying someone elses work and presenting it as your own without crediting them",
"By clicking below, you pledge that all of your submitted code A) is code you or your pair personally wrote, or B) comes from open source libraries like jQuery, or C) has been clearly attributed to its original authors. You also give us permission to audit your challenge solutions and revoke your certificate if we discover evidence of plagiarism.",
"#"
],
[
"//i.imgur.com/UedoV2G.jpg",
"An image of the text \"Front End Development Certificate requirements\"",
"Let's confirm that you have completed all of our basic and intermediate algorithm scripting challenges, and all our basic, intermediate, and advanced front end development projects. Click the button below to verify this.",
"#"
],
[
"//i.imgur.com/Q5Za9U6.jpg",
"An image of the word \"Congratulations\"",
"Congratulations! We've added your Front End Libraries Certificate to your portfolio page. Unless you choose to hide your solutions, this certificate will remain publicly visible and verifiable.",
""
]
],
"challengeSeed": [
{
"properties": [
"isHonest",
"isFrontEndCert"
],
"apis": [
"/certificate/honest",
"/certificate/verify/front-end"
],
"stepIndex": [
1,
2
]
}
],
"tests": [
{
"id": "bd7158d8c442eddfaeb5bd0f",
"title": "Build a Pomodoro Clock"
},
{
"id": "bd7158d8c442eddfaeb5bd17",
"title": "Build a JavaScript Calculator"
},
{
"id": "587d7dbc367417b2b2512bae",
"title": "Build a Drum Machine"
},
{
"id": "bd7157d8c242eddfaeb5bd13",
"title": "Build a Markdown Previewer"
},
{
"id": "bd7158d8c442eddfaeb5bd13",
"title": "Build a Random Quote Machine"
}
],
"type": "Waypoint",
"challengeType": 7,
"translations": {
"es": {
"title": "Reclama tu certificado de Desarrollo de interfaces",
"description": [
[
"//i.imgur.com/k8btNUB.jpg",
"Una imagen que muestra nuestro certificado de Desarrollo de interfaces",
"Este desafío te otorga tu certificado autenticado de Desarrollo de interfaces. Antes de que podamos emitir tu certificado, debemos verificar que has completado todos los desafíos básicos e intermedios de diseño de algoritmos, y todos los proyectos básicos e intermedios de desarrollo de interfaces. También debes aceptar nuestro Juramento de honestidad académica. Pulsa el botón siguiente para iniciar este proceso.",
""
],
[
"//i.imgur.com/HArFfMN.jpg",
"Plagio (nombre): acción y efecto de plagiar. Plagiar (verbo) - copiar en lo sustancial obras ajenas, dándolas como propias.",
"Al pulsar el botón siguiente, juras que todo el código en tus soluciones a los desafíos A) es código que tú o tu compañero escribieron personalmente, o B) proviene de librerías de código abierto como jQuery, o C) ha sido claramente atribuido a sus autores originales. También nos otorgas el permiso para auditar tus soluciones a los desafíos y revocar tu certificado si encontramos evidencia de plagio.",
"#"
],
[
"//i.imgur.com/14F2Van.jpg",
"Una imagen del texto \"Front End Development Certificate requirements\"",
"Confirmemos que has completado todos nuestros desafíos básicos e intermedios de diseño de algoritmos, y todos nuestros proyectos básicos e intermedios de desarrollo de interfaces. Pulsa el botón siguiente para hacer la verificación.",
"#"
],
[
"//i.imgur.com/16SIhHO.jpg",
"Una imagen de la palabra \"Congratulations\"",
"¡Felicitaciones! Hemos agregado tu certificado de Desarrollo de interfaces a tu portafolio. A menos que elijas no mostrar tus soluciones, este certificado será públicamente visible y verificable.",
""
]
]
}
}
}
]
}

View File

@ -0,0 +1,138 @@
{
"name": "Front End Frameworks Projects",
"order": 8,
"time": "150 hours",
"helpRoom": "Help",
"challenges": [
{
"id": "bd7158d8c442eddfaeb5bd13",
"title": "Build a Random Quote Machine",
"description": [
"Fulfill the user stories by getting all of the tests to pass. Use whichever libraries you need. Give it your own personal style.",
"Here's a <a href='http://codepen.io/freeCodeCamp/full/qRZeGZ' target='_blank'>working example</a>. Try not to look at its code.",
"You can build your project by forking <a href='http://codepen.io/freeCodeCamp/pen/MJjpwO' target='_blank'>this CodePen pen</a>. Or you can use this CDN link to run the tests in any environment you like: <code>https://gitcdn.link/repo/freeCodeCamp/testable-projects-fcc/master/build/bundle.js</code>",
"Once you're done, submit the URL to your working project with all its tests passing.",
"Remember to use the <a href='https://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> method if you get stuck."
],
"image": "A9mEKIF",
"tests": [],
"type": "zipline",
"isRequired": true,
"challengeType": 3,
"translations": {
"es": {
"title": "Crea una máquina de frases aleatorias",
"description": []
},
"ru": {
"title": "Создайте генератор случайных цитат",
"description": []
}
}
},
{
"id": "bd7157d8c242eddfaeb5bd13",
"title": "Build a Markdown Previewer",
"description": [
"Fulfill the user stories by getting all of the tests to pass. Use whichever libraries you need. Give it your own personal style.",
"Here's a <a href='http://codepen.io/freeCodeCamp/full/GrZVVO' target='_blank'>working example</a>. Try not to look at its code.",
"You can build your project by forking <a href='http://codepen.io/freeCodeCamp/pen/MJjpwO' target='_blank'>this CodePen pen</a>. Or you can use this CDN link to run the tests in any environment you like: <code>https://gitcdn.link/repo/freeCodeCamp/testable-projects-fcc/master/build/bundle.js</code>",
"Once you're done, submit the URL to your working project with all its tests passing.",
"Remember to use the <a href='https://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> method if you get stuck."
],
"releasedOn": "January 10, 2017",
"image": "FFDvuCP",
"tests": [],
"type": "zipline",
"isRequired": true,
"challengeType": 3,
"translations": {
"es": {
"title": "Crea una caja de recetas",
"description": []
},
"ru": {
"title": "Создайте хранилище рецептов",
"description": []
}
}
},
{
"id": "587d7dbc367417b2b2512bae",
"title": "Build a Drum Machine",
"description": [
"Fulfill the user stories by getting all of the tests to pass. Use whichever libraries you need. Give it your own personal style.",
"Here's a <a href='http://codepen.io/freeCodeCamp/full/MJyNMd' target='_blank'>working example</a>. Try not to look at its code.",
"You can build your project by forking <a href='http://codepen.io/freeCodeCamp/pen/MJjpwO' target='_blank'>this CodePen pen</a>. Or you can use this CDN link to run the tests in any environment you like: <code>https://gitcdn.link/repo/freeCodeCamp/testable-projects-fcc/master/build/bundle.js</code>",
"Once you're done, submit the URL to your working project with all its tests passing.",
"Remember to use the <a href='https://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> method if you get stuck."
],
"releasedOn": "February 17, 2017",
"image": "OkeFgKL",
"tests": [],
"type": "zipline",
"isRequired": true,
"challengeType": 3,
"translations": {
"es": {
"title": "Crea un Juego de la vida",
"description": []
},
"ru": {
"title": "Создайте игру \"Жизнь\"",
"description": []
}
}
},
{
"id": "bd7158d8c442eddfaeb5bd17",
"title": "Build a JavaScript Calculator",
"description": [
"Fulfill the user stories by getting all of the tests to pass. Use whichever libraries you need. Give it your own personal style.",
"Here's a <a href='http://codepen.io/freeCodeCamp/full/wgGVVX' target='_blank'>working example</a>. Try not to look at its code.",
"<strong>Note On Calculator Logic:</strong> It should be noted that there are two main schools of thought on calculator input logic: <dfn>immediate execution logic</dfn> and <dfn>formula logic</dfn>. Our example utilizes formula logic and observes order of operation precedence, immediate execution does not. Either is acceptable, but please note that depending on which you choose, your calculator may yield different results than ours for certain equations (see below example). As long as your math can be verified by another production calculator, please do not consider this a bug.",
"<strong>EXAMPLE:</strong> <code>3 + 5 x 6 - 2 / 4 =</code><br><ul><li><strong>Immediate Execution Logic:</strong> <code>11.5</code></li><li><strong>Formula/Expression Logic:</strong> <code>32.5</code></li></ul>",
"You can build your project by forking <a href='http://codepen.io/freeCodeCamp/pen/MJjpwO' target='_blank'>this CodePen pen</a>. Or you can use this CDN link to run the tests in any environment you like: <code>https://gitcdn.link/repo/freeCodeCamp/testable-projects-fcc/master/build/bundle.js</code>",
"Once you're done, submit the URL to your working project with all its tests passing.",
"Remember to use the <a href='https://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> method if you get stuck."
],
"image": "xlAXPjX",
"tests": [],
"type": "zipline",
"challengeType": 3,
"isRequired": true,
"translations": {
"es": {
"title": "Crea una calculadora JavaScript",
"description": []
}
}
},
{
"id": "bd7158d8c442eddfaeb5bd0f",
"title": "Build a Pomodoro Clock",
"description": [
"Fulfill the user stories by getting all of the tests to pass. Use whichever libraries you need. Give it your own personal style.",
"Here's a <a href='http://codepen.io/freeCodeCamp/full/XpKrrW' target='_blank'>working example</a>. Try not to look at its code.",
"You can build your project by forking <a href='http://codepen.io/freeCodeCamp/pen/MJjpwO' target='_blank'>this CodePen pen</a>. Or you can use this CDN link to run the tests in any environment you like: <code>https://gitcdn.link/repo/freeCodeCamp/testable-projects-fcc/master/build/bundle.js</code>",
"Once you're done, submit the URL to your working project with all its tests passing.",
"Remember to use the <a href='https://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> method if you get stuck."
],
"image": "u5RTBt4",
"tests": [],
"type": "zipline",
"isRequired": true,
"challengeType": 3,
"translations": {
"es": {
"title": "Crea un reloj pomodoro",
"description": []
},
"ru": {
"title": "Создайте таймер Pomodoro",
"description": []
}
}
}
]
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,27 @@
{
"name": "React and Redux",
"order": 7,
"time": "5 hours",
"helpRoom": "Help",
"challenges": [
{
"id": "587d7dbc367417b2b2512bb0",
"title": "Introduction to the React and Redux Challenges",
"description": [
[
"",
"",
"The React and Redux challenges have not been ported into freeCodeCamp yet. You can visit <a href=\"http://hysterical-amusement.surge.sh/\" target=\"_blank\">this link to work through the alpha version</a> of these challenges. If you have feedback, you can open an issue (or pull request) directly on <a href=\"https://github.com/bonham000/fcc-react-tests-module\" target=\"_blank\">this repository.</a>",
""
]
],
"releasedOn": "Feb 17, 2017",
"challengeSeed": [],
"tests": [],
"type": "waypoint",
"challengeType": 7,
"isRequired": false,
"translations": {}
}
]
}

View File

@ -0,0 +1,33 @@
{
"name": "React",
"order": 5,
"time": "5 hours",
"helpRoom": "Help",
"challenges": [
{
"id": "587d7dbc367417b2b2512bb1",
"title": "Introduction to the React Challenges",
"description": [
[
"",
"",
"React is a JavaScript library designed to make it easier to build complex user interfaces. React does this in a few ways:<br><br><ol><li>React allows HTML to render from a JavaScript file.</li><li>React breaks a website's parts into Components that can then be combined to build pages.</li><li>React Components can pass data to each other as properties</li></ol><br><br>React uses a virtual Document Object Model. Instead of changing the DOM directly, React makes a simplified copy of the DOM (the virtual DOM) when the page loads. This allows React to make changes to elements on the page without re-rendering the entire page. This can improve the responsiveness and functionality of single-page applications.<br><br>While not part of the React library and not required, JSX is often paired with React. JSX is a preprocessor for JavaScript written in a syntax akin to XML that results in more readable code.<br><br><strong>Fun fact:</strong> freeCodeCamp is built using React.",
""
],
[
"",
"",
"The React challenges have not been ported into freeCodeCamp yet. You can visit <a href=\"http://hysterical-amusement.surge.sh/\" target=\"_blank\">this link to work through the alpha version</a> of these challenges. If you have feedback, you can open an issue (or pull request) directly on <a href=\"https://github.com/bonham000/fcc-react-tests-module\" target=\"_blank\">this repository.</a>",
""
]
],
"releasedOn": "Feb 17, 2017",
"challengeSeed": [],
"tests": [],
"type": "waypoint",
"challengeType": 7,
"isRequired": false,
"translations": {}
}
]
}

View File

@ -0,0 +1,33 @@
{
"name": "Redux",
"order": 6,
"time": "5 hours",
"helpRoom": "Help",
"challenges": [
{
"id": "587d7dbd367417b2b2512bb2",
"title": "Introduction to the Redux Challenges",
"description": [
[
"",
"",
"Redux is self-described as a \"predictable state container for JavaScript apps.\" State (as introduced in the React challenges) is a way to manage what is displayed to a user based on that user's inputs or interactions with the application. While it's not necessary to use Redux with React, or vice-versa, the two are often used in conjunction as the features of Redux support applications built with React. Some of these features include:<br><br><ol><li>An immutable single state store or \"single state of truth\" through which the application makes UI updates</li><li>Logical structure of `actions` carrying data to `reducer` functions that return a new application state</li><li>A trackable history of changes to state</li></ol><br><br>Redux is often added to a project when the complexity of managing the application's state becomes tedious. It helps minimize some of the headaches that can be caused by data mutability or passing state back-and-forth between many React components. Redux also supports debugging with tools like <a href=\"https://github.com/gaearon/redux-devtools\" target=\"_blank\">Redux DevTools</a>. Let's jump in to learning how Redux can simplify your React apps.",
""
],
[
"",
"",
"The Redux challenges have not been ported into freeCodeCamp yet. You can visit <a href=\"http://hysterical-amusement.surge.sh/\" target=\"_blank\">this link to work through the alpha version</a> of these challenges. If you have feedback, you can open an issue (or pull request) directly on <a href=\"https://github.com/bonham000/fcc-react-tests-module\" target=\"_blank\">this repository.</a>",
""
]
],
"releasedOn": "Feb 17, 2017",
"challengeSeed": [],
"tests": [],
"type": "waypoint",
"challengeType": 7,
"isRequired": false,
"translations": {}
}
]
}

View File

@ -0,0 +1,481 @@
{
"name": "Sass",
"order": 4,
"time": "5 hours",
"helpRoom": "Help",
"challenges": [
{
"id": "587d7dbd367417b2b2512bb3",
"title": "Introduction to the Sass Challenges",
"description": [
[
"",
"",
"Sass, or \"Syntactically Awesome StyleSheets\", is a language extension of CSS. It adds features that aren't available using basic CSS syntax. Sass makes it easier for developers to simplify and maintain the style sheets for their projects.<br><br>Sass can extend the CSS language because it is a preprocessor. It takes code written using Sass syntax, and converts it into basic CSS. This allows you to create variables, nest CSS rules into others, and import other Sass files, among other things. The result is more compact, easier to read code.<br><br>This section introduces the basic features of Sass.",
""
]
],
"releasedOn": "Feb 17, 2017",
"challengeSeed": [],
"tests": [],
"type": "waypoint",
"challengeType": 7,
"isRequired": false,
"translations": {}
},
{
"id": "587d7dbd367417b2b2512bb4",
"title": "Store Data with Sass Variables",
"required": [
{
"link": "https://cdnjs.cloudflare.com/ajax/libs/sass.js/0.9.13/sass.min.js",
"raw": true
}
],
"description": [
"One feature of Sass that's different than CSS is it uses variables. They are declared and set to store data, similar to JavaScript.",
"In Javascript, variables are defined using the <code>let</code> and <code>const</code> keywords. In Sass, variables start with a <code>$</code> followed by the variable name.",
"Here are a couple examples:",
"<blockquote>$main-fonts: Arial, sans-serif;<br>$headings-color: green;<br><br>//To use variables:<br>h1 {<br>&nbsp;&nbsp;font-family: $main-fonts;<br>&nbsp;&nbsp;color: $headings-color;<br>}</blockquote>",
"One example where variables are useful is when a number of elements need to be the same color. If that color is changed, the only place to edit the code is the variable value.",
"<hr>",
"Create a variable <code>$text-color</code> and set it to red. Then change the value of the <code>color</code> property for the <code>.blog-post</code> and <code>h2</code> to the <code>$text-color</code> variable."
],
"challengeSeed": [
"<style>",
" ",
" ",
" .header{",
" text-align: center;",
" }",
" .blog-post h2 {",
" color: red;",
" }",
"</style>",
"",
"<h1 class=\"header\">Learn Sass</h1>",
"<div class=\"blog-post\">",
" <h2>Some random title</h2>",
" <p>This is a paragraph with some random text in it</p>",
"</div>",
"<div class=\"blog-post\">",
" <h2>Header #2</h2>",
" <p>Here is some more random text.</p>",
"</div>",
"<div class=\"blog-post\">",
" <h2>Here is another header</h2>",
" <p>Even more random text within a paragraph</p>",
"</div>"
],
"tests": [
"assert(code.match(/\\$text-color:\\s*?red;/g), 'message: Your code should have a Sass variable declared for <code>$text-color</code> with a value of red.');",
"assert(code.match(/color:\\s*?\\$text-color;/g), 'message: Your code should use the <code>$text-color</code> variable to change the <code>color</code> for the <code>.blog-post</code> and <code>h2</code> items.');",
"assert($('.blog-post').css('color') == 'rgb(255, 0, 0)', 'message: Your <code>.blog-post</code> element should have a </code>color</code> of red.');",
"assert($('h2').css('color') == 'rgb(255, 0, 0)', 'message: Your <code>h2</code> elements should have a </code>color</code> of red.');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
},
{
"id": "587d7dbd367417b2b2512bb5",
"title": "Nest CSS with Sass",
"required": [
{
"link": "https://cdnjs.cloudflare.com/ajax/libs/sass.js/0.9.13/sass.min.js",
"raw": true
}
],
"description": [
"Sass allows <code>nesting</code> of CSS rules, which is a useful way of organizing a style sheet.",
"Normally, each element is targeted on a different line to style it, like so:",
"<blockquote>nav {<br>&nbsp;&nbsp;background-color: red;<br>}<br><br>nav ul {<br>&nbsp;&nbsp;list-style: none;<br>}<br><br>nav ul li {<br>&nbsp;&nbsp;display: inline-block;<br>}</blockquote>",
"For a large project, the CSS file will have many lines and rules. This is where <code>nesting</code> can help organize your code by placing child style rules within the respective parent elements:",
"<blockquote>nav {<br>&nbsp;&nbsp;background-color: red;<br><br>&nbsp;&nbsp;ul {<br>&nbsp;&nbsp;&nbsp;&nbsp;list-style: none;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;li {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;display: inline-block;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;}<br>}<br></blockquote>",
"<hr>",
"Use the <code>nesting</code> technique shown above to re-organize the CSS rules for both children of <code>.blog-post</code> element. For testing purposes, the <code>h1</code> should come before the <code>p</code> element."
],
"challengeSeed": [
"<style>",
" .blog-post {",
" ",
" }",
" h1 {",
" text-align: center;",
" color: blue;",
" }",
" p {",
" font-size: 20px;",
" }",
"</style>",
"",
"<div class=\"blog-post\">",
" <h1>Blog Title</h1>",
" <p>This is a paragraph</p>",
"</div>"
],
"tests": [
"assert(code.match(/\\.blog-post\\s*?{\\s*?h1\\s*?{\\s*?text-align:\\s*?center;\\s*?color:\\s*?blue;\\s*?}\\s*?p\\s*?{\\s*?font-size:\\s*?20px;\\s*?}\\s*?}/gi), 'message: Your code should re-organize the CSS rules so the <code>h1</code> and <code>p</code> are nested in the <code>.blog-post</code> parent element.');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
},
{
"id": "587d7dbd367417b2b2512bb6",
"title": "Create Reusable CSS with Mixins",
"required": [
{
"link": "https://cdnjs.cloudflare.com/ajax/libs/sass.js/0.9.13/sass.min.js",
"raw": true
}
],
"description": [
"In Sass, a <code>mixin</code> is a group of CSS declarations that can be reused throughout the style sheet.",
"Newer CSS features take time before they are fully adopted and ready to use in all browsers. As features are added to browsers, CSS rules using them may need vendor prefixes. Consider \"box-shadow\":",
"<blockquote>div {<br>&nbsp;&nbsp;-webkit-box-shadow: 0px 0px 4px #fff;<br>&nbsp;&nbsp;-moz-box-shadow: 0px 0px 4px #fff;<br>&nbsp;&nbsp;-ms-box-shadow: 0px 0px 4px #fff;<br>&nbsp;&nbsp;box-shadow: 0px 0px 4px #fff;<br>}</blockquote>",
"It's a lot of typing to re-write this rule for all the elements that have a <code>box-shadow</code>, or to change each value to test different effects.",
"<code>Mixins</code> are like functions for CSS. Here is how to write one:",
"<blockquote>@mixin box-shadow($x, $y, $blur, $c){ <br>&nbsp;&nbsp;-webkit-box-shadow: $x, $y, $blur, $c;<br>&nbsp;&nbsp;-moz-box-shadow: $x, $y, $blur, $c;<br>&nbsp;&nbsp;-ms-box-shadow: $x, $y, $blur, $c;<br>&nbsp;&nbsp;box-shadow: $x, $y, $blur, $c;<br>}</blockquote>",
"The definition starts with <code>@mixin</code> followed by a custom name. The parameters (the <code>$x</code>, <code>$y</code>, <code>$blur</code>, and <code>$c</code> in the example above) are optional.",
"Now any time a <code>box-shadow</code> rule is needed, only a single line calling the <code>mixin</code> replaces having to type all the vendor prefixes. A <code>mixin</code> is called with the <code>@include</code> directive:",
"<blockquote>div {<br>&nbsp;&nbsp;@include box-shadow(0px, 0px, 4px, #fff);<br>}</blockquote>",
"<hr>",
"Write a <code>mixin</code> for <code>border-radius</code> and give it a <code>$radius</code> parameter. It should use all the vendor prefixes from the example. Then use the <code>border-radius</code> <code>mixin</code> to give the <code>#awesome</code> element a border radius of 15px."
],
"challengeSeed": [
"<style>",
" ",
" ",
" ",
" #awesome {",
" width: 150px;",
" height: 150px;",
" background-color: green;",
" ",
" }",
"</style>",
"",
"<div id=\"awesome\"></div>",
" "
],
"tests": [
"assert(code.match(/@mixin\\s+?border-radius\\(\\s*?\\$radius\\s*?\\)\\s*?{/gi), 'message: Your code should declare a <code>mixin</code> named <code>border-radius</code> which has a parameter named <code>$radius</code>.');",
"assert(code.match(/-webkit-border-radius:\\s*?\\$radius;/gi), 'message: Your code should include the <code>-webkit-border-radius</code> vender prefix that uses the <code>$radius</code> parameter.');",
"assert(code.match(/-moz-border-radius:\\s*?\\$radius;/gi), 'message: Your code should include the <code>-moz-border-radius</code> vender prefix that uses the <code>$radius</code> parameter.');",
"assert(code.match(/-ms-border-radius:\\s*?\\$radius;/gi), 'message: Your code should include the <code>-ms-border-radius</code> vender prefix that uses the <code>$radius</code> parameter.');",
"assert(code.match(/border-radius:\\s*?\\$radius;/gi).length == 4, 'message: Your code should include the general <code>border-radius</code> rule that uses the <code>$radius</code> parameter.');",
"assert(code.match(/@include\\s+?border-radius\\(\\s*?15px\\s*?\\);/gi), 'message: Your code should call the <code>border-radius mixin</code> using the <code>@include</code> keyword, setting it to 15px.');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
},
{
"id": "587d7dbe367417b2b2512bb8",
"title": "Use @if and @else to Add Logic To Your Styles",
"required": [
{
"link": "https://cdnjs.cloudflare.com/ajax/libs/sass.js/0.9.13/sass.min.js",
"raw": true
}
],
"description": [
"The <code>@if</code> directive in Sass is useful to test for a specific case - it works just like the <code>if</code> statement in JavaScript</code>.",
"<blockquote>@mixin make-bold($bool) {<br>&nbsp;&nbsp;@if $bool == bold { font-weight: bold; }<br>}</blockquote>",
"And just like in JavaScript, <code>@else if</code> and <code>@else</code> test for more conditions:",
"<blockquote>@mixin text-effect($val) {<br>&nbsp;&nbsp;@if $val == danger {color: red;}<br>&nbsp;&nbsp;@else if $val == alert {color: yellow;}<br>&nbsp;&nbsp;@else if $val == success {color: green;}<br>&nbsp;&nbsp;@else {color: black;}<br>}</blockquote>",
"<hr>",
"Create a <code>mixin</code> called <code>border-stroke</code> that takes a parameter <code>$val</code>. The <code>mixin</code> should check for the following conditions using <code>@if</code>, <code>@else if</code>, and <code>@else</code>:",
"<blockquote>light - 1px solid black<br>medium - 3px solid black<br>heavy - 6px solid black<br>none - no border</blockquote>"
],
"challengeSeed": [
"<style>",
" ",
" ",
" ",
" #box {",
" width: 150px;",
" height: 150px;",
" background-color: red;",
" @include border-stroke(medium);",
" } ",
"</style>",
"",
"<div id=\"box\"></div>"
],
"tests": [
"assert(code.match(/@mixin\\s+?border-stroke\\s*?\\(\\s*?\\$val\\s*?\\)\\s*?{/gi), 'message: Your code should declare a <code>mixin</code> named <code>border-stroke</code> which has a parameter named <code>$val</code>.');",
"assert(code.match(/@if\\s+?\\$val\\s*?===?\\s*?light\\s*?{\\s*?border\\s*?:\\s*?1px\\s+?solid\\s+?black\\s*?;\\s*?}/gi), 'message: Your <code>mixin</code> should have an <code>@if</code> statement to check if <code>$val</code> is light, and to set the <code>border</code> to 1px solid black.');",
"assert(code.match(/@else\\s+?if\\s+?\\$val\\s*?===?\\s*?medium\\s*?{\\s*?border\\s*?:\\s*?3px\\s+?solid\\s+?black\\s*?;\\s*?}/gi), 'message: Your <code>mixin</code> should have an <code>@else if</code> statement to check if <code>$val</code> is medium, and to set the <code>border</code> to 3px solid black.');",
"assert(code.match(/@else\\s+?if\\s+?\\$val\\s*?===?\\s*?heavy\\s*?{\\s*?border\\s*?:\\s*?6px\\s+?solid\\s+?black\\s*?;\\s*?}/gi), 'message: Your <code>mixin</code> should have an <code>@else if</code> statement to check if <code>$val</code> is heavy, and to set the <code>border</code> to 6px solid black.');",
"assert(code.match(/@else\\s*?{\\s*?border\\s*?:\\s*?none\\s*?;\\s*?}/gi), 'message: Your <code>mixin</code> should have an <code>@else</code> statement to set the <code>border</code> to none.');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
},
{
"id": "587d7dbe367417b2b2512bb9",
"title": "Use @for to Create a Sass Loop",
"required": [
{
"link": "https://cdnjs.cloudflare.com/ajax/libs/sass.js/0.9.13/sass.min.js",
"raw": true
}
],
"description": [
"The <code>@for</code> directive adds styles in a loop, very similar to a <code>for</code> loop in JavaScript.",
"<code>@for</code> is used in two ways: \"start through end\" or \"start to end\". The main difference is that \"start to end\" <em>excludes</em> the end number, and \"start through end\" <em>includes</em> the end number.",
"Here's a start <b>through</b> end example:",
"<blockquote>@for $i from 1 through 12 {<br>&nbsp;&nbsp;.col-#{$i} { width: 100%/12 * $i; }<br>}</blockquote>",
"The <code>#{$i}</code> part is the syntax to combine a variable (<code>i</code>) with text to make a string. When the Sass file is converted to CSS, it looks like this:",
"<blockquote>.col-1 {<br>&nbsp;&nbsp;width: 8.33333%;<br>}<br><br>.col-2 {<br>&nbsp;&nbsp;width: 16.66667%;<br>}<br><br>...<br><br>.col-12 {<br>&nbsp;&nbsp;width: 100%;<br>}</blockquote>",
"This is a powerful way to create a grid layout. Now you have twelve options for column widths available as CSS classes.",
"<hr>",
"Write a <code>@for</code> directive that takes a variable <code>$j</code> that goes from 1 <b>to</b> 6.",
"It should create 5 classes called <code>.text-1</code> to <code>.text-5</code> where each has a <code>font-size</code> set to 10px multiplied by the index."
],
"challengeSeed": [
"<style>",
" ",
" ",
" ",
"</style>",
"",
"<p class=\"text-1\">Hello</p>",
"<p class=\"text-2\">Hello</p>",
"<p class=\"text-3\">Hello</p>",
"<p class=\"text-4\">Hello</p>",
"<p class=\"text-5\">Hello</p>"
],
"tests": [
"assert(code.match(/@for /g), 'message: Your code should use the <code>@for</code> directive.');",
"assert($('.text-1').css('font-size') == '10px', 'message: Your <code>.text-1</code> class should have a <code>font-size</code> of 10px.');",
"assert($('.text-2').css('font-size') == '20px', 'message: Your <code>.text-2</code> class should have a <code>font-size</code> of 20px.');",
"assert($('.text-3').css('font-size') == '30px', 'message: Your <code>.text-3</code> class should have a <code>font-size</code> of 30px.');",
"assert($('.text-4').css('font-size') == '40px', 'message: Your <code>.text-4</code> class should have a <code>font-size</code> of 40px.');",
"assert($('.text-5').css('font-size') == '50px', 'message: Your <code>.text-5</code> class should have a <code>font-size</code> of 50px.');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
},
{
"id": "587d7dbf367417b2b2512bba",
"title": "Use @each to Map Over Items in a List",
"required": [
{
"link": "https://cdnjs.cloudflare.com/ajax/libs/sass.js/0.9.13/sass.min.js",
"raw": true
}
],
"description": [
"The last challenge showed how the <code>@for</code> directive uses a starting and ending value to loop a certain number of times. Sass also offers the <code>@each</code> directive which loops over each item in a list or map.",
"On each iteration, the variable gets assigned to the current value from the list or map.",
"<blockquote>@each $color in blue, red, green {<br>&nbsp;&nbsp;.#{$color}-text {color: $color;}<br>}</blockquote>",
"A map has slightly different syntax. Here's an example:",
"<blockquote>$colors: (color1: blue, color2: red, color3: green);<br><br>@each $key, $color in $colors {<br>&nbsp;&nbsp;.#{$color}-text {color: $color;}<br>}</blockquote>",
"Note that the <code>$key</code> variable is needed to reference the keys in the map. Otherwise, the compiled CSS would have <code>color1</code>, <code>color2</code>... in it.",
"Both of the above code examples are converted into the following CSS:",
"<blockquote>.blue-text {<br>&nbsp;&nbsp;color: blue;<br>}<br><br>.red-text {<br>&nbsp;&nbsp;color: red;<br>}<br><br>.green-text {<br>&nbsp;&nbsp;color: green;<br>}</blockquote>",
"<hr>",
"Write an <code>@each</code> directive that goes through a list: <code>blue, black, red</code> and assigns each variable to a <code>.color-bg</code> class, where the \"color\" part changes for each item.",
"Each class should set the <code>background-color</code> the respective color."
],
"challengeSeed": [
"<style>",
" ",
" ",
" ",
" div {",
" height: 200px;",
" width: 200px;",
" }",
"</style>",
"",
"<div class=\"blue-bg\"></div>",
"<div class=\"black-bg\"></div>",
"<div class=\"red-bg\"></div>"
],
"tests": [
"assert(code.match(/@each /g), 'message: Your code should use the <code>@each</code> directive.');",
"assert($('blue-bg').css('background-color') == 'rgb(0, 0, 255)', 'message: Your <code>.blue-bg</code> class should have a <code>background-color</code> of blue.');",
"assert($('black-bg').css('background-color') == 'rgb(0, 0, 0)', 'message: Your <code>.black-bg</code> class should have a <code>background-color</code> of black.');",
"assert($('red-bg').css('background-color') == 'rgb(255, 0, 0)', 'message: Your <code>.red-bg</code> class should have a <code>background-color</code> of red.');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
},
{
"id": "587d7dbf367417b2b2512bbb",
"title": "Apply a Style Until a Condition is Met with @while",
"required": [
{
"link": "https://cdnjs.cloudflare.com/ajax/libs/sass.js/0.9.13/sass.min.js",
"raw": true
}
],
"description": [
"The <code>@while</code> directive is an option with similar functionality to the JavaScript <code>while</code> loop. It creates CSS rules until a condition is met.",
"The <code>@for</code> challenge gave an example to create a simple grid system. This can also work with <code>@while</code>.",
"<blockquote>$x: 1;<br>@while $x < 13 {<br>&nbsp;&nbsp;.col-#{$x} { width: 100%/12 * $x;}<br>&nbsp;&nbsp;$x: $x + 1;<br>}</blockquote>",
"First, define a variable <code>$x</code> and set it to 1. Next, use the <code>@while</code> directive to create the grid system <i>while</i> <code>$x</code> is less than 13.",
"After setting the CSS rule for <code>width</code>, <code>$x</code> is incremented by 1 to avoid an infinite loop.",
"<hr>",
"Use <code>@while</code> to create a series of classes with different <code>font-sizes</code>.",
"There should be 10 different classes from <code>text-1</code> to <code>text-10</code>. Then set <code>font-size</code> to 5px multiplied by the current index number. Make sure to avoid an infinite loop!"
],
"challengeSeed": [
"<style>",
" ",
" ",
" ",
"</style>",
"",
"<p class=\"text-1\">Hello</p>",
"<p class=\"text-2\">Hello</p>",
"<p class=\"text-3\">Hello</p>",
"<p class=\"text-4\">Hello</p>",
"<p class=\"text-5\">Hello</p>",
"<p class=\"text-6\">Hello</p>",
"<p class=\"text-7\">Hello</p>",
"<p class=\"text-8\">Hello</p>",
"<p class=\"text-9\">Hello</p>",
"<p class=\"text-10\">Hello</p>"
],
"tests": [
"assert(code.match(/@while /g), 'message: Your code should use the <code>@while</code> directive.');",
"assert(code.match(/\\$.*:\\s*?1;/gi), 'message: Your code should set an index variable to 1 to start.');",
"assert(code.match(/\\$(.*):\\s*?\\$\\1\\s*?\\+\\s*?1;/gi), 'message: Your code should increment the counter variable.');",
"assert($('.text-1').css('font-size') == '5px', 'message: Your <code>.text-1</code> class should have a <code>font-size</code> of 5px.');",
"assert($('.text-2').css('font-size') == '10px', 'message: Your <code>.text-2</code> class should have a <code>font-size</code> of 10px.');",
"assert($('.text-3').css('font-size') == '15px', 'message: Your <code>.text-3</code> class should have a <code>font-size</code> of 15px.');",
"assert($('.text-4').css('font-size') == '20px', 'message: Your <code>.text-4</code> class should have a <code>font-size</code> of 20px.');",
"assert($('.text-5').css('font-size') == '25px', 'message: Your <code>.text-5</code> class should have a <code>font-size</code> of 25px.');",
"assert($('.text-6').css('font-size') == '30px', 'message: Your <code>.text-6</code> class should have a <code>font-size</code> of 30px.');",
"assert($('.text-7').css('font-size') == '35px', 'message: Your <code>.text-7</code> class should have a <code>font-size</code> of 35px.');",
"assert($('.text-8').css('font-size') == '40px', 'message: Your <code>.text-8</code> class should have a <code>font-size</code> of 40px.');",
"assert($('.text-9').css('font-size') == '45px', 'message: Your <code>.text-9</code> class should have a <code>font-size</code> of 45px.');",
"assert($('.text-10').css('font-size') == '50px', 'message: Your <code>.text-10</code> class should have a <code>font-size</code> of 50px.');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
},
{
"id": "587d7dbf367417b2b2512bbc",
"title": "Split Your Styles into Smaller Chunks with Partials",
"required": [
{
"link": "https://cdnjs.cloudflare.com/ajax/libs/sass.js/0.9.13/sass.min.js",
"raw": true
}
],
"description": [
"<code>Partials</code> in Sass are separate files that hold segments of CSS code. These are imported and used in other Sass files. This is a great way to group similar code into a module to keep it organized.",
"Names for <code>partials</code> start with the underscore (<code>_</code>) character, which tells Sass it is a small segment of CSS and not to convert it into a CSS file. Also, Sass files end with the <code>.scss</code> file extension. To bring the code in the <code>partial</code> into another Sass file, use the <code>@import</code> directive.",
"For example, if all your <code>mixins</code> are saved in a <code>partial</code> named \"_mixins.scss\", and they are needed in the \"main.scss\" file, this is how to use them in the main file:",
"<blockquote>// In the main.scss file<br><br>@import 'mixins'</blockquote>",
"Note that the underscore is not needed in the <code>import</code> statement - Sass understands it is a <code>partial</code>. Once a <code>partial</code> is imported into a file, all variables, <code>mixins</code>, and other code are available to use.",
"<hr>",
"Write an <code>@import</code> statement to import a <code>partial</code> named <code>_variables.scss</code> into the main.scss file."
],
"challengeSeed": [
"// The main.scss file",
"",
"",
"",
""
],
"tests": [
"assert(code.match(/@import\\s+?('|\")variables\\1/gi), 'message: Your code should use the <code>@import</code> directive, and should not include the underscore in the file name.');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
},
{
"id": "587d7fa5367417b2b2512bbd",
"title": "Extend One Set of CSS Styles to Another Element",
"required": [
{
"link": "https://cdnjs.cloudflare.com/ajax/libs/sass.js/0.9.13/sass.min.js",
"raw": true
}
],
"description": [
"Sass has a feature called <code>extend</code> that makes it easy to borrow the CSS rules from one element and build upon them in another.",
"For example, the below block of CSS rules style a <code>.panel</code> class. It has a <code>background-color</code>, <code>height</code> and <code>border</code>.",
"<blockquote>.panel{<br>&nbsp;&nbsp;background-color: red;<br>&nbsp;&nbsp;height: 70px;<br>&nbsp;&nbsp;border: 2px solid green;<br>}</blockquote>",
"Now you want another panel called <code>.big-panel</code>. It has the same base properties as <code>.panel</code>, but also needs a <code>width</code> and <code>font-size</code>.",
"It's possible to copy and paste the initial CSS rules from <code>.panel</code>, but the code becomes repetitive as you add more types of panels.",
"The <code>extend</code> directive is a simple way to reuse the rules written for one element, then add more for another:",
"<blockquote>.big-panel{<br>&nbsp;&nbsp;@extend .panel;<br>&nbsp;&nbsp;width: 150px;<br>&nbsp;&nbsp;font-size: 2em;<br>}</blockquote>",
"The <code>.big-panel</code> will have the same properties as <code>.panel</code> in addition to the new styles.",
"<hr>",
"Make a class <code>.info-important</code> that extends <code>.info</code> and also has a <code>background-color</code> set to magenta."
],
"challengeSeed": [
"<style>",
" h3{",
" text-align: center;",
" }",
" .info{",
" width: 200px;",
" border: 1px solid black;",
" margin: 0 auto;",
" }",
" ",
" ",
" ",
" ",
"</style>",
"<h3>Posts</h3>",
"<div class=\"info-important\">",
" <p>This is an important post. It should extend the class \".info\" and have its own CSS styles.</p>",
"</div>",
"",
"<div class=\"info\">",
" <p>This is a simple post. It has basic styling and can be extended for other uses.</p>",
"</div>"
],
"tests": [
"assert(code.match(/@extend\\s+?\\.info/g), 'message: Your code should use the <code>@extend</code> directive to extend the <code>info</code> class.');",
"assert($('.info-important').css('background-color') == 'rgb(255, 0, 255)', 'message: Your <code>info-important</code> class should have a <code>background-color</code> set to magenta.');",
"assert($('.info-important').css('width') == '200px', 'message: Your <code>info-important</code> class should inherit the styling from the <code>info</code> class.');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
}
]
}

View File

@ -0,0 +1,108 @@
{
"name": "Claim Your Data Visualization Certificate",
"order": 13,
"time": "5 minutes",
"challenges": [
{
"id": "587d7fa5367417b2b2512bbe",
"title": "Claim Your Data Visualization Certificate",
"description": [
[
"//i.imgur.com/k8btNUB.jpg",
"An image of our Data Visualization Certificate",
"This challenge will give you your verified Data Visualization Certificate. Before we issue your certificate, we must verify that you have completed all of our basic and intermediate algorithm scripting challenges, and all our basic, intermediate, and advanced front end development projects. You must also accept our Academic Honesty Pledge. Click the button below to start this process.",
""
],
[
"//i.imgur.com/uLPsUko.jpg",
"The definition of plagiarism: Plagiarism (noun) - copying someone elses work and presenting it as your own without crediting them",
"By clicking below, you pledge that all of your submitted code A) is code you or your pair personally wrote, or B) comes from open source libraries like jQuery, or C) has been clearly attributed to its original authors. You also give us permission to audit your challenge solutions and revoke your certificate if we discover evidence of plagiarism.",
"#"
],
[
"//i.imgur.com/UedoV2G.jpg",
"An image of the text \"Front End Development Certificate requirements\"",
"Let's confirm that you have completed all of our basic and intermediate algorithm scripting challenges, and all our basic, intermediate, and advanced front end development projects. Click the button below to verify this.",
"#"
],
[
"//i.imgur.com/Q5Za9U6.jpg",
"An image of the word \"Congratulations\"",
"Congratulations! We've added your Data Visualization Certificate to your portfolio page. Unless you choose to hide your solutions, this certificate will remain publicly visible and verifiable.",
""
]
],
"challengeSeed": [
{
"properties": [
"isHonest",
"isFrontEndCert"
],
"apis": [
"/certificate/honest",
"/certificate/verify/front-end"
],
"stepIndex": [
1,
2
]
}
],
"tests": [
{
"id": "587d7fa6367417b2b2512bc0",
"title": "Visualize Data with a Treemap Diagram"
},
{
"id": "587d7fa6367417b2b2512bbf",
"title": "Visualize Data with a Choropleth Map"
},
{
"id": "bd7188d8c242eddfaeb5bd13",
"title": "Visualize Data with a Heat Map"
},
{
"id": "bd7178d8c242eddfaeb5bd13",
"title": "Visualize Data with a Scatterplot Graph"
},
{
"id": "bd7168d8c242eddfaeb5bd13",
"title": "Visualize Data with a Bar Chart"
}
],
"type": "Waypoint",
"challengeType": 7,
"translations": {
"es": {
"title": "Reclama tu certificado de Desarrollo de interfaces",
"description": [
[
"//i.imgur.com/k8btNUB.jpg",
"Una imagen que muestra nuestro certificado de Desarrollo de interfaces",
"Este desafío te otorga tu certificado autenticado de Desarrollo de interfaces. Antes de que podamos emitir tu certificado, debemos verificar que has completado todos los desafíos básicos e intermedios de diseño de algoritmos, y todos los proyectos básicos e intermedios de desarrollo de interfaces. También debes aceptar nuestro Juramento de honestidad académica. Pulsa el botón siguiente para iniciar este proceso.",
""
],
[
"//i.imgur.com/HArFfMN.jpg",
"Plagio (nombre): acción y efecto de plagiar. Plagiar (verbo) - copiar en lo sustancial obras ajenas, dándolas como propias.",
"Al pulsar el botón siguiente, juras que todo el código en tus soluciones a los desafíos A) es código que tú o tu compañero escribieron personalmente, o B) proviene de librerías de código abierto como jQuery, o C) ha sido claramente atribuido a sus autores originales. También nos otorgas el permiso para auditar tus soluciones a los desafíos y revocar tu certificado si encontramos evidencia de plagio.",
"#"
],
[
"//i.imgur.com/14F2Van.jpg",
"Una imagen del texto \"Front End Development Certificate requirements\"",
"Confirmemos que has completado todos nuestros desafíos básicos e intermedios de diseño de algoritmos, y todos nuestros proyectos básicos e intermedios de desarrollo de interfaces. Pulsa el botón siguiente para hacer la verificación.",
"#"
],
[
"//i.imgur.com/16SIhHO.jpg",
"Una imagen de la palabra \"Congratulations\"",
"¡Felicitaciones! Hemos agregado tu certificado de Desarrollo de interfaces a tu portafolio. A menos que elijas no mostrar tus soluciones, este certificado será públicamente visible y verificable.",
""
]
]
}
}
}
]
}

View File

@ -0,0 +1,128 @@
{
"name": "Data Visualization Projects",
"order": 3,
"time": "150 hours",
"helpRoom": "Help",
"challenges": [
{
"id": "bd7168d8c242eddfaeb5bd13",
"title": "Visualize Data with a Bar Chart",
"description": [
"Fulfill the user stories by getting all of the tests to pass. Use whichever libraries you need. Give it your own personal style.",
"Here's a <a href='https://codepen.io/freeCodeCamp/full/GrZVaM' target='_blank'>working example</a>. Try not to look at its code.",
"Here is the dataset you will need to complete this project: <code>https://raw.githubusercontent.com/freeCodeCamp/ProjectReferenceData/master/GDP-data.json</code>",
"You can build your project by forking <a href='https://codepen.io/freeCodeCamp/pen/MJjpwO' target='_blank'>this CodePen pen</a>. Or you can use this CDN link to run the tests in any environment you like: <code>https://gitcdn.link/repo/freeCodeCamp/testable-projects-fcc/master/build/bundle.js</code>.",
"Once you're done, submit the URL to your working project with all its tests passing.",
"Remember to use the <a href='https://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> method if you get stuck."
],
"challengeSeed": [
"G6iPE6W"
],
"tests": [],
"isRequired": true,
"releasedOn": "January 1, 2016",
"type": "zipline",
"challengeType": 3,
"translations": {
"es": {
"title": "Visualiza datos utilizando un gráfico de barras",
"description": []
}
}
},
{
"id": "bd7178d8c242eddfaeb5bd13",
"title": "Visualize Data with a Scatterplot Graph",
"description": [
"Fulfill the user stories by getting all of the tests to pass. Use whichever libraries you need. Give it your own personal style.",
"Here's a <a href='https://codepen.io/freeCodeCamp/full/bgpXyK' target='_blank'>working example</a>. Try not to look at its code.",
"Here is the dataset you will need to complete this project: <code>https://raw.githubusercontent.com/freeCodeCamp/ProjectReferenceData/master/cyclist-data.json</code>",
"You can build your project by forking <a href='https://codepen.io/freeCodeCamp/pen/MJjpwO' target='_blank'>this CodePen pen</a>. Or you can use this CDN link to run the tests in any environment you like: <code>https://gitcdn.link/repo/freeCodeCamp/testable-projects-fcc/master/build/bundle.js</code>",
"Once you're done, submit the URL to your working project with all its tests passing.",
"Remember to use the <a href='https://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> method if you get stuck."
],
"challengeSeed": [
"opubu3f"
],
"tests": [],
"isRequired": true,
"releasedOn": "January 1, 2016",
"type": "zipline",
"challengeType": 3,
"translations": {
"es": {
"title": "Visualiza datos utilizando un gráfico de dispersión",
"description": []
}
}
},
{
"id": "bd7188d8c242eddfaeb5bd13",
"title": "Visualize Data with a Heat Map",
"description": [
"Fulfill the user stories by getting all of the tests to pass. Use whichever libraries you need. Give it your own personal style.",
"Here's a <a href='https://codepen.io/freeCodeCamp/full/JEXgeY' target='_blank'>working example</a>. Try not to look at its code.",
"Here is the dataset you will need to complete this project: <code>https://raw.githubusercontent.com/freeCodeCamp/ProjectReferenceData/master/global-temperature.json</code>",
"You can build your project by forking <a href='https://codepen.io/freeCodeCamp/pen/MJjpwO' target='_blank'>this CodePen pen</a>. Or you can use this CDN link to run the tests in any environment you like: <code>https://gitcdn.link/repo/freeCodeCamp/testable-projects-fcc/master/build/bundle.js</code>",
"Once you're done, submit the URL to your working project with all its tests passing.",
"Remember to use the <a href='https://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> method if you get stuck."
],
"challengeSeed": [
"s4XtjKa"
],
"tests": [],
"isRequired": true,
"releasedOn": "January 1, 2016",
"type": "zipline",
"challengeType": 3,
"translations": {
"es": {
"title": "Visualiza datos utilizando un mapa de calor",
"description": []
}
}
},
{
"id": "587d7fa6367417b2b2512bbf",
"title": "Visualize Data with a Choropleth Map",
"description": [
"Fulfill the user stories by getting all of the tests to pass. Use whichever libraries you need. Give it your own personal style.",
"Here's a <a href='https://codepen.io/freeCodeCamp/full/EZKqza' target='_blank'>working example</a>. Try not to look at its code.",
"Here are the datasets you will need to complete this project:<br><ul><li><strong>US Education Data: </strong><code>https://raw.githubusercontent.com/no-stack-dub-sack/testable-projects-fcc/master/src/data/choropleth_map/for_user_education.json</code></li><li><strong>US County Data: </strong><code>https://raw.githubusercontent.com/no-stack-dub-sack/testable-projects-fcc/master/src/data/choropleth_map/counties.json</code></li></ul>",
"You can build your project by forking <a href='https://codepen.io/freeCodeCamp/pen/MJjpwO' target='_blank'>this CodePen pen</a>. Or you can use this CDN link to run the tests in any environment you like: <code>https://gitcdn.link/repo/freeCodeCamp/testable-projects-fcc/master/build/bundle.js</code>",
"Once you're done, submit the URL to your working project with all its tests passing.",
"Remember to use the <a href='https://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> method if you get stuck."
],
"challengeSeed": [
"K3qqL7U"
],
"tests": [],
"isRequired": true,
"releasedOn": "February 17, 2017",
"type": "zipline",
"challengeType": 3,
"translations": {}
},
{
"id": "587d7fa6367417b2b2512bc0",
"title": "Visualize Data with a Treemap Diagram",
"description": [
"Fulfill the user stories by getting all of the tests to pass. Use whichever libraries you need. Give it your own personal style.",
"Here's a <a href='https://codepen.io/freeCodeCamp/full/KaNGNR' target='_blank'>working example</a>. Try not to look at its code.",
"For this project you can use any of the following datasets:<br><ul><li><strong>Kickstarter Pledges:</strong> <code>https://cdn.rawgit.com/freeCodeCamp/testable-projects-fcc/a80ce8f9/src/data/tree_map/kickstarter-funding-data.json</code></li><li><strong>Movie Sales:</strong> <code>https://cdn.rawgit.com/freeCodeCamp/testable-projects-fcc/a80ce8f9/src/data/tree_map/movie-data.json</code></li><li><strong>Video Game Sales:</strong> <code>https://cdn.rawgit.com/freeCodeCamp/testable-projects-fcc/a80ce8f9/src/data/tree_map/video-game-sales-data.json</code></li></ul>",
"You can build your project by forking <a href='https://codepen.io/freeCodeCamp/pen/MJjpwO' target='_blank'>this CodePen pen</a>. Or you can use this CDN link to run the tests in any environment you like: <code>https://gitcdn.link/repo/freeCodeCamp/testable-projects-fcc/master/build/bundle.js</code>",
"Once you're done, submit the URL to your working project with all its tests passing.",
"Remember to use the <a href='https://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> method if you get stuck."
],
"challengeSeed": [
""
],
"tests": [],
"isRequired": true,
"releasedOn": "February 17, 2017",
"type": "zipline",
"challengeType": 3,
"translations": {}
}
]
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,692 @@
{
"name": "JSON APIs and AJAX",
"order": 2,
"time": "2 hours",
"helpRoom": "Help",
"required": [
{
"link": "https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.css"
}
],
"challenges": [
{
"id": "587d7fad367417b2b2512be0",
"title": "Introduction to the JSON APIs and AJAX Challenges",
"description": [
[
"http://imgs.xkcd.com/comics/api.png",
"XKCD web comic with a user sitting at a computer reading the instructions for an API Guide for a site. The text below notes \"If you do things right, it can take people awhile to realize that your 'API documentation' is just instructions for how to look at your website.\"",
"Similar to how User Interfaces help people use programs, Application Programming Interfaces (APIs) help programs interact with other programs. APIs are tools that computers use to communicate with one another, in part to send and receive data. You can use API functionality in your page once you understand how to make requests and process data from it. Programmers often use AJAX technologies when working with APIs.<br><br>The term AJAX originated as an acronym for Asynchronous JavaScript And XML. It refers to a group of technologies that make asynchronous requests to a server to transfer data, then load any returned data into the page. An asynchronous process has a couple key properties. The browser does not stop loading a page to wait for the server's response. Also, the browser inserts updated data into part of the page without having to refresh the entire page.<br><br>User experience benefits from asynchronous processes in several ways. Pages load faster since the browser isn't waiting for the server to respond in the middle of a page render. Requests and transfers happen in the background, without interrupting what the user is doing. When the browser receives new data, only the necessary area of the page refreshes. These qualities especially enhance the user experience for single page applications.<br><br>The data transferred between the browser and server is often in a format called JavaScript Object Notation (JSON). JSON resembles JavaScript object literal syntax, except that it's transferred as a string. Once received, it can be converted into an object and used in a script.<br><br>This section covers how to transfer and use data using AJAX technologies with a freeCodeCamp API.",
""
]
],
"releasedOn": "Feb 17, 2017",
"challengeSeed": [],
"tests": [],
"type": "waypoint",
"challengeType": 7,
"isRequired": false,
"translations": {}
},
{
"id": "587d7fad367417b2b2512be1",
"title": "Handle Click Events with JavaScript using the onclick property",
"description": [
"You want your code to execute only once your page has finished loading. For that purpose, you can attach a JavaScript event to the document called <code>DOMContentLoaded</code>. Here's the code that does this:",
"<blockquote>document.addEventListener('DOMContentLoaded',function() {<br><br>});</blockquote>",
"You can implement event handlers that go inside of the <code>DOMContentLoaded</code> function. You can implement an <code>onclick</code> event handler which triggers when the user clicks on the element with id <code>getMessage</code>, by adding the following code:",
"<blockquote>document.getElementById('getMessage').onclick=function(){};</blockquote>",
"<hr>",
"Add a click event handler inside of the <code>DOMContentLoaded</code> function for the element with id of <code>getMessage</code>."
],
"challengeSeed": [
"<script>",
" document.addEventListener('DOMContentLoaded',function(){",
" // Add your code below this line",
" ",
" ",
" // Add your code above this line",
" });",
"</script>",
"<style>",
" body {",
" text-align: center;",
" font-family: \"Helvetica\", sans-serif;",
" }",
" h1 {",
" font-size: 2em;",
" font-weight: bold;",
" }",
" .box {",
" border-radius: 5px;",
" background-color: #eee;",
" padding: 20px 5px;",
" }",
" button {",
" color: white;",
" background-color: #4791d0;",
" border-radius: 5px;",
" border: 1px solid #4791d0;",
" padding: 5px 10px 8px 10px;",
" }",
" button:hover {",
" background-color: #0F5897;",
" border: 1px solid #0F5897;",
" }",
"</style>",
"<h1>Cat Photo Finder</h1> ",
"<p class=\"message box\">",
" The message will go here",
"</p>",
"<p>",
" <button id=\"getMessage\">",
" Get Message",
" </button>",
"</p>"
],
"tests": [
"assert(code.match(/document\\.getElementById\\(\\s*?('|\")getMessage\\1\\s*?\\)/g), 'message: Your code should use the <code>document.getElementById</code> method to select the <code>getMessage</code> element.');",
"assert(typeof document.getElementById('getMessage').onclick === 'function', 'message: Your code should add an <code>onclick</code> event handler.');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
},
{
"id": "587d7fad367417b2b2512be2",
"title": "Change Text with click Events",
"description": [
"When the click event happens, you can use JavaScript to update an HTML element.",
"For example, when a user clicks the \"Get Message\" button, it changes the text of the element with the class <code>message</code> to say \"Here is the message\".",
"This works by adding the following code within the click event:",
"<code>document.getElementsByClassName('message')[0].innerHTML=\"Here is the message\";</code>",
"<hr>",
"Add code inside the <code>onclick</code> event handler to change the text inside the <code>message</code> element to say \"Here is the message\"."
],
"challengeSeed": [
"<script>",
" document.addEventListener('DOMContentLoaded',function(){",
" document.getElementById('getMessage').onclick=function(){",
" // Add your code below this line",
" ",
" ",
" // Add your code above this line",
" }",
" });",
"</script>",
"<style>",
" body {",
" text-align: center;",
" font-family: \"Helvetica\", sans-serif;",
" }",
" h1 {",
" font-size: 2em;",
" font-weight: bold;",
" }",
" .box {",
" border-radius: 5px;",
" background-color: #eee;",
" padding: 20px 5px;",
" }",
" button {",
" color: white;",
" background-color: #4791d0;",
" border-radius: 5px;",
" border: 1px solid #4791d0;",
" padding: 5px 10px 8px 10px;",
" }",
" button:hover {",
" background-color: #0F5897;",
" border: 1px solid #0F5897;",
" }",
"</style>",
"<h1>Cat Photo Finder</h1> ",
"<p class=\"message box\">",
" The message will go here",
"</p>",
"<p>",
" <button id=\"getMessage\">",
" Get Message",
" </button>",
"</p>"
],
"tests": [
"assert(code.match(/document\\.getElementsByClassName\\(\\s*?('|\")message\\1\\s*?\\)\\[0\\]\\.innerHTML\\s*?=\\s*?('|\")Here is the message\\2/g), 'message: Your code should use the <code>document.getElementsByClassName</code> method to select the element with class <code>message</code> and set its <code>innerHTML</code> to the given string.');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
},
{
"id": "587d7fae367417b2b2512be3",
"title": "Get JSON with the JavaScript XMLHttpRequest Method",
"description": [
"You can also request data from an external source. This is where APIs come into play.",
"Remember that APIs - or Application Programming Interfaces - are tools that computers use to communicate with one another. You'll learn how to update HTML with the data we get from APIs using a technology called AJAX.",
"Most web APIs transfer data in a format called JSON. JSON stands for JavaScript Object Notation.",
"JSON syntax looks very similar to JavaScript object literal notation. JSON has object properties and their current values, sandwiched between a <code>{</code> and a <code>}</code>.",
"These properties and their values are often referred to as \"key-value pairs\".",
"However, JSON transmitted by APIs are sent as <code>bytes</code>, and your application receives it as a <code>string</code>. These can be converted into JavaScript objects, but they are not JavaScript objects by default. The <code>JSON.parse</code> method parses the string and constructs the JavaScript object described by it.",
"You can request the JSON from freeCodeCamp's Cat Photo API. Here's the code you can put in your click event to do this:",
"<blockquote>req=new XMLHttpRequest();<br>req.open(\"GET\",'/json/cats.json',true);<br>req.send();<br>req.onload=function(){<br> json=JSON.parse(req.responseText);<br> document.getElementsByClassName('message')[0].innerHTML=JSON.stringify(json);<br>};</blockquote>",
"Here's a review of what each piece is doing. The JavaScript <code>XMLHttpRequest</code> object has a number of properties and methods that are used to transfer data. First, an instance of the <code>XMLHttpRequest</code> object is created and saved in the <code>req</code> variable.",
"Next, the <code>open</code> method initializes a request - this example is requesting data from an API, therefore is a \"GET\" request. The second argument for <code>open</code> is the URL of the API you are requesting data from. The third argument is a Boolean value where <code>true</code> makes it an asynchronous request.",
"The <code>send</code> method sends the request. Finally, the <code>onload</code> event handler parses the returned data and applies the <code>JSON.stringify</code> method to convert the JavaScript object into a string. This string is then inserted as the message text.",
"<hr>",
"Update the code to create and send a \"GET\" request to the freeCodeCamp Cat Photo API. Then click the \"Get Message\" button. Your AJAX function will replace the \"The message will go here\" text with the raw JSON output from the API."
],
"challengeSeed": [
"<script>",
" document.addEventListener('DOMContentLoaded',function(){",
" document.getElementById('getMessage').onclick=function(){",
" // Add your code below this line",
" ",
" ",
" // Add your code above this line",
" };",
" });",
"</script>",
"<style>",
" body {",
" text-align: center;",
" font-family: \"Helvetica\", sans-serif;",
" }",
" h1 {",
" font-size: 2em;",
" font-weight: bold;",
" }",
" .box {",
" border-radius: 5px;",
" background-color: #eee;",
" padding: 20px 5px;",
" }",
" button {",
" color: white;",
" background-color: #4791d0;",
" border-radius: 5px;",
" border: 1px solid #4791d0;",
" padding: 5px 10px 8px 10px;",
" }",
" button:hover {",
" background-color: #0F5897;",
" border: 1px solid #0F5897;",
" }",
"</style>",
"<h1>Cat Photo Finder</h1> ",
"<p class=\"message box\">",
" The message will go here",
"</p>",
"<p>",
" <button id=\"getMessage\">",
" Get Message",
" </button>",
"</p>"
],
"tests": [
"assert(code.match(/new\\s+?XMLHttpRequest\\(\\s*?\\)/g), 'message: Your code should create a new <code>XMLHttpRequest</code>.');",
"assert(code.match(/\\.open\\(\\s*?('|\")GET\\1\\s*?,\\s*?('|\")\\/json\\/cats\\.json\\2\\s*?,\\s*?true\\s*?\\)/g), 'message: Your code should use the <code>open</code> method to initialize a \"GET\" request to the freeCodeCamp Cat Photo API.');",
"assert(code.match(/\\.send\\(\\s*\\)/g), 'message: Your code should use the <code>send</code> method to send the request.');",
"assert(code.match(/\\.onload=function\\(\\s*?\\)\\s*?{/g), 'message: Your code should have an <code>onload</code> event handler set to a function.');",
"assert(code.match(/JSON\\.parse\\(.*\\.responseText\\)/g), 'message: Your code should use the <code>JSON.parse</code> method to parse the <code>responseText</code>.');",
"assert(code.match(/document\\.getElementsByClassName\\(\\s*?('|\")message\\1\\s*?\\)\\[0\\]\\.innerHTML\\s*?=\\s*?JSON\\.stringify\\(.+?\\)/g), 'message: Your code should get the element with class <code>message</code> and change its inner HTML to the string of JSON data.');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
},
{
"id": "587d7fae367417b2b2512be4",
"title": "Access the JSON Data from an API",
"description": [
"In the previous challenge, you saw how to get JSON data from the freeCodeCamp Cat Photo API.",
"Now you'll take a closer look at the returned data to better understand the JSON format. Recall some notation in JavaScript:",
"<blockquote>[ ] -> Square brackets represent an array<br>{ } -> Curly brackets represent an object<br>\" \" -> Double quotes represent a string. They are also used for key names in JSON</blockquote>",
"Understanding the structure of the data that an API returns is important because it influences how you retrieve the values you need.",
"On the right, click the \"Get Message\" button to load the freeCodeCamp Cat Photo API JSON into the HTML.",
"The first and last character you see in the JSON data are square brackets <code>[ ]</code>. This means that the returned data is an array. The second character in the JSON data is a curly <code>{</code> bracket, which starts an object. Looking closely, you can see that there are three separate objects. The JSON data is an array of three objects, where each object contains information about a cat photo.",
"You learned earlier that objects contain \"key-value pairs\" that are separated by commas. In the Cat Photo example, the first object has <code>\"id\":0</code> where \"id\" is a key and 0 is its corresponding value. Similarly, there are keys for \"imageLink\", \"altText\", and \"codeNames\". Each cat photo object has these same keys, but with different values.",
"Another interesting \"key-value pair\" in the first object is <code>\"codeNames\":[\"Juggernaut\",\"Mrs. Wallace\",\"ButterCup\"]</code>. Here \"codeNames\" is the key and its value is an array of three strings. It's possible to have arrays of objects as well as a key with an array as a value.",
"Remember how to access data in arrays and objects. Arrays use bracket notation to access a specific index of an item. Objects use either bracket or dot notation to access the value of a given property. Here's an example that prints the \"altText\" of the first cat photo - note that the parsed JSON data in the editor is saved in a variable called <code>json</code>:",
"<blockquote>console.log(json[0].altText);<br>// Prints \"A white cat wearing a green helmet shaped melon on its head.\"</blockquote>",
"<hr>",
"For the cat with the \"id\" of 2, print to the console the second value in the <code>codeNames</code> array. You should use bracket and dot notation on the object (which is saved in the variable <code>json</code>) to access the value."
],
"challengeSeed": [
"<script>",
" document.addEventListener('DOMContentLoaded',function(){",
" document.getElementById('getMessage').onclick=function(){",
" req=new XMLHttpRequest();",
" req.open(\"GET\",'/json/cats.json',true);",
" req.send();",
" req.onload=function(){",
" json=JSON.parse(req.responseText);",
" document.getElementsByClassName('message')[0].innerHTML=JSON.stringify(json);",
" // Add your code below this line",
" ",
" ",
" // Add your code above this line",
" };",
" };",
" });",
"</script>",
"<style>",
" body {",
" text-align: center;",
" font-family: \"Helvetica\", sans-serif;",
" }",
" h1 {",
" font-size: 2em;",
" font-weight: bold;",
" }",
" .box {",
" border-radius: 5px;",
" background-color: #eee;",
" padding: 20px 5px;",
" }",
" button {",
" color: white;",
" background-color: #4791d0;",
" border-radius: 5px;",
" border: 1px solid #4791d0;",
" padding: 5px 10px 8px 10px;",
" }",
" button:hover {",
" background-color: #0F5897;",
" border: 1px solid #0F5897;",
" }",
"</style>",
"<h1>Cat Photo Finder</h1> ",
"<p class=\"message box\">",
" The message will go here",
"</p>",
"<p>",
" <button id=\"getMessage\">",
" Get Message",
" </button>",
"</p>"
],
"tests": [
"assert(code.match(/(?:json\\[2\\]\\.codeNames\\[1\\]|json\\[2\\]\\[('|\")codeNames\\1\\]\\[1\\])/g), 'message: Your code should use bracket and dot notation to access the proper code name, and print \"Loki\" to the console.');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
},
{
"id": "587d7fae367417b2b2512be5",
"title": "Convert JSON Data to HTML",
"description": [
"Now that you're getting data from a JSON API, you can display it in the HTML.",
"You can use a <code>forEach</code> method to loop through the data since the cat photo objects are held in an array. As you get to each item, you can modify the HTML elements.",
"First, declare an html variable with <code>var html = \"\";</code>.",
"Then, loop through the JSON, adding HTML to the variable that wraps the key names in <code>strong</code> tags, followed by the value. When the loop is finished, you render it.",
"Here's the code that does this:",
"<blockquote>json.forEach(function(val) {</br> var keys = Object.keys(val);</br> html += \"&lt;div class = 'cat'&gt;\";</br> keys.forEach(function(key) {</br> html += \"&lt;strong&gt;\" + key + \"&lt;/strong&gt;: \" + val[key] + \"&lt;br&gt;\";</br> });</br> html += \"&lt;/div&gt;&lt;br&gt;\";</br>});</blockquote>",
"<hr>",
"Add a <code>forEach</code> method to loop over the JSON data and create the HTML elements to display it.",
"Here is some example JSON",
"<blockquote>[</br> {</br> \"id\":0,</br> \"imageLink\":\"https://s3.amazonaws.com/freecodecamp/funny-cat.jpg\",</br> \"altText\":\"A white cat wearing a green helmet shaped melon on its head. \",</br> \"codeNames\":[</br> \"Juggernaut\",</br> \"Mrs. Wallace\",</br> \"Buttercup\"</br> ]</br> }</br>]</blockquote>"
],
"challengeSeed": [
"<script>",
" document.addEventListener('DOMContentLoaded',function(){",
" document.getElementById('getMessage').onclick=function(){",
" req=new XMLHttpRequest();",
" req.open(\"GET\",'/json/cats.json',true);",
" req.send();",
" req.onload=function(){",
" json=JSON.parse(req.responseText);",
" var html = \"\";",
" // Add your code below this line",
" ",
" ",
" ",
" // Add your code above this line",
" document.getElementsByClassName('message')[0].innerHTML=html;",
" };",
" };",
" });",
"</script>",
"<style>",
" body {",
" text-align: center;",
" font-family: \"Helvetica\", sans-serif;",
" }",
" h1 {",
" font-size: 2em;",
" font-weight: bold;",
" }",
" .box {",
" border-radius: 5px;",
" background-color: #eee;",
" padding: 20px 5px;",
" }",
" button {",
" color: white;",
" background-color: #4791d0;",
" border-radius: 5px;",
" border: 1px solid #4791d0;",
" padding: 5px 10px 8px 10px;",
" }",
" button:hover {",
" background-color: #0F5897;",
" border: 1px solid #0F5897;",
" }",
"</style>",
"<h1>Cat Photo Finder</h1> ",
"<p class=\"message box\">",
" The message will go here",
"</p>",
"<p>",
" <button id=\"getMessage\">",
" Get Message",
" </button>",
"</p>"
],
"tests": [
"assert(code.match(/json\\.forEach/g), 'message: Your code should use a <code>forEach</code> method to loop over the JSON data from the API.');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
},
{
"id": "587d7fae367417b2b2512be6",
"title": "Render Images from Data Sources",
"description": [
"The last few challenges showed that each object in the JSON array contains an <code>imageLink</code> key with a value that is the URL of a cat's image.",
"When you're looping through these objects, you can use this <code>imageLink</code> property to display this image in an <code>img</code> element.",
"Here's the code that does this:",
"<code>html += \"&lt;img src = '\" + val.imageLink + \"' \" + \"alt='\" + val.altText + \"'&gt;\";</code>",
"<hr>",
"Add code to use the <code>imageLink</code> and <code>altText</code> properties in an <code>img</code> tag."
],
"challengeSeed": [
"<script>",
" document.addEventListener('DOMContentLoaded',function(){",
" document.getElementById('getMessage').onclick=function(){",
" req=new XMLHttpRequest();",
" req.open(\"GET\",'/json/cats.json',true);",
" req.send();",
" req.onload=function(){",
" json=JSON.parse(req.responseText);",
" var html = \"\";",
" json.forEach(function(val) {",
" html += \"<div class = 'cat'>\";",
" // Add your code below this line",
" ",
" ",
" // Add your code above this line",
" html += \"</div><br>\";",
" });",
" document.getElementsByClassName('message')[0].innerHTML=html;",
" };",
" };",
" });",
"</script>",
"<style>",
" body {",
" text-align: center;",
" font-family: \"Helvetica\", sans-serif;",
" }",
" h1 {",
" font-size: 2em;",
" font-weight: bold;",
" }",
" .box {",
" border-radius: 5px;",
" background-color: #eee;",
" padding: 20px 5px;",
" }",
" button {",
" color: white;",
" background-color: #4791d0;",
" border-radius: 5px;",
" border: 1px solid #4791d0;",
" padding: 5px 10px 8px 10px;",
" }",
" button:hover {",
" background-color: #0F5897;",
" border: 1px solid #0F5897;",
" }",
"</style>",
"<h1>Cat Photo Finder</h1> ",
"<p class=\"message box\">",
" The message will go here",
"</p>",
"<p>",
" <button id=\"getMessage\">",
" Get Message",
" </button>",
"</p>"
],
"tests": [
"assert(code.match(/val\\.imageLink/g), 'message: You should use the <code>imageLink</code> property to display the images.');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
},
{
"id": "587d7fae367417b2b2512be7",
"title": "Pre-filter JSON to Get the Data You Need",
"description": [
"If you don't want to render every cat photo you get from the freeCodeCamp Cat Photo API, you can pre-filter the JSON before looping through it.",
"Given that the JSON data is stored in an array, you can use the <code>filter</code> method to filter out the cat whose \"id\" key has a value of 1.",
"Here's the code to do this:",
"<blockquote>json = json.filter(function(val) {<br> return (val.id !== 1);<br>});</blockquote>",
"<hr>",
"Add code to <code>filter</code> the json data to remove the cat with the \"id\" value of 1."
],
"challengeSeed": [
"<script>",
" document.addEventListener('DOMContentLoaded',function(){",
" document.getElementById('getMessage').onclick=function(){",
" req=new XMLHttpRequest();",
" req.open(\"GET\",'/json/cats.json',true);",
" req.send();",
" req.onload=function(){",
" json=JSON.parse(req.responseText);",
" var html = \"\";",
" // Add your code below this line",
" ",
" ",
" // Add your code above this line",
" json.forEach(function(val) {",
" html += \"<div class = 'cat'>\"",
" ",
" html += \"<img src = '\" + val.imageLink + \"' \" + \"alt='\" + val.altText + \"'>\"",
" ",
" html += \"</div>\"",
" });",
" document.getElementsByClassName('message')[0].innerHTML=html;",
" };",
" }; ",
" });",
"</script>",
"<style>",
" body {",
" text-align: center;",
" font-family: \"Helvetica\", sans-serif;",
" }",
" h1 {",
" font-size: 2em;",
" font-weight: bold;",
" }",
" .box {",
" border-radius: 5px;",
" background-color: #eee;",
" padding: 20px 5px;",
" }",
" button {",
" color: white;",
" background-color: #4791d0;",
" border-radius: 5px;",
" border: 1px solid #4791d0;",
" padding: 5px 10px 8px 10px;",
" }",
" button:hover {",
" background-color: #0F5897;",
" border: 1px solid #0F5897;",
" }",
"</style>",
"<h1>Cat Photo Finder</h1> ",
"<p class=\"message box\">",
" The message will go here",
"</p>",
"<p>",
" <button id=\"getMessage\">",
" Get Message",
" </button>",
"</p>"
],
"tests": [
"assert(code.match(/json\\.filter/g), 'message: Your code should use the <code>filter</code> method.');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
},
{
"id": "587d7faf367417b2b2512be8",
"title": "Get Geolocation Data to Find A User's GPS Coordinates",
"description": [
"Another cool thing you can do is access your user's current location. Every browser has a built in navigator that can give you this information.",
"The navigator will get the user's current longitude and latitude.",
"You will see a prompt to allow or block this site from knowing your current location. The challenge can be completed either way, as long as the code is correct.",
"By selecting allow, you will see the text on the output phone change to your latitude and longitude.",
"Here's code that does this:",
"<blockquote>if (navigator.geolocation){<br> navigator.geolocation.getCurrentPosition(function(position) {<br> document.getElementById('data').innerHTML=\"latitude: \"+ position.coords.latitude + \"&lt;br&gt;longitude: \" + position.coords.longitude;<br> });<br>}</blockquote>",
"First, it checks if the <code>navigator.geolocation</code> object exists. If it does, the <code>getCurrentPosition</code> method on that object is called, which initiates an asynchronous request for the user's position. If the request is successful, the callback function in the method runs. This function accesses the <code>position</code> object's values for latitude and longitude using dot notation and updates the HTML.",
"<hr>",
"Add the example code inside the <code>script</code> tags to check a user's current location and insert it into the HTML."
],
"challengeSeed": [
"<script>",
" // Add your code below this line",
" ",
" ",
" // Add your code above this line",
"</script>",
"<h4>You are here:</h4>",
"<div id=\"data\">",
"",
"</div>"
],
"tests": [
"assert(code.match(/navigator\\.geolocation\\.getCurrentPosition/g), 'message: Your code should use <code>navigator.geolocation</code> to access the user&#39;s current location.');",
"assert(code.match(/position\\.coords\\.latitude/g), 'message: Your code should use <code>position.coords.latitude</code> to display the user&#39;s latitudinal location.');",
"assert(code.match(/position\\.coords\\.longitude/g), 'message: Your code should use <code>position.coords.longitude</code> to display the user&#39;s longitudinal location.');",
"assert(code.match(/document\\.getElementById\\(\\s*?('|\")data\\1\\s*?\\)\\.innerHTML/g), 'message: You should display the user&#39;s position within the <code>data</code> div element.');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
},
{
"id": "587d7faf367417b2b2512be9",
"title": "Post Data with the JavaScript XMLHttpRequest Method",
"description": [
"In the previous examples, you received data from an external resource. You can also send data to an external resource, as long as that resource supports AJAX requests and you know the URL.",
"JavaScript's <code>XMLHttpRequest</code> method is also used to post data to a server. Here's an example:",
"<blockquote>req=new XMLHttpRequest();<br>req.open(\"POST\",url,true);<br>req.setRequestHeader('Content-Type','text/plain');<br>req.onreadystatechange=function(){<br> if(req.readyState==4 && req.status==200){<br> document.getElementsByClassName('message')[0].innerHTML=req.responseText;<br> }<br>};<br>req.send(userName);</blockquote>",
"You've seen several of these methods before. Here the <code>open</code> method initializes the request as a \"POST\" to the given URL of the external resource, and uses the <code>true</code> Boolean to make it asynchronous.",
"The <code>setRequestHeader</code> method sets the value of an HTTP request header, which contains information about the sender and the request. It must be called after the <code>open</code> method, but before the <code>send</code> method. The two parameters are the name of the header and the value to set as the body of that header.",
"Next, the <code>onreadystatechange</code> event listener handles a change in the state of the request. A <code>readyState</code> of 4 means the operation is complete, and a <code>status</code> of 200 means it was a successful request. The document's HTML can be updated.",
"Finally, the <code>send</code> method sends the request with the <code>userName</code> value, which was given by the user in the <code>input</code> field.",
"<hr>",
"Update the code to create and send a \"POST\" request. Then enter your name in input box and click \"Send Message\". Your AJAX function will replace \"Reply from Server will be here.\" with the reply of the server. In this case, it is your name appended with \" loves cats\"."
],
"challengeSeed": [
"<script>",
" document.addEventListener('DOMContentLoaded',function(){",
" document.getElementById('sendMessage').onclick=function(){",
" ",
" var userName=document.getElementById('name').value;",
" // Add your code below this line",
" ",
" ",
" // Add your code above this line",
" };",
" });",
"</script>",
"<style>",
" body {",
" text-align: center;",
" font-family: \"Helvetica\", sans-serif;",
" }",
" h1 {",
" font-size: 2em;",
" font-weight: bold;",
" }",
" .box {",
" border-radius: 5px;",
" background-color: #eee;",
" padding: 20px 5px;",
" }",
" button {",
" color: white;",
" background-color: #4791d0;",
" border-radius: 5px;",
" border: 1px solid #4791d0;",
" padding: 5px 10px 8px 10px;",
" }",
" button:hover {",
" background-color: #0F5897;",
" border: 1px solid #0F5897;",
" }",
"</style>",
"<h1>Cat Friends</h1> ",
"<p class=\"message box\">",
" Reply from Server will be here",
"</p>",
"<p>",
" <label for=\"name\">Your name:",
" <input type=\"text\" id=\"name\"/>",
" </label>",
" <button id=\"sendMessage\">",
" Send Message",
" </button>",
"</p>"
],
"tests": [
"assert(code.match(/new\\s+?XMLHttpRequest\\(\\s*?\\)/g), 'message: Your code should create a new <code>XMLHttpRequest</code>.');",
"assert(code.match(/\\.open\\(\\s*?('|\")POST\\1\\s*?,\\s*?url\\s*?,\\s*?true\\s*?\\)/g), 'message: Your code should use the <code>open</code> method to initialize a \"POST\" request to the server.');",
"assert(code.match(/\\.setRequestHeader\\(\\s*?('|\")Content-Type\\1\\s*?,\\s*?('|\")text\\/plain\\2\\s*?\\)/g), 'message: Your code should use the <code>setRequestHeader</code> method.');",
"assert(code.match(/\\.onreadystatechange\\s*?=/g), 'message: Your code should have an <code>onreadystatechange</code> event handler set to a function.');",
"assert(code.match(/document\\.getElementsByClassName\\(\\s*?('|\")message\\1\\s*?\\)\\[0\\]\\.innerHTML\\s*?=\\s*?.+?\\.responseText/g), 'message: Your code should get the element with class <code>message</code> and change its inner HTML to the <code>responseText</code>.');",
"assert(code.match(/\\.send\\(\\s*?userName\\s*?\\)/g), 'message: Your code should use the <code>send</code> method.');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
}
]
}

View File

@ -0,0 +1,207 @@
{
"name": "API and Microservice Projects",
"order": 4,
"time": "150 hours",
"helpRoom": "HelpBackend",
"challenges": [
{
"id": "57ed709d334ad35e8fe79acb",
"title": "New Backend Format",
"isBeta": "true",
"meta": "This is just a test",
"description": [
"This is just a test of the new backend challenge test framework"
],
"tests": [
{
"text": "website should return 200",
"testString": "getUserInput => $.ajax({ url: getUserInput('url'), method: 'HEAD' }).then(null, (err) => assert.fail(err));"
},
{
"text": "package.json should have a valid \"keywords\" key",
"testString": "getUserInput => ($.get(getUserInput('url') + '/_api/package.json').then(function(data){ var packJson = JSON.parse(data); assert(packJson.keywords); }, err => { throw new Error('Err: ' + err.statusText);}))"
},
{
"text": "\"keywords\" field should be an Array",
"testString": "getUserInput => ($.get(getUserInput('url') + '/_api/package.json').then(function(data){ var packJson = JSON.parse(data); assert.isArray(packJson.keywords); }, err => { throw new Error('Err: ' + err.statusText);}))"
},
{
"text": "\"keywords\" should include \"freecodecamp\"",
"testString": "getUserInput => ($.get(getUserInput('url') + '/_api/package.json').then(function(data){ var packJson = JSON.parse(data); assert.include(packJson.keywords, 'freecodecamp'); }, err => { throw new Error('Err: ' + err.statusText); }))"
}
],
"type": "backend"
},
{
"id": "bd7158d8c443edefaeb5bdef",
"title": "Timestamp Microservice",
"description": [
"Build a full stack JavaScript app that is functionally similar to this: <a href='https://curse-arrow.glitch.me/' target='_blank'>https://curse-arrow.glitch.me/</a>.",
"Working on this project will involve you writing your code on Glitch on our starter project. After completing this project you can copy your public glitch url (to the homepage of your app) into this screen to test it! Optionally you may choose to write your project on another platform but it must be publicaly visible for our testing.",
"Start this project on Glitch using <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-project-timestamp/'>this link</a> or clone <a href='https://github.com/freeCodeCamp/boilerplate-project-timestamp/'>this repository</a> on GitHub! If you use Glitch, remember to save the link to your project somewhere safe!"
],
"challengeSeed": [],
"tests": [
{
"text": "I can pass a string as a parameter, and it will check to see whether that string contains either a unix timestamp or a natural language date (example: January 1, 2016).",
"testString": ""
},
{
"text": "If it does, it returns both the Unix timestamp and the natural language form of that date.",
"testString": ""
},
{
"text": "If it does not contain a date or Unix timestamp, it returns null for those properties.",
"testString": ""
}
],
"solutions": [],
"hints": [],
"type": "backend",
"isRequired": true,
"releasedOn": "January 1, 2016",
"translations": {
"es": {
"title": "Microservicio de Marca Temporal",
"description": []
}
}
},
{
"id": "bd7158d8c443edefaeb5bdff",
"title": "Request Header Parser Microservice",
"description": [
"Build a full stack JavaScript app that is functionally similar to this: <a href='https://dandelion-roar.glitch.me/' target='_blank'>https://dandelion-roar.glitch.me/</a>.",
"Working on this project will involve you writing your code on Glitch on our starter project. After completing this project you can copy your public glitch url (to the homepage of your app) into this screen to test it! Optionally you may choose to write your project on another platform but it must be publicaly visible for our testing.",
"Start this project on Glitch using <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-project-headerparser/'>this link</a> or clone <a href='https://github.com/freeCodeCamp/boilerplate-project-headerparser/'>this repository</a> on GitHub! If you use Glitch, remember to save the link to your project somewhere safe!"
],
"challengeSeed": [],
"tests": [
{
"text": "I can get the IP address, language and operating system for my browser.",
"testString": ""
}
],
"solutions": [],
"hints": [],
"type": "backend",
"isRequired": true,
"releasedOn": "January 1, 2016",
"translations": {
"es": {
"title": "Microservicio para analizar el encabezado de una petición",
"description": []
}
}
},
{
"id": "bd7158d8c443edefaeb5bd0e",
"title": "URL Shortener Microservice",
"description": [
"Build a full stack JavaScript app that is functionally similar to this: <a href='https://thread-paper.glitch.me/' target='_blank'>https://thread-paper.glitch.me/</a>.",
"Working on this project will involve you writing your code on Glitch on our starter project. After completing this project you can copy your public glitch url (to the homepage of your app) into this screen to test it! Optionally you may choose to write your project on another platform but it must be publicaly visible for our testing.",
"Start this project on Glitch using <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-project-urlshortener/'>this link</a> or clone <a href='https://github.com/freeCodeCamp/boilerplate-project-urlshortener/'>this repository</a> on GitHub! If you use Glitch, remember to save the link to your project somewhere safe!"
],
"challengeSeed": [],
"tests": [
{
"text": "I can pass a URL as a parameter and I will receive a shortened URL in the JSON response.",
"testString": ""
},
{
"text": "If I pass an invalid URL that doesn't follow the valid http://www.example.com format, the JSON response will contain an error instead.",
"testString": ""
},
{
"text": "When I visit that shortened URL, it will redirect me to my original link.",
"testString": ""
}
],
"solutions": [],
"hints": [],
"type": "backend",
"isRequired": true,
"releasedOn": "January 1, 2016",
"translations": {
"es": {
"title": "Microservicio para acortar URLs",
"description": []
}
}
},
{
"id": "bd7158d8c443edefaeb5bdee",
"title": "Exercise Tracker",
"description": [
"Build a full stack JavaScript app that is functionally similar to this: <a href='https://fuschia-custard.glitch.me/' target='_blank'>https://fuschia-custard.glitch.me/</a>.",
"Working on this project will involve you writing your code on Glitch on our starter project. After completing this project you can copy your public glitch url (to the homepage of your app) into this screen to test it! Optionally you may choose to write your project on another platform but it must be publicaly visible for our testing.",
"Start this project on Glitch using <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-project-exercisetracker/'>this link</a> or clone <a href='https://github.com/freeCodeCamp/boilerplate-project-exercisetracker/'>this repository</a> on GitHub! If you use Glitch, remember to save the link to your project somewhere safe!"
],
"challengeSeed": [],
"tests": [
{
"text": "I can create a user by posting form data username to /api/exercise/new-user and returned will be an object with username and <code>_id</code>.",
"testString": ""
},
{
"text": "I can get an array of all users by getting api/exercise/users with the same info as when creating a user.",
"testString": ""
},
{
"text": "I can add an exercise to any user by posting form data userId(_id), description, duration, and optionally date to /api/exercise/add. If no date supplied it will use current date. Returned will the the user object with also with the exercise fields added.",
"testString": ""
},
{
"text": "I can retrieve a full exercise log of any user by getting /api/exercise/log with a parameter of userId(_id). Return will be the user object with added array log and count (total exercise count).",
"testString": ""
},
{
"text": "I can retrieve part of the log of any user by also passing along optional parameters of from & to or limit. (Date format yyyy-mm-dd, limit = int)",
"testString": ""
}
],
"solutions": [],
"hints": [],
"type": "backend",
"isRequired": true,
"releasedOn": "February 17, 2017",
"translations": {
"es": {
"title": "Capa de abstracción para buscar imágenes",
"description": []
}
}
},
{
"id": "bd7158d8c443edefaeb5bd0f",
"title": "File Metadata Microservice",
"description": [
"Build a full stack JavaScript app that is functionally similar to this: <a href='https://purple-paladin.glitch.me/' target='_blank'>https://purple-paladin.glitch.me/</a>.",
"Working on this project will involve you writing your code on Glitch on our starter project. After completing this project you can copy your public glitch url (to the homepage of your app) into this screen to test it! Optionally you may choose to write your project on another platform but it must be publicaly visible for our testing.",
"Start this project on Glitch using <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-project-filemetadata/'>this link</a> or clone <a href='https://github.com/freeCodeCamp/boilerplate-project-filemetadata/'>this repository</a> on GitHub! If you use Glitch, remember to save the link to your project somewhere safe!"
],
"challengeSeed": [],
"tests": [
{
"text": "I can submit a FormData object that includes a file upload.",
"testString": ""
},
{
"text": "When I submit something, I will receive the file size in bytes within the JSON response.",
"testString": ""
}
],
"solutions": [],
"hints": [],
"type": "backend",
"isRequired": true,
"releasedOn": "January 1, 2016",
"translations": {
"es": {
"title": "Microservicio de metadatos de archivos",
"description": []
}
}
}
]
}

View File

@ -0,0 +1,312 @@
{
"name": "Basic Node and Express",
"order": 2,
"time": "5 hours",
"helpRoom": "Help",
"challenges": [
{
"id": "587d7fb0367417b2b2512bec",
"title": "Introduction to the Basic Node and Express Challenges",
"description": [
[
"",
"",
"Node.js is a JavaScript tool that allows developers to write backend (server-side) programs in JavaScript. Node.js comes with a handful of built-in modules&mdash;small, independent programs&mdash;that help facilitate this purpose. Some of the core modules include:<br><br><ul><li>HTTP: a module that acts as a server</li><li>File System: a module that reads and modifies files</li><li>Path: a module for working with directory and file paths</li><li>Assertion Testing: a module that checks code against prescribed constraints</li></ul><br>Express, while not included with Node.js, is another module often used with it. Express runs between the server created by Node.js and the frontend pages of a web application. Express also handles an application's routing. Routing directs users to the correct page based on their interaction with the application.<br><br>While there are alternatives to using Express, its simplicity makes it a good place to begin when learning the interaction between a backend powered by Node.js and the frontend.",
""
],
[
"",
"",
"Working on these challenges will involve you writing your code on Glitch on our starter project. After completing each challenge you can copy your public Glitch url (to the homepage of your app) into the challenge screen to test it! Optionally you may choose to write your project on another platform but it must be publicly visible for our testing.<br>Start this project on Glitch using <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-express/'>this link</a> or clone <a href='https://github.com/freeCodeCamp/boilerplate-express/'>this repository</a> on GitHub! If you use Glitch, remember to save the link to your project somewhere safe!",
""
]
],
"releasedOn": "Feb 17, 2017",
"challengeSeed": [],
"tests": [],
"type": "waypoint",
"challengeType": 7,
"isRequired": false,
"translations": {}
},
{
"id": "587d7fb0367417b2b2512bed",
"title": "Meet the Node console",
"description": [
"During the development process, it is important to be able to check whats going on in your code. Node is just a JavaScript environment. Like client side JavaScript, you can use the console to display useful debug information. On your local machine, you would see the console output in a terminal. On Glitch you can open the logs in the lower part of the screen. You can toggle the log panel with the button Logs (top-left, under the app name).",
"To get started, just print the classic \"Hello World\" in the console. We recommend to keep the log panel open while working at these challenges. Reading the logs you can be aware of the nature of the errors that may occur."
],
"challengeSeed": [],
"tests": [
{
"text": "<code>\"Hello World\"</code> should be in the console",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/hello-console').then(data => { assert.isTrue(data.passed, '\"Hello World\" is not in the server console'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"translations": {}
},
{
"id": "587d7fb0367417b2b2512bee",
"title": "Start a Working Express Server",
"description": [
"In the first two lines of the file myApp.js you can see how its easy to create an Express app object. This object has several methods, and we will learn many of them in these challenges. One fundamental method is <code>app.listen(port)</code>. It tells your server to listen on a given port, putting it in running state. You can see it at the bottom of the file. It is inside comments because for testing reasons we need the app to be running in background. All the code that you may want to add goes between these two fundamental parts. Glitch stores the port number in the environemet variable <code>process.env.PORT</code>. Its value is <code>3000</code>.",
"Lets serve our first string! In Express, routes takes the following structure: <code>app.METHOD(PATH, HANDLER)</code>. METHOD is an http method in lowercase. PATH is a relative path on the server (it can be a string, or even a regular expression). HANDLER is a function that Express calls when the route is matched.",
"Handlers take the form <code>function(req, res) {...}</code>, where req is the request object, and res is the response object. For example, the handler",
"<blockquote>function(req, res) {<br> res.send('Response String');<br>}</blockquote>",
"will serve the string 'Response String'.",
"Use the <code>app.get()</code> method to serve the string Hello Express, to GET requests matching the / root path. Be sure that your code works by looking at the logs, then see the results in your browser, clicking the button Show Live in the Glitch UI."
],
"challengeSeed": [],
"tests": [
{
"text": "Your app should serve the string 'Hello Express'",
"testString": "getUserInput => $.get(getUserInput('url')).then(data => { assert.equal(data, 'Hello Express', 'Your app does not serve the text \"Hello Express\"'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"translations": {}
},
{
"id": "587d7fb0367417b2b2512bef",
"title": "Serve an HTML File",
"description": [
"We can respond with a file using the method <code>res.sendFile(path)</code>.",
"You can put it inside the <code>app.get('/', ...)</code> route handler. Behind the scenes this method will set the appropriate headers to instruct your browser on how to handle the file you want to send, according to its type. Then it will read and send the file. This method needs an absolute file path. We recommend you to use the Node global variable <code>__dirname</code> to calculate the path.",
"e.g. <code>absolutePath = __dirname + relativePath/file.ext</code>.",
"The file to send is <code>/views/index.html</code>. Try to Show Live your app, you should see a big HTML heading (and a form that we will use later…), with no style applied.",
"Note: You can edit the solution of the previous challenge, or create a new one. If you create a new solution, keep in mind that Express evaluates the routes from top to bottom. It executes the handler for the first match. You have to comment out the preceding solution, or the server will keep responding with a string."
],
"challengeSeed": [],
"tests": [
{
"text": "Your app should serve the file views/index.html",
"testString": "getUserInput => $.get(getUserInput('url')).then(data => { assert.match(data, /<h1>.*<\\/h1>/, 'Your app does not serve the expected HTML'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"translations": {}
},
{
"id": "587d7fb0367417b2b2512bf0",
"title": "Serve Static Assets",
"description": [
"An HTML server usually has one or more directories that are accessible by the user. You can place there the static assets needed by your application (stylesheets, scripts, images). In Express you can put in place this functionality using the middleware <code>express.static(path)</code>, where the parameter is the absolute path of the folder containing the assets. If dont know what a middleware is, dont worry. Well discuss about it later in details. Basically middlewares are functions that intercept route handlers, adding some kind of information. A middleware needs to be mounted using the method <code>app.use(path, middlewareFunction)</code>. The first path argument is optional. If you dont pass it, the middleware will be executed for all the requests.",
"Mount the <code>express.static()</code> middleware for all the requests with <code>app.use()</code>. The absolute path to the assets folder is <code>__dirname + /public</code>.",
"Now your app should be able to serve a CSS stylesheet. From outside the public folder will appear mounted to the root directory. Your front-page should look a little better now!"
],
"challengeSeed": [],
"tests": [
{
"text": "Your app should serve asset files from the <code>/public</code> directory",
"testString": "getUserInput => $.get(getUserInput('url') + '/style.css').then(data => { assert.match(data, /body\\s*\\{[^\\}]*\\}/, 'Your app does not serve static assets'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"translations": {}
},
{
"id": "587d7fb1367417b2b2512bf1",
"title": "Serve JSON on a Specific Route",
"description": [
"While an HTML server serves (you guessed it!) HTML, an API serves data. A <dfn>REST</dfn> (REpresentational State Transfer) API allows data exchange in a simple way, without the need for clients to know any detail about the server. The client only needs to know where the resource is (the URL), and the action it wants to perform on it (the verb). The GET verb is used when you are fetching some information, without modifying anything. These days, the preferred data format for moving information around the web is JSON. Simply put, JSON is a convenient way to represent a JavaScript object as a string, so it can be easily transmitted.",
"Let's create a simple API by creating a route that responds with JSON at the path <code>/json</code>. You can do it as usual, with the <code>app.get()</code> method. Inside the route handler use the method <code>res.json()</code>, passing in an object as an argument. This method closes the request-response loop, returning the data. Behind the scenes it converts a valid JavaScript object into a string, then sets the appropriate headers to tell your browser that you are serving JSON, and sends the data back. A valid object has the usual structure <code>{key: data}</code>. Data can ba a number, a string, a nested object or an array. Data can also be a variable or the result of a function call; in which case it will be evaluated before being converted into a string.",
"Serve the object <code>{\"message\": \"Hello json\"}</code> as a response in JSON format, to the GET requests to the route <code>/json</code>. Then point your browser to your-app-url/json, you should see the message on the screen."
],
"challengeSeed": [],
"tests": [
{
"text": "The endpoint <code>/json</code> should serve the json object <code>{\"message\": \"Hello json\"}</code>",
"testString": "getUserInput => $.get(getUserInput('url') + '/json').then(data => { assert.equal(data.message, 'Hello json', 'The \\'/json\\' endpoint does not serve the right data'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"translations": {}
},
{
"id": "587d7fb1367417b2b2512bf2",
"title": "Use the .env File",
"description": [
"The <code>.env</code> file is a hidden file that is used to pass environment variables to your application. This file is secret, no one but you can access it, and it can be used to store data that you want to keep private or hidden. For example, you can store API keys from external services or your database URI. You can also use it to store configuration options. By setting configuration options, you can change the behavior of your application, without the need to rewrite some code.",
"The environment variables are accessible from the app as <code>process.env.VAR_NAME</code>. The <code>process.env</code> object is a global Node object, and variables are passed as strings. By convention, the variable names are all uppercase, with words separated by an underscore. The <code>.env</code> is a shell file, so you dont need to wrap names or values in quotes. It is also important to note that there cannot be space around the equals sign when you are assigning values to your variables, e.g. <code>VAR_NAME=value</code>. Usually, you will put each variable definition on a separate line.",
"Let's add an environment variable as a configuration option. Store the variable <code>MESSAGE_STYLE=uppercase</code> in the <code>.env</code> file. Then tell the GET <code>/json</code> route handler that you created in the last challenge to transform the response objects message to uppercase if <code>process.env.MESSAGE_STYLE</code> equals <code>uppercase</code>. The response object should become <code>{\"message\": \"HELLO JSON\"}</code>."
],
"challengeSeed": [],
"tests": [
{
"text": "The response of the endpoint <code>/json</code> should change according to the environment variable <code>MESSAGE_STYLE</code>",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/use-env-vars').then(data => { assert.isTrue(data.passed, 'The response of \"/json\" does not change according to MESSAGE_STYLE'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"translations": {}
},
{
"id": "587d7fb1367417b2b2512bf3",
"title": "Implement a Root-Level Request Logger Middleware",
"description": [
"Before we introduced the <code>express.static()</code> middleware function. Now its time to see what middleware is, in more detail. Middleware functions are functions that take 3 arguments: the request object, the response object, and the next function in the applications request-response cycle. These functions execute some code that can have side effects on the app, and usually add informations to the request or response objects. They can also end the cycle sending the response, when some condition is met. If they dont send the response, when they are done they start the execution of the next function in the stack. This is triggered calling the 3rd argument <code>next()</code>. More information in the <a href='http://expressjs.com/en/guide/using-middleware.html' target='_blank'>express documentation</a>.",
"Look at the following example :",
"<blockquote>function(req, res, next) {<br> console.log(\"I'm a middleware...\");<br> next();<br>}</blockquote>",
"Lets suppose we mounted this function on a route. When a request matches the route, it displays the string “Im a middleware…”. Then it executes the next function in the stack.",
"In this exercise we are going to build a root-level middleware. As we have seen in challenge 4, to mount a middleware function at root level we can use the method <code>app.use(&lt;mware-function&gt;)</code>. In this case the function will be executed for all the requests, but you can also set more specific conditions. For example, if you want a function to be executed only for POST requests, you could use <code>app.post(&lt;mware-function&gt;)</code>. Analogous methods exist for all the http verbs (GET, DELETE, PUT, …).",
"Build a simple logger. For every request, it should log in the console a string taking the following format: <code>method path - ip</code>. An example would look like: <code>GET /json - ::ffff:127.0.0.1</code>. Note that there is a space between <code>method</code> and <code>path</code> and that the dash separating <code>path</code> and <code>ip</code> is surrounded by a space on either side. You can get the request method (http verb), the relative route path, and the callers ip from the request object, using <code>req.method</code>, <code>req.path</code> and <code>req.ip</code>. Remember to call <code>next()</code> when you are done, or your server will be stuck forever. Be sure to have the Logs opened, and see what happens when some request arrives…",
"Hint: Express evaluates functions in the order they appear in the code. This is true for middleware too. If you want it to work for all the routes, it should be mounted before them."
],
"challengeSeed": [],
"tests": [
{
"text": "Root level logger middleware should be active",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/root-middleware-logger').then(data => { assert.isTrue(data.passed, 'root-level logger is not working as expected'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"translations": {}
},
{
"id": "587d7fb1367417b2b2512bf4",
"title": "Chain Middleware to Create a Time Server",
"description": [
"Middleware can be mounted at a specific route using <code>app.METHOD(path, middlewareFunction)</code>. Middleware can also be chained inside route definition.",
"Look at the following example:",
"<blockquote>app.get('/user', function(req, res, next) {<br> req.user = getTheUserSync(); // Hypotetical synchronous operation<br> next();<br>}, function(req, res) {<br> res.send(req.user);<br>})</blockquote>",
"This approach is useful to split the server operations into smaller units. That leads a to a better app structure, and the possibility to reuse code in different places. This approach can also be used to perform some validation on the data. At each point of the middleware stack you can block the execution of the current chain and pass control to functions specifically designed to handle errors. Or you can pass control to the next matching route, to handle special cases. We will see how in the advanced Express section.",
"In the route <code>app.get('/now', ...)</code> chain a middleware function and the final handler. In the middleware function you should add the current time to the request object in the <code>req.time</code> key. You can use <code>new Date().toString()</code>. In the handler, respond with a JSON object, taking the structure <code>{time: req.time}</code>.",
"Hint: The test will not pass if you dont chain the middleware. If you mount the function somewhere else, the test will fail, even if the output result is correct."
],
"challengeSeed": [],
"tests": [
{
"text": "The /now endpoint should have mounted middleware",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/chain-middleware-time').then(data => { assert.equal(data.stackLength, 2, '\"/now\" route has no mounted middleware'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "The /now endpoint should return a time that is +/- 20 secs from now",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/chain-middleware-time').then(data => { var now = new Date(); assert.isAtMost(Math.abs(new Date(data.time) - now), 20000, 'the returned time is not between +- 20 secs from now'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"translations": {}
},
{
"id": "587d7fb2367417b2b2512bf5",
"title": "Get Route Parameter Input from the Client",
"description": [
"When building an API, we have to allow users to comunicate us what they want to get from our service. For example, if the client is requesting information about a user stored in the database, they need a way to let us know which user they're interested in. One possible way to achieve this result is using route parameters. Route parameters are named segments of the URL, delimited by slashes (/). Each segment captures the value of the part of the URL which matches its position. The captured values can be found in the <code>req.params</code> object.",
"<blockquote>route_path: '/user/:userId/book/:bookId'<br>actual_request_URL: '/user/546/book/6754' <br>req.params: {userId: '546', bookId: '6754'}</blockquote>",
"Build an echo server, mounted at the route <code>GET /:word/echo</code>. Respond with a JSON object, taking the structure <code>{echo: word}</code>. You can find the word to be repeated at <code>req.params.word</code>. You can test your route from your browser's address bar, visiting some matching routes, e.g. your-app-rootpath/freecodecamp/echo"
],
"challengeSeed": [],
"tests": [
{
"text": "Test 1 : Your echo server should repeat words correctly",
"testString": "getUserInput => $.get(getUserInput('url') + '/eChOtEsT/echo').then(data => { assert.equal(data.echo, 'eChOtEsT', 'Test 1: the echo server is not working as expected') }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Test 2 : Your echo server should repeat words correctly",
"testString": "getUserInput => $.get(getUserInput('url') + '/ech0-t3st/echo').then(data => { assert.equal(data.echo, 'ech0-t3st', 'Test 2: the echo server is not working as expected') }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"translations": {}
},
{
"id": "587d7fb2367417b2b2512bf6",
"title": "Get Query Parameter Input from the Client",
"description": [
"Another common way to get input from the client is by encoding the data after the route path, using a query string. The query string is delimited by a question mark (?), and includes field=value couples. Each couple is separated by an ampersand (&). Express can parse the data from the query string, and populate the object <code>req.query</code>. Some characters cannot be in URLs, they have to be encoded in a <a href='https://en.wikipedia.org/wiki/Percent-encoding' target='_blank'>different format</a> before you can send them. If you use the API from JavaScript, you can use specific methods to encode/decode these characters.",
"<blockquote>route_path: '/library'<br>actual_request_URL: '/library?userId=546&bookId=6754' <br>req.query: {userId: '546', bookId: '6754'}</blockquote>",
"Build an API endpoint, mounted at <code>GET /name</code>. Respond with a JSON document, taking the structure <code>{ name: 'firstname lastname'}</code>. The first and last name parameters should be encoded in a query string e.g. <code>?first=firstname&last=lastname</code>.",
"TIP: In the following exercise we are going to receive data from a POST request, at the same <code>/name</code> route path. If you want you can use the method <code>app.route(path).get(handler).post(handler)</code>. This syntax allows you to chain different verb handlers on the same path route. You can save a bit of typing, and have cleaner code."
],
"challengeSeed": [],
"tests": [
{
"text": "Test 1 : Your API endpoint should respond with the correct name",
"testString": "getUserInput => $.get(getUserInput('url') + '/name?first=Mick&last=Jagger').then(data => { assert.equal(data.name, 'Mick Jagger', 'Test 1: \"GET /name\" route does not behave as expected') }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Test 2 : Your APi endpoint should respond with the correct name",
"testString": "getUserInput => $.get(getUserInput('url') + '/name?last=Richards&first=Keith').then(data => { assert.equal(data.name, 'Keith Richards', 'Test 2: \"GET /name\" route does not behave as expected') }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"translations": {}
},
{
"id": "587d7fb2367417b2b2512bf7",
"title": "Use body-parser to Parse POST Requests",
"description": [
"Besides GET there is another common http verb, it is POST. POST is the default method used to send client data with HTML forms. In the REST convention POST is used to send data to create new items in the database (a new user, or a new blog post). We dont have a database in this project, but we are going to learn how to handle POST requests anyway.",
"In these kind of requests the data doesnt appear in the URL, it is hidden in the request body. This is a part of the HTML request, also called payload. Since HTML is text based, even if you dont see the data, it doesnt mean that they are secret. The raw content of an HTTP POST request is shown below:",
"<blockquote>POST /path/subpath HTTP/1.0<br>From: john@example.com<br>User-Agent: someBrowser/1.0<br>Content-Type: application/x-www-form-urlencoded<br>Content-Length: 20<br>name=John+Doe&age=25</blockquote>",
"As you can see the body is encoded like the query string. This is the default format used by HTML forms. With Ajax we can also use JSON to be able to handle data having a more complex structure. There is also another type of encoding: multipart/form-data. This one is used to upload binary files.",
"In this exercise we will use an urlencoded body.",
"To parse the data coming from POST requests, you have to install a package: the body-parser. This package allows you to use a series of middleware, which can decode data in different formats. See the docs <a href=\"https://github.com/expressjs/body-parser\" target=\"_blank\" >here</a>.",
"Install the body-parser module in your package.json. Then require it at the top of the file. Store it in a variable named bodyParser.",
"The middleware to handle url encoded data is returned by <code>bodyParser.urlencoded({extended: false})</code>. <code>extended=false</code> is a configuration option that tells the parser to use the classic encoding. When using it, values can be only strings or arrays. The extended version allows more data flexibility, but it is outmatched by JSON. Pass to <code>app.use()</code> the function returned by the previous method call. As usual, the middleware must be mounted before all the routes which need it."
],
"challengeSeed": [],
"tests": [
{
"text": "The 'body-parser' middleware should be mounted",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/add-body-parser').then(data => { assert.isAbove(data.mountedAt, 0, '\"body-parser\" is not mounted correctly') }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"translations": {}
},
{
"id": "587d7fb2367417b2b2512bf8",
"title": "Get Data from POST Requests",
"description": [
"Mount a POST handler at the path <code>/name</code>. Its the same path as before. We have prepared a form in the html frontpage. It will submit the same data of exercise 10 (Query string). If the body-parser is configured correctly, you should find the parameters in the object <code>req.body</code>. Have a look at the usual library example:",
"<blockquote>route: POST '/library'<br>urlencoded_body: userId=546&bookId=6754 <br>req.body: {userId: '546', bookId: '6754'}</blockquote>",
"Respond with the same JSON object as before: <code>{name: 'firstname lastname'}</code>. Test if your endpoint works using the html form we provided in the app frontpage.",
"Tip: There are several other http methods other than GET and POST. And by convention there is a corrispondence between the http verb, and the operation you are going to execute on the server. The conventional mapping is:",
"POST (sometimes PUT) - Create a new resource using the information sent with the request,",
"GET - Read an existing resource without modifying it,",
"PUT or PATCH (sometimes POST) - Update a resource using the data sent,",
"DELETE => Delete a resource.",
"There are also a couple of other methods which are used to negotiate a connection with the server. Except from GET, all the other methods listed above can have a payload (i.e. the data into the request body). The body-parser middleware works with these methods as well."
],
"challengeSeed": [],
"tests": [
{
"text": "Test 1 : Your API endpoint should respond with the correct name",
"testString": "getUserInput => $.post(getUserInput('url') + '/name', {first: 'Mick', last: 'Jagger'}).then(data => { assert.equal(data.name, 'Mick Jagger', 'Test 1: \"POST /name\" route does not behave as expected') }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Test 2 : Your API endpoint should respond with the correct name",
"testString": "getUserInput => $.post(getUserInput('url') + '/name', {first: 'Keith', last: 'Richards'}).then(data => { assert.equal(data.name, 'Keith Richards', 'Test 2: \"POST /name\" route does not behave as expected') }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"translations": {}
}
]
}

View File

@ -0,0 +1,108 @@
{
"name": "Claim Your APIs and Microservices Certificate",
"order": 13,
"time": "5 minutes",
"challenges": [
{
"id": "587d7fb3367417b2b2512bf9",
"title": "Claim Your APIs and Microservices Certificate",
"description": [
[
"//i.imgur.com/k8btNUB.jpg",
"An image of our APIs and Microservices Certificate",
"This challenge will give you your verified APIs and Microservices Certificate. Before we issue your certificate, we must verify that you have completed all of our basic and intermediate algorithm scripting challenges, and all our basic, intermediate, and advanced front end development projects. You must also accept our Academic Honesty Pledge. Click the button below to start this process.",
""
],
[
"//i.imgur.com/uLPsUko.jpg",
"The definition of plagiarism: Plagiarism (noun) - copying someone elses work and presenting it as your own without crediting them",
"By clicking below, you pledge that all of your submitted code A) is code you or your pair personally wrote, or B) comes from open source libraries like jQuery, or C) has been clearly attributed to its original authors. You also give us permission to audit your challenge solutions and revoke your certificate if we discover evidence of plagiarism.",
"#"
],
[
"//i.imgur.com/UedoV2G.jpg",
"An image of the text \"Front End Development Certificate requirements\"",
"Let's confirm that you have completed all of our basic and intermediate algorithm scripting challenges, and all our basic, intermediate, and advanced front end development projects. Click the button below to verify this.",
"#"
],
[
"//i.imgur.com/Q5Za9U6.jpg",
"An image of the word \"Congratulations\"",
"Congratulations! We've added your APIs and Microservices Certificate to your portfolio page. Unless you choose to hide your solutions, this certificate will remain publicly visible and verifiable.",
""
]
],
"challengeSeed": [
{
"properties": [
"isHonest",
"isFrontEndCert"
],
"apis": [
"/certificate/honest",
"/certificate/verify/front-end"
],
"stepIndex": [
1,
2
]
}
],
"tests": [
{
"id": "bd7158d8c443edefaeb5bdef",
"title": "Timestamp Microservice"
},
{
"id": "bd7158d8c443edefaeb5bdff",
"title": "Request Header Parser Microservice"
},
{
"id": "bd7158d8c443edefaeb5bd0e",
"title": "URL Shortener Microservice"
},
{
"id": "bd7158d8c443edefaeb5bd0f",
"title": "File Metadata Microservice"
},
{
"id": "bd7158d8c443edefaeb5bdee",
"title": "Exercise Tracker"
}
],
"type": "Waypoint",
"challengeType": 7,
"translations": {
"es": {
"title": "Reclama tu certificado de Desarrollo de interfaces",
"description": [
[
"//i.imgur.com/k8btNUB.jpg",
"Una imagen que muestra nuestro certificado de Desarrollo de interfaces",
"Este desafío te otorga tu certificado autenticado de Desarrollo de interfaces. Antes de que podamos emitir tu certificado, debemos verificar que has completado todos los desafíos básicos e intermedios de diseño de algoritmos, y todos los proyectos básicos e intermedios de desarrollo de interfaces. También debes aceptar nuestro Juramento de honestidad académica. Pulsa el botón siguiente para iniciar este proceso.",
""
],
[
"//i.imgur.com/HArFfMN.jpg",
"Plagio (nombre): acción y efecto de plagiar. Plagiar (verbo) - copiar en lo sustancial obras ajenas, dándolas como propias.",
"Al pulsar el botón siguiente, juras que todo el código en tus soluciones a los desafíos A) es código que tú o tu compañero escribieron personalmente, o B) proviene de librerías de código abierto como jQuery, o C) ha sido claramente atribuido a sus autores originales. También nos otorgas el permiso para auditar tus soluciones a los desafíos y revocar tu certificado si encontramos evidencia de plagio.",
"#"
],
[
"//i.imgur.com/14F2Van.jpg",
"Una imagen del texto \"Front End Development Certificate requirements\"",
"Confirmemos que has completado todos nuestros desafíos básicos e intermedios de diseño de algoritmos, y todos nuestros proyectos básicos e intermedios de desarrollo de interfaces. Pulsa el botón siguiente para hacer la verificación.",
"#"
],
[
"//i.imgur.com/16SIhHO.jpg",
"Una imagen de la palabra \"Congratulations\"",
"¡Felicitaciones! Hemos agregado tu certificado de Desarrollo de interfaces a tu portafolio. A menos que elijas no mostrar tus soluciones, este certificado será públicamente visible y verificable.",
""
]
]
}
}
}
]
}

View File

@ -0,0 +1,307 @@
{
"name": "Managing Packages with npm",
"order": 1,
"time": "5 hours",
"helpRoom": "Help",
"challenges": [
{
"id": "587d7fb3367417b2b2512bfa",
"title": "Introduction to the Managing Packages with npm Challenges",
"description": [
[
"",
"",
"The Node Package Manager (npm) is a command-line tool used by developers to share and control modules (or packages) of JavaScript code written for use with Node.js.<br><br>When starting a new project, npm generates a <code>package.json</code> file. This file lists the package dependencies for your project. Since npm packages are regularly updated, the <code>package.json</code> file allows you to set specific version numbers for each dependency. This ensures that updates to a package don't break your project.<br><br>npm saves packages in a folder named <code>node_modules</code>. These packages can be installed in two ways:<br><br><ol><li>globally in a root <code>node_modules</code> folder, accessible by all projects.</li><li>locally within a project's own <code>node_modules</code> folder, accessible only to that project.</li></ol><br>Most developers prefer to install packages local to each project to create a separation between the dependencies of different projects.",
""
],
[
"",
"",
"Working on these challenges will involve you writing your code on Glitch on our starter project. After completing each challenge you can copy your public Glitch url (to the homepage of your app) into the challenge screen to test it! Optionally you may choose to write your project on another platform but it must be publicly visible for our testing.<br>Start this project on Glitch using <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-npm'>this link</a> or clone <a href='https://github.com/freeCodeCamp/boilerplate-npm/'>this repository</a> on GitHub! If you use Glitch, remember to save the link to your project somewhere safe!",
""
]
],
"releasedOn": "Feb 17, 2017",
"challengeSeed": [],
"tests": [],
"type": "waypoint",
"challengeType": 7,
"isRequired": false,
"translations": {}
},
{
"id": "587d7fb3367417b2b2512bfb",
"title": "How to Use package.json, the Core of Any Node.js Project or npm Package",
"description": [
"The file package.json is the center of any Node.js project or npm package. It stores information about your project just like the <head>-section in a HTML document describes the content of a webpage. The package.json consists of a single JSON-object where information is stored in \"key\": value-pairs. There are only two required fields in a minimal package.json - name and version - but its a good practice to provide additional information about your project that could be useful to future users or maintainers.",
"The author-field",
"If you go to the Glitch project that you set up previously and look at on the left side of your screen, youll find the file tree where you can see an overview of the various files in your project. Under the file trees back-end section, youll find package.json - the file that well be improving in the next couple of challenges.",
"One of the most common pieces of information in this file is the author-field that specifies whos the creator of a project. It can either be a string or an object with contact details. The object is recommended for bigger projects but in our case, a simple string like the following example will do.",
"<code>\"author\": \"Jane Doe\",</code>",
"Instructions",
"Add your name to the author-field in the package.json of your Glitch project.",
"Remember that youre writing JSON.",
"All field-names must use double-quotes (\"), e.g. \"author\"",
"All fields must be separated with a comma (,)"
],
"challengeSeed": [],
"tests": [
{
"text": "package.json should have a valid \"author\" key",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert(packJson.author, '\"author\" is missing'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"translations": {}
},
{
"id": "587d7fb3367417b2b2512bfc",
"title": "Add a Description to Your package.json",
"description": [
"The next part of a good package.json is the description-field, where a short but informative description about your project belongs.",
"If you some day plan to publishing a package to npm, remember that this is the string that should sell your idea to the user when they decide whether to install your package or not. However, thats not the only use case for the description: Since its a great way to summarize what a project does, its just as important for your normal Node.js-projects to help other developers, future maintainers or even your future self understand the project quickly.",
"Regardless of what you plan for your project, a description is definitely recommended. Lets add something similar to this:",
"<code>\"description\": \"A project that does something awesome\",</code>",
"Instructions",
"Add a description to the package.json in your Glitch project.",
"Remember to use double-quotes for field-names (\") and commas (,) to separate fields."
],
"challengeSeed": [],
"tests": [
{
"text": "package.json should have a valid \"description\" key",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert(packJson.description, '\"description\" is missing'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"translations": {}
},
{
"id": "587d7fb4367417b2b2512bfd",
"title": "Add Keywords to Your package.json",
"description": [
"The keywords-field is where you can describe your project using related keywords.",
"Example",
"<code>\"keywords\": [ \"descriptive\", \"related\", \"words\" ],</code>",
"As you can see, this field is structured as an array of double-quoted strings.",
"Instructions",
"Add an array of suitable strings to the keywords-field in the package.json of your Glitch project.",
"One of the keywords should be freecodecamp."
],
"challengeSeed": [],
"tests": [
{
"text": "package.json should have a valid \"keywords\" key",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert(packJson.keywords, '\"keywords\" is missing'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "\"keywords\" field should be an Array",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert.isArray(packJson.keywords, '\"keywords\" is not an array'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "\"keywords\" should include \"freecodecamp\"",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert.include(packJson.keywords, 'freecodecamp', '\"keywords\" does not include \"freecodecamp\"'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"translations": {}
},
{
"id": "587d7fb4367417b2b2512bfe",
"title": "Add a License to Your package.json",
"description": [
"TODO: This challenge could be used to inspire more people to develop OSS - we should really improve this description.",
"The license-field is where you inform users of your project what they are allowed to do with it.",
"Some common licenses for open source projects include MIT and BSD. http://choosealicense.com is a great resource if you want to learn more about what license could fit your project.",
"License information is not required. Copyright laws in most countries will give you ownership of what you create by default. However, its always a good practice to explicitly state what users can and cant do.",
"Example",
"<code>\"license\": \"MIT\",</code>",
"Instructions",
"Fill the license-field in the package.json of your Glitch project as you find suitable."
],
"challengeSeed": [],
"tests": [
{
"text": "package.json should have a valid \"license\" key",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert(packJson.license, '\"license\" is missing'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"translations": {}
},
{
"id": "587d7fb4367417b2b2512bff",
"title": "Add a Version to Your package.json",
"description": [
"The version is together with name one of the required fields in a package.json. This field describes the current version of your project.",
"Example",
"<code>\"version\": \"1.2\",</code>",
"Instructions",
"Add a version to the package.json in your Glitch project."
],
"challengeSeed": [],
"tests": [
{
"text": "package.json should have a valid \"version\" key",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert(packJson.version, '\"version\" is missing'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"translations": {}
},
{
"id": "587d7fb4367417b2b2512c00",
"title": "Expand Your Project with External Packages from npm",
"description": [
"One of the biggest reasons to use a package manager is their powerful dependency management. Instead of manually having to make sure that you get all dependencies whenever you set up a project on a new computer, npm automatically installs everything for you. But how can npm know exactly what your project needs? Meet the dependencies-section of your package.json.",
"In the dependencies-section, packages your project require are stored using the following format:",
"<code>\"dependencies\": {</code>",
"<code> \"package-name\": \"version\",</code>",
"<code> \"express\": \"4.14.0\"</code>",
"<code>}</code>",
"Instructions",
"Add version 2.14.0 of the package moment to the dependencies-field of your package.json",
"Moment is a handy library for working with time and dates."
],
"challengeSeed": [],
"tests": [
{
"text": "\"dependencies\" should include \"moment\"",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, 'moment', '\"dependencies\" does not include \"moment\"'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "\"moment\" version should be \"2.14.0\"",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert.match(packJson.dependencies.moment, /^[\\^\\~]?2\\.14\\.0/, 'Wrong version of \"moment\" installed. It should be 2.14.0'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"translations": {}
},
{
"id": "587d7fb5367417b2b2512c01",
"title": "Manage npm Dependencies By Understanding Semantic Versioning",
"description": [
"Versions of the npm packages in the dependencies-section of your package.json follow whats called Semantic Versioning (SemVer), an industry standard for software versioning aiming to make it easier to manage dependencies. Libraries, frameworks or other tools published on npm should use SemVer in order to clearly communicate what kind of changes that projects who depend on the package can expect if they update.",
"SemVer doesnt make sense in projects without public APIs - so unless your project is similar to the examples above, use another versioning format.",
"So why do you need to understand SemVer?",
"Knowing SemVer can be useful when you develop software that use external dependencies (which you almost always do). One day, your understanding of these numbers will save you from accidentally introducing breaking changes to your project without understanding why things “that worked yesterday” suddenly doesnt.",
"This is how Semantic Versioning works according to the official website:",
"Given a version number MAJOR.MINOR.PATCH, increment the:",
"MAJOR version when you make incompatible API changes,",
"MINOR version when you add functionality in a backwards-compatible manner, and",
"PATCH version when you make backwards-compatible bug fixes.",
"This means that PATCHes are bug fixes and MINORs add new features but neither of them break what worked before. Finally, MAJORs add changes that wont work with earlier versions.",
"Example",
"A semantic version number: 1.3.8",
"Instructions",
"In the dependencies-section of your package.json, change the version of moment to match MAJOR version 2, MINOR version 10 and PATCH version 2"
],
"challengeSeed": [],
"tests": [
{
"text": "\"dependencies\" should include \"moment\"",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, 'moment', '\"dependencies\" does not include \"moment\"'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "\"moment\" version should be \"2.10.2\"",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert.match(packJson.dependencies.moment, /^[\\^\\~]?2\\.10\\.2/, 'Wrong version of \"moment\". It should be 2.10.2'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"translations": {}
},
{
"id": "587d7fb5367417b2b2512c02",
"title": "Use the Tilde-Character to Always Use the Latest Patch Version of a Dependency",
"description": [
"In the last challenge, we told npm to only include a specific version of a package. Thats a useful way to freeze your dependencies if you need to make sure that different parts of your project stay compatible with each other. But in most use cases you dont want to miss bug fixes, since they often include important security patches and (hopefully) dont break things in doing so.",
"To allow a npm dependency to get updated to the latest PATCH-version, you can prefix the dependencys version with the tilde-character (~). In package.json, our current rule for how npm may upgrade moment is to use a specific version only (2.10.2), but we want to allow the latest 2.10.x-version.",
"Example",
"<code>\"some-package-name\": \"~1.3.8\" allows updates to any 1.3.x version.</code>",
"Instructions",
"Use the tilde-character (~) to prefix the version of moment in your dependencies and allow npm to update it to any new PATCH release.",
"Note that the version numbers themselves not should be changed."
],
"challengeSeed": [],
"tests": [
{
"text": "\"dependencies\" should include \"moment\"",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, 'moment', '\"dependencies\" does not include \"moment\"'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "\"moment\" version should match \"~2.10.2\"",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert.match(packJson.dependencies.moment, /^\\~2\\.10\\.2/, 'Wrong version of \"moment\". It should be ~2.10.2'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"translations": {}
},
{
"id": "587d7fb5367417b2b2512c03",
"title": "Use the Caret-Character to Use the Latest Minor Version of a Dependency",
"description": [
"Similar to how the tilde (~) we learned about in the last challenge allow npm to install the latest PATCH for a dependency, the caret (^) allows npm to install future updates as well. The difference is that the caret will allow both MINOR updates and PATCHes.",
"At the moment, your current version of moment should be ~2.10.2 which allows npm to install to the latest 2.10.x-version. If we instead were to use the caret (^) as our version prefix, npm would instead be allowed to update to any 2.x.x-version.",
"Example",
"<code>\"some-package-name\": \"^1.3.8\" allows updates to any 1.x.x version.</code>",
"Instructions",
"Use the caret-character (^) to prefix the version of moment in your dependencies and allow npm to update it to any new MINOR release.",
"Note that the version numbers themselves not should be changed."
],
"challengeSeed": [],
"tests": [
{
"text": "\"dependencies\" should include \"moment\"",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, 'moment', '\"dependencies\" does not include \"moment\"'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "\"moment\" version should match \"^2.x.x\"",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert.match(packJson.dependencies.moment, /^\\^2\\./, 'Wrong version of \"moment\". It should be ^2.10.2'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"translations": {}
},
{
"id": "587d7fb5367417b2b2512c04",
"title": "Remove a Package from Your Dependencies",
"description": [
"Now youve tested a few ways you can manage dependencies of your project by using the package.json's dependencies-section. Youve included external packages by adding them to the file and even told npm what types of versions you want by using special characters as the tilde (~) or the caret (^).",
"But what if you want to remove an external package that you no longer need? You might already have guessed it - Just remove the corresponding \"key\": value-pair for that from your dependencies.",
"This same method applies to removing other fields in your package.json as well",
"Instructions",
"Remove the package moment from your dependencies.",
"Make sure you have the right amount of commas after removing it."
],
"challengeSeed": [],
"tests": [
{
"text": "\"dependencies\" should not include \"moment\"",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert.notProperty(packJson.dependencies, 'moment', '\"dependencies\" still includes \"moment\"'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"translations": {}
}
]
}

View File

@ -0,0 +1,285 @@
{
"name": "MongoDB and Mongoose",
"order": 3,
"time": "5 hours",
"helpRoom": "Help",
"challenges": [
{
"id": "587d7fb5367417b2b2512c05",
"title": "Introduction to the MongoDB and Mongoose Challenges",
"description": [
[
"",
"",
"MongoDB is a database that stores data records (documents) for use by an application. Mongo is a non-relational, \"NoSQL\" database. This means Mongo stores all data associated within one record, instead of storing it across many preset tables as in a SQL database. Some benefits of this storage model are:<br><br><ul><li>Scalability: by default, non-relational databases are split (or \"sharded\") across many systems instead of only one. This makes it easier to improve performance at a lower cost.</li><li>Flexibility: new datasets and properties can be added to a document without the need to make a new table for that data.</li><li>Replication: copies of the database run in parallel so if one goes down, one of the copies becomes the new primary data source.</li></ul><br>While there are many non-relational databases, Mongo's use of JSON as its document storage structure makes it a logical choice when learning backend JavaScript. Accessing documents and their properties is like accessing objects in JavaScript.<br><br>Mongoose.js is an npm module for Node.js that allows you to write objects for Mongo as you would in JavaScript. This can make is easier to construct documents for storage in Mongo.",
""
],
[
"",
"",
"Working on these challenges will involve you writing your code on Glitch on our starter project. After completing each challenge you can copy your public glitch url (to the homepage of your app) into the challenge screen to test it! Optionally you may choose to write your project on another platform but it must be publicaly visible for our testing.<br>Start this project on Glitch using <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-mongomongoose/'>this link</a> or clone <a href='https://github.com/freeCodeCamp/boilerplate-mongomongoose/'>this repository</a> on GitHub! If you use Glitch, remember to save the link to your project somewhere safe!",
""
]
],
"releasedOn": "Feb 17, 2017",
"challengeSeed": [],
"tests": [],
"type": "waypoint",
"challengeType": 7,
"isRequired": false,
"translations": {}
},
{
"id": "587d7fb6367417b2b2512c06",
"title": "Install and Set Up Mongoose",
"description": [
"Add mongodb and mongoose to the projects package.json. Then require mongoose. Store your mLab database URI in the private .env file as MONGO_URI. Connect to the database using mongoose.connect(<Your URI>)"
],
"challengeSeed": [],
"tests": [
{
"text": "\"mongodb\" dependency should be in package.json",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/file/package.json').then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, 'mongodb'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "\"mongoose\" dependency should be in package.json",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/file/package.json').then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, 'mongooose'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"translations": {}
},
{
"id": "587d7fb6367417b2b2512c07",
"title": "Create a Model",
"description": [
"First of all we need a Schema. Each schema maps to a MongoDB collection. It defines the shape of the documents within that collection.",
"Schemas are building block for Models. They can be nested to create complex models, but in this case well keep things simple.",
"A model allows you to create instances of your objects, called documents.",
"Create a person having this prototype :",
"<code>- Person Prototype -</code>",
"<code>--------------------</code>",
"<code>name : string [required]</code>",
"<code>age : number</code>",
"<code>favoriteFoods : array of strings (*) </code>",
"Use the mongoose basic schema types. If you want you can also add",
"more fields, use simple validators like required or unique,",
"and set default values. See the <a href='http://mongoosejs.com/docs/guide.html'>mongoose docs</a>.",
"[C]RUD Part I - CREATE",
"Note: Glitch is a real server, and in real servers the interactions with the db happen in handler functions. These function are executed when some event happens (e.g. someone hits an endpoint on your API). Well follow the same approach in these exercises. The done() function is a callback that tells us that we can proceed after completing an asynchronous operation such as inserting, searching, updating or deleting. Its following the Node convention and should be called as done(null, data) on success, or done(err) on error.",
"Warning - When interacting with remote services, errors may occur !",
"<code>/* Example */</code>",
"<code>var someFunc = function(done) {</code>",
"<code> //... do something (risky) ...</code>",
"<code> if(error) return done(error);</code>",
"<code> done(null, result);</code>",
"<code>};</code>"
],
"challengeSeed": [],
"tests": [
{
"text": "Creating an instance from a mongoose schema should succeed",
"testString": "getUserInput => $.post(getUserInput('url') + '/_api/mongoose-model', {name: 'Mike', age: 28, favoriteFoods: ['pizza', 'cheese']}).then(data => { assert.equal(data.name, 'Mike', '\"model.name\" is not what expected'); assert.equal(data.age, '28', '\"model.age\" is not what expected'); assert.isArray(data.favoriteFoods, '\"model.favoriteFoods\" is not an Array'); assert.include(data.favoriteFoods, 'pizza', '\"model.favoriteFoods\" does not include the expected items'); assert.include(data.favoriteFoods, 'cheese', '\"model.favoriteFoods\" does not include the expected items'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"translations": {}
},
{
"id": "587d7fb6367417b2b2512c09",
"title": "Create and Save a Record of a Model",
"description": [
"Create a document instance using the Person constructor you build before. Pass to the constructor an object having the fields name, age, and favoriteFoods. Their types must be conformant to the ones in the Person Schema. Then call the method document.save() on the returned document instance. Pass to it a callback using the Node convention. This is a common pattern, all the following CRUD methods take a callback function like this as the last argument.",
"<code>/* Example */</code>",
"<code>// ...</code>",
"<code>person.save(function(err, data) {</code>",
"<code>// ...do your stuff here...</code>",
"<code>});</code>"
],
"challengeSeed": [],
"tests": [
{
"text": "Creating and saving a db item should succeed",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/create-and-save-person').then(data => { assert.isString(data.name, '\"item.name\" should be a String'); assert.isNumber(data.age, '28', '\"item.age\" should be a Number'); assert.isArray(data.favoriteFoods, '\"item.favoriteFoods\" should be an Array'); assert.equal(data.__v, 0, 'The db item should be not previously edited'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"translations": {}
},
{
"id": "587d7fb7367417b2b2512c0a",
"title": "Create Many Records with model.create()",
"description": [
"Sometimes you need to create many instances of your models, e.g. when seeding a database with initial data. Model.create() takes an array of objects like [{name: 'John', ...}, {...}, ...] as the first argument, and saves them all in the db. Create many people with Model.create(), using the function argument arrayOfPeople."
],
"challengeSeed": [],
"tests": [
{
"text": "Creating many db items at once should succeed",
"testString": "getUserInput => $.ajax({url: getUserInput('url') + '/_api/create-many-people', type: 'POST', contentType:'application/json', data: JSON.stringify([{name: 'John', age: 24, favoriteFoods: ['pizza', 'salad']}, {name: 'Mary', age: 21, favoriteFoods: ['onions', 'chicken']}])}).then(data => { assert.isArray(data, 'the response should be an array'); assert.equal(data.length, 2, 'the response does not contain the expected number of items'); assert.equal(data[0].name, 'John', 'The first item is not correct'); assert.equal(data[0].__v, 0, 'The first item should be not previously edited'); assert.equal(data[1].name, 'Mary', 'The second item is not correct'); assert.equal(data[1].__v, 0, 'The second item should be not previously edited'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"translations": {}
},
{
"id": "587d7fb7367417b2b2512c0b",
"title": "Use model.find() to Search Your Database",
"description": [
"Find all the people having a given name, using Model.find() -> [Person]",
"In its simplest usage, Model.find() accepts a query document (a JSON object ) as the first argument, then a callback. It returns an array of matches. It supports an extremely wide range of search options. Check it in the docs. Use the function argument personName as search key."
],
"challengeSeed": [],
"tests": [
{
"text": "Find all items corresponding to a criteria should succeed",
"testString": "getUserInput => $.post(getUserInput('url') + '/_api/find-all-by-name', {name: 'r@nd0mN4m3', age: 24, favoriteFoods: ['pizza']}).then(data => { assert.isArray(data, 'the response should be an Array'); assert.equal(data[0].name, 'r@nd0mN4m3', 'item.name is not what expected'); assert.equal(data[0].__v, 0, 'The item should be not previously edited'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"translations": {}
},
{
"id": "587d7fb7367417b2b2512c0c",
"title": "Use model.findOne() to Return a Single Matching Document from Your Database",
"description": [
"Model.findOne() behaves like .find(), but it returns only one document (not an array), even if there are items. It is especially useful when searching by properties that you have declared as unique. Find just one person which has a certain food in her favorites, using Model.findOne() -> Person. Use the function argument food as search key."
],
"challengeSeed": [],
"tests": [
{
"text": "Find one item should succeed",
"testString": "getUserInput => $.post(getUserInput('url') + '/_api/find-one-by-food', {name: 'Gary', age: 46, favoriteFoods: ['chicken salad']}).then(data => { assert.equal(data.name, 'Gary', 'item.name is not what expected'); assert.deepEqual(data.favoriteFoods, ['chicken salad'], 'item.favoriteFoods is not what expected'); assert.equal(data.__v, 0, 'The item should be not previously edited'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"translations": {}
},
{
"id": "587d7fb7367417b2b2512c0d",
"title": "Use model.findById() to Search Your Database By _id",
"description": [
"When saving a document, mongodb automatically adds the field _id, and set it to a unique alphanumeric key. Searching by _id is an extremely frequent operation, so moongose provides a dedicated method for it. Find the (only!!) person having a given _id, using Model.findById() -> Person. Use the function argument personId as search key."
],
"challengeSeed": [],
"tests": [
{
"text": "Find an item by Id should succeed",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/find-by-id').then(data => { assert.equal(data.name, 'test', 'item.name is not what expected'); assert.equal(data.age, 0, 'item.age is not what expected'); assert.deepEqual(data.favoriteFoods, ['none'], 'item.favoriteFoods is not what expected'); assert.equal(data.__v, 0, 'The item should be not previously edited'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"translations": {}
},
{
"id": "587d7fb8367417b2b2512c0e",
"title": "Perform Classic Updates by Running Find, Edit, then Save",
"description": [
"In the good old days this was what you needed to do if you wanted to edit a document and be able to use it somehow e.g. sending it back in a server response. Mongoose has a dedicated updating method : Model.update(). It is binded to the low-level mongo driver. It can bulk edit many documents matching certain criteria, but it doesnt send back the updated document, only a status message. Furthermore it makes model validations difficult, because it just directly calls the mongo driver.",
"Find a person by _id ( use any of the above methods ) with the parameter personId as search key. Add “hamburger” to the list of her favoriteFoods (you can use Array.push()). Then - inside the find callback - save() the updated Person.",
"[*] Hint: This may be tricky if in your Schema you declared favoriteFoods as an Array, without specifying the type (i.e. [String]). In that casefavoriteFoods defaults to Mixed type, and you have to manually mark it as edited using document.markModified('edited-field'). (http://mongoosejs.com/docs/schematypes.html - #Mixed )"
],
"challengeSeed": [],
"tests": [
{
"text": "Find-edit-update an item should succeed",
"testString": "getUserInput => $.post(getUserInput('url') + '/_api/find-edit-save', {name:'Poldo', age: 40, favoriteFoods:['spaghetti']}).then(data => { assert.equal(data.name, 'Poldo', 'item.name is not what expected'); assert.equal(data.age, 40, 'item.age is not what expected'); assert.deepEqual(data.favoriteFoods, ['spaghetti', 'hamburger'], 'item.favoriteFoods is not what expected'); assert.equal(data.__v, 1, 'The item should be previously edited'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"translations": {}
},
{
"id": "587d7fb8367417b2b2512c0f",
"title": "Perform New Updates on a Document Using model.findOneAndUpdate()",
"description": [
"Recent versions of mongoose have methods to simplify documents updating. Some more advanced features (i.e. pre/post hooks, validation) behave differently with this approach, so the Classic method is still useful in many situations. findByIdAndUpdate() can be used when searching by Id.",
"Find a person by Name and set her age to 20. Use the function parameter personName as search key.",
"Hint: We want you to return the updated document. o do that you need to pass the options document { new: true } as the 3rd argument to findOneAndUpdate(). By default these methods return the unmodified object."
],
"challengeSeed": [],
"tests": [
{
"text": "findOneAndUpdate an item should succeed",
"testString": "getUserInput => $.post(getUserInput('url') + '/_api/find-one-update', {name:'Dorian Gray', age: 35, favoriteFoods:['unknown']}).then(data => { assert.equal(data.name, 'Dorian Gray', 'item.name is not what expected'); assert.equal(data.age, 20, 'item.age is not what expected'); assert.deepEqual(data.favoriteFoods, ['unknown'], 'item.favoriteFoods is not what expected'); assert.equal(data.__v, 0, 'findOneAndUpdate does not increment version by design !!!'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"translations": {}
},
{
"id": "587d7fb8367417b2b2512c10",
"title": "Delete One Document Using model.findByIdAndRemove",
"description": [
"Delete one person by her _id. You should use one of the methods findByIdAndRemove() or findOneAndRemove(). They are like the previous update methods. They pass the removed document to the cb. As usual, use the function argument personId as search key."
],
"challengeSeed": [],
"tests": [
{
"text": "Deleting an item should succeed",
"testString": "getUserInput => $.post(getUserInput('url') + '/_api/remove-one-person', {name:'Jason Bourne', age: 36, favoriteFoods:['apples']}).then(data => { assert.equal(data.name, 'Jason Bourne', 'item.name is not what expected'); assert.equal(data.age, 36, 'item.age is not what expected'); assert.deepEqual(data.favoriteFoods, ['apples'], 'item.favoriteFoods is not what expected'); assert.equal(data.__v, 0); assert.equal(data.count, 0, 'the db items count is not what expected'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"translations": {}
},
{
"id": "587d7fb8367417b2b2512c11",
"title": "Delete Many Documents with model.remove()",
"description": [
"Model.remove() is useful to delete all the documents matching given criteria. Delete all the people whose name is “Mary”, using Model.remove(). Pass to it a query ducument with the “name” field set, and of course a callback.",
"Note: Model.remove() doesnt return the deleted document, but a JSON object containing the outcome of the operation, and the number of items affected. Dont forget to pass it to the done() callback, since we use it in tests."
],
"challengeSeed": [],
"tests": [
{
"text": "Deleting many items at once should succeed",
"testString": "getUserInput => $.ajax({url: getUserInput('url') + '/_api/remove-many-people', type: 'POST', contentType:'application/json', data: JSON.stringify([{name: 'Mary', age: 16, favoriteFoods: ['lollipop']}, {name: 'Mary', age: 21, favoriteFoods: ['steak']}])}).then(data => { assert.isTrue(!!data.ok, 'The mongo stats are not what expected'); assert.equal(data.n, 2, 'The number of items affected is not what expected'); assert.equal(data.count, 0, 'the db items count is not what expected'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"translations": {}
},
{
"id": "587d7fb9367417b2b2512c12",
"title": "Chain Search Query Helpers to Narrow Search Results",
"description": [
"If you dont pass the callback as the last argument to Model.find() (or to the other search methods), the query is not executed. You can store the query in a variable for later use. This kind of object enables you to build up a query using chaining syntax. The actual db search is executed when you finally chain the method .exec(). Pass your callback to this last method. There are many query helpers, here well use the most famous ones.",
"Find people who like \"burrito\". Sort them by name, limit the results to two documents, and hide their age. Chain .find(), .sort(), .limit(), .select(), and then .exec(). Pass the done(err, data) callback to exec()."
],
"challengeSeed": [],
"tests": [
{
"text": "Chaining query helpers should succeed",
"testString": "getUserInput => $.ajax({url: getUserInput('url') + '/_api/query-tools', type: 'POST', contentType:'application/json', data: JSON.stringify([{name: 'Pablo', age: 26, favoriteFoods: ['burrito', 'hot-dog']}, {name: 'Ashley', age: 32, favoriteFoods: ['steak', 'burrito']}, {name: 'Mario', age: 51, favoriteFoods: ['burrito', 'prosciutto']} ]) }).then(data => { assert.isArray(data, 'the response should be an Array'); assert.equal(data.length, 2, 'the data array length is not what expected'); assert.notProperty(data[0], 'age', 'The returned first item has too many properties'); assert.equal(data[0].name, 'Ashley', 'The returned first item name is not what expected'); assert.notProperty(data[1], 'age', 'The returned second item has too many properties'); assert.equal(data[1].name, 'Mario', 'The returned second item name is not what expected');}, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"translations": {}
}
]
}

View File

@ -0,0 +1,787 @@
{
"name": "Advanced Node and Express",
"order": 3,
"time": "5 hours",
"helpRoom": "Help",
"challenges": [
{
"id": "5895f6fff9fc0f352b528e62",
"title": "Advanced Node/Express Introduction",
"description": [
[
"",
"",
"<em>Authentication</em> is the process or action of verifying the identity of a user or process. Up to this point you have not been able to create an app utilizing this key concept.<br>The most common and easiest to use authentication middleware for Node.js is <a href='http://passportjs.org/'>Passport</a>. It is easy to learn, light-weight, and extremely flexible allowing for many <em>strategies</em>, which we will talk about in later challenges. In addition to authentication we will also look at template engines which allow for use of <em>Pug</em> and web sockets which allow for real time communication between all your clients and your server. Working on these challenges will involve you writing your code on Glitch on our starter project. After completing each challenge you can copy your public glitch url (to the homepage of your app) into the challenge screen to test it! Optionally you may choose to write your project on another platform but it must be publicaly visible for our testing.<br>Start this project on Glitch using <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/'>this link</a> or clone <a href='https://github.com/freeCodeCamp/boilerplate-advancednode/'>this repository</a> on GitHub! If you use Glitch, remember to save the link to your project somewhere safe!",
""
]
],
"releasedOn": "Feb 17, 2017",
"challengeSeed": [],
"tests": [],
"type": "waypoint",
"challengeType": 7,
"isRequired": false,
"translations": {}
},
{
"id": "5895f700f9fc0f352b528e63",
"title": "Set up a Template Engine",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-advancednode/'>GitHub</a>.",
"A template engine enables you to use static template files (such as those written in <em>Pug</em>) in your app. At runtime, the template engine replaces variables in a template file with actual values which can be supplied by your server, and transforms the template into a static HTML file that is then sent to the client. This approach makes it easier to design an HTML page and allows for displaying of variables on the page without needing to make an API call from the client.",
"To set up <em>Pug</em> for use in your project, you will need to add it as a dependency first in your package.json. <code>\"pug\": \"^0.1.0\"</code>",
"Now to tell Node/Express to use the templating engine you will have to tell your express <b>app</b> to <b>set</b> 'pug' as the 'view-engine'. <code>app.set('view engine', 'pug')</code>",
"Lastly, you should change your response to the request for the index route to <code>res.render</code> with the path to the view <em>views/pug/index.pug</em>.",
"If all went as planned, you should refresh your apps home page and see a small message saying you're successfully rending the Pug from our Pug file! Submit your page when you think you've got it right."
],
"challengeSeed": [],
"tests": [
{
"text": "Pug is a dependency",
"testString": "getUserInput => $.get(getUserInput('url')+ '/_api/package.json') .then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, 'pug', 'Your project should list \"pug\" as a dependency'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "View engine is Pug",
"testString": "getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /('|\")view engine('|\"),( |)('|\")pug('|\")/gi, 'Your project should set Pug as a view engine'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "Pug is working",
"testString": "getUserInput => $.get(getUserInput('url')+ '/') .then(data => { assert.match(data, /pug-success-message/gi, 'Your projects home page should now be rendered by pug with the projects .pug file unaltered'); }, xhr => { throw new Error(xhr.statusText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"challengeType": 0,
"translations": {}
},
{
"id": "5895f70bf9fc0f352b528e64",
"title": "Use a Template Engine's Powers",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-advancednode/'>GitHub</a>.",
"One of the greatest features of using a template engine is being able to pass variables from the server to the template file before rendering it to HTML.",
"In your Pug file, you're about to use a variable by referencing the variable name as <code>#{variable_name}</code> inline with other text on an element or by using an equal side on the element without a space such as <code>p= variable_name</code> which sets that p elements text to equal the variable.",
"We strongly recommend looking at the syntax and structure of Pug <a href='https://github.com/pugjs/pug'>here</a> on their Githubs README. Pug is all about using whitespace and tabs to show nested elements and cutting down on the amount of code needed to make a beautiful site.",
"Looking at our pug file 'index.pug' included in your project, we used the variables <em>title</em> and <em>message</em>",
"To pass those alone from our server, you will need to add an object as a second argument to your <em>res.render</em> with the variables and their value. For example, pass this object along setting the variables for your index view: <code>{title: 'Hello', message: 'Please login'</code>",
"It should look like: <code>res.render(process.cwd() + '/views/pug/index', {title: 'Hello', message: 'Please login'});</code>",
"Now refresh your page and you should see those values rendered in your view in the correct spot as layed out in your index.pug file! Submit your page when you think you've got it right."
],
"challengeSeed": [],
"tests": [
{
"text": "Pug render variables correct",
"testString": "getUserInput => $.get(getUserInput('url')+ '/') .then(data => { assert.match(data, /pug-variable(\"|')>Please login/gi, 'Your projects home page should now be rendered by pug with the projects .pug file unaltered'); }, xhr => { throw new Error(xhr.statusText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"challengeType": 0,
"translations": {}
},
{
"id": "5895f70cf9fc0f352b528e65",
"title": "Set up Passport",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-advancednode/'>GitHub</a>.",
"It's time to set up <em>Passport</em> so we can finally start allowing a user to register or login to an account! In addition to Passport, we will use Express-session to handle sessions. Using this middleware saves the session id as a cookie in the client and allows us to access the session data using that id on the server. This way we keep personal account information out of the cookie used by the client to verify to our server they are authenticated and just keep the <em>key</em> to access the data stored on the server.",
"To set up Passport for use in your project, you will need to add it as a dependency first in your package.json. <code>\"passport\": \"^0.3.2\"</code>",
"In addition, add Express-session as a dependency now as well. Express-session has a ton of advanced features you can use but for now we're just going to use the basics! <code>\"express-session\": \"^1.15.0\"</code>",
"You will need to set up the session settings now and initialize Passport. Be sure to first create the variables 'session' and 'passport' to require 'express-session' and 'passport' respectively.",
"To set up your express app to use use the session we'll define just a few basic options. Be sure to add 'SESSION_SECRET' to your .env file and give it a random value. This is used to compute the hash used to encrypt your cookie!",
"<pre>app.use(session({\n secret: process.env.SESSION_SECRET,\n resave: true,\n saveUninitialized: true,\n}));</pre>",
"As well you can go ahead and tell your express app to <b>use</b> 'passport.initialize()' and 'passport.session()'. (For example, <code>app.use(passport.initialize());</code>)",
"Submit your page when you think you've got it right. If you're running into errors, you can check out the project completed up to this point <a href='https://gist.github.com/JosephLivengood/338a9c5a326923c3826a666d430e65c3'>here</a>."
],
"challengeSeed": [],
"tests": [
{
"text": "Passort and Express-session are dependencies",
"testString": "getUserInput => $.get(getUserInput('url')+ '/_api/package.json') .then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, 'passport', 'Your project should list \"passport\" as a dependency'); assert.property(packJson.dependencies, 'express-session', 'Your project should list \"express-session\" as a dependency'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "Dependencies correctly required",
"testString": "getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /require.*(\"|')passport(\"|')/gi, 'You should have required passport'); assert.match(data, /require.*(\"|')express-session(\"|')/gi, 'You should have required express-session'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "Express app uses new dependencies",
"testString": "getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /passport.initialize/gi, 'Your express app should use \"passport.initialize()\"'); assert.match(data, /passport.session/gi, 'Your express app should use \"passport.session()\"'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "Session and session secret correctly set up",
"testString": "getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /secret:( |)process.env.SESSION_SECRET/gi, 'Your express app should have express-session set up with your secret as process.env.SESSION_SECRET'); }, xhr => { throw new Error(xhr.statusText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"challengeType": 0,
"translations": {}
},
{
"id": "5895f70cf9fc0f352b528e66",
"title": "Serialization of a User Object",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-advancednode/'>GitHub</a>.",
"Serialization and deserialization are important concepts in regards to authentication. To serialize an object means to convert its contents into a small <em>key</em> essentially that can then be deserialized into the original object. This is what allows us to know whos communicated with the server without having to send the authentication data like username and password at each request for a new page.",
"To set this up properly, we need to have a serialize function and a deserialize function. In passport we create these with <code>passport.serializeUser( OURFUNCTION )</code> and <code>passport.deserializeUser( OURFUNCTION )</code>",
"The serializeUser is called with 2 arguments, the full user object and a callback used by passport. Returned in the callback should be a unique key to identify that user- the easiest one to use being the users _id in the object as it should be unique as it generated by MongoDb. Similarly deserializeUser is called with that key and a callback function for passport as well, but this time we have to take that key and return the users full object to the callback. To make a query search for a Mongo _id you will have to create <code>const ObjectID = require('mongodb').ObjectID;</code>, and then to use it you call <code>new ObjectID(THE_ID)</code>. Be sure to add MongoDB as a dependency. You can see this in the examples below:",
"<pre>passport.serializeUser((user, done) => {\n done(null, user._id);\n });</pre><br><pre>passport.deserializeUser((id, done) => {\n db.collection('users').findOne(\n {_id: new ObjectID(id)},\n (err, doc) => {\n done(null, doc);\n }\n );\n });</pre>",
"NOTE: This deserializeUser will throw an error until we set up the DB in the next step so comment out the whole block and just call <code>done(null, null)</code> in the function deserializeUser.",
"Submit your page when you think you've got it right."
],
"challengeSeed": [],
"tests": [
{
"text": "Serialize user function correct",
"testString": "getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /passport.serializeUser/gi, 'You should have created your passport.serializeUser function'); assert.match(data, /null, user._id/gi, 'There should be a callback in your serializeUser with (null, user._id)'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "Deserialize user function correct",
"testString": "getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /passport.deserializeUser/gi, 'You should have created your passport.deserializeUser function'); assert.match(data, /null,( |)null/gi, 'There should be a callback in your deserializeUser with (null, null) for now'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "MongoDB is a dependency",
"testString": "getUserInput => $.get(getUserInput('url')+ '/_api/package.json') .then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, 'mongodb', 'Your project should list \"mongodb\" as a dependency'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "Mongodb properly required including the ObjectId",
"testString": "getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /require.*(\"|')mongodb(\"|')/gi, 'You should have required mongodb'); assert.match(data, /new ObjectID.*id/gi, 'Even though the block is commented out, you should use new ObjectID(id) for when we add the database'); }, xhr => { throw new Error(xhr.statusText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"challengeType": 0,
"translations": {}
},
{
"id": "5895f70cf9fc0f352b528e67",
"title": "Implement the Serialization of a Passport User",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-advancednode/'>GitHub</a>.",
"Right now we're not loading an actually users object since we haven't set up our database. This can be done many different ways, but for our project we will connect to the database once when we start the server and keep a persistent connection for the full life-cycle of the app.",
"To do this, add MongoDB as a dependency and require it in your server. (<code>const mongo = require('mongodb').MongoClient;</code>)",
"Now we want to the connect to our database then start listening for requests. The purpose of this is to not allow requests before our database is connected or if there is a database error. To accomplish you will want to encompass your serialization and your app listener in the following:",
"<pre>mongo.connect(process.env.DATABASE, (err, db) => {\n if(err) {\n console.log('Database error: ' + err);\n } else {\n console.log('Successful database connection');\n\n //serialization and app.listen\n\n}});</pre>",
"You can now uncomment the block in deserializeUser and remove your <code>done(null, null)</code>. Be sure to set <em>DATABASE</em> in your .env file to your database's connection string (for example: <code>DATABASE=mongodb://admin:pass@mlab.com:12345/my-project</code>). You can set up a free database on <a href='https://mlab.com/welcome/'>mLab</a>. Congratulations- you've finished setting up serialization!",
"Submit your page when you think you've got it right. If you're running into errors, you can check out the project completed up to this point <a href='https://gist.github.com/JosephLivengood/e192e809a1d27cb80dc2c6d3467b7477'>here</a>."
],
"challengeSeed": [],
"tests": [
{
"text": "Database connection is present",
"testString": "getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /mongo.connect/gi, 'You should have created a connection to your database'); assert.match(data, /mongo.connect[^]*app.listen[^]*}[^]*}/gi, 'You should have your app.listen nested at within your database connection at the bottom'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "Deserialization is now correctly using the DB and <code>done(null, null)</code> is erased",
"testString": "getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.notMatch(data, /null,( |)null/gi, 'The callback in deserializeUser of (null, null) should be completely removed for the db block uncommented out'); }, xhr => { throw new Error(xhr.statusText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"challengeType": 0,
"translations": {}
},
{
"id": "5895f70df9fc0f352b528e68",
"title": "Authentication Strategies",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-advancednode/'>GitHub</a>.",
"A strategy is a way of authenticating a user. You can use a strategy for allowing users to authenticate based on locally saved information (if you have them register first) or from a variety of providers such as Google or Github. For this project we will set up a local strategy. To see a list of the 100's of strategies, visit Passports site <a href='http://passportjs.org/'>here</a>.",
"Add <em>passport-local</em> as a dependency and add it to your server as follows: <code>const LocalStrategy = require('passport-local');</code>",
"Now you will have to tell passport to <b>use</b> an instantiated LocalStartegy object with a few settings defined. Make sure this as well as everything from this point on is encapsulated in the database connection since it relies on it! <pre>passport.use(new LocalStrategy(\n function(username, password, done) {\n db.collection('users').findOne({ username: username }, function (err, user) {\n console.log('User '+ username +' attempted to log in.');\n if (err) { return done(err); }\n if (!user) { return done(null, false); }\n if (password !== user.password) { return done(null, false); }\n return done(null, user);\n });\n }\n));</pre> This is defining the process to take when we try to authenticate someone locally. First it tries to find a user in our database with the username entered, then it checks for the password to match, then finally if no errors have popped up that we checked for, like an incorrect password, the users object is returned and they are authenticated.",
"Many strategies are set up using different settings, general it is easy to set it up based on the README in that strategies repository though. A good example of this is the Github strategy where we don't need to worry about a username or password because the user will be sent to Github's auth page to authenticate and as long as they are logged in and agree then Github returns their profile for us to use.",
"In the next step we will set up how to actually call the authentication strategy to validate a user based on form data! Submit your page when you think you've got it right up to this point."
],
"challengeSeed": [],
"tests": [
{
"text": "Passport-local is a dependency",
"testString": " getUserInput => $.get(getUserInput('url')+ '/_api/package.json') .then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, 'passport-local', 'Your project should list \"passport-local \" as a dependency'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "Passport-local correctly required and setup",
"testString": "getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /require.*(\"|')passport-local(\"|')/gi, 'You should have required passport-local'); assert.match(data, /new LocalStrategy/gi, 'You should have told passport to use a new strategy'); assert.match(data, /findOne/gi, 'Your new local strategy should use the findOne query to find a username based on the inputs'); }, xhr => { throw new Error(xhr.statusText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"challengeType": 0,
"translations": {}
},
{
"id": "5895f70df9fc0f352b528e69",
"title": "How to Use Passport Strategies",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-advancednode/'>GitHub</a>.",
"In the index.pug file supplied there is actually a login form. It has previously been hidden because of the inline javascript <code>if showLogin</code> with the form indented after it. Before showLogin as a variable was never defined, it never rendered the code block containing the form. Go ahead and on the res.render for that page add a new variable to the object <code>showLogin: true</code>. When you refresh your page, you should then see the form! This form is set up to <b>POST</b> on <em>/login</em> so this is where we should set up to accept the POST and authenticate the user.",
"For this challenge you should add the route /login to accept a POST request. To authenticate on this route you need to add a middleware to do so before then sending a response. This is done by just passing another argument with the middleware before your <code>function(req,res)</code> with your response! The middleware to use is <code>passport.authenticate('local')</code>.",
"<em>passport.authenticate</em> can also take some options as an argument such as: <code>{ failureRedirect: '/' }</code> which is incredibly useful so be sure to add that in as well. As a response after using the middleware (which will only be called if the authentication middleware passes) should be to redirect the user to <em>/profile</em> and that route should render the view 'profile.pug'.",
"If the authentication was successful, the user object will be saved in <em>req.user</em>.",
"Now at this point if you enter a username and password in the form, it should redirect to the home page <em>/</em> and in the console of your server should be 'User {USERNAME} attempted to log in.' since we currently cannot login a user who isn't registered.",
"Submit your page when you think you've got it right. If you're running into errors, you can check out the project completed up to this point <a href='https://gist.github.com/JosephLivengood/8a335d1a68ed9170da02bb9d8f5b71d5'>here</a>."
],
"challengeSeed": [],
"tests": [
{
"text": "All steps correctly implemented in the server.js",
"testString": " getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /showLogin:( |)true/gi, 'You should be passing the variable \"showLogin\" as true to your render function for the homepage'); assert.match(data, /failureRedirect:( |)('|\")\\/('|\")/gi, 'Your code should include a failureRedirect to the \"/\" route'); assert.match(data, /login[^]*post[^]*local/gi, 'You should have a route for login which accepts a POST and passport.authenticates local'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "A POST request to /login correctly redirects to /",
"testString": "getUserInput => $.post(getUserInput('url')+ '/login') .then(data => { assert.match(data, /Home page/gi, 'A login attempt at this point should redirect to the homepage since we do not have any registered users'); }, xhr => { throw new Error(xhr.statusText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"challengeType": 0,
"translations": {}
},
{
"id": "5895f70df9fc0f352b528e6a",
"title": "Create New Middleware",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-advancednode/'>GitHub</a>.",
"As in, any user can just go to /profile whether they authenticated or not by typing in the url. We want to prevent this by checking if the user is authenticated first before rendering the profile page. This is the perfect example of when to create a middleware.",
"The challenge here is creating the middleware function <code>ensureAuthenticated(req, res, next)</code>, which will check if a user is authenticated by calling passports isAuthenticated on the <em>request</em> which in turn checks for <em>req.user</em> is to be defined. If it is then <em>next()</em> should be called, otherwise we can just respond to the request with a redirect to our homepage to login. An implementation of this middleware is:",
"<pre>function ensureAuthenticated(req, res, next) {\n if (req.isAuthenticated()) {\n return next();\n }\n res.redirect('/');\n};</pre>",
"Now add <em>ensureAuthenticated</em> as a middleware to the request for the profile page before the argument to the get request containing the function that renders the page.",
"<pre>app.route('/profile')\n .get(ensureAuthenticated, (req,res) => {\n res.render(process.cwd() + '/views/pug/profile');\n });</pre>",
"Submit your page when you think you've got it right."
],
"challengeSeed": [],
"tests": [
{
"text": "Middleware ensureAuthenticated should be implemented and on our /profile route",
"testString": "getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /ensureAuthenticated[^]*req.isAuthenticated/gi, 'Your ensureAuthenticated middleware should be defined and utilize the req.isAuthenticated function'); assert.match(data, /profile[^]*get[^]*ensureAuthenticated/gi, 'Your ensureAuthenticated middleware should be attached to the /profile route'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "A Get request to /profile correctly redirects to / since we are not authenticated",
"testString": "getUserInput => $.get(getUserInput('url')+ '/profile') .then(data => { assert.match(data, /Home page/gi, 'An attempt to go to the profile at this point should redirect to the homepage since we are not logged in'); }, xhr => { throw new Error(xhr.statusText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"challengeType": 0,
"translations": {}
},
{
"id": "5895f70ef9fc0f352b528e6b",
"title": "How to Put a Profile Together",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-advancednode/'>GitHub</a>.",
"Now that we can ensure the user accessing the <em>/profile</em> is authenticated, we can use the information contained in 'req.user' on our page!",
"Go ahead and pass the object containing the variable <em>username</em> equaling 'req.user.username' into the render method of the profile view. Then go to your 'profile.pug' view and add the line <code>h2.center#welcome Welcome, #{username}!</code> creating the h2 element with the class 'center' and id 'welcome' containing the text 'Welcome, ' and the username!",
"Also in the profile, add a link to <em>/logout</em>. That route will host the logic to unauthenticate a user. <code>a(href='/logout') Logout</code>",
"Submit your page when you think you've got it right."
],
"challengeSeed": [],
"tests": [
{
"text": "Correctly added a Pug render variable to /profile",
"testString": "getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /\\/views\\/pug\\/profile[^]*username:( |)req.user.username/gi, 'You should be passing the variable username with req.user.username into the render function of the profile page'); }, xhr => { throw new Error(xhr.statusText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"challengeType": 0,
"translations": {}
},
{
"id": "58965611f9fc0f352b528e6c",
"title": "Logging a User Out",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-advancednode/'>GitHub</a>.",
"Creating the logout logic is easy. The route should just unauthenticate the user and redirect to the home page instead of rendering any view.",
"In passport, unauthenticating a user is as easy as just calling <code>req.logout();</code> before redirecting.",
"<pre>app.route('/logout')\n .get((req, res) => {\n req.logout();\n res.redirect('/');\n });</pre>",
"You may have noticed we also we're not handling missing pages (404), the common way to handle this in Node is with the following middleware. Go ahead and add this in after all your other routes:",
"<pre>app.use((req, res, next) => {\n res.status(404)\n .type('text')\n .send('Not Found');\n});</pre>",
"Submit your page when you think you've got it right."
],
"challengeSeed": [],
"tests": [
{
"text": "Logout route",
"testString": "getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /req.logout/gi, 'You should be call req.logout() in youre /logout route'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "Logout should redirect to the home page /",
"testString": "getUserInput => $.get(getUserInput('url')+ '/logout') .then(data => { assert.match(data, /Home page/gi, 'When a user logs out they should be redirected to the homepage'); }, xhr => { throw new Error(xhr.statusText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"challengeType": 0,
"translations": {}
},
{
"id": "58966a17f9fc0f352b528e6d",
"title": "Registration of New Users",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-advancednode/'>GitHub</a>.",
"Now we need to allow a new user on our site to register an account. On the res.render for the home page add a new variable to the object passed along- <code>showRegistration: true</code>. When you refresh your page, you should then see the registration form that was already created in your index.pug file! This form is set up to <b>POST</b> on <em>/register</em> so this is where we should set up to accept the POST and create the user object in the database.",
"The logic of the registration route should be as follows: Register the new user > Authenticate the new user > Redirect to /profile",
"The logic of step 1, registering the new user, should be as follows: Query database with a findOne command > if user is returned then it exists and redirect back to home <em>OR</em> if user is undefined and no error occurs then 'insertOne' into the database with the username and password and as long as no errors occur then call <em>next</em> to go to step 2, authenticating the new user, which we've already written the logic for in our POST /login route.",
"<pre>app.route('/register')\n .post((req, res, next) => {\n db.collection('users').findOne({ username: req.body.username }, function (err, user) {\n if(err) {\n next(err);\n } else if (user) {\n res.redirect('/');\n } else {\n db.collection('users').insertOne(\n {username: req.body.username,\n password: req.body.password},\n (err, doc) => {\n if(err) {\n res.redirect('/');\n } else {\n next(null, user);\n }\n }\n )\n }\n })},\n passport.authenticate('local', { failureRedirect: '/' }),\n (req, res, next) => {\n res.redirect('/profile');\n }\n);</pre>",
"Submit your page when you think you've got it right. If you're running into errors, you can check out the project completed up to this point <a href='https://gist.github.com/JosephLivengood/6c47bee7df34df9f11820803608071ed'>here</a>."
],
"challengeSeed": [],
"tests": [
{
"text": "Register route and display on home",
"testString": "getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /showRegistration:( |)true/gi, 'You should be passing the variable \"showRegistration\" as true to your render function for the homepage'); assert.match(data, /register[^]*post[^]*findOne[^]*username:( |)req.body.username/gi, 'You should have a route accepted a post request on register that querys the db with findone and the query being \"username: req.body.username\"'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "Registering should work",
"testString": "getUserInput => $.ajax({url: getUserInput('url')+ '/register',data: {username: 'freeCodeCampTester', password: 'freeCodeCampTester'},crossDomain: true, type: 'POST', xhrFields: { withCredentials: true }}) .then(data => { assert.match(data, /Profile/gi, 'I should be able to register and it direct me to my profile. CLEAR YOUR DATABASE if this test fails (each time until its right!)'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "Login should work",
"testString": "getUserInput => $.ajax({url: getUserInput('url')+ '/login',data: {username: 'freeCodeCampTester', password: 'freeCodeCampTester'}, type: 'POST', xhrFields: { withCredentials: true }}) .then(data => { assert.match(data, /Profile/gi, 'Login should work if previous test was done successfully and redirect successfully to the profile. Check your work and clear your DB'); assert.match(data, /freeCodeCampTester/gi, 'The profile should properly display the welcome to the user logged in'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "Logout should work",
"testString": "getUserInput => $.ajax({url: getUserInput('url')+ '/logout', type: 'GET', xhrFields: { withCredentials: true }}) .then(data => { assert.match(data, /Home/gi, 'Logout should redirect to home'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "Profile should no longer work after logout",
"testString": "getUserInput => $.ajax({url: getUserInput('url')+ '/profile', type: 'GET', crossDomain: true, xhrFields: { withCredentials: true }}) .then(data => { assert.match(data, /Home/gi, 'Profile should redirect to home when we are logged out now again'); }, xhr => { throw new Error(xhr.statusText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"challengeType": 0,
"translations": {}
},
{
"id": "58a25c98f9fc0f352b528e7f",
"title": "Hashing Your Passwords",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-advancednode/'>GitHub</a>.",
"Going back to the information security section you may remember that storing plaintext passwords is <em>never</em> okay. Now it is time to implement BCrypt to solve this issue.",
"<hr>Add BCrypt as a dependency and require it in your server. You will need to handle hashing in 2 key areas: where you handle registering/saving a new account and when you check to see that a password is correct on login.",
"Currently on our registeration route, you insert a user's password into the database like the following: <code>password: req.body.password</code>. An easy way to implement saving a hash instead is to add the following before your database logic <code>var hash = bcrypt.hashSync(req.body.password, 8);</code> and replacing the <code>req.body.password</code> in the database saving with just <code>password: hash</code>. (In our small scale app, it is fine to use sync hashing especially with a low cost of 8 as it wont block the thread very much at all)",
"Finally on our authentication strategy we check for the following in our code before completing the process: <code>if (password !== user.password) { return done(null, false); }</code>. After making the previous changes, now <code>user.password</code> is a hash. Before making a change to the existing code, notice how the statement is checking if the password is NOT equal then return non-authenticated. With this in mind your code could look as follows to properly check the password entered against the hash: <code>if (!bcrypt.compareSync(password, user.password)) { return done(null, false); }</code>",
"That is all it takes to implement one of the most important security features when you have to store passwords! Submit your page when you think you've got it right."
],
"challengeSeed": [],
"tests": [
{
"text": "BCrypt is a dependency",
"testString": " getUserInput => $.get(getUserInput('url')+ '/_api/package.json') .then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, 'bcrypt', 'Your project should list \"bcrypt\" as a dependency'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "BCrypt correctly required and implemented",
"testString": "getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /require.*(\"|')bcrypt(\"|')/gi, 'You should have required bcrypt'); assert.match(data, /bcrypt.hash/gi, 'You should use hash the password in the registration'); assert.match(data, /bcrypt.compare/gi, 'You should compare the password to the hash in your strategy'); }, xhr => { throw new Error(xhr.statusText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"challengeType": 0,
"translations": {}
},
{
"id": "589690e6f9fc0f352b528e6e",
"title": "Clean Up Your Project with Modules",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-advancednode/'>GitHub</a>.",
"Right now everything you have is in your server.js file. This can lead to hard to manage code that isn't very expandable.",
"Create 2 new files: Routes.js and Auth.js",
"Both should start with the following code: <pre>module.exports = function (app, db) {\n\n\n}</pre>",
"Now in the top of your server file, require these files like such: <code>const routes = require('./routes.js');</code>",
"Right after you establish a successful connect with the database instantiate each of them like such: <code>routes(app, db)</code>",
"Finally, take all of the routes in your server and paste them into your new files and remove them from your server file. Also take the ensureAuthenticated since we created that middleware function for routing specifically. You will have to now correctly add the dependencies in that are used, such as <code>const passport = require('passport');</code>, at the very top above the export line in your routes.js file.",
"Keep adding them until no more errors exist, and your server file no longer has any routing!",
"Now do the same thing in your auth.js file with all of the things related to authentication such as the serialization and the setting up of the local strategy and erase them from your server file. Be sure to add the dependencies in and call <code>auth(app,db)</code> in the server in the same spot. Be sure to have <code>auth(app, db)</code> before <code>routes(app, db)</code> since our registration route depends on passport being initiated!",
"Congratulations- you're at the end of this section of Advanced Node and Express and have some beautiful code to show for it! Submit your page when you think you've got it right. If you're running into errors, you can check out an example of the completed project <a href='https://glitch.com/#!/project/delicious-herring'>here</a>."
],
"challengeSeed": [],
"tests": [
{
"text": "Modules present",
"testString": "getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /require.*(\"|').\\/routes.js(\"|')/gi, 'You should have required your new files'); assert.match(data, /mongo.connect[^]*routes/gi, 'Your new modules should be called after your connection to the database'); }, xhr => { throw new Error(xhr.statusText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"challengeType": 0,
"translations": {}
},
{
"id": "589a69f5f9fc0f352b528e6f",
"title": "Social Authentication with OAuth",
"description": [
[
"",
"",
"OAuth 2.0 is the industry-standard authorization and is used across the internet for social login such as letting you login to freeCodeCamp with your Github account.<br>Implementing social login with passport using OAuth is extremely easy to do because of the <a href='http://passportjs.org/'>300+ modules</a> already on npm for adding new strategies to your app. In addition to the ease of installation, it is also easier to use because you do not have to deal with a separate <em>registration</em> or any user input.<br>Start this project on Glitch using <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-socialauth/'>this link</a> or clone <a href='https://github.com/freeCodeCamp/boilerplate-socialauth/'>this repository</a> on GitHub! If you use Glitch, remember to save the link to your project somewhere safe. Be sure to enter your database in the .env file- it can be the same one from last project since you'll be using a new collection!",
""
]
],
"releasedOn": "Feb 17, 2017",
"challengeSeed": [],
"tests": [],
"type": "waypoint",
"challengeType": 7,
"isRequired": false,
"translations": {}
},
{
"id": "589a69f5f9fc0f352b528e70",
"title": "Implementation of Social Authentication",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-socialauth/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-socialauth/'>GitHub</a>.",
"The basic path this kind of authentication will follow in your app is: <ol><li>User clicks a button or link sending them to our route to authenticate using a specific strategy (EG. Github)</li><li>Your route calls <code>passport.authenticate('github')</code> which redirects them to Github.</li><li>The page the user lands on, on Github, allows them to login if they aren't already then asks them to approve access to their profile from our app.</li><li>The user is then returned to our app at a specific callback url with their profile if they approved.</li><li>They are now authenticated and your app should check if it is a returning profile, or save it in your database if it is not.</li></ol>",
"Strategies with OAuth require you to have at least a <em>Client ID</em> and a <em>Client Secret</em> which is a way for them to verify who the authentication request is coming from and if it is valid. These are obtained from the site you are trying to implement authentication with, such as Github, and are unique to your app- <b>THEY ARE NOT TO BE SHARED</b> and should never be uploaded to a public repository or written directly in your code. A common practice is to put them in your <em>.env</em> file and reference them like: <code>process.env.GITHUB_CLIENT_ID</code>. For this challenge we're going to use the Github strategy.",
"Obtaining your <em>Client ID and Secret<em> from Github is done in your account profile settings under 'developer settings', then '<a href='https://github.com/settings/developers'>OAuth applications</a>'. Click 'Register a new application', name your app, paste in the url to your glitch homepage (<b>Not the project code's url</b>), and lastly for the callback url, paste in the same url as the homepage but with '/auth/github/callback' added on. This is where users will be redirected to for us to handle after authenticating on Github. Save the returned information as 'GITHUB_CLIENT_ID' and 'GITHUB_CLIENT_SECRET' in your .env file.",
"On your remixed project, create 2 routes accepting GET requests: /auth/github and /auth/github/callback. The first should only call passport to authenticate 'github' and the second should call passport to authenticate 'github' with a failure redirect to '/' and then if that is successful redirect to '/profile' (similar to our last project).",
"An example of how '/auth/github/callback' should look is similar to how we handled a normal login in our last project: <pre>app.route('/login')\n .post(passport.authenticate('local', { failureRedirect: '/' }), (req,res) => { \n res.redirect('/profile'); \n });</pre>",
"Submit your page when you think you've got it right. If you're running into errors, you can check out the project up to this point <a href='https://gist.github.com/JosephLivengood/28ea2cae7e1dc6a53d7f0c42d987313b'>here</a>."
],
"challengeSeed": [],
"tests": [
{
"text": "Route /auth/github correct",
"testString": "getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /('|\")\\/auth\\/github('|\")[^]*get.*passport.authenticate.*github/gi, 'Route auth/github should only call passport.authenticate with github'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "Route /auth/github/callback correct",
"testString": "getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /('|\")\\/auth\\/github\\/callback('|\")[^]*get.*passport.authenticate.*github.*failureRedirect:( |)(\"|')\\/(\"|')/gi, 'Route auth/github/callback should accept a get request and call passport.authenticate for github with a failure redirect to home'); }, xhr => { throw new Error(xhr.statusText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"challengeType": 0,
"translations": {}
},
{
"id": "589a69f5f9fc0f352b528e71",
"title": "Implementation of Social Authentication II",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-socialauth/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-socialauth/'>GitHub</a>.",
"The last part of setting up your Github authentication is to create the strategy itself. For this, you will need to add the dependency of 'passport-github' to your project and require it as GithubStrategy like <code>const GitHubStrategy = require('passport-github').Strategy;</code>.",
"To set up the Github strategy, you have to tell <b>passport</b> to <b>use</b> an instantiated <b>GithubStrategy</b>, which accepts 2 arguments: An object (containing <em>clientID</em>, <em>clientSecret</em>, and <em>callbackURL</em>) and a function to be called when a user is successfully authenticated which we will determine if the user is new and what fields to save initially in the user's database object. This is common across many strategies but some may require more information as outlined in that specific strategy's github README; for example, Google requires a <em>scope</em> as well which determines what kind of information your request is asking returned and asks the user to approve such access. The current strategy we are implementing has its usage outlined <a>here</a>, but we're going through it all right here on freeCodeCamp!",
"Here's how your new strategy should look at this point: <pre>passport.use(new GitHubStrategy({\n clientID: process.env.GITHUB_CLIENT_ID,\n clientSecret: process.env.GITHUB_CLIENT_SECRET,\n callbackURL: /*INSERT CALLBACK URL ENTERED INTO GITHUB HERE*/\n },\n function(accessToken, refreshToken, profile, cb) {\n console.log(profile);\n //Database logic here with callback containing our user object\n }\n));</pre>",
"Your authentication won't be successful yet, and actually throw an error, without the database logic and callback, but it should log to your console your Github profile if you try it!",
"Submit your page when you think you've got it right."
],
"challengeSeed": [],
"tests": [
{
"text": "Dependency added",
"testString": "getUserInput => $.get(getUserInput('url')+ '/_api/package.json') .then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, 'passport-github', 'Your project should list \"passport-github\" as a dependency'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "Dependency required",
"testString": "getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /require.*(\"|')passport-github(\"|')/gi, 'You should have required passport-github'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "Github strategy setup correctly thus far",
"testString": "getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /passport.use.*new GitHubStrategy/gi, 'Passport should use a new GitHubStrategy'); assert.match(data, /callbackURL:( |)(\"|').*(\"|')/gi, 'You should have a callbackURL'); assert.match(data, /process.env.GITHUB_CLIENT_SECRET/g, 'You should use process.env.GITHUB_CLIENT_SECRET'); assert.match(data, /process.env.GITHUB_CLIENT_ID/g, 'You should use process.env.GITHUB_CLIENT_ID'); }, xhr => { throw new Error(xhr.statusText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"challengeType": 0,
"translations": {}
},
{
"id": "589a8eb3f9fc0f352b528e72",
"title": "Implementation of Social Authentication III",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-socialauth/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-socialauth/'>GitHub</a>.",
"The final part of the strategy is handling the profile returned from Github. We need to load the users database object if it exists or create one if it doesn't and populate the fields from the profile, then return the user's object. Github supplies us a unique <em>id</em> within each profile which we can use to search with to serialize the user with (already implemented). Below is an example implementation you can use in your project- it goes within the function that is the second argument for the new strategy, right below the <code>console.log(profile);</code> currently is:",
"<pre>db.collection('socialusers').findAndModify(\n {id: profile.id},\n {},\n {$setOnInsert:{\n id: profile.id,\n name: profile.displayName || 'John Doe',\n photo: profile.photos[0].value || '',\n email: profile.emails[0].value || 'No public email',\n created_on: new Date(),\n provider: profile.provider || ''\n },$set:{\n last_login: new Date()\n },$inc:{\n login_count: 1\n }},\n {upsert:true, new: true},\n (err, doc) => {\n return cb(null, doc.value);\n }\n);</pre>",
"With a findAndModify, it allows you to search for an object and update it, as well as upsert the object if it doesn't exist and receive the new object back each time in our callback function. In this example, we always set the last_login as now, we always increment the login_count by 1, and only when we insert a new object(new user) do we populate the majority of the fields. Something to notice also is the use of default values. Sometimes a profile returned won't have all the information filled out or it will have been chosen by the user to remain private; so in this case we have to handle it to prevent an error.",
"You should be able to login to your app now- try it! Submit your page when you think you've got it right. If you're running into errors, you can check out an example of this mini-project's finished code <a href='https://glitch.com/#!/project/guttural-birch'>here</a>."
],
"challengeSeed": [],
"tests": [
{
"text": "Github strategy setup complete",
"testString": "getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /GitHubStrategy[^]*db.collection/gi, 'Strategy should use now use the database to search for the user'); assert.match(data, /GitHubStrategy[^]*socialusers/gi, 'Strategy should use \"socialusers\" as db collection'); assert.match(data, /GitHubStrategy[^]*return cb/gi, 'Strategy should return the callback function \"cb\"'); }, xhr => { throw new Error(xhr.statusText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"challengeType": 0,
"translations": {}
},
{
"id": "589fc820f9fc0f352b528e73",
"title": "Socket.IO Introduction",
"description": [
[
"",
"",
"<dfn>Socket.IO</dfn> enables real-time, reliable, speedy communication between your server and clients from all devices and browsers. It listens for connects on your server that come from the client which connects with a single javascript statement. The whole library is based on emitting, broadcasting, and recieving events that contain an event name and some data which can include things like strings, objects, arrays, and even blobs like files or video. This is used for all sorts of purposes including instant messaging online, real-time analytics, streaming, and document collaboration.<br>Start this project on Glitch using <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-socketio/'>this link</a> or clone <a href='https://github.com/freeCodeCamp/boilerplate-socketio/'>this repository</a> on GitHub! If you use Glitch, remember to save the link to your project somewhere safe.",
""
],
[
"",
"",
"To set up this project to get started now in the .env file:<ol><li>Create a random session secret</li><li>Fill in the database (it may be the same as the last few projects since this will use a new collection)</li><li>Obtain another set of Github OAuth credentials with the callback once again pointed at '/auth/github/callback' and add it in</li></ol>",
""
],
[
"",
"",
"A few changes have been made to this starter.<br>Instead of <code>app.listen</code>, you now have <pre>const http = require('http').Server(app);\n\nhttp.listen(process.env.PORT || 3000);</pre> This is required because for the initial handshake between the server and client, http is used. Setting up our server like this allows us to have both processes use a single port.<br>Also, we have declared <code>const sessionStore = new session.MemoryStore();</code> and used <code>sessionStore</code> as the store in our express session. In our previous apps we have not done this because by default it is done automattically. It is not this way so we can reference/use the <code>sessionStore</code> in other parts of our code now. In addition, we've given our session a key to reference it easier.",
""
]
],
"releasedOn": "Feb 17, 2017",
"challengeSeed": [],
"tests": [],
"type": "waypoint",
"challengeType": 7,
"isRequired": false,
"titleEs": "",
"descriptionEs": [
[]
],
"titleFr": "",
"descriptionFr": [
[]
],
"titleDe": "",
"descriptionDe": [
[]
]
},
{
"id": "589fc830f9fc0f352b528e74",
"title": "Set up the Enviroment",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-socketio/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-socketio/'>GitHub</a>.",
"Add Socket.IO as a dependency and require/instanciate it in your server defined as 'io' with the http server as an argument. <code>const io = require('socket.io')(http);</code>",
"The first thing needing to be handled is listening for a new connection from the client. The <dfn>on</dfn> keyword does just that- listen for a specific event. It requires 2 arguments: a string containing the title of the event thats emitted, and a function with which the data is passed though. In the case of our connection listener, we use <em>socket</em> to define the data in the second argument. A socket is an individual client who is connected.",
"For listening for connections on our server, add the following between the comments in your project:<pre>io.on('connection', socket => {\n console.log('A user has connected');\n});</pre>",
"Now for the client to connect, you just need to add the following to your client.js which is loaded by the page after you've authenticated: <pre>/*global io*/\nvar socket = io();</pre>The comment supresses the error you would normally see since 'io' is not defined in the file. We've already added a reliable CDN to the Socket.IO library on the page in chat.pug.",
"Now try loading up your app and authenticate and you should see in your server console 'A user has connected'!",
"<strong>Note</strong><br><code>io()</code> works only when connecting to a socket hosted on the same url/server. For connecting to an external socket hosted elsewhere, you would use <code>io.connect('URL');</code>.",
"Submit your page when you think you've got it right."
],
"challengeSeed": [],
"tests": [
{
"text": "Socket.IO is a dependency",
"testString": "getUserInput => $.get(getUserInput('url')+ '/_api/package.json') .then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, 'socket.io', 'Your project should list \"socket.io\" as a dependency'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "Socket.IO has been properly required and instanciated",
"testString": "getUserInput => $.get(getUserInput('url')+ '/_api/server.js').then(data => {assert.match(data, /io.*=.*require.*('|\")socket.io('|\").*http/gi, 'You should correctly require and instanciate socket.io as io.');}, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "Socket.IO should be listening for connections",
"testString": "getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /io.on.*('|\")connection('|\").*socket/gi, 'io should listen for \"connection\" and socket should be the 2nd arguments variable'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "Your client should connect to your server",
"testString": "getUserInput => $.get(getUserInput('url')+ '/public/client.js') .then(data => { assert.match(data, /socket.*=.*io/gi, 'Your client should be connection to server with the connection defined as socket'); }, xhr => { throw new Error(xhr.statusText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"challengeType": 0,
"translations": {}
},
{
"id": "589fc831f9fc0f352b528e75",
"title": "Communicate by Emitting",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-socketio/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-socketio/'>GitHub</a>.",
"<dfn>Emit</dfn> is the most common way of communicating you will use. When you emit something from the server to 'io', you send an event's name and data to all the connected sockets. A good example of this concept would be emiting the current count of connected users each time a new user connects!",
"<hr>Start by adding a variable to keep track of the users just before where you are currently listening for connections. <code>var currentUsers = 0;</code>",
"Now when someone connects you should increment the count before emiting the count so you will want to add the incrementer within the connection listener. <code>++currentUsers;</code>",
"Finally after incrementing the count, you should emit the event(still within the connection listener). The event should be named 'user count' and the data should just be the 'currentUsers'. <code>io.emit('user count', currentUsers);</code>",
"<hr>Now you can implement a way for your client to listen for this event! Similarly to listening for a connection on the server you will use the <em>on</em> keyword. <pre>socket.on('user count', function(data){\n console.log(data);\n});</pre>",
"Now try loading up your app and authenticate and you should see in your client console '1' representing the current user count! Try loading more clients up and authenticating to see the number go up.",
"Submit your page when you think you've got it right."
],
"challengeSeed": [],
"tests": [
{
"text": "currentUsers is defined",
"testString": "getUserInput => $.get(getUserInput('url')+ '/_api/server.js').then(data => {assert.match(data, /currentUsers/gi, 'You should have variable currentUsers defined');}, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "Server emits the current user count at each new connection",
"testString": "getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /io.emit.*('|\")user count('|\").*currentUsers/gi, 'You should emit \"user count\" with data currentUsers'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "Your client is listening for 'user count' event",
"testString": "getUserInput => $.get(getUserInput('url')+ '/public/client.js') .then(data => { assert.match(data, /socket.on.*('|\")user count('|\")/gi, 'Your client should be connection to server with the connection defined as socket'); }, xhr => { throw new Error(xhr.statusText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"challengeType": 0,
"translations": {}
},
{
"id": "589fc831f9fc0f352b528e76",
"title": "Handle a Disconnect",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-socketio/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-socketio/'>GitHub</a>.",
"You may notice that up to now you have only been increasing the user count. Handling a user disconnecting is just as easy as handling the initial connect except the difference is you have to listen for it on each socket versus on the whole server.",
"<hr>To do this, add in to your existing connect listener a listener that listens for 'disconnect' on the socket with no data passed through. You can test this functionality by just logging to the console a user has disconnected. <code>socket.on('disconnect', () => { /*anything you want to do on disconnect*/ });</code>",
"To make sure clients continuously have the updated count of current users, you should decrease the currentUsers by 1 when the disconnect happens then emit the 'user count' event with the updated count!",
"<strong>Note</strong><br>Just like 'disconnect', all other events that a socket can emit to the server should be handled within the connecting listener where we have 'socket' defined.",
"Submit your page when you think you've got it right."
],
"challengeSeed": [],
"tests": [
{
"text": "Server handles the event disconnect from a socket",
"testString": "getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /socket.on.*('|\")disconnect('|\")/gi, ''); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "Your client is listening for 'user count' event",
"testString": "getUserInput => $.get(getUserInput('url')+ '/public/client.js') .then(data => { assert.match(data, /socket.on.*('|\")user count('|\")/gi, 'Your client should be connection to server with the connection defined as socket'); }, xhr => { throw new Error(xhr.statusText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"challengeType": 0,
"translations": {}
},
{
"id": "589fc831f9fc0f352b528e77",
"title": "Authentication with Socket.IO",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-socketio/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-socketio/'>GitHub</a>.",
"Currently, you cannot determine who is connected to your web socket. While 'req.user' containers the user object, thats only when your user interacts with the web server and with web sockets you have no req (request) and therefor no user data. One way to solve the problem of knowing who is connected to your web socket is by parsing and decoding the cookie that contains the passport session then deserializing it to obtain the user object. Luckily, there is a package on NPM just for this that turns a once complex task into something simple!",
"<hr>Add 'passport.socketio' as a dependency and require it as 'passportSocketIo'.",
"Now we just have to tell Socket.IO to use it and set the options. Be sure this is added before the existing socket code and not in the existing connection listener. For your server it should look as follows:<pre>io.use(passportSocketIo.authorize({\n cookieParser: cookieParser,\n key: 'express.sid',\n secret: process.env.SESSION_SECRET,\n store: sessionStore\n}));</pre>You can also optionally pass 'success' and 'fail' with a function that will be called after the authentication process completes when a client trys to connect.",
"The user object is now accessable on your socket object as <code>socket.request.user</code>. For example, now you can add the following: <code>console.log('user ' + socket.request.user.name + ' connected');</code> and it will log to the server console who has connected!",
"Submit your page when you think you've got it right. If you're running into errors, you can check out the project up to this point <a href='https://gist.github.com/JosephLivengood/a9e69ff91337500d5171e29324e1ff35'>here</a>."
],
"challengeSeed": [],
"tests": [
{
"text": "passportSocketIo is a dependency",
"testString": "getUserInput => $.get(getUserInput('url')+ '/_api/package.json') .then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, 'passportSocketIo', 'Your project should list \"passportSocketIo\" as a dependency'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "passportSocketIo is properly required",
"testString": "getUserInput => $.get(getUserInput('url')+ '/_api/server.js').then(data => {assert.match(data, /passportSockerIo.*=.*require.*('|\")passportSocketIo('|\")/gi, 'You should correctly require and instanciate socket.io as io.');}, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "passportSocketIo is properly setup",
"testString": "getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /io.use.*passportSocketIo.authorize/gi, 'You should have told io to use passportSockIo.authorize with the correct options'); }, xhr => { throw new Error(xhr.statusText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"challengeType": 0,
"translations": {}
},
{
"id": "589fc832f9fc0f352b528e78",
"title": "Announce New Users",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-socketio/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-socketio/'>GitHub</a>.",
"Many chat rooms are able to annouce when a user connects or disconnects and then display that to all of the connected users in the chat. Seeing as though you already are emitting an event on connect and disconnect, you will just have to modify this event to support such feature. The most logical way of doing so is sending 3 pieces of data with the event: name of the user connected/disconnected, the current user count, and if that name connected or disconnected.",
"<hr>Change the event name to 'user' and as the data pass an object along containing fields 'name', 'currentUsers', and boolean 'connected' (to be true if connection, or false for disconnection of the user sent). Be sure to make the change to both points we had the 'user count' event and set the disconnect one to sent false for field 'connected' instead of true like the event emitted on connect. <code>io.emit('user', {name: socket.request.user.name, currentUsers, connected: true});</code>",
"Now your client will have all the nesesary information to correctly display the current user count and annouce when a user connects or disconnects! To handle this event on the client side we should listen for 'user' and then update the current user count by using jQuery to change the text of <code>#num-users</code> to '{NUMBER} users online', as well as append a <code>&#60;li&#62;</code> to the unordered list with id 'messages' with '{NAME} has {joined/left} the chat.'.",
"An implementation of this could look like the following:<pre>socket.on('user', function(data){\n $('#num-users').text(data.currentUsers+' users online');\n var message = data.name;\n if(data.connected) {\n message += ' has joined the chat.';\n } else {\n message += ' has left the chat.';\n }\n $('#messages').append($('&#60;li&#62;').html('&#60;b&#62;'+ message +'&#60;\\/b&#62;'));\n});</pre>",
"Submit your page when you think you've got it right."
],
"challengeSeed": [],
"tests": [
{
"text": "Event 'user' is emitted with name, currentUsers, and connected",
"testString": "getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /io.emit.*('|\")user('|\").*name.*currentUsers.*connected/gi, 'You should have an event emitted named user sending name, currentUsers, and connected'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "Client properly handling and displaying the new data from event 'user'",
"testString": "getUserInput => $.get(getUserInput('url')+ '/public/client.js') .then(data => { assert.match(data, /socket.on.*('|\")user('|\")[^]*num-users/gi, 'You should change the text of #num-users within on your client within the \"user\" even listener to show the current users connected'); assert.match(data, /socket.on.*('|\")user('|\")[^]*messages.*li/gi, 'You should append a list item to #messages on your client within the \"user\" event listener to annouce a user came or went'); }, xhr => { throw new Error(xhr.statusText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"challengeType": 0,
"translations": {}
},
{
"id": "589fc832f9fc0f352b528e79",
"title": "Send and Display Chat Messages",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-socketio/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-socketio/'>GitHub</a>.",
"It's time you start allowing clients to send a chat message to the server to emit to all the clients! Already in your client.js file you should see there is already a block of code handling when the messgae form is submitted! (<code>$('form').submit(function(){ /*logic*/ });</code>)",
"<hr>Within the code you're handling the form submit you should emit an event after you define 'messageToSend' but before you clear the text box <code>#m</code>. The event should be named 'chat message' and the data should just be 'messageToSend'. <code>socket.emit('chat message', messageToSend);</code>",
"Now on your server you should be listening to the socket for the event 'chat message' with the data being named 'message'. Once the event is recieved it should then emit the event 'chat message' to all sockets <code>io.emit</code> with the data being an object containing 'name' and 'message'.",
"On your client now again, you should now listen for event 'chat message' and when recieved, append a list item to <code>#messages</code> with the name a colon and the message!",
"At this point the chat should be fully functional and sending messages across all clients! Submit your page when you think you've got it right. If you're running into errors, you can check out the project up to this point <a href='https://gist.github.com/JosephLivengood/3e4b7750f6cd42feaa2768458d682136'>here for the server</a> and <a href='https://gist.github.com/JosephLivengood/41ba76348df3013b7870dc64861de744'>here for the client</a>."
],
"challengeSeed": [],
"tests": [
{
"text": "Server listens for 'chat message' then emits it properly",
"testString": "getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /socket.on.*('|\")chat message('|\")[^]*io.emit.*('|\")chat message('|\").*name.*message/gi, 'Your server should listen to the socket for \"chat message\" then emit to all users \"chat message\" with name and message in the data object'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "Client properly handling and displaying the new data from event 'chat message'",
"testString": "getUserInput => $.get(getUserInput('url')+ '/public/client.js') .then(data => { assert.match(data, /socket.on.*('|\")chat message('|\")[^]*messages.*li/gi, 'You should append a list item to #messages on your client within the \"chat message\" event listener to display the new message'); }, xhr => { throw new Error(xhr.statusText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"challengeType": 0,
"translations": {}
},
{
"id": "58a0b2caf9fc0f352b528e7a",
"title": "Continuing Your Live Chat",
"description": [
[
"",
"",
"From this point, you could choose to implement a plethora of features with just the knowledge you have learned up to this point! Some ideas you could choose to continue this project on with include, but aren't limited to the following:<ul><li>Displaying the users profile picture next to the messages</li><li>Displaying a time stamp on messages</li><li>Saving the most recent messages so when a new user connects they can see the most recent messages sent before they connected</li><li>Add a sidebar showing active users</li><li>Create a {user} is typing feature</li><li>Turn the client into a React component you can add to any of your previous projects</li></ul>",
""
]
],
"releasedOn": "Feb 17, 2017",
"challengeSeed": [],
"tests": [],
"type": "waypoint",
"challengeType": 7,
"isRequired": false,
"titleEs": "",
"descriptionEs": [
[]
],
"titleFr": "",
"descriptionFr": [
[]
],
"titleDe": "",
"descriptionDe": [
[]
]
}
]
}

View File

@ -0,0 +1,108 @@
{
"name": "Claim Your Information Security and Quality Assurance Certificate",
"order": 13,
"time": "5 minutes",
"challenges": [
{
"id": "587d8247367417b2b2512c35",
"title": "Claim Your Information Security and Quality Assurance Certificate",
"description": [
[
"//i.imgur.com/k8btNUB.jpg",
"An image of our Information Security and Quality Assurance Certificate",
"This challenge will give you your verified Information Security and Quality Assurance Certificate. Before we issue your certificate, we must verify that you have completed all of our basic and intermediate algorithm scripting challenges, and all our basic, intermediate, and advanced front end development projects. You must also accept our Academic Honesty Pledge. Click the button below to start this process.",
""
],
[
"//i.imgur.com/uLPsUko.jpg",
"The definition of plagiarism: Plagiarism (noun) - copying someone elses work and presenting it as your own without crediting them",
"By clicking below, you pledge that all of your submitted code A) is code you or your pair personally wrote, or B) comes from open source libraries like jQuery, or C) has been clearly attributed to its original authors. You also give us permission to audit your challenge solutions and revoke your certificate if we discover evidence of plagiarism.",
"#"
],
[
"//i.imgur.com/UedoV2G.jpg",
"An image of the text \"Front End Development Certificate requirements\"",
"Let's confirm that you have completed all of our basic and intermediate algorithm scripting challenges, and all our basic, intermediate, and advanced front end development projects. Click the button below to verify this.",
"#"
],
[
"//i.imgur.com/Q5Za9U6.jpg",
"An image of the word \"Congratulations\"",
"Congratulations! We've added your Information Security and Quality Assurance Certificate to your portfolio page. Unless you choose to hide your solutions, this certificate will remain publicly visible and verifiable.",
""
]
],
"challengeSeed": [
{
"properties": [
"isHonest",
"isFrontEndCert"
],
"apis": [
"/certificate/honest",
"/certificate/verify/front-end"
],
"stepIndex": [
1,
2
]
}
],
"tests": [
{
"id": "587d8249367417b2b2512c42",
"title": "Issue Tracker"
},
{
"id": "587d8249367417b2b2512c41",
"title": "Metric-Imperial Converter"
},
{
"id": "587d824a367417b2b2512c43",
"title": "Personal Library"
},
{
"id": "587d824a367417b2b2512c44",
"title": "Stock Price Checker"
},
{
"id": "587d824a367417b2b2512c45",
"title": "Anonymous Message Board"
}
],
"type": "Waypoint",
"challengeType": 7,
"translations": {
"es": {
"title": "Reclama tu certificado de Desarrollo de interfaces",
"description": [
[
"//i.imgur.com/k8btNUB.jpg",
"Una imagen que muestra nuestro certificado de Desarrollo de interfaces",
"Este desafío te otorga tu certificado autenticado de Desarrollo de interfaces. Antes de que podamos emitir tu certificado, debemos verificar que has completado todos los desafíos básicos e intermedios de diseño de algoritmos, y todos los proyectos básicos e intermedios de desarrollo de interfaces. También debes aceptar nuestro Juramento de honestidad académica. Pulsa el botón siguiente para iniciar este proceso.",
""
],
[
"//i.imgur.com/HArFfMN.jpg",
"Plagio (nombre): acción y efecto de plagiar. Plagiar (verbo) - copiar en lo sustancial obras ajenas, dándolas como propias.",
"Al pulsar el botón siguiente, juras que todo el código en tus soluciones a los desafíos A) es código que tú o tu compañero escribieron personalmente, o B) proviene de librerías de código abierto como jQuery, o C) ha sido claramente atribuido a sus autores originales. También nos otorgas el permiso para auditar tus soluciones a los desafíos y revocar tu certificado si encontramos evidencia de plagio.",
"#"
],
[
"//i.imgur.com/14F2Van.jpg",
"Una imagen del texto \"Front End Development Certificate requirements\"",
"Confirmemos que has completado todos nuestros desafíos básicos e intermedios de diseño de algoritmos, y todos nuestros proyectos básicos e intermedios de desarrollo de interfaces. Pulsa el botón siguiente para hacer la verificación.",
"#"
],
[
"//i.imgur.com/16SIhHO.jpg",
"Una imagen de la palabra \"Congratulations\"",
"¡Felicitaciones! Hemos agregado tu certificado de Desarrollo de interfaces a tu portafolio. A menos que elijas no mostrar tus soluciones, este certificado será públicamente visible y verificable.",
""
]
]
}
}
}
]
}

View File

@ -0,0 +1,400 @@
{
"name": "Information Security with HelmetJS",
"order": 1,
"time": "5 hours",
"helpRoom": "HelpBackend",
"challenges": [
{
"id": "58af07504bbe015e85a91dbd",
"title": "Information Security Introduction",
"description": [
[
"",
"",
"Working on these challenges will involve you writing your code on Glitch on our starter project. After completing each challenge you can copy your public glitch url (to the homepage of your app) into the challenge screen to test it! Optionally you may choose to write your project on another platform but it must be publicaly visible for our testing.<br>Start this project on Glitch using <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-infosec/'>this link</a> or clone <a href='https://github.com/freeCodeCamp/boilerplate-infosec/'>this repository</a> on GitHub! If you use Glitch, remember to save the link to your project somewhere safe!",
""
]
],
"releasedOn": "Feb 17, 2017",
"challengeSeed": [],
"tests": [],
"type": "waypoint",
"challengeType": 7,
"isRequired": false,
"translations": {}
},
{
"id": "587d8247367417b2b2512c36",
"title": "Install and Require Helmet",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-infosec/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-infosec/'>GitHub</a>.",
"Helmet helps you secure your Express apps by setting various HTTP headers. Install the package, then require it."
],
"challengeSeed": [],
"tests": [
{
"text": "\"helmet\" dependency should be in package.json",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, 'helmet'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
},
{
"id": "587d8247367417b2b2512c37",
"title": "Hide Potentially Dangerous Information Using helmet.hidePoweredBy()",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-infosec/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-infosec/'>GitHub</a>.",
"Hackers can exploit known vulnerabilities in Express/Node if they see that your site is powered by Express. X-Powered-By: Express is sent in every request coming from Express by default. The helmet.hidePoweredBy() middleware will remove the X-Powered-By header. You can also explicitly set the header to something else, to throw people off. e.g. app.use(helmet.hidePoweredBy({ setTo: 'PHP 4.2.0' }))"
],
"challengeSeed": [],
"tests": [
{
"text": "helmet.hidePoweredBy() middleware should be mounted correctly",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/app-info').then(data => { assert.include(data.appStack, 'hidePoweredBy'); assert.notEqual(data.headers['x-powered-by'], 'Express')}, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
},
{
"id": "587d8247367417b2b2512c38",
"title": "Mitigate the Risk of Clickjacking with helmet.frameguard()",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-infosec/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-infosec/'>GitHub</a>.",
"Your page could be put in a <frame> or <iframe> without your consent. This can result in clickjacking attacks, among other things. Clickjacking is a technique of tricking a user into interacting with a page different from what the user thinks it is. This can be obtained executing your page in a malicious context, by mean of iframing. In that context a hacker can put a hidden layer over your page. Hidden buttons can be used to run bad scripts. This middleware sets the X-Frame-Options header. It restricts who can put your site in a frame. It has three modes: DENY, SAMEORIGIN, and ALLOW-FROM.",
"We dont need our app to be framed. You should use helmet.frameguard() passing with the configuration object {action: 'deny'}."
],
"challengeSeed": [],
"tests": [
{
"text": "helmet.frameguard() middleware should be mounted correctly",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/app-info').then(data => { assert.include(data.appStack, 'frameguard', 'helmet.frameguard() middleware is not mounted correctly'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "helmet.frameguard() 'action' should be set to 'DENY'",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/app-info').then(data => { assert.property(data.headers, 'x-frame-options'); assert.equal(data.headers['x-frame-options'], 'DENY');}, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
},
{
"id": "587d8247367417b2b2512c39",
"title": "Mitigate the Risk of Cross Site Scripting (XSS) Attacks with helmet.xssFilter()",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-infosec/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-infosec/'>GitHub</a>.",
"Cross-site scripting (XSS) is a frequent type of attack where malicious scripts are injected into vulnerable pages, with the purpose of stealing sensitive data like session cookies, or passwords.",
"The basic rule to lower the risk of an XSS attack is simple: “Never trust users input”. As a developer you should always sanitize all the input coming from the outside. This includes data coming from forms, GET query urls, and even from POST bodies. Sanitizing means that you should find and encode the characters that may be dangerous e.g. <, >.",
"Modern browsers can help mitigating the risk by adopting better software strategies. Often these are configurable via http headers.",
"The X-XSS-Protection HTTP header is a basic protection. The browser detects a potential injected script using a heuristic filter. If the header is enabled, the browser changes the script code, neutralizing it.",
"It still has limited support."
],
"challengeSeed": [],
"tests": [
{
"text": "helmet.xssFilter() middleware should be mounted correctly",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/app-info').then(data => { assert.include(data.appStack, 'xXssProtection'); assert.property(data.headers, 'x-xss-protection'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
},
{
"id": "587d8248367417b2b2512c3a",
"title": "Avoid Inferring the Response MIME Type with helmet.noSniff()",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-infosec/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-infosec/'>GitHub</a>.",
"Browsers can use content or MIME sniffing to adapt to different datatypes coming from a response. They override the Content-Type headers to guess and process the data. While this can be convenient in some scenarios, it can also lead to some dangerous attacks. This middleware sets the X-Content-Type-Options header to nosniff. This instructs the browser to not bypass the provided Content-Type."
],
"challengeSeed": [],
"tests": [
{
"text": "helmet.noSniff() middleware should be mounted correctly",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/app-info').then(data => { assert.include(data.appStack, 'nosniff'); assert.equal(data.headers['x-content-type-options'], 'nosniff'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
},
{
"id": "587d8248367417b2b2512c3b",
"title": "Prevent IE from Opening Untrusted HTML with helmet.ieNoOpen()",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-infosec/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-infosec/'>GitHub</a>.",
"Some web applications will serve untrusted HTML for download. Some versions of Internet Explorer by default open those HTML files in the context of your site. This means that an untrusted HTML page could start doing bad things in the context of your pages. This middleware sets the X-Download-Options header to noopen. This will prevent IE users from executing downloads in the trusted sites context."
],
"challengeSeed": [],
"tests": [
{
"text": "helmet.ieNoOpen() middleware should be mounted correctly",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/app-info').then(data => { assert.include(data.appStack, 'ienoopen'); assert.equal(data.headers['x-download-options'], 'noopen'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
},
{
"id": "587d8248367417b2b2512c3c",
"title": "Ask Browsers to Access Your Site via HTTPS Only with helmet.hsts()",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-infosec/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-infosec/'>GitHub</a>.",
"HTTP Strict Transport Security (HSTS) is a web security policy which helps to protect websites against protocol downgrade attacks and cookie hijacking. If your website can be accessed via HTTPS you can ask users browsers to avoid using insecure HTTP. By setting the header Strict-Transport-Security, you tell the browsers to use HTTPS for the future requests in a specified amount of time. This will work for the requests coming after the initial request.",
"Configure helmet.hsts() to use HTTPS for the next 90 days. Pass the config object {maxAge: timeInMilliseconds, force: true}. Glitch already has hsts enabled. To override its settings you need to set the field \"force\" to true in the config object. We will intercept and restore the Glitch header, after inspecting it for testing.",
"Note: Configuring HTTPS on a custom website requires the acquisition of a domain, and a SSL/TSL Certificate."
],
"challengeSeed": [],
"tests": [
{
"text": "helmet.hsts() middleware should be mounted correctly",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/app-info').then(data => { assert.include(data.appStack, 'hsts'); assert.property(data.headers, 'strict-transport-security'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "maxAge should be equal to 7776000 ms (90 days)",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/app-info').then(data => { assert.match(data.headers['strict-transport-security'], /^max-age=777600000;?/); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
},
{
"id": "587d8248367417b2b2512c3d",
"title": "Disable DNS Prefetching with helmet.dnsPrefetchControl()",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-infosec/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-infosec/'>GitHub</a>.",
"To improve performance, most browsers prefetch DNS records for the links in a page. In that way the destination ip is already known when the user clicks on a link. This may lead to over-use of the DNS service (if you own a big website, visited by millions people…), privacy issues (one eavesdropper could infer that you are on a certain page), or page statistics alteration (some links may appear visited even if they are not). If you have high security needs you can disable DNS prefetching, at the cost of a performance penalty."
],
"challengeSeed": [],
"tests": [
{
"text": "helmet.dnsPrefetchControl() middleware should be mounted correctly",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/app-info').then(data => { assert.include(data.appStack, 'dnsPrefetchControl'); assert.equal(data.headers['x-dns-prefetch-control'], 'off'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
},
{
"id": "587d8249367417b2b2512c3e",
"title": "Disable Client-Side Caching with helmet.noCache()",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-infosec/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-infosec/'>GitHub</a>.",
"If you are releasing an update for your website, and you want the users to always download the newer version, you can (try to) disable caching on clients browser. It can be useful in development too. Caching has performance benefits, which you will lose, so only use this option when there is a real need."
],
"challengeSeed": [],
"tests": [
{
"text": "helmet.noCache() middleware should be mounted correctly",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/app-info').then(data => { assert.include(data.appStack, 'nocache'); assert.equal(data.headers['cache-control'], 'no-store, no-cache, must-revalidate, proxy-revalidate'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
},
{
"id": "587d8249367417b2b2512c3f",
"title": "Set a Content Security Policy with helmet.contentSecurityPolicy()",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-infosec/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-infosec/'>GitHub</a>.",
"This challenge highlights one promising new defense that can significantly reduce the risk and impact of many type of attacks in modern browsers. By setting and configuring a Content Security Policy you can prevent the injection of anything unintended into your page. This will protect your app from XSS vulnerabilities, undesired tracking, malicious frames, and much more. CSP works by defining a whitelist of content sources which are trusted. You can configure them for each kind of resource a web page may need (scripts, stylesheets, fonts, frames, media, and so on…). There are multiple directives available, so a website owner can have a granular control. See HTML 5 Rocks, KeyCDN for more details. Unfortunately CSP in unsupported by older browser.",
"By default, directives are wide open, so its important to set the defaultSrc directive as a fallback. Helmet supports both defaultSrc and default-src naming styles. The fallback applies for most of the unspecified directives. In this exercise, use helmet.contentSecurityPolicy(), and configure it setting the defaultSrc directive to [\"self\"] (the list of allowed sources must be in an array), in order to trust only your website address by default. Set also the scriptSrc directive so that you will allow scripts to be downloaded from your website, and from the domain 'trusted-cdn.com'.",
"Hint: in the \"'self'\" keyword, the single quotes are part of the keyword itself, so it needs to be enclosed in double quotes to be working."
],
"challengeSeed": [],
"tests": [
{
"text": "helmet.csp() middleware should be mounted correctly",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/app-info').then(data => { assert.include(data.appStack, 'csp'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Your csp config is not correct. defaultSrc should be [\"'self'\"] and scriptSrc should be [\"'self'\", 'trusted-cdn.com']",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/app-info').then(data => { var cspHeader = Object.keys(data.headers).filter(function(k){ return k === 'content-security-policy' || k === 'x-webkit-csp' || k === 'x-content-security-policy' })[0]; assert.equal(data.headers[cspHeader], \"default-src 'self'; script-src 'self' trusted-cdn.com\"); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
},
{
"id": "587d8249367417b2b2512c40",
"title": "Configure Helmet Using the parent helmet() Middleware",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-infosec/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-infosec/'>GitHub</a>.",
"app.use(helmet()) will automatically include all the middleware introduced above, except noCache(), and contentSecurityPolicy(), but these can be enabled if necessary. You can also disable or configure any other middleware individually, using a configuration object.",
"// Example",
"<code>app.use(helmet({</code>",
"<code> frameguard: { // configure</code>",
"<code> action: 'deny'</code>",
"<code> },</code>",
"<code> contentSecurityPolicy: { // enable and configure</code>",
"<code> directives: {</code>",
"<code> defaultSrc: [\"self\"],</code>",
"<code> styleSrc: ['style.com'],</code>",
"<code> }</code>",
"<code> },</code>",
"<code> dnsPrefetchControl: false // disable</code>",
"<code>}))</code>",
"We introduced each middleware separately for teaching purpose, and for ease of testing. Using the parent helmet() middleware is easiest, and cleaner, for a real project."
],
"challengeSeed": [],
"tests": [
{
"text": "no tests - it's a descriptive challenge",
"testString": "assert(true)"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
},
{
"id": "58a25bcef9fc0f352b528e7b",
"title": "Protect Your Data with BCrypt",
"description": [
[
"",
"",
"The safest way to protect a password is to never even store it- even encrypted. The solution to this security problem is hashing. Unlike encryptions, hashes cannot be transformed back into the original data. So how do you use a hash? A hash is used to verify data like a password again at a later point in time without actually knowing what it is in the future by hashing the entered password in the same manner as the original and comparing the results; if they match then you can be sure it is the same data. A widely used library for this is <em>BCrypt</em>. With how easy BCrypt is to implement into your web applications, you should never have any excuse to store a plain text password in your databases.<br>Start this project on Glitch using <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-bcrypt/'>this link</a> or clone <a href='https://github.com/freeCodeCamp/boilerplate-bcrypt/'>this repository</a> on GitHub! If you use Glitch, remember to save the link to your project somewhere safe.",
""
]
],
"releasedOn": "",
"challengeSeed": [],
"tests": [],
"type": "Waypoint",
"challengeType": 7,
"isRequired": false,
"titleEs": "",
"descriptionEs": [
[]
],
"titleFr": "",
"descriptionFr": [
[]
],
"titleDe": "",
"descriptionDe": [
[]
]
},
{
"id": "58a25bcef9fc0f352b528e7c",
"title": "Understand BCrypt Hashes",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-bcrypt/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-bcrypt/'>GitHub</a>.",
"BCrypt hashes are very secure. A hash is basically a fingerprint of the original data- always unique. This is accomplished by feeding the original data into a algorithm and having returned a fixed length result. To further complicate this process and make it more secure, you can also <em>salt</em> your hash. Salting your hash involves adding random data to the original data before the hashing process which makes it even harder to crack the hash.",
"BCrypt hashes will always looks like <code>$2a$13$ZyprE5MRw2Q3WpNOGZWGbeG7ADUre1Q8QO.uUUtcbqloU0yvzavOm</code> which does have a structure. The first small bit of data <code>$2a</code> is defining what kind of hash algorithm was used. The next portion <code>$13</code> defines the <em>cost</em>. Cost is about how much power it takes to compute the hash. It is on a logarithmic scale of 2^cost and determines how many times the data is put through the hashing algorithm. For example, at a cost of 10 you are able to hash 10 passwords a second on an average computer, however at a cost of 15 it takes 3 seconds per hash... and to take it further, at a cost of 31 it would takes multiple days to complete a hash. A cost of 12 is considered very secure at this time. The last portion of your hash <code>$ZyprE5MRw2Q3WpNOGZWGbeG7ADUre1Q8QO.uUUtcbqloU0yvzavOm</code>, looks like 1 large string of numbers, periods, and letters but it is actually 2 separate pieces of information. The first 22 characters is the salt in plain text, and the rest is the hashed password!",
"<hr>To begin using BCrypt, add it as a dependency in your project and require it as 'bcrypt' in your server.",
"Submit your page when you think you've got it right."
],
"challengeSeed": [],
"tests": [
{
"text": "BCyrpt is a dependency",
"testString": "getUserInput => $.get(getUserInput('url')+ '/_api/package.json') .then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, 'bcrypt', 'Your project should list \"bcrypt\" as a dependency'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "BCrypt has been properly required",
"testString": "getUserInput => $.get(getUserInput('url')+ '/_api/server.js').then(data => {assert.match(data, /bcrypt.*=.*require.*('|\")bcrypt('|\")/gi, 'You should correctly require and instanciate socket.io as io.');}, xhr => { throw new Error(xhr.statusText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
},
{
"id": "58a25bcff9fc0f352b528e7d",
"title": "Hash and Compare Passwords Asynchronously",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-bcrypt/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-bcrypt/'>GitHub</a>.",
"As hashing is designed to be computationally intensive, it is recommended to do so asyncronously on your server as to avoid blocking incoming connections while you hash. All you have to do to hash a password asynchronous is call <code>bcrypt.hash(myPlaintextPassword, saltRounds, (err, hash) => { /*Store hash in your db*/ });</code>",
"<hr>Add this hashing function to your server(we've already defined the variables used in the function for you to use) and log it to the console for you to see! At this point you would normally save the hash to your database.",
"Now when you need to figure out if a new input is the same data as the hash you would just use the compare function <code>bcrypt.compare(myPlaintextPassword, hash, (err, res) => { /*res == true or false*/ });</code>. Add this into your existing hash function(since you need to wait for the hash to complete before calling the compare function) after you log the completed hash and log 'res' to the console within the compare. You should see in the console a hash then 'true' is printed! If you change 'myPlaintextPassword' in the compare function to 'someOtherPlaintextPassword' then it should say false.",
"<pre>bcrypt.hash('passw0rd!', 13, (err, hash) => {\n console.log(hash); //$2a$12$Y.PHPE15wR25qrrtgGkiYe2sXo98cjuMCG1YwSI5rJW1DSJp0gEYS\n bcrypt.compare('passw0rd!', hash, (err, res) => {\n console.log(res); //true\n });\n});</pre>",
"Submit your page when you think you've got it right."
],
"challengeSeed": [],
"tests": [
{
"text": "Async hash generated and correctly compared",
"testString": "getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /START_ASYNC[^]*bcrypt.hash.*myPlaintextPassword( |),( |)saltRounds( |),( |).*err( |),( |)hash[^]*END_ASYNC/gi, 'You should call bcrypt.hash on myPlaintextPassword and saltRounds and handle err and hash as a result in the callback'); assert.match(data, /START_ASYNC[^]*bcrypt.hash[^]*bcrypt.compare.*myPlaintextPassword( |),( |)hash( |),( |).*err( |),( |)res[^]*}[^]*}[^]*END_ASYNC/gi, 'Nested within the hash function should be the compare function comparing myPlaintextPassword to hash'); }, xhr => { throw new Error(xhr.statusText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
},
{
"id": "58a25bcff9fc0f352b528e7e",
"title": "Hash and Compare Passwords Synchronously",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-bcrypt/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-bcrypt/'>GitHub</a>.",
"Hashing synchronously is just as easy to do but can cause lag if using it server side with a high cost or with hashing done very often. Hashing with this method is as easy as calling <code>var hash = bcrypt.hashSync(myPlaintextPassword, saltRounds);</code>",
"<hr>Add this method of hashing to your code and then log the result to the console. Again, the variables used are already defined in the server so you wont need to adjust them. You may notice even though you are hashing the same password as in the async function, the result in the console is different- this is due to the salt being randomly generated each time as seen by the first 22 characters in the third string of the hash.",
"Now to compare a password input with the new sync hash, you would use the compareSync method: <code>var result = bcrypt.compareSync(myPlaintextPassword, hash);</code> with the result being a boolean true or false. Add this function in and log to the console the result to see it working.",
"Submit your page when you think you've got it right. If you ran into errors during these challenges you can take a look at the example completed code <a href='https://gist.github.com/JosephLivengood/9a2698fb63e42d9d8b4b84235c08b4c4'>here</a>."
],
"challengeSeed": [],
"tests": [
{
"text": "Sync hash generated and correctly compared",
"testString": "getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /START_SYNC[^]*hash.*=.*bcrypt.hashSync.*myPlaintextPassword( |),( |)saltRounds[^]*END_SYNC/gi, 'You should call bcrypt.hashSync on myPlaintextPassword with saltRounds'); assert.match(data, /START_SYNC[^]*result.*=.*bcrypt.compareSync.*myPlaintextPassword( |),( |)hash[^]*END_SYNC/gi, 'You should call bcrypt.compareSync on myPlaintextPassword with the hash generated in the last line'); }, xhr => { throw new Error(xhr.statusText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
}
]
}

View File

@ -0,0 +1,298 @@
{
"name": "Information Security and Quality Assurance Projects",
"order": 4,
"time": "150 hours",
"helpRoom": "HelpBackend",
"challenges": [
{
"id": "587d8249367417b2b2512c41",
"title": "Metric-Imperial Converter",
"description": [
"Build a full stack JavaScript app that is functionally similar to this: <a href='https://hard-twilight.glitch.me/' target='_blank'>https://hard-twilight.glitch.me/</a>.",
"Working on this project will involve you writing your code on Glitch on our starter project. After completing this project you can copy your public glitch url (to the homepage of your app) into this screen to test it! Optionally you may choose to write your project on another platform but it must be publicaly visible for our testing.",
"Start this project on Glitch using <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-project-metricimpconverter/'>this link</a> or clone <a href='https://github.com/freeCodeCamp/boilerplate-project-metricimpconverter/'>this repository</a> on GitHub! If you use Glitch, remember to save the link to your project somewhere safe!"
],
"challengeSeed": [],
"tests": [
{
"text": "I will prevent the client from trying to guess(sniff) the MIME type.",
"testString": ""
},
{
"text": "I will prevent cross-site scripting (XSS) attacks.",
"testString": ""
},
{
"text": "I can GET /api/convert with a single parameter containing an accepted number and unit and have it converted. (Hint: Split the input by looking for the index of the first character which will mark the start of the unit)",
"testString": ""
},
{
"text": "I can convert 'gal' to 'L' and vice versa. (1 gal to 3.78541 L)",
"testString": ""
},
{
"text": "I can convert 'lbs' to 'kg' and vice versa. (1 lbs to 0.453592 kg)",
"testString": ""
},
{
"text": "I can convert 'mi' to 'km' and vice versa. (1 mi to 1.60934 km)",
"testString": ""
},
{
"text": "If my unit of measurement is invalid, returned will be 'invalid unit'.",
"testString": ""
},
{
"text": "If my number is invalid, returned with will 'invalid number'.",
"testString": ""
},
{
"text": "If both are invalid, return will be 'invalid number and unit'.",
"testString": ""
},
{
"text": "I can use fractions, decimals or both in my parameter(ie. 5, 1/2, 2.5/6), but if nothing is provided it will default to 1.",
"testString": ""
},
{
"text": "My return will consist of the initNum, initUnit, returnNum, returnUnit, and string spelling out units in format '{initNum} {initial_Units} converts to {returnNum} {return_Units}' with the result rounded to 5 decimals in the string.",
"testString": ""
},
{
"text": "All 16 unit tests are complete and passing.",
"testString": ""
},
{
"text": "All 5 functional tests are complete and passing.",
"testString": ""
}
],
"solutions": [],
"hints": [],
"type": "backend",
"isRequired": true,
"releasedOn": "January 15, 2017",
"translations": {}
},
{
"id": "587d8249367417b2b2512c42",
"title": "Issue Tracker",
"description": [
"Build a full stack JavaScript app that is functionally similar to this: <a href='https://protective-garage.glitch.me/' target='_blank'>https://protective-garage.glitch.me/</a>.",
"Working on this project will involve you writing your code on Glitch on our starter project. After completing this project you can copy your public glitch url (to the homepage of your app) into this screen to test it! Optionally you may choose to write your project on another platform but it must be publicaly visible for our testing.",
"Start this project on Glitch using <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-project-issuetracker/'>this link</a> or clone <a href='https://github.com/freeCodeCamp/boilerplate-project-issuetracker/'>this repository</a> on GitHub! If you use Glitch, remember to save the link to your project somewhere safe!"
],
"challengeSeed": [],
"tests": [
{
"text": "Prevent cross site scripting (XSS) attacks.",
"testString": ""
},
{
"text": "I can POST /api/issues/{projectname} with form data containing required issue_title, issue_text, created_by, and optional assigned_to and status_text.",
"testString": ""
},
{
"text": "The object saved (and returned) will include all of those fields (blank for optional no input) and also include created_on(date/time), updated_on(date/time), open(boolean, true for open, false for closed), and _id.",
"testString": ""
},
{
"text": "I can PUT /api/issues/{projectname} with a id and any fields in the object with a value to object said object. Returned will be 'successfully updated' or 'could not update '+id. This should always update updated_on. If no fields are sent return 'no updated field sent'.",
"testString": ""
},
{
"text": "I can DELETE /api/issues/{projectname} with a id to completely delete an issue. If no _id is sent return 'id error', success: 'deleted '+id, failed: 'could not delete '+id.",
"testString": ""
},
{
"text": "I can GET /api/issues/{projectname} for an array of all issues on that specific project with all the information for each issue as was returned when posted.",
"testString": ""
},
{
"text": "I can filter my get request by also passing along any field and value in the query(ie. /api/issues/{project}?open=false). I can pass along as many fields/values as I want.",
"testString": ""
},
{
"text": "All 11 functional tests are complete and passing.",
"testString": ""
}
],
"solutions": [],
"hints": [],
"type": "backend",
"isRequired": true,
"releasedOn": "January 15, 2017",
"translations": {}
},
{
"id": "587d824a367417b2b2512c43",
"title": "Personal Library",
"description": [
"Build a full stack JavaScript app that is functionally similar to this: <a href='https://spark-cathedral.glitch.me/' target='_blank'>https://spark-cathedral.glitch.me/</a>.",
"Working on this project will involve you writing your code on Glitch on our starter project. After completing this project you can copy your public glitch url (to the homepage of your app) into this screen to test it! Optionally you may choose to write your project on another platform but must be publicaly visible for our testing.",
"Start this project on Glitch using <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-project-library/'>this link</a> or clone <a href='https://github.com/freeCodeCamp/boilerplate-project-library/'>this repository</a> on GitHub! If you use Glitch, remember to save the link to your project somewhere safe!"
],
"challengeSeed": [],
"tests": [
{
"text": "Nothing from my website will be cached in my client.",
"testString": ""
},
{
"text": "The headers will say that the site is powered by 'PHP 4.2.0' even though it isn't (as a security measure).",
"testString": ""
},
{
"text": "I can post a title to /api/books to add a book and returned will be the object with the title and a unique _id.",
"testString": ""
},
{
"text": "I can get /api/books to retrieve an array of all books containing title, _id, and commentcount.",
"testString": ""
},
{
"text": "I can get /api/books/{id} to retrieve a single object of a book containing _title, _id, & an array of comments (empty array if no comments present).",
"testString": ""
},
{
"text": "I can post a comment to /api/books/{id} to add a comment to a book and returned will be the books object similar to get /api/books/{id} including the new comment.",
"testString": ""
},
{
"text": "I can delete /api/books/{_id} to delete a book from the collection. Returned will be 'delete successful' if successful.",
"testString": ""
},
{
"text": "If I try to request a book that doesn't exist I will be returned 'no book exists'.",
"testString": ""
},
{
"text": "I can send a delete request to /api/books to delete all books in the database. Returned will be 'complete delete successful' if successful.",
"testString": ""
},
{
"text": "All 6 functional tests required are complete and passing.",
"testString": ""
}
],
"solutions": [],
"hints": [],
"type": "backend",
"isRequired": true,
"releasedOn": "January 15, 2017",
"translations": {}
},
{
"id": "587d824a367417b2b2512c44",
"title": "Stock Price Checker",
"description": [
"Build a full stack JavaScript app that is functionally similar to this: <a href='https://giant-chronometer.glitch.me/' target='_blank'>https://giant-chronometer.glitch.me/</a>.",
"Working on this project will involve you writing your code on Glitch on our starter project. After completing this project you can copy your public glitch url (to the homepage of your app) into this screen to test it! Optionally you may choose to write your project on another platform but must be publicaly visible for our testing.",
"Start this project on Glitch using <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-project-stockchecker/'>this link</a> or clone <a href='https://github.com/freeCodeCamp/boilerplate-project-stockchecker/'>this repository</a> on GitHub! If you use Glitch, remember to save the link to your project somewhere safe!"
],
"challengeSeed": [],
"tests": [
{
"text": "Set the content security policies to only allow loading of scripts and css from your server.",
"testString": ""
},
{
"text": "I can GET /api/stock-prices with form data containing a Nasdaq stock ticker and recieve back an object stockData.",
"testString": ""
},
{
"text": "In stockData, I can see the stock(string, the ticker), price(decimal in string format), and likes(int).",
"testString": ""
},
{
"text": "I can also pass along field like as true(boolean) to have my like added to the stock(s). Only 1 like per ip should be accepted.",
"testString": ""
},
{
"text": "If I pass along 2 stocks, the return object will be an array with both stock's info. Instead of likes, it will display rel_likes(the difference between the likes on both stocks) on both.",
"testString": ""
},
{
"text": "A good way to receive current price is the following external API(replacing 'GOOG' with your stock): https://finance.google.com/finance/info?q=NASDAQ%3aGOOG",
"testString": ""
},
{
"text": "All 5 functional tests are complete and passing.",
"testString": ""
}
],
"solutions": [],
"hints": [],
"type": "backend",
"isRequired": true,
"releasedOn": "January 15, 2017",
"translations": {}
},
{
"id": "587d824a367417b2b2512c45",
"title": "Anonymous Message Board",
"description": [
"Build a full stack JavaScript app that is functionally similar to this: <a href='https://horn-celery.glitch.me/' target='_blank'>https://horn-celery.glitch.me/</a>.",
"Working on this project will involve you writing your code on Glitch on our starter project. After completing this project you can copy your public glitch url (to the homepage of your app) into this screen to test it! Optionally you may choose to write your project on another platform but it must be publicaly visible for our testing.",
"Start this project on Glitch using <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-project-messageboard/'>this link</a> or clone <a href='https://github.com/freeCodeCamp/boilerplate-project-messageboard/'>this repository</a> on GitHub! If you use Glitch, remember to save the link to your project somewhere safe!"
],
"challengeSeed": [],
"tests": [
{
"text": "Only allow your site to be loading in an iFrame on your own pages.",
"testString": ""
},
{
"text": "Do not allow DNS prefetching.",
"testString": ""
},
{
"text": "Only allow your site to send the referrer for your own pages.",
"testString": ""
},
{
"text": "I can POST a thread to a specific message board by passing form data text and deletepassword_ to /api/threads/{board}.(Recommend res.redirect to board page /b/{board}) Saved will be at least _id, text, createdon_(date&time), bumpedon_(date&time, starts same as created_on), reported(boolean), deletepassword_, & replies(array).",
"testString": ""
},
{
"text": "I can POST a reply to a thread on a specific board by passing form data text, deletepassword_, & threadid_ to /api/replies/{board} and it will also update the bumped_on date to the comments date.(Recommend res.redirect to thread page /b/{board}/{thread_id}) In the thread's replies array will be saved _id, text, createdon_, deletepassword_, & reported.",
"testString": ""
},
{
"text": "I can GET an array of the most recent 10 bumped threads on the board with only the most recent 3 replies each from /api/threads/{board}. The reported and deletepasswords_ fields will not be sent to the client.",
"testString": ""
},
{
"text": "I can GET an entire thread with all its replies from /api/replies/{board}?thread_id={thread_id}. Also hiding the same fields the client should be see.",
"testString": ""
},
{
"text": "I can delete a thread completely if I send a DELETE request to /api/threads/{board} and pass along the threadid_ & deletepassword_. (Text response will be 'incorrect password' or 'success')",
"testString": ""
},
{
"text": "I can delete a post(just changing the text to '[deleted]' instead of removing completely like a thread) if I send a DELETE request to /api/replies/{board} and pass along the threadid_, replyid_, & deletepassword_. (Text response will be 'incorrect password' or 'success')",
"testString": ""
},
{
"text": "I can report a thread and change its reported value to true by sending a PUT request to /api/threads/{board} and pass along the threadid_. (Text response will be 'success')",
"testString": ""
},
{
"text": "I can report a reply and change its reported value to true by sending a PUT request to /api/replies/{board} and pass along the threadid_ & replyid_. (Text response will be 'success')",
"testString": ""
},
{
"text": "Complete functional tests that wholly test routes and pass.",
"testString": ""
}
],
"solutions": [],
"hints": [],
"type": "backend",
"isRequired": true,
"releasedOn": "January 15, 2017",
"translations": {}
}
]
}

View File

@ -0,0 +1,858 @@
{
"name": "Quality Assurance and Testing with Chai",
"order": 2,
"time": "5 hours",
"helpRoom": "Help",
"challenges": [
{
"id": "58af0b4b4bbe015e85a91dbe",
"title": "Quality Assurance Introduction",
"description": [
[
"",
"",
"Working on these challenges will involve you writing your code on Glitch on our starter project. After completing each challenge you can copy your public glitch url (to the homepage of your app) into the challenge screen to test it! Optionally you may choose to write your project on another platform but it must be publicaly visible for our testing.<br>Start this project on Glitch using <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-mochachai/'>this link</a> or clone <a href='https://github.com/freeCodeCamp/boilerplate-mochachai/'>this repository</a> on GitHub! If you use Glitch, remember to save the link to your project somewhere safe!",
""
]
],
"releasedOn": "Feb 17, 2017",
"challengeSeed": [],
"tests": [],
"type": "waypoint",
"challengeType": 7,
"isRequired": false,
"translations": {}
},
{
"id": "587d824a367417b2b2512c46",
"title": "Learn How JavaScript Assertions Work",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-mochachai/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-mochachai/'>GitHub</a>.",
"Use assert.isNull() or assert.isNotNull() to make the tests pass."
],
"challengeSeed": [],
"tests": [
{
"text": "All tests should pass",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=0').then(data => {assert.equal(data.state,'passed'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - isNull vs. isNotNull",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=0').then(data => { assert.equal(data.assertions[0].method, 'isNull', 'Null is null'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - isNull vs. isNotNull",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=0').then(data => { assert.equal(data.assertions[1].method, 'isNotNull', '1 is not null'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
},
{
"id": "587d824b367417b2b2512c47",
"title": "Test if a Variable or Function is Defined",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-mochachai/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-mochachai/'>GitHub</a>.",
"Use assert.isDefined() or assert.isUndefined() to make the tests pass"
],
"challengeSeed": [],
"tests": [
{
"text": "All tests should pass",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=1').then(data => {assert.equal(data.state,'passed'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - isDefined vs. isUndefined",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=1').then(data => { assert.equal(data.assertions[0].method, 'isDefined', 'Null is not undefined'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - isDefined vs. isUndefined",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=1').then(data => { assert.equal(data.assertions[1].method, 'isUndefined', 'Undefined is undefined'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - isDefined vs. isUndefined",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=1').then(data => { assert.equal(data.assertions[2].method, 'isDefined', 'A string is not undefined'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
},
{
"id": "587d824b367417b2b2512c48",
"title": "Use Assert.isOK and Assert.isNotOK",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-mochachai/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-mochachai/'>GitHub</a>.",
"Use assert.isOk() or assert.isNotOk() to make the tests pass.",
".isOk(truthy) and .isNotOk(falsey) will pass."
],
"challengeSeed": [],
"tests": [
{
"text": "All tests should pass",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=2').then(data => {assert.equal(data.state,'passed'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - isOk vs. isNotOk",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=2').then(data => { assert.equal(data.assertions[0].method, 'isNotOk', 'Null is falsey'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - isOk vs. isNotOk",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=2').then(data => { assert.equal(data.assertions[1].method, 'isOk','A string is truthy'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - isOk vs. isNotOk",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=2').then(data => { assert.equal(data.assertions[2].method, 'isOk', 'true is truthy'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
},
{
"id": "587d824b367417b2b2512c49",
"title": "Test for Truthiness",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-mochachai/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-mochachai/'>GitHub</a>.",
"Use assert.isTrue() or assert.isNotTrue() to make the tests pass.",
".isTrue(true) and .isNotTrue(everything else) will pass.",
".isFalse() and .isNotFalse() also exist."
],
"challengeSeed": [],
"tests": [
{
"text": "All tests should pass",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=3').then(data => {assert.equal(data.state,'passed'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - isTrue vs. isNotTrue",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=3').then(data => { assert.equal(data.assertions[0].method, 'isTrue', 'True is true'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - isTrue vs. isNotTrue",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=3').then(data => { assert.equal(data.assertions[1].method, 'isTrue', 'Double negation of a truthy value is true'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - isTrue vs. isNotTrue",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=3').then(data => { assert.equal(data.assertions[2].method, 'isNotTrue', 'A truthy object is not true - neither is a false one'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
},
{
"id": "587d824b367417b2b2512c4a",
"title": "Use the Double Equals to Assert Equality",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-mochachai/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-mochachai/'>GitHub</a>.",
".equal(), .notEqual()",
".equal() compares objects using '=='"
],
"challengeSeed": [],
"tests": [
{
"text": "All tests should pass",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=4').then(data => {assert.equal(data.state,'passed'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - equal vs. notEqual",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=4').then(data => { assert.equal(data.assertions[0].method, 'equal', 'Numbers are coerced into strings with == '); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - equal vs. notEqual",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=4').then(data => { assert.equal(data.assertions[1].method, 'notEqual', ' == compares object references'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - equal vs. notEqual",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=4').then(data => { assert.equal(data.assertions[2].method, 'equal', '6 * \\'2\\' is 12 ! It should be equal to \\'12\\''); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - equal vs. notEqual",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=4').then(data => { assert.equal(data.assertions[3].method, 'notEqual', '6 + \\'2\\' is \\'62\\'...'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
},
{
"id": "587d824b367417b2b2512c4b",
"title": "Use the Triple Equals to Assert Strict Equality",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-mochachai/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-mochachai/'>GitHub</a>.",
".strictEqual(), .notStrictEqual()",
".strictEqual() compares objects using '==='"
],
"challengeSeed": [],
"tests": [
{
"text": "All tests should pass",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=5').then(data => {assert.equal(data.state,'passed'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - strictEqual vs. notStrictEqual",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=5').then(data => { assert.equal(data.assertions[0].method, 'notStrictEqual', 'with strictEqual the type must match'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - strictEqual vs. notStrictEqual",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=5').then(data => { assert.equal(data.assertions[1].method, 'strictEqual', '3*2 = 6...'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - strictEqual vs. notStrictEqual",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=5').then(data => { assert.equal(data.assertions[2].method, 'strictEqual', '6 * \\'2\\' is 12. Types match !'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - strictEqual vs. notStrictEqual",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=5').then(data => { assert.equal(data.assertions[3].method, 'notStrictEqual', 'Even if they have the same elements, the Arrays are notStrictEqual'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
},
{
"id": "587d824c367417b2b2512c4c",
"title": "Assert Deep Equality with .deepEqual and .notDeepEqual",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-mochachai/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-mochachai/'>GitHub</a>.",
".deepEqual(), .notDeepEqual()",
".deepEqual() asserts that two object are deep equal"
],
"challengeSeed": [],
"tests": [
{
"text": "All tests should pass",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=6').then(data => {assert.equal(data.state,'passed'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - deepEqual vs. notDeepEqual",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=6').then(data => { assert.equal(data.assertions[0].method, 'deepEqual', 'The order of the keys does not matter'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - deepEqual vs. notDeepEqual",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=6').then(data => { assert.equal(data.assertions[1].method, 'notDeepEqual', 'The position of elements within an array does matter'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
},
{
"id": "587d824c367417b2b2512c4d",
"title": "Compare the Properties of Two Elements",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-mochachai/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-mochachai/'>GitHub</a>.",
".isAbove() => a > b , .isAtMost() => a <= b"
],
"challengeSeed": [],
"tests": [
{
"text": "All tests should pass",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=7').then(data => {assert.equal(data.state,'passed'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - isAbove vs. isAtMost",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=7').then(data => { assert.equal(data.assertions[0].method, 'isAtMost', '5 is at most (<=) 5'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - isAbove vs. isAtMost",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=7').then(data => { assert.equal(data.assertions[1].method, 'isAbove', '1 is greater than 0'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - isAbove vs. isAtMost",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=7').then(data => { assert.equal(data.assertions[2].method, 'isAbove', 'Math.PI = 3.14159265 is greater than 3'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - isAbove vs. isAtMost",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=7').then(data => { assert.equal(data.assertions[3].method, 'isAtMost', '1 - Math.random() is > 0 and <= 1. It is atMost 1 !'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
},
{
"id": "587d824c367417b2b2512c4e",
"title": "Test if One Value is Below or At Least as Large as Another",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-mochachai/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-mochachai/'>GitHub</a>.",
".isBelow() => a < b , .isAtLeast => a >= b"
],
"challengeSeed": [],
"tests": [
{
"text": "All tests should pass",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=8').then(data => {assert.equal(data.state,'passed'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - isBelow vs. isAtLeast",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=8').then(data => { assert.equal(data.assertions[0].method, 'isAtLeast', '5 is at least (>=) 5'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - isBelow vs. isAtLeast",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=8').then(data => { assert.equal(data.assertions[0].method, 'isAtLeast', '2 * Math.random() is at least 0'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - isBelow vs. isAtLeast",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=8').then(data => { assert.equal(data.assertions[0].method, 'isBelow', '1 is smaller than 2'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - isBelow vs. isAtLeast",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=8').then(data => { assert.equal(data.assertions[0].method, 'isBelow', '2/3 (0.6666) is smaller than 1'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
},
{
"id": "587d824c367417b2b2512c4f",
"title": "Test if a Value Falls within a Specific Range",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-mochachai/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-mochachai/'>GitHub</a>.",
".approximately",
".approximately(actual, expected, range, [message])",
"actual = expected +/- range",
"Choose the minimum range (3rd parameter) to make the test always pass",
"it should be less than 1"
],
"challengeSeed": [],
"tests": [
{
"text": "All tests should pass",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=10').then(data => {assert.equal(data.state,'passed'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Use approximately(actual, expected, range) - Chose the correct range",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=10').then(data => { assert.equal(data.assertions[0].method, 'isApproximately', 'weirdNumbers(0.5) is in the range (0.5, 1.5]. It\\'s within 1 +/- 0.5'); assert.equal(data.assertions[0].args[2], 0.5); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Use approximately(actual, expected, range) - Chose the correct range",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=10').then(data => { assert.equal(data.assertions[1].method, 'isApproximately'); assert.equal(data.assertions[1].args[2], 0.8, 'weirdNumbers(0.2) is in the range (0.2, 1.2] It\\'s within 1 +/- 0.8'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
},
{
"id": "587d824d367417b2b2512c50",
"title": "Test if a Value is an Array",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-mochachai/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-mochachai/'>GitHub</a>."
],
"challengeSeed": [],
"tests": [
{
"text": "All tests should pass",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=10').then(data => {assert.equal(data.state,'passed'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - isArray vs. isNotArray",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=10').then(data => { assert.equal(data.assertions[0].method, 'isArray', 'String.prototype.split() returns an Array'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - isArray vs. isNotArray",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=10').then(data => { assert.equal(data.assertions[1].method, 'isNotArray', 'Array.prototype.indexOf() returns a number'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
},
{
"id": "587d824d367417b2b2512c51",
"title": "Test if an Array Contains an Item",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-mochachai/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-mochachai/'>GitHub</a>."
],
"challengeSeed": [],
"tests": [
{
"text": "All tests should pass",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=11').then(data => { assert.equal(data.state,'passed'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - include vs. notInclude",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=11').then(data => { assert.equal(data.assertions[0].method, 'notInclude', 'It\\'s summer in july...'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - include vs. notInclude",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=11').then(data => { assert.equal(data.assertions[1].method, 'include', 'JavaScript is a backend language !!'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
},
{
"id": "587d824d367417b2b2512c52",
"title": "Test if a Value is a String",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-mochachai/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-mochachai/'>GitHub</a>.",
"#isString asserts that the actual value is a string."
],
"challengeSeed": [],
"tests": [
{
"text": "All tests should pass",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=12').then(data => { assert.equal(data.state,'passed'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - isString vs. isNotString",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=12').then(data => { assert.equal(data.assertions[0].method, 'isNotString', 'A float number is not a string'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - isString vs. isNotString",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=12').then(data => { assert.equal(data.assertions[1].method, 'isString', 'environment vars are strings (or undefined)'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - isString vs. isNotString",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=12').then(data => { assert.equal(data.assertions[2].method, 'isString', 'A JSON is a string'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
},
{
"id": "587d824d367417b2b2512c53",
"title": "Test if a String Contains a Substring",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-mochachai/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-mochachai/'>GitHub</a>.",
"#include (on #notInclude ) works for strings too !!",
"It asserts that the actual string contains the expected substring"
],
"challengeSeed": [],
"tests": [
{
"text": "All tests should pass",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=13').then(data => { assert.equal(data.state,'passed'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - include vs. notInclude",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=13').then(data => { assert.equal(data.assertions[0].method, 'include', '\\'Arrow\\' contains \\'row\\'...'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - include vs. notInclude",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=13').then(data => { assert.equal(data.assertions[1].method, 'notInclude', '... a \\'dart\\' doesn\\'t contain a \\'queue\\''); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
},
{
"id": "587d824d367417b2b2512c54",
"title": "Use Regular Expressions to Test a String",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-mochachai/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-mochachai/'>GitHub</a>.",
"#match Asserts that the actual value",
"matches the second argument regular expression."
],
"challengeSeed": [],
"tests": [
{
"text": "All tests should pass",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=14').then(data => { assert.equal(data.state,'passed'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - match vs. notMatch",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=14').then(data => { assert.equal(data.assertions[0].method, 'match', '\\'# name: John Doe, age: 35\\' matches the regex'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - match vs. notMatch",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=14').then(data => { assert.equal(data.assertions[1].method, 'notMatch', '\\'# name: Paul Smith III, age: twenty-four\\' does not match the regex (the age must be numeric)'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
},
{
"id": "587d824e367417b2b2512c55",
"title": "Test if an Object has a Property",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-mochachai/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-mochachai/'>GitHub</a>.",
"#property asserts that the actual object has a given property.",
"Use #property or #notProperty where appropriate"
],
"challengeSeed": [],
"tests": [
{
"text": "All tests should pass",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=15').then(data => { assert.equal(data.state,'passed'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - property vs. notProperty",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=15').then(data => { assert.equal(data.assertions[0].method, 'notProperty', 'A car has not wings'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - property vs. notProperty",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=15').then(data => { assert.equal(data.assertions[1].method, 'property', 'planes have engines'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - property vs. notProperty",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=15').then(data => { assert.equal(data.assertions[2].method, 'property', 'Cars have wheels'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
},
{
"id": "587d824e367417b2b2512c56",
"title": "Test if a Value is of a Specific Data Structure Type",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-mochachai/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-mochachai/'>GitHub</a>.",
"#typeOf asserts that values type is the given string, as determined by Object.prototype.toString.",
"Use #typeOf or #notTypeOf where appropriate"
],
"challengeSeed": [],
"tests": [
{
"text": "All tests should pass",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=16').then(data => { assert.equal(data.state,'passed'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - typeOf vs. notTypeOf",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=16').then(data => { assert.equal(data.assertions[0].method, 'typeOf', 'myCar is typeOf Object'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - typeOf vs. notTypeOf",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=16').then(data => { assert.equal(data.assertions[1].method, 'typeOf', 'Car.model is a String'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - typeOf vs. notTypeOf",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=16').then(data => { assert.equal(data.assertions[1].method, 'notTypeOf', 'Plane.wings is a Number (not a String)'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - typeOf vs. notTypeOf",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=16').then(data => { assert.equal(data.assertions[3].method, 'typeOf', 'Plane.engines is an Array'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - typeOf vs. notTypeOf",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=16').then(data => { assert.equal(data.assertions[4].method, 'typeOf', 'Car.wheels is a Number'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
},
{
"id": "587d824e367417b2b2512c57",
"title": "Test if an Object is an Instance of a Constructor",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-mochachai/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-mochachai/'>GitHub</a>.",
"#instanceOf asserts that an object is an instance of a constructor.",
"Use #instanceOf or #notInstanceOf where appropriate"
],
"challengeSeed": [],
"tests": [
{
"text": "All tests should pass",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=17').then(data => { assert.equal(data.state,'passed'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - instanceOf vs. notInstanceOf",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=17').then(data => { assert.equal(data.assertions[0].method, 'notInstanceOf', 'myCar is not an instance of Plane'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - instanceOf vs. notInstanceOf",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=17').then(data => { assert.equal(data.assertions[1].method, 'instanceOf', 'airlinePlane is an instance of Plane'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - instanceOf vs. notInstanceOf",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=17').then(data => { assert.equal(data.assertions[2].method, 'instanceOf', 'everything is an Object in JavaScript...'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - instanceOf vs. notInstanceOf",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=17').then(data => { assert.equal(data.assertions[3].method, 'notInstanceOf', 'myCar.wheels is not an instance of String'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
},
{
"id": "587d824e367417b2b2512c58",
"title": "Run Functional Tests on API Endpoints using Chai-HTTP",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-mochachai/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-mochachai/'>GitHub</a>.",
"Replace assert.fail(). Test the status and the text.response. Make the test pass.",
"Don't send a name in the query, the endpoint with responds with 'hello Guest'."
],
"challengeSeed": [],
"tests": [
{
"text": "All tests should pass",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=functional&n=0').then(data => { assert.equal(data.state,'passed'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "You should test for 'res.status' == 200",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=functional&n=0').then(data => { assert.equal(data.assertions[0].method, 'equal'); assert.equal(data.assertions[0].args[0], 'res.status'); assert.equal(data.assertions[0].args[1], '200');}, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "You should test for 'res.text' == 'hello Guest'",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=functional&n=0').then(data => { assert.equal(data.assertions[1].method, 'equal'); assert.equal(data.assertions[1].args[0], 'res.text'); assert.equal(data.assertions[1].args[1], '\\'hello Guest\\'');}, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
},
{
"id": "587d824f367417b2b2512c59",
"title": "Run Functional Tests on API Endpoints using Chai-HTTP II",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-mochachai/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-mochachai/'>GitHub</a>.",
"Replace assert.fail(). Test the status and the text.response. Make the test pass.",
"Send you name in the query appending ?name=<your_name>, the endpoint with responds with 'hello <your_name>'."
],
"challengeSeed": [],
"tests": [
{
"text": "All tests should pass",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=functional&n=1').then(data => { assert.equal(data.state,'passed'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "You should test for 'res.status' == 200",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=functional&n=1').then(data => { assert.equal(data.assertions[0].method, 'equal'); assert.equal(data.assertions[0].args[0], 'res.status'); assert.equal(data.assertions[0].args[1], '200');}, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "You should test for 'res.text' == 'hello Guest'",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=functional&n=1').then(data => { assert.equal(data.assertions[1].method, 'equal'); assert.equal(data.assertions[1].args[0], 'res.text'); assert.match(data.assertions[1].args[1], /hello [\\w\\d_-]/);}, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
},
{
"id": "587d824f367417b2b2512c5a",
"title": "Run Functional Tests on an API Response using Chai-HTTP III - PUT method",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-mochachai/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-mochachai/'>GitHub</a>.",
"In the next example we'll see how to send data in a request payload (body).",
"We are going to test a PUT request. The '/travellers' endpoint accepts",
"a JSON object taking the structure :",
" {surname: [last name of a traveller of the past]} ,",
"The route responds with :",
" {name: [first name], surname:[last name], dates: [birth - death years]}",
"see the server code for more details.",
"Send {surname: 'Colombo'}. Replace assert.fail() and make the test pass.",
"Check for 1) status, 2) type, 3) body.name, 4) body.surname",
"Follow the assertion order above, We rely on it."
],
"challengeSeed": [],
"tests": [
{
"text": "All tests should pass",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=functional&n=2').then(data => { assert.equal(data.state,'passed'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "You should test for 'res.status' to be 200",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=functional&n=2').then(data => { assert.equal(data.assertions[0].method, 'equal'); assert.equal(data.assertions[0].args[0], 'res.status'); assert.equal(data.assertions[0].args[1], '200');}, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "You should test for 'res.type' to be 'application/json'",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=functional&n=2').then(data => { assert.equal(data.assertions[1].method, 'equal'); assert.equal(data.assertions[1].args[0], 'res.type'); assert.equal(data.assertions[1].args[1], '\\'application/json\\'');}, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "You should test for 'res.body.name' to be 'Cristoforo'",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=functional&n=2').then(data => { assert.equal(data.assertions[2].method, 'equal'); assert.equal(data.assertions[2].args[0], 'res.body.name'); assert.equal(data.assertions[2].args[1], '\\'Cristoforo\\'');}, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "You should test for 'res.body.surname' to be 'Colombo'",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=functional&n=2').then(data => { assert.equal(data.assertions[3].method, 'equal'); assert.equal(data.assertions[3].args[0], 'res.body.surname'); assert.equal(data.assertions[3].args[1], '\\'Colombo\\'');}, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
},
{
"id": "587d824f367417b2b2512c5b",
"title": "Run Functional Tests on an API Response using Chai-HTTP IV - PUT method redux",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-mochachai/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-mochachai/'>GitHub</a>.",
"This exercise is similar to the preceding. Look at it for the details.",
"Send {surname: 'da Verrazzano'}. Replace assert.fail() and make the test pass.",
"Check for 1) status, 2) type, 3) body.name, 4) body.surname",
"Follow the assertion order above, We rely on it."
],
"challengeSeed": [],
"tests": [
{
"text": "All tests should pass",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=functional&n=3').then(data => { assert.equal(data.state,'passed'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "You should test for 'res.status' to be 200",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=functional&n=3').then(data => { assert.equal(data.assertions[0].method, 'equal'); assert.equal(data.assertions[0].args[0], 'res.status'); assert.equal(data.assertions[0].args[1], '200');}, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "You should test for 'res.type' to be 'application/json'",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=functional&n=3').then(data => { assert.equal(data.assertions[1].method, 'equal'); assert.equal(data.assertions[1].args[0], 'res.type'); assert.equal(data.assertions[1].args[1], '\\'application/json\\'');}, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "You should test for 'res.body.name' to be 'Giovanni'",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=functional&n=3').then(data => { assert.equal(data.assertions[2].method, 'equal'); assert.equal(data.assertions[2].args[0], 'res.body.name'); assert.equal(data.assertions[2].args[1], '\\'Giovanni\\'');}, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "You should test for 'res.body.surname' to be 'da Verrazzano'",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=functional&n=3').then(data => { assert.equal(data.assertions[3].method, 'equal'); assert.equal(data.assertions[3].args[0], 'res.body.surname'); assert.equal(data.assertions[3].args[1], '\\'da Verrazzano\\'');}, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
},
{
"id": "587d824f367417b2b2512c5c",
"title": "Run Functional Tests using a Headless Browser",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-mochachai/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-mochachai/'>GitHub</a>.",
"In the next challenges we are going to simulate the human interaction with a page using a device called 'Headless Browser'.",
"A headless browser is a web browser without a graphical user interface. These kind of tools are particularly useful for testing web pages as they are able to render and understand HTML, CSS, and JavaScript the same way a browser would.",
"For these challenges we are using Zombie.JS. It's a lightweight browser which is totally based on JS, without relying on additional binaries to be installed. This feature makes it usable in an environment such as Glitch. There are many other (more powerful) options.<br>",
"Look at the examples in the code for the exercise directions Follow the assertions order, We rely on it."
],
"challengeSeed": [],
"tests": [
{
"text": "All tests should pass",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=functional&n=4').then(data => { assert.equal(data.state,'passed'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "assert that the headless browser request succeded",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=functional&n=4').then(data => { assert.equal(data.assertions[0].method, 'browser.success'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "assert that the text inside the element 'span#name' is 'Cristoforo'",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=functional&n=4').then(data => { assert.equal(data.assertions[1].method, 'browser.text'); assert.equal(data.assertions[1].args[0], '\\'span#name\\''); assert.equal(data.assertions[1].args[1], '\\'Cristoforo\\'');}, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "assert that the text inside the element 'span#surname' is 'Colombo'",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=functional&n=4').then(data => { assert.equal(data.assertions[2].method, 'browser.text'); assert.equal(data.assertions[2].args[0], '\\'span#surname\\''); assert.equal(data.assertions[2].args[1], '\\'Colombo\\'');}, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "assert that the element 'span#dates' exist and its count is 1",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=functional&n=4').then(data => { assert.equal(data.assertions[3].method, 'browser.element'); assert.equal(data.assertions[3].args[0], '\\'span#dates\\''); assert.equal(data.assertions[3].args[1], 1);}, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
},
{
"id": "587d8250367417b2b2512c5d",
"title": "Run Functional Tests using a Headless Browser II",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-mochachai/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-mochachai/'>GitHub</a>.",
"This exercise is similar to the preceding.",
"Look at the code for directions. Follow the assertions order, We rely on it."
],
"challengeSeed": [],
"tests": [
{
"text": "All tests should pass",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=functional&n=5').then(data => { assert.equal(data.state,'passed'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": " assert that the headless browser request succeded",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=functional&n=5').then(data => { assert.equal(data.assertions[0].method, 'browser.success'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "assert that the text inside the element 'span#name' is 'Amerigo'",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=functional&n=5').then(data => { assert.equal(data.assertions[1].method, 'browser.text'); assert.equal(data.assertions[1].args[0], '\\'span#name\\''); assert.equal(data.assertions[1].args[1], '\\'Amerigo\\'');}, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "assert that the text inside the element 'span#surname' is 'Vespucci'",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=functional&n=5').then(data => { assert.equal(data.assertions[2].method, 'browser.text'); assert.equal(data.assertions[2].args[0], '\\'span#surname\\''); assert.equal(data.assertions[2].args[1], '\\'Vespucci\\'');}, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "assert that the element 'span#dates' exist and its count is 1",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=functional&n=5').then(data => { assert.equal(data.assertions[3].method, 'browser.element'); assert.equal(data.assertions[3].args[0], '\\'span#dates\\''); assert.equal(data.assertions[3].args[1], 1);}, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"type": "backend",
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {}
}
]
}

View File

@ -0,0 +1,28 @@
{
"name": "Open Source Contributions",
"order": 22,
"time": "800 Hours",
"isLocked": true,
"message": "Before you can get credit toward your final Full Stack Development Certificate by contributing to open source, we recommend you complete all six of your certifications.",
"challenges": [
{
"title": "Contribute Pull Requests to Open Source projects",
"isRequired": true
},
{
"title": "QA Other Developers' Pull Requests",
"isRequired": true
},
{
"title": "Greenfield Code Grant Project for a Nonprofit",
"isRequired": true
},
{
"title": "Legacy Code Grant Project for a Nonprofit",
"isRequired": true
},
{
"title": "Claim Your Full Stack Development Certificate"
}
]
}

View File

@ -0,0 +1,642 @@
{
"name": "Coding Interview Algorithm Questions",
"order": 1,
"time": "",
"helpRoom": "HelpJavaScript",
"challenges": [
{
"id": "aff0395860f5d3034dc0bfc9",
"title": "Validate US Telephone Numbers",
"description": [
"Return <code>true</code> if the passed string looks like a valid US phone number.",
"The user may fill out the form field any way they choose as long as it has the format of a valid US number. The following are examples of valid formats for US numbers (refer to the tests below for other variants):",
"<blockquote>555-555-5555\n(555)555-5555\n(555) 555-5555\n555 555 5555\n5555555555\n1 555 555 5555</blockquote>",
"For this challenge you will be presented with a string such as <code>800-692-7753</code> or <code>8oo-six427676;laskdjf</code>. Your job is to validate or reject the US phone number based on any combination of the formats provided above. The area code is required. If the country code is provided, you must confirm that the country code is <code>1</code>. Return <code>true</code> if the string is a valid US phone number; otherwise return <code>false</code>.",
"Remember to use <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> if you get stuck. Try to pair program. Write your own code."
],
"challengeSeed": [
"function telephoneCheck(str) {",
" // Good luck!",
" return true;",
"}",
"",
"telephoneCheck(\"555-555-5555\");"
],
"solutions": [
"var re = /^([+]?1[\\s]?)?((?:[(](?:[2-9]1[02-9]|[2-9][02-8][0-9])[)][\\s]?)|(?:(?:[2-9]1[02-9]|[2-9][02-8][0-9])[\\s.-]?)){1}([2-9]1[02-9]|[2-9][02-9]1|[2-9][02-9]{2}[\\s.-]?){1}([0-9]{4}){1}$/;\n\nfunction telephoneCheck(str) {\n return re.test(str);\n}\n\ntelephoneCheck(\"555-555-5555\");"
],
"tests": [
"assert(typeof telephoneCheck(\"555-555-5555\") === \"boolean\", 'message: <code>telephoneCheck(\"555-555-5555\")</code> should return a boolean.');",
"assert(telephoneCheck(\"1 555-555-5555\") === true, 'message: <code>telephoneCheck(\"1 555-555-5555\")</code> should return true.');",
"assert(telephoneCheck(\"1 (555) 555-5555\") === true, 'message: <code>telephoneCheck(\"1 (555) 555-5555\")</code> should return true.');",
"assert(telephoneCheck(\"5555555555\") === true, 'message: <code>telephoneCheck(\"5555555555\")</code> should return true.');",
"assert(telephoneCheck(\"555-555-5555\") === true, 'message: <code>telephoneCheck(\"555-555-5555\")</code> should return true.');",
"assert(telephoneCheck(\"(555)555-5555\") === true, 'message: <code>telephoneCheck(\"(555)555-5555\")</code> should return true.');",
"assert(telephoneCheck(\"1(555)555-5555\") === true, 'message: <code>telephoneCheck(\"1(555)555-5555\")</code> should return true.');",
"assert(telephoneCheck(\"555-5555\") === false, 'message: <code>telephoneCheck(\"555-5555\")</code> should return false.');",
"assert(telephoneCheck(\"5555555\") === false, 'message: <code>telephoneCheck(\"5555555\")</code> should return false.');",
"assert(telephoneCheck(\"1 555)555-5555\") === false, 'message: <code>telephoneCheck(\"1 555)555-5555\")</code> should return false.');",
"assert(telephoneCheck(\"1 555 555 5555\") === true, 'message: <code>telephoneCheck(\"1 555 555 5555\")</code> should return true.');",
"assert(telephoneCheck(\"1 456 789 4444\") === true, 'message: <code>telephoneCheck(\"1 456 789 4444\")</code> should return true.');",
"assert(telephoneCheck(\"123**&!!asdf#\") === false, 'message: <code>telephoneCheck(\"123**&!!asdf#\")</code> should return false.');",
"assert(telephoneCheck(\"55555555\") === false, 'message: <code>telephoneCheck(\"55555555\")</code> should return false.');",
"assert(telephoneCheck(\"(6054756961)\") === false, 'message: <code>telephoneCheck(\"(6054756961)\")</code> should return false');",
"assert(telephoneCheck(\"2 (757) 622-7382\") === false, 'message: <code>telephoneCheck(\"2 (757) 622-7382\")</code> should return false.');",
"assert(telephoneCheck(\"0 (757) 622-7382\") === false, 'message: <code>telephoneCheck(\"0 (757) 622-7382\")</code> should return false.');",
"assert(telephoneCheck(\"-1 (757) 622-7382\") === false, 'message: <code>telephoneCheck(\"-1 (757) 622-7382\")</code> should return false');",
"assert(telephoneCheck(\"2 757 622-7382\") === false, 'message: <code>telephoneCheck(\"2 757 622-7382\")</code> should return false.');",
"assert(telephoneCheck(\"10 (757) 622-7382\") === false, 'message: <code>telephoneCheck(\"10 (757) 622-7382\")</code> should return false.');",
"assert(telephoneCheck(\"27576227382\") === false, 'message: <code>telephoneCheck(\"27576227382\")</code> should return false.');",
"assert(telephoneCheck(\"(275)76227382\") === false, 'message: <code>telephoneCheck(\"(275)76227382\")</code> should return false.');",
"assert(telephoneCheck(\"2(757)6227382\") === false, 'message: <code>telephoneCheck(\"2(757)6227382\")</code> should return false.');",
"assert(telephoneCheck(\"2(757)622-7382\") === false, 'message: <code>telephoneCheck(\"2(757)622-7382\")</code> should return false.');",
"assert(telephoneCheck(\"555)-555-5555\") === false, 'message: <code>telephoneCheck(\"555)-555-5555\")</code> should return false.');",
"assert(telephoneCheck(\"(555-555-5555\") === false, 'message: <code>telephoneCheck(\"(555-555-5555\")</code> should return false.');",
"assert(telephoneCheck(\"(555)5(55?)-5555\") === false, 'message: <code>telephoneCheck(\"(555)5(55?)-5555\")</code> should return false.');"
],
"type": "bonfire",
"MDNlinks": [
"RegExp"
],
"challengeType": 5,
"translations": {
"es": {
"title": "Valida Números Telefónicos de los EEUU",
"description": [
"Haz que la función devuelva true (verdadero) si el texto introducido parece un número válido en los EEUU.",
"El usuario debe llenar el campo del formulario de la forma que desee siempre y cuando tenga el formato de un número válido en los EEUU. Los números mostrados a continuación tienen formatos válidos en los EEUU:",
"<blockquote>555-555-5555\n(555)555-5555\n(555) 555-5555\n555 555 5555\n5555555555\n1 555 555 5555</blockquote>",
"Para esta prueba se te presentará una cadena de texto como por ejemplo: <code>800-692-7753</code> o <code>8oo-six427676;laskdjf</code>. Tu trabajo consiste en validar o rechazar el número telefónico tomando como base cualquier combinación de los formatos anteriormente presentados. El código de área es requrido. Si el código de país es provisto, debes confirmar que este es <code>1</code>. La función debe devolver true si la cadena de texto es un número telefónico válido en los EEUU; de lo contrario, debe devolver false.",
"Recuerda utilizar <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> si te sientes atascado. Intenta programar en pareja. Escribe tu propio código."
]
},
"it": {
"title": "Verifica i numeri telefonici degli Stati Uniti",
"description": [
"Ritorna <code>true</code> se la stringa passata come argomento è un numero valido negli Stati Uniti.",
"L'utente può digitare qualunque stringa nel campo di inserimento, purchè sia un numero di telefono valido negli Stati Uniti. Qui sotto alcuni esempi di numeri di telefono validi negli Stati Uniti (fai riferimento ai test per le altre varianti):",
"<blockquote>555-555-5555\n(555)555-5555\n(555) 555-5555\n555 555 5555\n5555555555\n1 555 555 5555</blockquote>",
"In questo problema ti saranno presentate delle stringe come <code>800-692-7753</code> o <code>8oo-six427676;laskdjf</code>. Il tuo obiettivo è di validare o rigettare il numero di telefono basato su una qualunque combinazione dei formati specificati sopra. Il prefisso di zona è obbligatorio. Se il prefisso nazionale è presente, devi confermare che corrisponda a <code>1</code>. Ritorna <code>true</code> se la stringa è un numero di telefono valido negli Stati Uniti; altrimenti ritorna <code>false</code>.",
"Ricorda di usare <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Leggi-Cerca-Chiedi</a> se rimani bloccato. Prova a programmare in coppia. Scrivi il codice da te."
]
},
"pt-br": {
"title": "Valida números telefônicos dos EUA",
"description": [
"Retorna <code>true</code> se a string passada é um número telefônico válido nos EUA.",
"O usuário pode preencher o campo de qualquer maneira com tanto que seja um número válido nos EUA. Os seguintes exemplos são formatos válidos para números de telefone nos EUA (baseie-se nos testes abaixo para outras variações):",
"<blockquote>555-555-5555\n(555)555-5555\n(555) 555-5555\n555 555 5555\n5555555555\n1 555 555 5555</blockquote>",
"Para esse desafio será dado a você uma string como <code>800-692-7753</code> ou <code>8oo-six427676;laskdjf</code>. Seu trabalho é validar ou rejeitar o número de telefone dos EUA baseado nos exmplos de formatos fornecidos acima. O código de área é obrigatório. Se o código do país for fornecido, você deve confirmar que o código do país é <code>1</code>. Retorne <code>true</code> se a string é um número válido nos EUA; caso contrário retorne <code>false</code>.",
"Lembre-se de usar <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Ler-Procurar-Perguntar</a> se você ficar preso. Tente programar em par. Escreva seu próprio código."
]
}
}
},
{
"id": "a3f503de51cf954ede28891d",
"title": "Symmetric Difference",
"description": [
"Create a function that takes two or more arrays and returns an array of the <dfn>symmetric difference</dfn> (<code>&xutri;</code> or <code>&oplus;</code>) of the provided arrays.",
"Given two sets (for example set <code>A = {1, 2, 3}</code> and set <code>B = {2, 3, 4}</code>), the mathematical term \"symmetric difference\" of two sets is the set of elements which are in either of the two sets, but not in both (<code>A &xutri; B = C = {1, 4}</code>). For every additional symmetric difference you take (say on a set <code>D = {2, 3}</code>), you should get the set with elements which are in either of the two the sets but not both (<code>C &xutri; D = {1, 4} &xutri; {2, 3} = {1, 2, 3, 4}</code>). The resulting array must contain only unique values (<em>no duplicates</em>).",
"Remember to use <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> if you get stuck. Try to pair program. Write your own code."
],
"challengeSeed": [
"function sym(args) {",
" return args;",
"}",
"",
"sym([1, 2, 3], [5, 2, 1, 4]);"
],
"solutions": [
"function sym() {\n var arrays = [].slice.call(arguments);\n return arrays.reduce(function (symDiff, arr) {\n return symDiff.concat(arr).filter(function (val, idx, theArr) {\n return theArr.indexOf(val) === idx \n && (symDiff.indexOf(val) === -1 || arr.indexOf(val) === -1);\n });\n });\n}\nsym([1, 2, 3], [5, 2, 1, 4]);\n"
],
"tests": [
"assert.sameMembers(sym([1, 2, 3], [5, 2, 1, 4]), [3, 4, 5], 'message: <code>sym([1, 2, 3], [5, 2, 1, 4])</code> should return <code>[3, 4, 5]</code>.');",
"assert.equal(sym([1, 2, 3], [5, 2, 1, 4]).length, 3, 'message: <code>sym([1, 2, 3], [5, 2, 1, 4])</code> should contain only three elements.');",
"assert.sameMembers(sym([1, 2, 3, 3], [5, 2, 1, 4]), [3, 4, 5], 'message: <code>sym([1, 2, 3, 3], [5, 2, 1, 4])</code> should return <code>[3, 4, 5]</code>.');",
"assert.equal(sym([1, 2, 3, 3], [5, 2, 1, 4]).length, 3, 'message: <code>sym([1, 2, 3, 3], [5, 2, 1, 4])</code> should contain only three elements.');",
"assert.sameMembers(sym([1, 2, 3], [5, 2, 1, 4, 5]), [3, 4, 5], 'message: <code>sym([1, 2, 3], [5, 2, 1, 4, 5])</code> should return <code>[3, 4, 5]</code>.');",
"assert.equal(sym([1, 2, 3], [5, 2, 1, 4, 5]).length, 3, 'message: <code>sym([1, 2, 3], [5, 2, 1, 4, 5])</code> should contain only three elements.');",
"assert.sameMembers(sym([1, 2, 5], [2, 3, 5], [3, 4, 5]), [1, 4, 5], 'message: <code>sym([1, 2, 5], [2, 3, 5], [3, 4, 5])</code> should return <code>[1, 4, 5]</code>');",
"assert.equal(sym([1, 2, 5], [2, 3, 5], [3, 4, 5]).length, 3, 'message: <code>sym([1, 2, 5], [2, 3, 5], [3, 4, 5])</code> should contain only three elements.');",
"assert.sameMembers(sym([1, 1, 2, 5], [2, 2, 3, 5], [3, 4, 5, 5]), [1, 4, 5], 'message: <code>sym([1, 1, 2, 5], [2, 2, 3, 5], [3, 4, 5, 5])</code> should return <code>[1, 4, 5]</code>.');",
"assert.equal(sym([1, 1, 2, 5], [2, 2, 3, 5], [3, 4, 5, 5]).length, 3, 'message: <code>sym([1, 1, 2, 5], [2, 2, 3, 5], [3, 4, 5, 5])</code> should contain only three elements.');",
"assert.sameMembers(sym([3, 3, 3, 2, 5], [2, 1, 5, 7], [3, 4, 6, 6], [1, 2, 3]), [2, 3, 4, 6, 7], 'message: <code>sym([3, 3, 3, 2, 5], [2, 1, 5, 7], [3, 4, 6, 6], [1, 2, 3])</code> should return <code>[2, 3, 4, 6, 7]</code>.');",
"assert.equal(sym([3, 3, 3, 2, 5], [2, 1, 5, 7], [3, 4, 6, 6], [1, 2, 3]).length, 5, 'message: <code>sym([3, 3, 3, 2, 5], [2, 1, 5, 7], [3, 4, 6, 6], [1, 2, 3])</code> should contain only five elements.');",
"assert.sameMembers(sym([3, 3, 3, 2, 5], [2, 1, 5, 7], [3, 4, 6, 6], [1, 2, 3], [5, 3, 9, 8], [1]), [1, 2, 4, 5, 6, 7, 8, 9], 'message: <code>sym([3, 3, 3, 2, 5], [2, 1, 5, 7], [3, 4, 6, 6], [1, 2, 3], [5, 3, 9, 8], [1])</code> should return <code>[1, 2, 4, 5, 6, 7, 8, 9]</code>.');",
"assert.equal(sym([3, 3, 3, 2, 5], [2, 1, 5, 7], [3, 4, 6, 6], [1, 2, 3], [5, 3, 9, 8], [1]).length, 8, 'message: <code>sym([3, 3, 3, 2, 5], [2, 1, 5, 7], [3, 4, 6, 6], [1, 2, 3], [5, 3, 9, 8], [1])</code> should contain only eight elements.');"
],
"type": "bonfire",
"MDNlinks": [
"Array.prototype.reduce()",
"Symmetric Difference"
],
"challengeType": 5,
"translations": {
"es": {
"title": "Diferencia Simétrica",
"description": [
"Crea una función que acepte dos o más arreglos y que devuelva un arreglo conteniendo la diferenia simétrica entre ambos",
"En Matemáticas, el término 'diferencia simétrica' se refiere a los elementos en dos conjuntos que están en el primer conjunto o en el segundo, pero no en ambos.",
"Recuerda utilizar <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> si te sientes atascado. Intenta programar en pareja. Escribe tu propio código."
]
},
"it": {
"title": "Differenza Simmetrica",
"description": [
"Crea una funzione che accetti due o più array e che ritorni un array contenente la <dfn>differenza simmetrica</dfn> (<code>&xutri;</code> o <code>&oplus;</code>) degli stessi.",
"Dati due insiemi (per esempio l'insieme <code>A = {1, 2, 3}<code> e l'insieme <code>B = {2, 3, 4}</code>, il termine matematico \"differenza simmetrica\" di due insiemi è l'insieme degli elementi che sono in almeno uno dei due insiemi, ma non in entrambi (<code>A &xutri; B = C = {1, 4}</code>). Per ogni differenza simmetrica aggiuntiva che fai (per esempio su un insieme <code>D = {2, 3}</code>), devi prendere l'insieme degli elementi che sono in almeno uno dei due insiemi ma non in entrambi (<code>C &xutri; D = {1, 4} &xutri; {2, 3} = {1, 2, 3, 4}</code>).",
"Ricorda di usare <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Leggi-Cerca-Chiedi</a> se rimani bloccato. Prova a programmare in coppia. Scrivi il codice da te."
]
},
"pt-br": {
"title": "Diferença Simétrica",
"description": [
"Crie uma função que recebe duas ou mais matrizes e retorna a matriz <dfn>diferença simétrica</dfn> (<code>&xutri;</code> ou <code>&oplus;</code>) das matrizes fornecidas.",
"Dado dois conjuntos (por exemplo conjunto <code>A = {1, 2, 3}</code> e conjunto <code>B = {2, 3, 4}</code>), o termo matemático \"diferença simétrica\" dos dois cojuntos é o conjunto dos elementos que estão em um dos conjuntos, mas não nos dois (<code>A &xutri; B = C = {1, 4}</code>). Para cada diferença simétrica adicional que você faz (digamos em um terceiro conjunto <code>D = {2, 3}</code>), voce deve retornar o conjunto no qual os elementos estão em um dos conjuntos mas não nos dois (<code>C &xutri; D = {1, 4} &xutri; {2, 3} = {1, 2, 3, 4}</code>). O conjunto final deve ter somentes valores únicos (<em>sem números repetidos</em>).",
"Lembre-se de usar <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Ler-Procurar-Perguntar</a> se você ficar preso. Tente programar em par. Escreva seu próprio código."
]
}
}
},
{
"id": "aa2e6f85cab2ab736c9a9b24",
"title": "Exact Change",
"description": [
"Design a cash register drawer function <code>checkCashRegister()</code> that accepts purchase price as the first argument (<code>price</code>), payment as the second argument (<code>cash</code>), and cash-in-drawer (<code>cid</code>) as the third argument.",
"<code>cid</code> is a 2D array listing available currency.",
"Return the string <code>\"Insufficient Funds\"</code> if cash-in-drawer is less than the change due or if you cannot return the exact change. Return the string <code>\"Closed\"</code> if cash-in-drawer is equal to the change due.",
"Otherwise, return change in coin and bills, sorted in highest to lowest order.",
"Remember to use <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> if you get stuck. Try to pair program. Write your own code.",
"<table class='table table-striped'><tr><th>Currency Unit</th><th>Amount</th></tr><tr><td>Penny</td><td>$0.01 (PENNY)</td></tr><tr><td>Nickel</td><td>$0.05 (NICKEL)</td></tr><tr><td>Dime</td><td>$0.1 (DIME)</td></tr><tr><td>Quarter</td><td>$0.25 (QUARTER)</td></tr><tr><td>Dollar</td><td>$1 (DOLLAR)</td></tr><tr><td>Five Dollars</td><td>$5 (FIVE)</td></tr><tr><td>Ten Dollars</td><td>$10 (TEN)</td></tr><tr><td>Twenty Dollars</td><td>$20 (TWENTY)</td></tr><tr><td>One-hundred Dollars</td><td>$100 (ONE HUNDRED)</td></tr></table>"
],
"challengeSeed": [
"function checkCashRegister(price, cash, cid) {",
" var change;",
" // Here is your change, ma'am.",
" return change;",
"}",
"",
"// Example cash-in-drawer array:",
"// [[\"PENNY\", 1.01],",
"// [\"NICKEL\", 2.05],",
"// [\"DIME\", 3.1],",
"// [\"QUARTER\", 4.25],",
"// [\"ONE\", 90],",
"// [\"FIVE\", 55],",
"// [\"TEN\", 20],",
"// [\"TWENTY\", 60],",
"// [\"ONE HUNDRED\", 100]]",
"",
"checkCashRegister(19.5, 20, [[\"PENNY\", 1.01], [\"NICKEL\", 2.05], [\"DIME\", 3.1], [\"QUARTER\", 4.25], [\"ONE\", 90], [\"FIVE\", 55], [\"TEN\", 20], [\"TWENTY\", 60], [\"ONE HUNDRED\", 100]]);"
],
"solutions": [
"var denom = [\n\t{ name: 'ONE HUNDRED', val: 100},\n\t{ name: 'TWENTY', val: 20},\n\t{ name: 'TEN', val: 10},\n\t{ name: 'FIVE', val: 5},\n\t{ name: 'ONE', val: 1},\n\t{ name: 'QUARTER', val: 0.25},\n\t{ name: 'DIME', val: 0.1},\n\t{ name: 'NICKEL', val: 0.05},\n\t{ name: 'PENNY', val: 0.01}\n];\n\nfunction checkCashRegister(price, cash, cid) {\n var change = cash - price;\n var register = cid.reduce(function(acc, curr) {\n acc.total += curr[1];\n acc[curr[0]] = curr[1];\n return acc;\n }, {total: 0});\n if(register.total === change) {\n return 'Closed';\n }\n if(register.total < change) {\n return 'Insufficient Funds';\n }\n var change_arr = denom.reduce(function(acc, curr) {\n var value = 0;\n while(register[curr.name] > 0 && change >= curr.val) {\n change -= curr.val;\n register[curr.name] -= curr.val;\n value += curr.val;\n change = Math.round(change * 100) / 100;\n }\n if(value > 0) {\n acc.push([ curr.name, value ]);\n }\n return acc;\n }, []);\n if(change_arr.length < 1 || change > 0) {\n return \"Insufficient Funds\";\n }\n return change_arr;\n}"
],
"tests": [
"assert.isArray(checkCashRegister(19.5, 20, [[\"PENNY\", 1.01], [\"NICKEL\", 2.05], [\"DIME\", 3.1], [\"QUARTER\", 4.25], [\"ONE\", 90], [\"FIVE\", 55], [\"TEN\", 20], [\"TWENTY\", 60], [\"ONE HUNDRED\", 100]]), 'message: <code>checkCashRegister(19.5, 20, [[\"PENNY\", 1.01], [\"NICKEL\", 2.05], [\"DIME\", 3.1], [\"QUARTER\", 4.25], [\"ONE\", 90], [\"FIVE\", 55], [\"TEN\", 20], [\"TWENTY\", 60], [\"ONE HUNDRED\", 100]])</code> should return an array.');",
"assert.isString(checkCashRegister(19.5, 20, [[\"PENNY\", 0.01], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 0], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]]), 'message: <code>checkCashRegister(19.5, 20, [[\"PENNY\", 0.01], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 0], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]])</code> should return a string.');",
"assert.isString(checkCashRegister(19.5, 20, [[\"PENNY\", 0.5], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 0], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]]), 'message: <code>checkCashRegister(19.5, 20, [[\"PENNY\", 0.5], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 0], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]])</code> should return a string.');",
"assert.deepEqual(checkCashRegister(19.5, 20, [[\"PENNY\", 1.01], [\"NICKEL\", 2.05], [\"DIME\", 3.1], [\"QUARTER\", 4.25], [\"ONE\", 90], [\"FIVE\", 55], [\"TEN\", 20], [\"TWENTY\", 60], [\"ONE HUNDRED\", 100]]), [[\"QUARTER\", 0.5]], 'message: <code>checkCashRegister(19.5, 20, [[\"PENNY\", 1.01], [\"NICKEL\", 2.05], [\"DIME\", 3.1], [\"QUARTER\", 4.25], [\"ONE\", 90], [\"FIVE\", 55], [\"TEN\", 20], [\"TWENTY\", 60], [\"ONE HUNDRED\", 100]])</code> should return <code>[[\"QUARTER\", 0.5]]</code>.');",
"assert.deepEqual(checkCashRegister(3.26, 100, [[\"PENNY\", 1.01], [\"NICKEL\", 2.05], [\"DIME\", 3.1], [\"QUARTER\", 4.25], [\"ONE\", 90], [\"FIVE\", 55], [\"TEN\", 20], [\"TWENTY\", 60], [\"ONE HUNDRED\", 100]]), [[\"TWENTY\", 60], [\"TEN\", 20], [\"FIVE\", 15], [\"ONE\", 1], [\"QUARTER\", 0.5], [\"DIME\", 0.2], [\"PENNY\", 0.04]], 'message: <code>checkCashRegister(3.26, 100, [[\"PENNY\", 1.01], [\"NICKEL\", 2.05], [\"DIME\", 3.1], [\"QUARTER\", 4.25], [\"ONE\", 90], [\"FIVE\", 55], [\"TEN\", 20], [\"TWENTY\", 60], [\"ONE HUNDRED\", 100]])</code> should return <code>[[\"TWENTY\", 60], [\"TEN\", 20], [\"FIVE\", 15], [\"ONE\", 1], [\"QUARTER\", 0.5], [\"DIME\", 0.2], [\"PENNY\", 0.04]]</code>.');",
"assert.deepEqual(checkCashRegister(19.5, 20, [[\"PENNY\", 0.01], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 0], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]]), \"Insufficient Funds\", 'message: <code>checkCashRegister(19.5, 20, [[\"PENNY\", 0.01], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 0], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]])</code> should return \"Insufficient Funds\".');",
"assert.deepEqual(checkCashRegister(19.5, 20, [[\"PENNY\", 0.01], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 1], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]]), \"Insufficient Funds\", 'message: <code>checkCashRegister(19.5, 20, [[\"PENNY\", 0.01], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 1], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]])</code> should return \"Insufficient Funds\".');",
"assert.deepEqual(checkCashRegister(19.5, 20, [[\"PENNY\", 0.5], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 0], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]]), \"Closed\", 'message: <code>checkCashRegister(19.5, 20, [[\"PENNY\", 0.5], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 0], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]])</code> should return \"Closed\".');"
],
"type": "bonfire",
"MDNlinks": [
"Global Object",
"Floating Point Guide"
],
"challengeType": 5,
"translations": {
"es": {
"title": "Cambio Exacto",
"description": [
"Crea una función que simule una caja registradora que acepte el precio de compra como el primer argumento, la cantidad recibida como el segundo argumento, y la cantidad de dinero disponible en la registradora (cid) como tercer argumento",
"cid es un arreglo bidimensional que lista la cantidad de dinero disponible",
"La función debe devolver la cadena de texto \"Insufficient Funds\" si el cid es menor al cambio requerido. También debe devolver \"Closed\" si el cid es igual al cambio",
"De no ser el caso, devuelve el cambio en monedas y billetes, ordenados de mayor a menor denominación.",
"Recuerda utilizar <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> si te sientes atascado. Intenta programar en pareja. Escribe tu propio código."
]
},
"it": {
"title": "Cambio Esatto",
"description": [
"Scrivi una funzione che simuli un registro di cassa chiamata <code>checkCashRegister()</code> che accetti il prezzo degli articoli come primo argomento (<code>price</code>), la somma pagata (<code>cash</code>), e la somma disponibile nel registratore di cassa (<code>cid</code>) come terzo argomento.",
"<code>cid</code> è un array a due dimensioni che contiene la quantità di monete e banconote disponibili.",
"Ritorna la stringa <code>\"Insufficient Funds\"</code> se la quantità di denaro disponibile nel registratore di cassa non è abbastanza per restituire il resto. Ritorna la stringa <code>\"Closed\"</code> se il denaro disponibile è esattamente uguale al resto.",
"Altrimenti, ritorna il resto in monete e banconote, ordinate da quelle con valore maggiore a quelle con valore minore.",
"Ricorda di usare <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Leggi-Cerca-Chiedi</a> se rimani bloccato. Prova a programmare in coppia. Scrivi il codice da te."
]
},
"pt-br": {
"title": "Troco Exato",
"description": [
"Crie uma função que simula uma caixa registradora chamada <code>checkCashRegister()</code> e aceita o valor da compra como primeiro argumento (<code>price</code>), pagamento como segundo argumento (<code>cash</code>), e o dinheiro na caixa registradora (<code>cid</code>) como terceiro argumento.",
"<code>cid</code> é uma matriz bidimensional que lista o dinheiro disponível.",
"Retorne a string <code>\"Insufficient Funds\"</code> se o dinheiro na caixa registradora é menor do que o troco ou se não é possível retornar o troco exato. Retorne a string <code>\"Closed\"</code> se o dinheiro na caixa é igual ao troco.",
"Case cotrário, retorne o troco em moedas e notas, ordenado do maior para menor.",
"Lembre-se de usar <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Ler-Procurar-Perguntar</a> se você ficar preso. Tente programar em par. Escreva seu próprio código.",
"<table class='table table-striped'><tr><th>Currency Unit</th><th>Amount</th></tr><tr><td>Penny</td><td>$0.01 (PENNY)</td></tr><tr><td>Nickel</td><td>$0.05 (NICKEL)</td></tr><tr><td>Dime</td><td>$0.1 (DIME)</td></tr><tr><td>Quarter</td><td>$0.25 (QUARTER)</td></tr><tr><td>Dollar</td><td>$1 (DOLLAR)</td></tr><tr><td>Five Dollars</td><td>$5 (FIVE)</td></tr><tr><td>Ten Dollars</td><td>$10 (TEN)</td></tr><tr><td>Twenty Dollars</td><td>$20 (TWENTY)</td></tr><tr><td>One-hundred Dollars</td><td>$100 (ONE HUNDRED)</td></tr></table>"
]
}
}
},
{
"id": "a56138aff60341a09ed6c480",
"title": "Inventory Update",
"description": [
"Compare and update the inventory stored in a 2D array against a second 2D array of a fresh delivery. Update the current existing inventory item quantities (in <code>arr1</code>). If an item cannot be found, add the new item and quantity into the inventory array. The returned inventory array should be in alphabetical order by item.",
"Remember to use <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> if you get stuck. Try to pair program. Write your own code."
],
"challengeSeed": [
"function updateInventory(arr1, arr2) {",
" // All inventory must be accounted for or you're fired!",
" return arr1;",
"}",
"",
"// Example inventory lists",
"var curInv = [",
" [21, \"Bowling Ball\"],",
" [2, \"Dirty Sock\"],",
" [1, \"Hair Pin\"],",
" [5, \"Microphone\"]",
"];",
"",
"var newInv = [",
" [2, \"Hair Pin\"],",
" [3, \"Half-Eaten Apple\"],",
" [67, \"Bowling Ball\"],",
" [7, \"Toothpaste\"]",
"];",
"",
"updateInventory(curInv, newInv);"
],
"solutions": [
"function updateInventory(arr1, arr2) {\n arr2.forEach(function(item) {\n createOrUpdate(arr1, item);\n });\n // All inventory must be accounted for or you're fired!\n return arr1;\n}\n\nfunction createOrUpdate(arr1, item) {\n var index = -1;\n while (++index < arr1.length) {\n if (arr1[index][1] === item[1]) {\n arr1[index][0] += item[0];\n return;\n }\n if (arr1[index][1] > item[1]) {\n break;\n }\n }\n arr1.splice(index, 0, item);\n}\n\n// Example inventory lists\nvar curInv = [\n [21, 'Bowling Ball'],\n [2, 'Dirty Sock'],\n [1, 'Hair Pin'],\n [5, 'Microphone']\n];\n\nvar newInv = [\n [2, 'Hair Pin'],\n [3, 'Half-Eaten Apple'],\n [67, 'Bowling Ball'],\n [7, 'Toothpaste']\n];\n\nupdateInventory(curInv, newInv);\n"
],
"tests": [
"assert.isArray(updateInventory([[21, \"Bowling Ball\"], [2, \"Dirty Sock\"], [1, \"Hair Pin\"], [5, \"Microphone\"]], [[2, \"Hair Pin\"], [3, \"Half-Eaten Apple\"], [67, \"Bowling Ball\"], [7, \"Toothpaste\"]]), 'message: The function <code>updateInventory</code> should return an array.');",
"assert.equal(updateInventory([[21, \"Bowling Ball\"], [2, \"Dirty Sock\"], [1, \"Hair Pin\"], [5, \"Microphone\"]], [[2, \"Hair Pin\"], [3, \"Half-Eaten Apple\"], [67, \"Bowling Ball\"], [7, \"Toothpaste\"]]).length, 6, 'message: <code>updateInventory([[21, \"Bowling Ball\"], [2, \"Dirty Sock\"], [1, \"Hair Pin\"], [5, \"Microphone\"]], [[2, \"Hair Pin\"], [3, \"Half-Eaten Apple\"], [67, \"Bowling Ball\"], [7, \"Toothpaste\"]])</code> should return an array with a length of 6.');",
"assert.deepEqual(updateInventory([[21, \"Bowling Ball\"], [2, \"Dirty Sock\"], [1, \"Hair Pin\"], [5, \"Microphone\"]], [[2, \"Hair Pin\"], [3, \"Half-Eaten Apple\"], [67, \"Bowling Ball\"], [7, \"Toothpaste\"]]), [[88, \"Bowling Ball\"], [2, \"Dirty Sock\"], [3, \"Hair Pin\"], [3, \"Half-Eaten Apple\"], [5, \"Microphone\"], [7, \"Toothpaste\"]], 'message: <code>updateInventory([[21, \"Bowling Ball\"], [2, \"Dirty Sock\"], [1, \"Hair Pin\"], [5, \"Microphone\"]], [[2, \"Hair Pin\"], [3, \"Half-Eaten Apple\"], [67, \"Bowling Ball\"], [7, \"Toothpaste\"]])</code> should return <code>[[88, \"Bowling Ball\"], [2, \"Dirty Sock\"], [3, \"Hair Pin\"], [3, \"Half-Eaten Apple\"], [5, \"Microphone\"], [7, \"Toothpaste\"]]</code>.');",
"assert.deepEqual(updateInventory([[21, \"Bowling Ball\"], [2, \"Dirty Sock\"], [1, \"Hair Pin\"], [5, \"Microphone\"]], []), [[21, \"Bowling Ball\"], [2, \"Dirty Sock\"], [1, \"Hair Pin\"], [5, \"Microphone\"]], 'message: <code>updateInventory([[21, \"Bowling Ball\"], [2, \"Dirty Sock\"], [1, \"Hair Pin\"], [5, \"Microphone\"]], [])</code> should return <code>[[21, \"Bowling Ball\"], [2, \"Dirty Sock\"], [1, \"Hair Pin\"], [5, \"Microphone\"]]</code>.');",
"assert.deepEqual(updateInventory([], [[2, \"Hair Pin\"], [3, \"Half-Eaten Apple\"], [67, \"Bowling Ball\"], [7, \"Toothpaste\"]]), [[67, \"Bowling Ball\"], [2, \"Hair Pin\"], [3, \"Half-Eaten Apple\"], [7, \"Toothpaste\"]], 'message: <code>updateInventory([], [[2, \"Hair Pin\"], [3, \"Half-Eaten Apple\"], [67, \"Bowling Ball\"], [7, \"Toothpaste\"]])</code> should return <code>[[67, \"Bowling Ball\"], [2, \"Hair Pin\"], [3, \"Half-Eaten Apple\"], [7, \"Toothpaste\"]]</code>.');",
"assert.deepEqual(updateInventory([[0, \"Bowling Ball\"], [0, \"Dirty Sock\"], [0, \"Hair Pin\"], [0, \"Microphone\"]], [[1, \"Hair Pin\"], [1, \"Half-Eaten Apple\"], [1, \"Bowling Ball\"], [1, \"Toothpaste\"]]), [[1, \"Bowling Ball\"], [0, \"Dirty Sock\"], [1, \"Hair Pin\"], [1, \"Half-Eaten Apple\"], [0, \"Microphone\"], [1, \"Toothpaste\"]], 'message: <code>updateInventory([[0, \"Bowling Ball\"], [0, \"Dirty Sock\"], [0, \"Hair Pin\"], [0, \"Microphone\"]], [[1, \"Hair Pin\"], [1, \"Half-Eaten Apple\"], [1, \"Bowling Ball\"], [1, \"Toothpaste\"]])</code> should return <code>[[1, \"Bowling Ball\"], [0, \"Dirty Sock\"], [1, \"Hair Pin\"], [1, \"Half-Eaten Apple\"], [0, \"Microphone\"], [1, \"Toothpaste\"]]</code>.');"
],
"type": "bonfire",
"MDNlinks": [
"Global Array Object"
],
"challengeType": 5,
"translations": {
"es": {
"title": "Actualizando el Inventario",
"description": [
"Compara y actualiza el inventario actual, almacenado en un arreglo bidimensional, contra otro arreglo bidimensional de inventario nuevo. Actualiza las cantidades en el inventario actual y, en caso de recibir una nueva mercancía, añade su nombre y la cantidad recibida al arreglo del inventario en orden alfabético.",
"Recuerda utilizar <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> si te sientes atascado. Intenta programar en pareja. Escribe tu propio código."
]
},
"it": {
"title": "Aggiornamento dell'Inventario",
"description": [
"Confronta e aggiorna l'inventario, contenuto in un array bidimensionale, con un secondo array bidimensionale relativo ad una nuova consegna. Aggiorna le quantità disponibili in inventario (dentro <code>arr1</code>). Se uno degli articoli non è presente nell'inventario, aggiungi allo stesso il nuovo articolo e la sua quantità. Ritorna un array con l'inventario aggiornato, che deve essere ordinato alfabeticamente per articolo.",
"Ricorda di usare <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Leggi-Cerca-Chiedi</a> se rimani bloccato. Prova a programmare in coppia. Scrivi il codice da te."
]
},
"pt-br": {
"title": "Atualizando Inventário",
"description": [
"Compare e atualize o inventário armazenado em um matriz 2D contra uma segunda matriz 2D de uma entrega recente. Atualize a quantidade de itens no inventário atual (em <code>arr1</code>). Se um item não pode ser encontrado, adicione um novo item e a sua quantidade na matriz do inventário. O inventário retornado deve estar em ordem alfabética por item.",
"Lembre-se de usar <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Ler-Procurar-Perguntar</a> se você ficar preso. Tente programar em par. Escreva seu próprio código."
]
}
}
},
{
"id": "a7bf700cd123b9a54eef01d5",
"title": "No Repeats Please",
"description": [
"Return the number of total permutations of the provided string that don't have repeated consecutive letters. Assume that all characters in the provided string are each unique.",
"For example, <code>aab</code> should return 2 because it has 6 total permutations (<code>aab</code>, <code>aab</code>, <code>aba</code>, <code>aba</code>, <code>baa</code>, <code>baa</code>), but only 2 of them (<code>aba</code> and <code>aba</code>) don't have the same letter (in this case <code>a</code>) repeating.",
"Remember to use <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> if you get stuck. Try to pair program. Write your own code."
],
"challengeSeed": [
"function permAlone(str) {",
" return str;",
"}",
"",
"permAlone('aab');"
],
"solutions": [
"function permAlone(str) {\n return permutor(str).filter(function(perm) {\n return !perm.match(/(.)\\1/g);\n }).length;\n}\n\nfunction permutor(str) {\n // http://staff.roguecc.edu/JMiller/JavaScript/permute.html\n //permArr: Global array which holds the list of permutations\n //usedChars: Global utility array which holds a list of \"currently-in-use\" characters\n var permArr = [], usedChars = [];\n function permute(input) {\n //convert input into a char array (one element for each character)\n var i, ch, chars = input.split(\"\");\n for (i = 0; i < chars.length; i++) {\n //get and remove character at index \"i\" from char array\n ch = chars.splice(i, 1);\n //add removed character to the end of used characters\n usedChars.push(ch);\n //when there are no more characters left in char array to add, add used chars to list of permutations\n if (chars.length === 0) permArr[permArr.length] = usedChars.join(\"\");\n //send characters (minus the removed one from above) from char array to be permuted\n permute(chars.join(\"\"));\n //add removed character back into char array in original position\n chars.splice(i, 0, ch);\n //remove the last character used off the end of used characters array\n usedChars.pop();\n }\n }\n permute(str);\n return permArr;\n}\n\npermAlone('aab');\n"
],
"tests": [
"assert.isNumber(permAlone('aab'), 'message: <code>permAlone(\"aab\")</code> should return a number.');",
"assert.strictEqual(permAlone('aab'), 2, 'message: <code>permAlone(\"aab\")</code> should return 2.');",
"assert.strictEqual(permAlone('aaa'), 0, 'message: <code>permAlone(\"aaa\")</code> should return 0.');",
"assert.strictEqual(permAlone('aabb'), 8, 'message: <code>permAlone(\"aabb\")</code> should return 8.');",
"assert.strictEqual(permAlone('abcdefa'), 3600, 'message: <code>permAlone(\"abcdefa\")</code> should return 3600.');",
"assert.strictEqual(permAlone('abfdefa'), 2640, 'message: <code>permAlone(\"abfdefa\")</code> should return 2640.');",
"assert.strictEqual(permAlone('zzzzzzzz'), 0, 'message: <code>permAlone(\"zzzzzzzz\")</code> should return 0.');",
"assert.strictEqual(permAlone('a'), 1, 'message: <code>permAlone(\"a\")</code> should return 1.');",
"assert.strictEqual(permAlone('aaab'), 0, 'message: <code>permAlone(\"aaab\")</code> should return 0.');",
"assert.strictEqual(permAlone('aaabb'), 12, 'message: <code>permAlone(\"aaabb\")</code> should return 12.');"
],
"type": "bonfire",
"MDNlinks": [
"Permutations",
"RegExp"
],
"challengeType": 5,
"translations": {
"es": {
"title": "Sin Repeticiones, por Favor",
"description": [
"Crea una función que devuelva el número total de permutaciones de las letras en la cadena de texto provista, en las cuales no haya letras consecutivas repetidas",
"Por ejemplo, 'aab' debe retornar 2 porque, del total de 6 permutaciones posibles, solo 2 de ellas no tienen repetida la misma letra (en este caso 'a').",
"Recuerda utilizar <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> si te sientes atascado. Intenta programar en pareja. Escribe tu propio código."
]
},
"it": {
"title": "Niente Ripetizioni, per Favore",
"description": [
"Ritorna il numero totale di permutazioni della stringa passata che non hanno lettere consecutive riptetute. Assumi che tutti i caratteri nella stringa passata siano unici.",
"Per esempio, <code>aab</code> deve ritornare 2, perchè la stringa ha 6 permutazioni possibili in totale (<code>aab</code>, <code>aab</code>, <code>aba</code>, <code>aba</code>, <code>baa</code>, <code>baa</code>), ma solo 2 di loro (<code>aba</code> e <code>aba</code>) non contengono la stessa lettera (in questo caso <code>a</code> ripetuta).",
"Ricorda di usare <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Leggi-Cerca-Chiedi</a> se rimani bloccato. Prova a programmare in coppia. Scrivi il codice da te."
]
},
"pt-br": {
"title": "Sem repetição, por favor",
"description": [
"Retorne o número total de permutações da string fornecida que não tem letras consecutivas repetidas. Assuma que todos os caracteres na string fornecida são únicos.",
"Por exemplo, <code>aab</code> deve retornar 2 porque tem um total de 6 permutações (<code>aab</code>, <code>aab</code>, <code>aba</code>, <code>aba</code>, <code>baa</code>, <code>baa</code>), mas somente duas delas (<code>aba</code> and <code>aba</code>) não tem a mesma letra (nesse caso <code>a</code>) se repetindo.",
"Lembre-se de usar <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Ler-Procurar-Perguntar</a> se você ficar preso. Tente programar em par. Escreva seu próprio código."
]
}
}
},
{
"id": "a3f503de51cfab748ff001aa",
"title": "Pairwise",
"description": [
"Given an array <code>arr</code>, find element pairs whose sum equal the second argument <code>arg</code> and return the sum of their indices.",
"You may use multiple pairs that have the same numeric elements but different indices. Each pair should use the lowest possible available indices. Once an element has been used it cannot be reused to pair with another element.",
"For example <code>pairwise([7, 9, 11, 13, 15], 20)</code> returns <code>6</code>. The pairs that sum to 20 are <code>[7, 13]</code> and <code>[9, 11]</code>. We can then write out the array with their indices and values.",
"<table class=\"table\"><tr><th><strong>Index</strong></th><th>0</th><th>1</th><th>2</th><th>3</th><th>4</th></tr><tr><td>Value</td><td>7</td><td>9</td><td>11</td><td>13</td><td>15</td></tr></table>",
"Below we'll take their corresponding indices and add them.",
"7 + 13 = 20 &#8594; Indices 0 + 3 = 3<br>9 + 11 = 20 &#8594; Indices 1 + 2 = 3<br>3 + 3 = 6 &#8594 Return <code>6</code>",
"Remember to use <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> if you get stuck. Try to pair program. Write your own code."
],
"challengeSeed": [
"function pairwise(arr, arg) {",
" return arg;",
"}",
"",
"pairwise([1,4,2,3,0,5], 7);"
],
"solutions": [
"function pairwise(arr, arg) {\n var sum = 0;\n arr.forEach(function(e, i, a) {\n if (e != null) { \n var diff = arg-e;\n a[i] = null;\n var dix = a.indexOf(diff);\n if (dix !== -1) {\n sum += dix;\n sum += i;\n a[dix] = null;\n } \n }\n });\n return sum;\n}\n\npairwise([1,4,2,3,0,5], 7);\n"
],
"tests": [
"assert.deepEqual(pairwise([1, 4, 2, 3, 0, 5], 7), 11, 'message: <code>pairwise([1, 4, 2, 3, 0, 5], 7)</code> should return 11.');",
"assert.deepEqual(pairwise([1, 3, 2, 4], 4), 1, 'message: <code>pairwise([1, 3, 2, 4], 4)</code> should return 1.');",
"assert.deepEqual(pairwise([1, 1, 1], 2), 1, 'message: <code>pairwise([1, 1, 1], 2)</code> should return 1.');",
"assert.deepEqual(pairwise([0, 0, 0, 0, 1, 1], 1), 10, 'message: <code>pairwise([0, 0, 0, 0, 1, 1], 1)</code> should return 10.');",
"assert.deepEqual(pairwise([], 100), 0, 'message: <code>pairwise([], 100)</code> should return 0.');"
],
"type": "bonfire",
"MDNlinks": [
"Array.prototype.reduce()"
],
"challengeType": 5,
"translations": {
"es": {
"title": "En Parejas",
"description": [
"Crea una función que devuelva la suma de todos los índices de los elementos de 'arr' que pueden ser emparejados con otro elemento de tal forma que la suma de ambos equivalga al valor del segundo argumento, 'arg'. Si varias combinaciones son posibles, devuelve la menor suma de índices. Una vez un elemento ha sido usado, no puede ser usado de nuevo para emparejarlo con otro elemento.",
"Por ejemplo, pairwise([1, 4, 2, 3, 0, 5], 7) debe devolver 11 porque 4, 2, 3 y 5 pueden ser emparejados para obtener una suma de 7",
"pairwise([1, 3, 2, 4], 4) devolvería el valor de 1, porque solo los primeros dos elementos pueden ser emparejados para sumar 4. ¡Recuerda que el primer elemento tiene un índice de 0!",
"Recuerda utilizar <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> si te sientes atascado. Intenta programar en pareja. Escribe tu propio código."
]
},
"it": {
"title": "A Coppie",
"description": [
"Dato un array <code>arr</code>, trova le coppie di elementi la cui somma è uguale al secondo argomento passato <code>arg</code>. Ritorna quindi la somma dei loro indici.",
"Se ci sono più coppie possibili che hanno lo stesso valore numerico ma indici differenti, ritorna la somma degli indici minore. Una volta usato un elemento, lo stesso non può essere riutilizzato per essere accoppiato con un altro.",
"Per esempio <code>pairwise([7, 9, 11, 13, 15], 20)</code> ritorna <code>6</code>. Le coppia la cui somma è 20 sono <code>[7, 13]</code> e <code>[9, 11]</code>. Possiamo quindi osservare l'array con i loro indici e valori.",
"<table class=\"table\"><tr><th><strong>Indice</strong></th><th>0</th><th>1</th><th>2</th><th>3</th><th>4</th></tr><tr><td>Valore</td><td>7</td><td>9</td><td>11</td><td>13</td><td>15</td></tr></table>",
"Qui sotto prendiamo gli indici corrispondenti e li sommiamo.",
"7 + 13 = 20 &#8594; Indici 0 + 3 = 3<br>9 + 11 = 20 &#8594; Indici 1 + 2 = 3<br>3 + 3 = 6 &#8594 Ritorna <code>6</code>",
"Ricorda di usare <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Leggi-Cerca-Chiedi</a> se rimani bloccato. Prova a programmare in coppia. Scrivi il codice da te."
]
},
"pt-br": {
"title": "Emparelhados",
"description": [
"Dado uma matriz <code>arr</code>, encontre pares de elementos no qual a soma é igual ao segundo argumento <code>arg</code> e retorne a soma dos seus indices.",
"Se multiplos pares tem o mesmo elemento numérico mas indices diferentes, retorne a soma dos menores indices. Uma vez que um elemento é usado, este não pode ser emparelhado novamente com outro elemento.",
"Por exemplo <code>pairwise([7, 9, 11, 13, 15], 20)</code> retorna <code>6</code>. Os pares que somam 20 são <code>[7, 13]</code> e <code>[9, 11]</code>. Nós podemos então criar a matriz com seus indices e valores.",
"<table class=\"table\"><tr><th><strong>Index</strong></th><th>0</th><th>1</th><th>2</th><th>3</th><th>4</th></tr><tr><td>Value</td><td>7</td><td>9</td><td>11</td><td>13</td><td>15</td></tr></table>",
"Abaixo nós pegamos os índices correspondentes e somá-los.",
"7 + 13 = 20 &#8594; Indices 0 + 3 = 3<br>9 + 11 = 20 &#8594; Indices 1 + 2 = 3<br>3 + 3 = 6 &#8594 Retorna <code>6</code>",
"Lembre-se de usar <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Ler-Procurar-Perguntar</a> se você ficar preso. Tente programar em par. Escreva seu próprio código."
]
}
}
},
{
"id": "8d5123c8c441eddfaeb5bdef",
"title": "Implement Bubble Sort",
"description": [
"This is the first of several challenges on sorting algorithms. Given an array of unsorted items, we want to be able to return a sorted array. We will see several different methods to do this and learn some tradeoffs between these different approaches. While most modern languages have built-in sorting methods for operations like this, it is still important to understand some of the common basic approaches and learn how they can be implemented.",
"Here we will see bubble sort. The bubble sort method starts at the beginning of an unsorted array and 'bubbles up' unsorted values towards the end, iterating through the array until it is completely sorted. It does this by comparing adjacent items and swapping them if they are out of order. The method continues looping through the array until no swaps occur at which point the array is sorted.",
"This method requires multiple iterations through the array and for average and worst cases has quadratic time complexity. While simple, it is usually impractical in most situations.",
"<strong>Instructions:</strong> Write a function <code>bubbleSort</code> which takes an array of integers as input and returns an array of these integers in sorted order from least to greatest.",
"<strong>Note:</strong><br>We are calling this function from behind the scenes; the test array we are using is commented out in the editor. Try logging <code>array</code> to see your sorting alogrithm in action!"
],
"challengeSeed": [
"function bubbleSort(array) {",
" // change code below this line",
"",
" // change code above this line",
" return array;",
"}",
"",
"// test array:",
"// [1, 4, 2, 8, 345, 123, 43, 32, 5643, 63, 123, 43, 2, 55, 1, 234, 92]"
],
"tail": [
"function isSorted(arr) {",
" var check = (i) => (i == arr.length - 1) ? true : (arr[i] > arr[i + 1]) ? false : check(i + 1);",
" return check(0);",
"};"
],
"tests": [
"assert(typeof bubbleSort == 'function', 'message: <code>bubbleSort</code> is a function.');",
"assert(isSorted(bubbleSort([1,4,2,8,345,123,43,32,5643,63,123,43,2,55,1,234,92])), 'message: <code>bubbleSort</code> returns a sorted array (least to greatest).');",
"assert.sameMembers(bubbleSort([1,4,2,8,345,123,43,32,5643,63,123,43,2,55,1,234,92]), [1,4,2,8,345,123,43,32,5643,63,123,43,2,55,1,234,92], 'message: <code>bubbleSort</code> returns an array that is unchanged except for order.');",
"assert.strictEqual(code.search(/\\.sort\\(/), -1, 'message: <code>bubbleSort</code> should not use the built-in <code>.sort()</code> method.');"
],
"type": "waypoint",
"solutions": [],
"challengeType": 1,
"translations": {},
"releasedOn": "February 17, 2017"
},
{
"id": "587d8259367417b2b2512c85",
"title": "Implement Selection Sort",
"description": [
"Here we will implement selection sort. Selection sort works by selecting the minimum value in a list and swapping it with the first value in the list. It then starts at the second position, selects the smallest value in the remaining list, and swaps it with the second element. It continues iterating through the list and swapping elements until it reaches the end of the list. Now the list is sorted. Selection sort has quadratic time complexity in all cases.",
"<stong>Instructions</stong>: Write a function <code>selectionSort</code> which takes an array of integers as input and returns an array of these integers in sorted order from least to greatest.",
"<strong>Note:</strong><br>We are calling this function from behind the scenes; the test array we are using is commented out in the editor. Try logging <code>array</code> to see your sorting alogrithm in action!"
],
"challengeSeed": [
"function selectionSort(array) {",
" // change code below this line",
"",
" // change code above this line",
" return array;",
"}",
"",
"// test array:",
"// [1, 4, 2, 8, 345, 123, 43, 32, 5643, 63, 123, 43, 2, 55, 1, 234, 92]"
],
"tail": [
"function isSorted(arr) {",
" var check = (i) => (i == arr.length - 1) ? true : (arr[i] > arr[i + 1]) ? false : check(i + 1);",
" return check(0);",
"};"
],
"tests": [
"assert(typeof selectionSort == 'function', 'message: <code>selectionSort</code> is a function.');",
"assert(isSorted(selectionSort([1,4,2,8,345,123,43,32,5643,63,123,43,2,55,1,234,92])), 'message: <code>selectionSort</code> returns a sorted array (least to greatest).');",
"assert.sameMembers(selectionSort([1,4,2,8,345,123,43,32,5643,63,123,43,2,55,1,234,92]), [1,4,2,8,345,123,43,32,5643,63,123,43,2,55,1,234,92], 'message: <code>selectionSort</code> returns an array that is unchanged except for order.');",
"assert.strictEqual(code.search(/\\.sort\\(/), -1, 'message: <code>selectionSort</code> should not use the built-in <code>.sort()</code> method.');"
],
"type": "waypoint",
"solutions": [],
"challengeType": 1,
"translations": {},
"releasedOn": "February 17, 2017"
},
{
"id": "587d8259367417b2b2512c86",
"title": "Implement Insertion Sort",
"description": [
"The next sorting method we'll look at is insertion sort. This method works by building up a sorted array at the beginning of the list. It begins the sorted array with the first element. Then it inspects the next element and swaps it backwards into the sorted array until it is in sorted position. It continues iterating through the list and swapping new items backwards into the sorted portion until it reaches the end. This algorithm has quadratic time complexity in the average and worst cases.",
"<strong>Instructions:</strong> Write a function <code>insertionSort</code> which takes an array of integers as input and returns an array of these integers in sorted order from least to greatest.",
"<strong>Note:</strong><br>We are calling this function from behind the scenes; the test array we are using is commented out in the editor. Try logging <code>array</code> to see your sorting alogrithm in action!"
],
"challengeSeed": [
"function insertionSort(array) {",
" // change code below this line",
"",
" // change code above this line",
" return array;",
"}",
"",
"// test array:",
"// [1, 4, 2, 8, 345, 123, 43, 32, 5643, 63, 123, 43, 2, 55, 1, 234, 92]"
],
"tail": [
"function isSorted(arr) {",
" var check = (i) => (i == arr.length - 1) ? true : (arr[i] > arr[i + 1]) ? false : check(i + 1);",
" return check(0);",
"};"
],
"tests": [
"assert(typeof insertionSort == 'function', 'message: <code>insertionSort</code> is a function.');",
"assert(isSorted(insertionSort([1,4,2,8,345,123,43,32,5643,63,123,43,2,55,1,234,92])), 'message: <code>insertionSort</code> returns a sorted array (least to greatest).');",
"assert.sameMembers(insertionSort([1,4,2,8,345,123,43,32,5643,63,123,43,2,55,1,234,92]), [1,4,2,8,345,123,43,32,5643,63,123,43,2,55,1,234,92], 'message: <code>insertionSort</code> returns an array that is unchanged except for order.');",
"assert.strictEqual(code.search(/\\.sort\\(/), -1, 'message: <code>insertionSort</code> should not use the built-in <code>.sort()</code> method.');"
],
"type": "waypoint",
"solutions": [],
"challengeType": 1,
"translations": {},
"releasedOn": "February 17, 2017"
},
{
"id": "587d825a367417b2b2512c89",
"title": "Implement Quick Sort",
"description": [
"Here we will move on to an intermediate sorting algorithm: quick sort. Quick sort is an efficient, recursive divide-and-conquer approach to sorting an array. In this method, a pivot value is chosen in the original array. The array is then partitioned into two subarrays of values less than and greater than the pivot value. We then combine the result of recursively calling the quick sort algorithm on both sub-arrays. This continues until the base case of an empty or single-item array is reached, which we return. The unwinding of the recursive calls return us the sorted array.",
"Quick sort is a very efficient sorting method, providing <i>O(nlog(n))</i> performance on average. It is also relatively easy to implement. These attributes make it a popular and useful sorting method.",
"<strong>Instructions:</strong> Write a function <code>quickSort</code> which takes an array of integers as input and returns an array of these integers in sorted order from least to greatest. While the choice of the pivot value is important, any pivot will do for our purposes here. For simplicity, the first or last element could be used.",
"<strong>Note:</strong><br>We are calling this function from behind the scenes; the test array we are using is commented out in the editor. Try logging <code>array</code> to see your sorting alogrithm in action!"
],
"challengeSeed": [
"function quickSort(array) {",
" // change code below this line",
"",
" // change code above this line",
" return array;",
"}",
"",
"// test array:",
"// [1, 4, 2, 8, 345, 123, 43, 32, 5643, 63, 123, 43, 2, 55, 1, 234, 92]"
],
"tests": [
"assert(typeof quickSort == 'function', 'message: <code>quickSort</code> is a function.');",
"assert(isSorted(quickSort([1,4,2,8,345,123,43,32,5643,63,123,43,2,55,1,234,92])), 'message: <code>quickSort</code> returns a sorted array (least to greatest).');",
"assert.sameMembers(quickSort([1,4,2,8,345,123,43,32,5643,63,123,43,2,55,1,234,92]), [1,4,2,8,345,123,43,32,5643,63,123,43,2,55,1,234,92], 'message: <code>quickSort</code> returns an array that is unchanged except for order.');",
"assert.strictEqual(code.search(/\\.sort\\(/), -1, 'message: <code>quickSort</code> should not use the built-in <code>.sort()</code> method.');"
],
"tail": [
"function isSorted(arr) {",
" var check = (i) => (i == arr.length - 1) ? true : (arr[i] > arr[i + 1]) ? false : check(i + 1);",
" return check(0);",
"};"
],
"type": "waypoint",
"solutions": [],
"challengeType": 1,
"translations": {},
"releasedOn": "February 17, 2017"
},
{
"id": "587d825c367417b2b2512c8f",
"title": "Implement Merge Sort",
"description": [
"Another intermediate sorting algorithm that is very common is merge sort. Like quick sort, merge sort also uses a divide-and-conquer, recursive methodology to sort an array. It takes advantage of the fact that it is relatively easy to sort two arrays as long as each is sorted in the first place. But we'll start with only one array as input, so how do we get to two sorted arrays from that? Well, we can recursively divide the original input in two until we reach the base case of an array with one item. A single-item array is naturally sorted, so then we can start combining. This combination will unwind the recursive calls that split the original array, eventually producing a final sorted array of all the elements. The steps of merge sort, then, are:",
"<strong>1)</strong> Recursively split the input array in half until a sub-array with only one element is produced.",
"<strong>2)</strong> Merge each sorted sub-array together to produce the final sorted array.",
"Merge sort is an efficient sorting method, with time complexity of <i>O(nlog(n))</i>. This algorithm is popular because it is performant and relatively easy to implement.",
"As an aside, this will be the last sorting algorithm we cover here. However, later in the section on tree data structures we will describe heap sort, another efficient sorting method that requires a binary heap in its implementation.",
"<strong>Instructions:</strong> Write a function <code>mergeSort</code> which takes an array of integers as input and returns an array of these integers in sorted order from least to greatest. A good way to implement this is to write one function, for instance <code>merge</code>, which is responsible for merging two sorted arrays, and another function, for instance <code>mergeSort</code>, which is responsible for the recursion that produces single-item arrays to feed into merge. Good luck!",
"<strong>Note:</strong><br>We are calling this function from behind the scenes; the test array we are using is commented out in the editor. Try logging <code>array</code> to see your sorting alogrithm in action!"
],
"challengeSeed": [
"function mergeSort(array) {",
" // change code below this line",
"",
" // change code above this line",
" return array;",
"}",
"",
"// test array:",
"// [1, 4, 2, 8, 345, 123, 43, 32, 5643, 63, 123, 43, 2, 55, 1, 234, 92]"
],
"tests": [
"assert(typeof mergeSort == 'function', 'message: <code>mergeSort</code> is a function.');",
"assert(isSorted(mergeSort([1,4,2,8,345,123,43,32,5643,63,123,43,2,55,1,234,92])), 'message: <code>mergeSort</code> returns a sorted array (least to greatest).');",
"assert.sameMembers(mergeSort([1,4,2,8,345,123,43,32,5643,63,123,43,2,55,1,234,92]), [1,4,2,8,345,123,43,32,5643,63,123,43,2,55,1,234,92], 'message: <code>mergeSort</code> returns an array that is unchanged except for order.');",
"assert.strictEqual(code.search(/\\.sort\\(/), -1, 'message: <code>mergeSort</code> should not use the built-in <code>.sort()</code> method.');"
],
"tail": [
"function isSorted(arr) {",
" var check = (i) => (i == arr.length - 1) ? true : (arr[i] > arr[i + 1]) ? false : check(i + 1);",
" return check(0);",
"};"
],
"type": "waypoint",
"solutions": [],
"challengeType": 1,
"translations": {},
"releasedOn": "February 17, 2017"
}
]
}

View File

@ -0,0 +1,112 @@
{
"name": "JavaScript Multiple Choice Questions",
"order": 8,
"time": "",
"helpRoom": "HelpJavaScript",
"challenges": [
{
"id": "59874fc749228906236a3275",
"title": "Array.prototype.map",
"description": [
{
"subtitle": "Flooring an Array",
"question": "What will the following code print out?\n<pre><code class='language-javascript'>const results = [1.32, 2.43, 3.9]\n .map(Math.floor);\nconsole.log(results);</code></pre>",
"choices": [
"<pre><code class='language-javascript'>1.32 2.43 3.9</code></pre>",
"<pre><code class='language-javascript'>['1.32', '2.43', '3.9']</code></pre>",
"<pre><code class='language-javascript'>[1, 2, 3]</code></pre>",
"<pre><code class='language-javascript'>'1 2 3'</code></pre>"
],
"answer": 2,
"explanation": "The map function takes a callback function as it's first parameter and applies that function against every value inside the array. In this example, our callback function is the <code>Math.floor</code> function which will truncate the decimal points of all the numbers and convert them to integers."
},
{
"subtitle": "Custom Map Functions",
"question": "What will the following code print out?\n<pre><code class='language-javascript'>const results = ['a', 'b', 'c']\n .map(a => [a.toUpperCase()]);\nconsole.log(results);</code></pre>",
"choices": [
"<pre><code class='language-javascript'>[['A'], ['B'], ['C']]</code></pre>",
"<pre><code class='language-javascript'>['A', 'B', 'C']</code></pre>",
"<pre><code class='language-javascript'>['a', 'b', 'c]</code></pre>",
"<pre><code class='language-javascript'>'ABC'</code></pre>"
],
"answer": 0,
"explanation": "The map function will return a new array with each element equal to the old element ran through a callback function. Our callback function takes our original element, changes it to a upper case, and then wraps it in an array; thus, leaving us with <code>[['A', 'B', 'C']]</code>"
},
{
"subtitle": "Maps on Maps",
"question": "What will the following code print out?\n<pre><code class='language-javascript'>const results = [[4, 1], [2, 0], [3, 3]]\n .map(a => \n a.map(b => b % 2)[0] + a.map(b => b - 1)[1]\n )\nconsole.log(results);</code></pre>",
"choices": [
"<pre><code class='language-javascript'>[[0, 1], [0, 0], [1, 1]]</code></pre>",
"<pre><code class='language-javascript'>[[0, 0], [0, -1], [1, 2]]</code></pre>",
"<pre><code class='language-javascript'>[1, 1, 2]</code></pre>",
"<pre><code class='language-javascript'>[0, -1, 3]</code></pre>"
],
"answer": 3,
"explanation": "This answer can be explained by first looking at the example of what happens with the first element in our array, <code>[4, 1]</code>. Our first map callback will run a mod 2 map function over <code>[4, 1]</code> leaving us with a new array of <code>[0, 1]</code>. The second map call which is inside our callback will subtract 1 from every element, leaving us with <code>[3, 0]</code>. Last, we take element at index 0, <code>0</code>, and add it to element of index 1 from our second map function, <code>0</code>, leaving us with 0; thus, after the first iteration of the top level map function, we are left with an array that looks like so: <code>[1, [2, 0], [3, 3]]</code>. We simply keep doing that logic for the other elements until we finish: <code>[1, -1, [3, 3]]</code>, and <code>[1, -1, 3]</code>"
},
{
"subtitle": "Words Containing 'a'",
"question": "What will the following code print out?\n<pre><code class='language-javascript'>const results = ['apple', 'dog', 'cat']\n .map((a, i) => \n a.indexOf('a') !== -1 ? i : null)\nconsole.log(results);</code></pre>",
"choices": [
"<pre><code class='language-javascript'>[0, -1, 1]</code></pre>",
"<pre><code class='language-javascript'>[0, null, 2]</code></pre>",
"<pre><code class='language-javascript'>[null, null, null]</code></pre>",
"<pre><code class='language-javascript'>[-1, null, 2]</code></pre>"
],
"answer": 1,
"explanation": "This map example will return an array where each elements of the new array is either the original array index when the element contains the character 'a'; otherwise, an element of null for any words that do not have the character 'a'."
},
{
"subtitle": "Accessing the Original Array Elements",
"question": "What will the following code print out?\n<pre><code class='language-javascript'>const results = [1, 2, 3]\n .map((a, _, o) => a + o[0])\nconsole.log(results);</code></pre>",
"choices": [
"<pre><code class='language-javascript'>[1, 2, 3]</code></pre>",
"<pre><code class='language-javascript'>[0, 0, 0]</code></pre>",
"<pre><code class='language-javascript'>[3, 2, 1]</code></pre>",
"<pre><code class='language-javascript'>[2, 3, 4]</code></pre>"
],
"answer": 3,
"explanation": "This map example will add the value of the first element in the original array to all the other elements in the array."
},
{
"subtitle": "More Map Hacking",
"question": "What will the following code print out?\n<pre><code class='language-javascript'>const results = [8, 5, 3]\n .map((a, i, o) => o[o.length - i - i])\nconsole.log(results);</code></pre>",
"choices": [
"<pre><code class='language-javascript'>[3, 5, 8]</code></pre>",
"<pre><code class='language-javascript'>[5, 3, 8]</code></pre>",
"<pre><code class='language-javascript'>[8, 5, 3]</code></pre>",
"<pre><code class='language-javascript'>[3, 8, 5]</code></pre>"
],
"answer": 0,
"explanation": "This map example will reverse the array. The third argument to the map callback function is the original array; therefore, we can use the current index in the map function, and work our way backwards from the end of the array using the o.length."
},
{
"subtitle": "Custom Scoping",
"question": "What will the following code print out?\n<pre><code class='language-javascript'>const results = ['a', 'b', 'c']\n .map(function(a) { return this[a]; }, {a: 9, b: 3, c: 1})\nconsole.log(results);</code></pre>",
"choices": [
"<pre><code class='language-javascript'>['a', 'b', 'c']</code></pre>",
"<pre><code class='language-javascript'>[9, 3, 1]</code></pre>",
"<pre><code class='language-javascript'>[3, 9, 1]</code></pre>",
"<pre><code class='language-javascript'>[{a: 9}, {b: 3}, {c: 1}]</code></pre>"
],
"answer": 1,
"explanation": "This map example will reverse the array. The third argument to the map callback function is the original array; therefore, we can use the current index in the map function, and work our way backwards from the end of the array using the o.length."
},
{
"subtitle": "Reversing in Map, Just Because",
"question": "What will the following code print out?\n<pre><code class='language-javascript'>const results = [1, 2, 3, 4, 5]\n .map((a, _, o) => o.reverse() && a)\nconsole.log(results);</code></pre>",
"choices": [
"<pre><code class='language-javascript'>[5, 4, 3, 2, 1]</code></pre>",
"<pre><code class='language-javascript'>[5, 2, 3, 5, 1]</code></pre>",
"<pre><code class='language-javascript'>[1, 2, 3, 4, 5]</code></pre>",
"<pre><code class='language-javascript'>[1, 4, 3, 2, 5]</code></pre>"
],
"answer": 3,
"explanation": "This map example will reverse the array. The third argument to the map callback function is the original array; therefore, we can use the current index in the map function, and work our way backwards from the end of the array using the o.length."
}
],
"tests": [],
"challengeType": 8
}
]
}

View File

@ -0,0 +1,681 @@
{
"name": "Coding Interview Take-home Projects",
"order": 4,
"time": "",
"helpRoom": "HelpFrontEnd",
"challenges": [
{
"id": "bd7158d8c442eddfaeb5bd10",
"title": "Show the Local Weather",
"description": [
"<strong>Objective:</strong> Build a <a href='https://codepen.io' target='_blank'>CodePen.io</a> app that is functionally similar to this: <a href='https://codepen.io/freeCodeCamp/full/bELRjV' target='_blank'>https://codepen.io/freeCodeCamp/full/bELRjV</a>.",
"Fulfill the below <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>user stories</a>. Use whichever libraries or APIs you need. Give it your own personal style.",
"<strong>User Story:</strong> I can see the weather in my current location.",
"<strong>User Story:</strong> I can see a different icon or background image (e.g. snowy mountain, hot desert) depending on the weather.",
"<strong>User Story:</strong> I can push a button to toggle between Fahrenheit and Celsius.",
"<strong>Note:</strong> Many internet browsers now require an HTTP Secure (<code>https://</code>) connection to obtain a user's locale via HTML5 Geolocation. For this reason, we recommend using HTML5 Geolocation to get user location and then use the freeCodeCamp Weather API <a href='https://fcc-weather-api.glitch.me' target='_blank'>https://fcc-weather-api.glitch.me</a> which uses an HTTP Secure connection for the weather. Also, be sure to connect to <a href='https://codepen.io' target='_blank'>CodePen.io</a> via <code>https://</code>.",
"Remember to use <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> if you get stuck.",
"When you are finished, click the \"I've completed this challenge\" button and include a link to your CodePen.",
"You can get feedback on your project by sharing it with your friends on Facebook."
],
"challengeSeed": [
"GCLiJU-vvVc"
],
"tests": [],
"type": "zipline",
"challengeType": 3,
"isRequired": false,
"translations": {
"es": {
"title": "Muestra el clima local",
"description": [
"<span class='text-info'>Objetivo:</span> Crea una aplicación con <a href='https://codepen.io' target='_blank'>CodePen.io</a> cuya funcionalidad sea similar a la de esta: <a href='https://codepen.io/freeCodeCamp/full/bELRjV' target='_blank'>https://codepen.io/freeCodeCamp/full/bELRjV</a>.",
"Satisface las siguientes <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>historias de usuario</a>. Usa cualquier librería o APIs que necesites.",
"<span class='text-info'>Historia de usuario:</span> Pedo obtener información acerca del clima en mi localización actual.",
"<span class='text-info'>Historia de usuario:</span> Puedo ver un icono diferente o una imagen de fondo diferente (e.g. montaña con nieve, desierto caliente) dependiendo del clima.",
"<span class='text-info'>Historia de usuario:</span> Puedo pulsar un botón para cambiar la unidad de temperatura de grados Fahrenheit a Celsius y viceversa.",
"Recomendamos utilizar <a href='https://openweathermap.org/current#geo' target='_blank'>Open Weather API</a>. Al utilizarlo tendrás que crear una llave API gratuita. Normalmente debes evitar exponer llaves de API en CodePen, pero por el momento no hemos encontrado un API de clima que no requiera llave.",
"Recuerda utilizar <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Leer-Buscar-Preguntar</a> si te sientes atascado.",
"Cuando hayas terminado, pulsa el botón de \"I've completed this challenge\" e incluye un enlace a tu CodePen.",
"Puedes obtener retroalimentación sobre tu proyecto por parte de otros campistas, compartiendolo en nuestra <a href='//gitter.im/freecodecamp/codereview' target='_blank'>Sala de chat para revisión de código</a>. También puedes compartirlo en Twitter y en el campamento de tu ciudad (en Facebook)."
]
},
"ru": {
"title": "Покажите местную погоду",
"description": [
"<span class='text-info'>Задание:</span> Создайте <a href='https://codepen.io' target='_blank'>CodePen.io</a> который успешно копирует вот этот: <a href='https://codepen.io/freeCodeCamp/full/bELRjV' target='_blank'>https://codepen.io/freeCodeCamp/full/bELRjV</a>.",
"<span class='text-info'>Правило #1:</span> Не подсматривайте код приведенного на CodePen примера. Напишите его самостоятельно.",
"<span class='text-info'>Правило #2:</span> Можете использовать любые библиотеки или API, которые потребуются.",
"<span class='text-info'>Правило #3:</span> Воссоздайте функционал приведенного примера и не стесняйтесь добавить что-нибудь от себя.",
"Реализуйте следующие <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>пользовательские истории</a>, сделайте также бонусные по желанию:",
"<span class='text-info'>Пользовательская история:</span> В качестве пользователя, я могу узнать погоду с учетом моего текущего местоположения.",
"<span class='text-info'>Бонусная пользовательская история:</span> В качестве пользователя, я могу в зависимости от погоды видеть различные температурные значки.",
"<span class='text-info'>Бонусная пользовательская история:</span> В качестве пользователя, я могу в зависимости от погоды видеть различные фоновые изображения (снежные горы, знойная пустыня).",
"<span class='text-info'>Бонусная пользовательская история:</span> В качестве пользователя, я могу нажать на кнопку чтобы переключится между градусами по Цельсию или по Фаренгейту.",
"Если что-то не получается, воспользуйтесь <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a>.",
"Когда выполните задание кликните кнопку \"I've completed this challenge\" и добавьте ссылку на ваш CodePen. Если вы программировали с кем-то в паре, также добавьте имя вашего напарника.",
"Если вы хотите получить немедленную оценку вашего проекта, нажмите эту кнопку и добавьте ссылку на ваш CodePen. В противном случае мы проверим его перед тем как вы приступите к проектам для некоммерческих организаций.<br><br><a class='btn btn-primary btn-block' href='https://twitter.com/intent/tweet?text=Check%20out%20the%20project%20I%20just%20built%20with%20%40FreeCodeCamp:%20%0A%20%23LearnToCode%20%23JavaScript' target='_blank'>Click here then add your link to your tweet's text</a>"
]
}
}
},
{
"id": "bd7158d8c442eddfaeb5bd19",
"title": "Build a Wikipedia Viewer",
"description": [
"<strong>Objective:</strong> Build a <a href='https://codepen.io' target='_blank'>CodePen.io</a> app that is functionally similar to this: <a href='https://codepen.io/freeCodeCamp/full/wGqEga/' target='_blank'>https://codepen.io/freeCodeCamp/full/wGqEga/</a>.",
"Fulfill the below <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>user stories</a>. Use whichever libraries or APIs you need. Give it your own personal style.",
"<strong>User Story:</strong> I can search Wikipedia entries in a search box and see the resulting Wikipedia entries.",
"<strong>User Story:</strong> I can click a button to see a random Wikipedia entry.",
"<span class='text-info'>Hint #1:</span> Here's a URL you can use to get a random Wikipedia article: <code>https://en.wikipedia.org/wiki/Special:Random</code>.",
"<span class='text-info'>Hint #2:</span> Here's an entry on using Wikipedia's API: <code>https://www.mediawiki.org/wiki/API:Main_page</code>.",
"<span class='text-info'>Hint #3:</span> Use this <a href='https://en.wikipedia.org/wiki/Special:ApiSandbox#action=query&titles=Main%20Page&prop=revisions&rvprop=content&format=jsonfm' target='_blank'>link</a> to experiment with Wikipedia's API.",
"Remember to use <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> if you get stuck.",
"When you are finished, click the \"I've completed this challenge\" button and include a link to your CodePen.",
"You can get feedback on your project by sharing it with your friends on Facebook."
],
"challengeSeed": [
"wJhcPwVYA1g"
],
"tests": [],
"type": "zipline",
"challengeType": 3,
"isRequired": false,
"translations": {
"es": {
"title": "Crea un buscador de Wikipedia",
"description": [
"<span class='text-info'>Objetivo:</span> Crea una aplicación con <a href='https://codepen.io' target='_blank'>CodePen.io</a> cuya funcionalidad sea similar a la de esta: <a href='https://codepen.io/freeCodeCamp/full/wGqEga/' target='_blank'>https://codepen.io/freeCodeCamp/full/wGqEga/</a>.",
"Satisface las siguientes <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>historias de usuario</a>. Usa cualquier librería o APIs que necesites. Dale tu estilo personal.",
"<span class='text-info'>Historia de usuario:</span> Pedo obtener información acerca del clima en mi localización actual.",
"<span class='text-info'>Historia de usuario:</span> Puedo ver un icono diferente o una imagen de fondo diferente (e.g. montaña con nieve, desierto caliente) dependiendo del clima.",
"<span class='text-info'>Historia de usuario:</span> Puedo pulsar un botón para cambiar la unidad de temperatura de grados Fahrenheit a Celsius y viceversa.",
"<span class='text-info'>Historia de usuario:</span> Puedo buscar entradas en Wikipedia en un cuadro de búsqueda y ver las entradas de Wikipedia resultantes.",
"<span class='text-info'>Historia de usuario:</span>Puedo pulsar un botón para ver un artículo aleatorio de Wikipedia.",
"<span class='text-info'>Pista 1:</span> Aquí está una URL donde puedes ver una entrada aleatoria de Wikipedia: <code>https://en.wikipedia.org/wiki/Special:Random<</code>.",
"<span class='text-info'>Pista 2:</span> Este es un artículo muy útil relativo al uso del API de Wikipedia: <code>https://www.mediawiki.org/wiki/API:Main_page</code>.",
"<span class='text-info'>Pista 3:</span> Usa este <a href='https://en.wikipedia.org/wiki/Special:ApiSandbox#action=query&titles=Main%20Page&prop=revisions&rvprop=content&format=jsonfm' target='_blank'>enlace</a> para experimentar con el API de Wikipedia.",
"Recuerda utilizar <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Leer-Buscar-Preguntar</a> si te sientes atascado.",
"Cuando hayas terminado, pulsa el botón de \"I've completed this challenge\" e incluye un enlace a tu CodePen.",
"Puedes obtener retroalimentación sobre tu proyecto por parte de otros campistas, compartiendolo en nuestra <a href='//gitter.im/freecodecamp/codereview' target='_blank'>Sala de chat para revisión de código</a>. También puedes compartirlo en Twitter y en el campamento de tu ciudad (en Facebook)."
]
}
}
},
{
"id": "bd7158d8c442eddfaeb5bd1f",
"title": "Use the Twitch.tv JSON API",
"description": [
"<strong>Objective:</strong> Build a <a href='https://codepen.io' target='_blank'>CodePen.io</a> app that is functionally similar to this: <a href='https://codepen.io/freeCodeCamp/full/Myvqmo/' target='_blank'>https://codepen.io/freeCodeCamp/full/Myvqmo/</a>.",
"Fulfill the below <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>user stories</a>. Use whichever libraries or APIs you need. Give it your own personal style.",
"<strong>User Story:</strong> I can see whether freeCodeCamp is currently streaming on Twitch.tv.",
"<strong>User Story:</strong> I can click the status output and be sent directly to the freeCodeCamp's Twitch.tv channel.",
"<strong>User Story:</strong> if a Twitch user is currently streaming, I can see additional details about what they are streaming.",
"<strong>Hint:</strong> See an example call to Twitch.tv's JSONP API at <a href='http://forum.freeCodeCamp.com/t/use-the-twitchtv-json-api/19541' target='_blank'>http://forum.freeCodeCamp.com/t/use-the-twitchtv-json-api/19541</a>.",
"<strong>Hint:</strong> The relevant documentation about this API call is here: <a href='https://dev.twitch.tv/docs/v5/reference/streams/#get-stream-by-user' target='_blank'>https://dev.twitch.tv/docs/v5/reference/streams/#get-stream-by-user</a>.",
"<strong>Hint:</strong> Here's an array of the Twitch.tv usernames of people who regularly stream: <code>[\"ESL_SC2\", \"OgamingSC2\", \"cretetion\", \"freecodecamp\", \"storbeck\", \"habathcx\", \"RobotCaleb\", \"noobs2ninjas\"]</code>",
"Remember to use <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> if you get stuck.",
"When you are finished, click the \"I've completed this challenge\" button and include a link to your CodePen.",
"You can get feedback on your project by sharing it with your friends on Facebook."
],
"challengeSeed": [
"6WrbY1d-IHI"
],
"tests": [],
"type": "zipline",
"challengeType": 3,
"isRequired": false,
"translations": {
"es": {
"title": "Usa el API JSON de Twitch.tv",
"description": [
"<span class='text-info'>Objetivo:</span> Crea una aplicación con <a href='https://codepen.io' target='_blank'>CodePen.io</a> cuya funcionalidad sea similar a la de esta: <a href='https://codepen.io/freeCodeCamp/full/Myvqmo/' target='_blank'>https://codepen.io/freeCodeCamp/full/Myvqmo/</a>.",
"Satisface las siguientes <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>historias de usuario</a>. Usa cualquier librería o APIs que necesites. Dale tu estilo personal.",
"<span class='text-info'>Historia de usuario:</span> Puedo verificar si freeCodeCamp está transmitiendo actualmente en Twitch.tv",
"<span class='text-info'>Historia de usuario:</span> Puedo pulsar el estatus y ser enviado directamente al canal de freeCodeCamp en Twitch.tv.",
"<span class='text-info'>Historia de usuario:</span> Si un usuario Twitch está transmitiendo actualmente, puedo ver detalles adicionales acerca del contenido que están transmitiendo.",
"<span class='text-info'>Pista:</span> Obseva una llamada de ejemplo al API JSONP de Twitch.tv en <code>http://forum.freeCodeCamp.com/t/use-the-twitchtv-json-api/19541</code>.",
"<span class='text-info'>Pista:</span> La documentación relevante sobre esta llamada al API está aquí: <a href='https://github.com/justintv/Twitch-API/blob/master/v3_resources/streams.md#get-streamschannel' target='_blank'>https://github.com/justintv/Twitch-API/blob/master/v3_resources/streams.md#get-streamschannel</a>.",
"<span class='text-info'>Pista:</span> Aquí está un vector de usuarios en Twitch.tv que regularmente transmiten sobre programación: <code>[\"ESL_SC2\", \"OgamingSC2\", \"cretetion\", \"freecodecamp\", \"storbeck\", \"habathcx\", \"RobotCaleb\", \"noobs2ninjas\"]</code>",
"Recuerda utilizar <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Leer-Buscar-Preguntar</a> si te sientes atascado.",
"Cuando hayas terminado, pulsa el botón de \"I've completed this challenge\" e incluye un enlace a tu CodePen.",
"Puedes obtener retroalimentación sobre tu proyecto por parte de otros campistas, compartiendolo en nuestra <a href='//gitter.im/freecodecamp/codereview' target='_blank'>Sala de chat para revisión de código</a>. También puedes compartirlo en Twitter y en el campamento de tu ciudad (en Facebook)."
]
},
"ru": {
"title": "Используйте Twitch.tv JSON API",
"description": [
"<span class='text-info'>Задание:</span> Создайте <a href='https://codepen.io' target='_blank'>CodePen.io</a> который успешно копирует вот этот: <a href='https://codepen.io/freeCodeCamp/full/Myvqmo/' target='_blank'>https://codepen.io/freeCodeCamp/full/Myvqmo/</a>.",
"<span class='text-info'>Правило #1:</span> Не подсматривайте код приведенного на CodePen примера. Напишите его самостоятельно.",
"<span class='text-info'>Правило #2:</span> Можете использовать любые библиотеки или API, которые потребуются.",
"<span class='text-info'>Правило #3:</span> Воссоздайте функционал приведенного примера и не стесняйтесь добавить что-нибудь от себя.",
"Реализуйте следующие <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>пользовательские истории</a>, сделайте также бонусные по желанию:",
"<span class='text-info'>Пользовательская история:</span> В качестве пользователя, я могу увидеть идет ли в данный момент на Twitch.tv трансляция freeCodeCamp.",
"<span class='text-info'>Пользовательская история:</span> В качестве пользователя, я могу, кликнув на описание трансляции, перейти на канал freeCodeCamp.",
"<span class='text-info'>Пользовательская история:</span> В качестве пользователя, я могу видеть дополнительную информацию о текущей трансляции freeCodeCamp.",
"<span class='text-info'>Бонусная пользовательская история:</span> В качестве пользователя, я могу произвести поиск среди перечисленных каналов.",
"<span class='text-info'>Подсказка:</span> Пример запроса к Twitch.tv JSON API: <code>https://api.twitch.tv/kraken/streams/freecodecamp</code>.",
"<span class='text-info'>Подсказка:</span> Документацию об этом запросе можно найти по ссылке: <a href='https://github.com/justintv/Twitch-API/blob/master/v3_resources/streams.md#get-streamschannel' target='_blank'>https://github.com/justintv/Twitch-API/blob/master/v3_resources/streams.md#get-streamschannel</a>.",
"<span class='text-info'>Подсказка:</span> В этом массиве приведены имена пользователей, которые регулярно пишут код онлайн: <code>[\"ESL_SC2\", \"OgamingSC2\", \"cretetion\", \"freecodecamp\", \"storbeck\", \"habathcx\", \"RobotCaleb\", \"noobs2ninjas\"]</code>",
"Если что-то не получается, воспользуйтесь <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a>.",
"Когда выполните задание кликните кнопку \"I've completed this challenge\" и добавьте ссылку на ваш CodePen. Если вы программировали с кем-то в паре, также добавьте имя вашего напарника.",
"Если вы хотите получить немедленную оценку вашего проекта, нажмите эту кнопку и добавьте ссылку на ваш CodePen. В противном случае мы проверим его перед тем как вы приступите к проектам для некоммерческих организаций.<br><br><a class='btn btn-primary btn-block' href='https://twitter.com/intent/tweet?text=Check%20out%20the%20project%20I%20just%20built%20with%20%40FreeCodeCamp:%20%0A%20%23LearnToCode%20%23JavaScript' target='_blank'>Click here then add your link to your tweet's text</a>"
]
}
}
},
{
"id": "bd7158d8c442eedfaeb5bd1c",
"title": "Build a Tic Tac Toe Game",
"description": [
"<strong>Objective:</strong> Build a <a href='https://codepen.io' target='_blank'>CodePen.io</a> app that is functionally similar to this: <a href='https://codepen.io/freeCodeCamp/full/KzXQgy/' target='_blank'>https://codepen.io/freeCodeCamp/full/KzXQgy/</a>.",
"Fulfill the below <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>user stories</a>. Use whichever libraries or APIs you need. Give it your own personal style.",
"<strong>User Story:</strong> I can play a game of Tic Tac Toe with the computer.",
"<strong>User Story:</strong> My game will reset as soon as it's over so I can play again.",
"<strong>User Story:</strong> I can choose whether I want to play as X or O.",
"Remember to use <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> if you get stuck.",
"When you are finished, click the \"I've completed this challenge\" button and include a link to your CodePen.",
"You can get feedback on your project by sharing it with your friends on Facebook."
],
"challengeSeed": [
"Ia69O1ZNGEg"
],
"tests": [],
"type": "zipline",
"challengeType": 3,
"isRequired": false,
"translations": {
"es": {
"title": "Crea un juego de Tic Tac Toe",
"description": [
"<span class='text-info'>Objetivo:</span> Construye una aplicación en <a href='https://codepen.io' target='_blank'>CodePen.io</a> cuya funcionalidad sea similar a la de esta: <a href='https://codepen.io/freeCodeCamp/full/KzXQgy/' target='_blank'>https://codepen.io/freeCodeCamp/full/KzXQgy/</a>.",
"Satisface las siguientes <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>historias de usuario</a>. Usa cualquier librería o APIs que necesites. Dale tu estilo personal.",
"<span class='text-info'>Historia de usuario:</span> Puedo jugar un juego de Tic Tac Toe contra el computador.",
"<span class='text-info'>Historia de usuario:</span> Mi juego se reiniciará tan pronto como termine para poder jugar de nuevo.",
"<span class='text-info'>Historia de usuario:</span> Puedo elegir si quiero jugar como X o como O.",
"Recuerda utilizar <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Leer-Buscar-Preguntar</a> si te sientes atascado.",
"Cuando hayas terminado, pulsa el botón de \"I've completed this challenge\" e incluye un enlace a tu CodePen.",
"Puedes obtener retroalimentación sobre tu proyecto por parte de otros campistas, compartiéndolo en nuestra <a href='//gitter.im/freecodecamp/codereview' target='_blank'>Sala de chat para revisión de código</a>. También puedes compartirlo en Twitter y en el campamento de tu ciudad (en Facebook)."
]
}
}
},
{
"id": "bd7158d8c442eddfaeb5bd1c",
"title": "Build a Simon Game",
"description": [
"<strong>Objective:</strong> Build a <a href='https://codepen.io' target='_blank'>CodePen.io</a> app that is functionally similar to this: <a href='https://codepen.io/Em-Ant/full/QbRyqq/' target='_blank'>https://codepen.io/freeCodeCamp/full/obYBjE</a>.",
"Fulfill the below <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>user stories</a>. Use whichever libraries or APIs you need. Give it your own personal style.",
"<strong>User Story:</strong> I am presented with a random series of button presses.",
"<strong>User Story:</strong> Each time I input a series of button presses correctly, I see the same series of button presses but with an additional step.",
"<strong>User Story:</strong> I hear a sound that corresponds to each button both when the series of button presses plays, and when I personally press a button.",
"<strong>User Story:</strong> If I press the wrong button, I am notified that I have done so, and that series of button presses starts again to remind me of the pattern so I can try again.",
"<strong>User Story:</strong> I can see how many steps are in the current series of button presses.",
"<strong>User Story:</strong> If I want to restart, I can hit a button to do so, and the game will return to a single step.",
"<strong>User Story:</strong> I can play in strict mode where if I get a button press wrong, it notifies me that I have done so, and the game restarts at a new random series of button presses.",
"<strong>User Story:</strong> I can win the game by getting a series of 20 steps correct. I am notified of my victory, then the game starts over.",
"<strong>Hint:</strong> Here are mp3s you can use for each button: <code>https://s3.amazonaws.com/freecodecamp/simonSound1.mp3</code>, <code>https://s3.amazonaws.com/freecodecamp/simonSound2.mp3</code>, <code>https://s3.amazonaws.com/freecodecamp/simonSound3.mp3</code>, <code>https://s3.amazonaws.com/freecodecamp/simonSound4.mp3</code>.",
"Remember to use <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> if you get stuck.",
"When you are finished, click the \"I've completed this challenge\" button and include a link to your CodePen.",
"You can get feedback on your project by sharing it with your friends on Facebook."
],
"challengeSeed": [
"tAPut8a47bA"
],
"tests": [],
"type": "zipline",
"challengeType": 3,
"isRequired": false,
"translations": {
"es": {
"title": "Construye un juego de Simon",
"description": [
"<span class='text-info'>Objetivo:</span> Construye una aplicación en <a href='https://codepen.io' target='_blank'>CodePen.io</a> cuya funcionalidad sea similar a la de esta: <a href='https://codepen.io/Em-Ant/full/QbRyqq/' target='_blank'>https://codepen.io/Em-Ant/full/QbRyqq/</a>.",
"Satisface las siguientes <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>historias de usuario</a>. Usa cualquier librería o APIs que necesites. Dale tu estilo personal.",
"<span class='text-info'>Historia de usuario:</span> Se me presenta una serie aleatoria de pulsaciones a botones.",
"<span class='text-info'>Historia de usuario:</span> Cada vez que presiono una secuencia de pulsaciones correctamente, veo que vuelve a ejecutarse la misma serie de pulsaciones con un paso adicional.",
"<span class='text-info'>Historia de usuario:</span> Escucho un sonido que corresponde a cada botón cuando se ejecuta una secuencia de pulsaciones, así como cuando yo presiono un botón.",
"<span class='text-info'>Historia de usuario:</span> Si presiono el botón equivocado, se me notifica sobre mi error, y se ejecuta de nuevo la serie correcta de pulsaciones para recordarme cuál es la secuencia correcta, tras lo cual puedo intentar de nuevo.",
"<span class='text-info'>Historia de usuario:</span> Puedo ver cuántos pasos hay en la serie de pulsaciones actual.",
"<span class='text-info'>Historia de usuario:</span> Si deseo reiniciar, puedo pulsar un botón para hacerlo, y el juego comenzará desde una secuencia con un solo paso.",
"<span class='text-info'>Historia de usuario:</span> Puedo jugar en modo estricto donde si presiono el botón equivocado, se me notifica de mi error, y el juego vuelve a comenzar con una nueva serie aleatoria de colores.",
"<span class='text-info'>Historia de usuario:</span> Puedo ganar el juego si completo 20 pasos correctos. Se me notifica sobre mi victoria, tras lo cual el juego se reinicia.",
"<span class='text-info'>Pista:</span> Aquí hay algunos mp3s que puedes utilizar para tus botones: <code>https://s3.amazonaws.com/freecodecamp/simonSound1.mp3</code>, <code>https://s3.amazonaws.com/freecodecamp/simonSound2.mp3</code>, <code>https://s3.amazonaws.com/freecodecamp/simonSound3.mp3</code>, <code>https://s3.amazonaws.com/freecodecamp/simonSound4.mp3</code>.",
"Recuerda utilizar <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Leer-Buscar-Preguntar</a> si te sientes atascado.",
"Cuando hayas terminado, pulsa el botón de \"I've completed this challenge\" e incluye un enlace a tu CodePen.",
"Puedes obtener retroalimentación sobre tu proyecto por parte de otros campistas, compartiéndolo en nuestra <a href='//gitter.im/freecodecamp/codereview' target='_blank'>Sala de chat para revisión de código</a>. También puedes compartirlo en Twitter y en el campamento de tu ciudad (en Facebook)."
]
}
}
},
{
"id": "bd7156d8c242eddfaeb5bd13",
"title": "Build a Camper Leaderboard",
"description": [
"<strong>Objective:</strong> Build a <a href='https://codepen.io' target='_blank'>CodePen.io</a> app that is functionally similar to this: <a href='https://codepen.io/freeCodeCamp/full/eZGMjp/' target='_blank'>https://codepen.io/freeCodeCamp/full/eZGMjp/</a>.",
"Fulfill the below <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>user stories</a>. Use whichever libraries or APIs you need. Give it your own personal style.",
"<strong>User Story:</strong> I can see a table of the freeCodeCamp campers who've earned the most brownie points in the past 30 days.",
"<strong>User Story:</strong> I can see how many brownie points they've earned in the past 30 days, and how many they've earned total.",
"<strong>User Story:</strong> I can toggle between sorting the list by how many brownie points they've earned in the past 30 days and by how many brownie points they've earned total.",
"<strong>Hint:</strong> To get the top 100 campers for the last 30 days: <a href='https://fcctop100.herokuapp.com/api/fccusers/top/recent' target='_blank'>https://fcctop100.herokuapp.com/api/fccusers/top/recent</a>.",
"<strong>Hint:</strong> To get the top 100 campers of all time: <a href='https://fcctop100.herokuapp.com/api/fccusers/top/alltime' target='_blank'>https://fcctop100.herokuapp.com/api/fccusers/top/alltime</a>.",
"Remember to use <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> if you get stuck.",
"When you are finished, click the \"I've completed this challenge\" button and include a link to your CodePen. ",
"You can get feedback on your project by sharing it with your friends on Facebook."
],
"releasedOn": "January 1, 2016",
"challengeSeed": [
"LJQcFNo_-QY"
],
"tests": [],
"type": "zipline",
"isRequired": false,
"challengeType": 3,
"translations": {
"es": {
"title": "Crea un marcador para los campistas",
"description": [
"<strong>Objetivo:</strong> Construye una aplicación en <a href='https://codepen.io' target='_blank'>CodePen.io</a> que funcione de forma similar al siguiente ejemplo: <a href='https://codepen.io/freeCodeCamp/full/eZGMjp/' target='_blank'>https://codepen.io/freeCodeCamp/full/eZGMjp/</a>.",
"Satisface las siguientes <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>historias de usuario</a>. Usa cualquier librería o API que sea necesaria. ¡Ponle un toque personal!.",
"<strong>Historia de usuario:</strong> Puedo ver un tablero con los campistas de freeCodeCamp que han ganado más puntos de brownie en los últimos 30 días.",
"<strong>Historia de usuario:</strong> Puedo ver cuántos puntos de brownie han ganado en los últimos 30 días, y cuántos han ganado en total.",
"<strong>Historia de usuario:</strong> Puedo elegir entre dos formas de organizar la lista: 1) En base a cuántos puntos de brownie se han ganado en los últimos 30 días. 2) En base al número de puntos de brownie que han ganado en total.",
"<strong>Pista:</strong> Para obtener los 100 mejores campistas para los últimos 30 días: <a href='https://fcctop100.herokuapp.com/api/fccusers/top/recent' target='_blank'>https://fcctop100.herokuapp.com/api/fccusers/top/recent</a>.",
"<strong>Pista:</strong> Para obtener los 100 mejores campistas de toda la historia: <a href='http://fcctop100.herokuapp.com/api/fccusers/top/alltime' target='_blank'>http://fcctop100.herokuapp.com/api/fccusers/top/alltime</a>.",
"Recuerda utilizar <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> si te sientes atascado.",
"Cuando termines, haz clic en el botón de \"I've completed this challenge\" e incluye el vínculo de tu proyecto en CodePen. ",
"Puedes obtener retroalimentación acerca de tu proyecto de parte de tus compañeros campistas compartiéndolo en nuestro <a href='//gitter.im/freecodecamp/codereview' target='_blank'>Cuarto de revisión de código</a>. También puedes compartirlo en Twitter y en el campamento de tu ciudad (en Facebook)."
]
},
"ru": {
"title": "Создайте таблицу Кемперов-Лидеров",
"description": [
"<strong>Задание:</strong> Создайте приложение <a href='https://codepen.io' target='_blank'>CodePen.io</a>, функционал которого схож с этим: <a href='https://codepen.io/freeCodeCamp/full/eZGMjp/' target='_blank'>https://codepen.io/freeCodeCamp/full/eZGMjp/</a>.",
"Приложение должно удовлетворять нижеприведённым <a href='https://ru.wikipedia.org/wiki/Пользовательскиестории' target='_blank'>пользовательским историям</a>. Используйте любые библиотеки или API, которые потребуются. Придайте ему свой личный стиль.",
"<strong>Пользовательская история:</strong> Я могу видеть таблицу кемперов freeCodeCamp, которые получили наибольшее количество очков за последние 30 дней.",
"<strong>Пользовательская история:</strong> Я могу видеть сколько очков они получили за последние 30 дней, и сколько они получили их всего.",
"<strong>Пользовательская история:</strong> Я могу отсортировать список по количеству очков, которые они получили за последние 30 дней, и по общему количеству полученных очков.",
"<strong>Подсказка:</strong> Ссылка на топ 100 кемперов за последние 30 дней в формате JSON: <a href='https://fcctop100.herokuapp.com/api/fccusers/top/recent' target='_blank'>https://fcctop100.herokuapp.com/api/fccusers/top/recent</a>.",
"<strong>Подсказка:</strong> Ссылка на топ 100 кемперов за все время в формате JSON: <a href='http://fcctop100.herokuapp.com/api/fccusers/top/alltime' target='_blank'>http://fcctop100.herokuapp.com/api/fccusers/top/alltime</a>.",
"Если что-то не получается, не забывайте пользоваться методом <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Читай-Ищи-Спрашивай</a>.",
"Когда закончите, нажмите кнопку \"I've completed this challenge\" и укажите ссылку на вашу работу на CodePen.",
"Вы можете получить отзыв о вашем проекте от коллег, поделившись ссылкой на него в нашем <a href='//gitter.im/freecodecamp/codereview' target='_blank'>чате для рассмотрения кода</a>. Также вы можете поделиться ею через Twitter и на странице freeCodeCamp вашего города на Facebook."
]
}
}
},
{
"id": "bd7155d8c242eddfaeb5bd13",
"title": "Build a Recipe Box",
"description": [
"<strong>Objective:</strong> Build a <a href='https://codepen.io' target='_blank'>CodePen.io</a> app that is functionally similar to this: <a href='https://codepen.io/freeCodeCamp/full/dNVazZ/' target='_blank'>https://codepen.io/freeCodeCamp/full/dNVazZ/</a>.",
"Fulfill the below <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>user stories</a>. Use whichever libraries or APIs you need. Give it your own personal style.",
"<strong>User Story:</strong> I can create recipes that have names and ingredients.",
"<strong>User Story:</strong> I can see an index view where the names of all the recipes are visible.",
"<strong>User Story:</strong> I can click into any of those recipes to view it.",
"<strong>User Story:</strong> I can edit these recipes.",
"<strong>User Story:</strong> I can delete these recipes.",
"<strong>User Story:</strong> All new recipes I add are saved in my browser's local storage. If I refresh the page, these recipes will still be there.",
"<strong>Hint: </strong> You should prefix your local storage keys on CodePen, i.e. <code>_username_recipes</code>",
"Remember to use <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/FreeCodeCamp-Get-Help' target='_blank'>Read-Search-Ask</a> if you get stuck.",
"When you are finished, click the \"I've completed this challenge\" button and include a link to your CodePen.",
"You can get feedback on your project by sharing it with your friends on Facebook."
],
"releasedOn": "January 1, 2016",
"challengeSeed": [
"6tZ4c-Bxstg"
],
"tests": [],
"type": "zipline",
"isRequired": false,
"challengeType": 3,
"titleRu": "Создайте хранилище рецептов",
"descriptionRu": [
"<strong>Задание:</strong> Создайте приложение <a href='https://codepen.io' target='_blank'>CodePen.io</a>, функционал которого схож с этим: <a href='https://codepen.io/freeCodeCamp/full/dNVazZ/' target='_blank'>https://codepen.io/freeCodeCamp/full/dNVazZ/</a>.",
"<strong>Правило #1:</strong> Не подсматривайте код приложения-примера. Напишите его самостоятельно.",
"<strong>Правило #2:</strong> Приложение должно удовлетворять нижеприведённым <a href='https://ru.wikipedia.org/wiki/Пользовательскиестории' target='_blank'>пользовательским историям</a>. Используйте любые библиотеки или API, которые потребуются. Придайте ему свой личный стиль.",
"<strong>Правило #3:</strong> Для создания этого проекта вы должны использовать Sass и React.",
"<strong>Пользовательская история:</strong> Я могу создавать рецепты, содержащие название и ингредиенты.",
"<strong>Пользовательская история:</strong> Я могу просмотреть корневой вид, на котором видны все рецепты.",
"<strong>Пользовательская история:</strong> Я могу нажать на имя каждого из рецептов для просмотра содержимого.",
"<strong>Пользовательская история:</strong> Я могу отредактировать эти рецепты.",
"<strong>Пользовательская история:</strong> Я могу удалить эти рецепты.",
"<strong>Пользовательская история:</strong> Все новые рецепты, которые я добавил, сохранены в локальном хранилище моего браузера. Если я обновлю страницу, эти рецепты будут всё ещё там.",
"Если что-то не получается, не забывайте пользоваться методом <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/FreeCodeCamp-Get-Help' target='_blank'>Читай-Ищи-Спрашивай</a>.",
"Когда закончите, нажмите кнопку \"I've completed this challenge\" и укажите ссылку на вашу работу на CodePen.",
"Вы можете получить отзыв о вашем проекте от коллег, поделившись ссылкой на него в нашем <a href='//gitter.im/freecodecamp/codereview' target='_blank'>чате для рассмотрения кода</a>. Также вы можете поделиться ею через Twitter и на странице Free Code Camp вашего города на Facebook."
],
"titleEs": "Crea una caja de recetas",
"descriptionEs": [
"<strong>Objetivo:</strong> Construye una aplicación en <a href='https://codepen.io' target='_blank'>CodePen.io</a> que funcione de forma similar al siguiente ejemplo: <a href='https://codepen.io/freeCodeCamp/full/dNVazZ/' target='_blank'>https://codepen.io/freeCodeCamp/full/dNVazZ/</a>.",
"<strong>Regla #1:</strong> No veas el código del proyecto de ejemplo. Encuentra la forma de hacerlo por tu cuenta.",
"<strong>Regla #2:</strong> Satisface las siguientes <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>historias de usuario</a>. Usa cualquier librería o API que sea necesaria. ¡Ponle un toque personal!.",
"<strong>Rule #3:</strong> Debes utilizar ambos Sass y React para construir este proyecto.",
"<strong>Historia de usuario:</strong> Puedo crear recetas a las que les puedo poner un nombre y los ingredientes necesarios.",
"<strong>Historia de usuario:</strong> Puedo ver un índice que contenga los nombres de todas las recetas.",
"<strong>Historia de usuario:</strong> Puedo pulsar cualquiera de las recetas para verla.",
"<strong>Historia de usuario:</strong> Puedo editar las recetas.",
"<strong>Historia de usuario:</strong> Puedo eliminar las recetas.",
"<strong>Historia de usuario:</strong> Las recetas que voy agregando deben guardarse en el almacenamiento local de mi navegador. Las recetas deben seguir allí si refresco la página.",
"Recuerda utilizar <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/FreeCodeCamp-Get-Help' target='_blank'>Read-Search-Ask</a> si te sientes atascado.",
"Cuando termines, haz clic en el botón de \"I've completed this challenge\" e incluye el vínculo de tu proyecto en CodePen. ",
"Puedes obtener retroalimentación acerca de tu proyecto de parte de tus compañeros campistas compartiéndolo en nuestro <a href='//gitter.im/freecodecamp/codereview' target='_blank'>Cuarto de revisión de código</a>. También puedes compartirlo en Twitter y en el campamento de tu ciudad (en Facebook)."
]
},
{
"id": "bd7154d8c242eddfaeb5bd13",
"title": "Build the Game of Life",
"description": [
"<strong>Objective:</strong> Build a <a href='https://codepen.io' target='_blank'>CodePen.io</a> app that is functionally similar to this: <a href='https://codepen.io/freeCodeCamp/full/BpwMZv/' target='_blank'>https://codepen.io/freeCodeCamp/full/BpwMZv/</a>.",
"Fulfill the below <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>user stories</a>. Use whichever libraries or APIs you need. Give it your own personal style.",
"<strong>User Story:</strong> When I first arrive at the game, it will randomly generate a board and start playing.",
"<strong>User Story:</strong> I can start and stop the board.",
"<strong>User Story:</strong> I can set up the board.",
"<strong>User Story:</strong> I can clear the board.",
"<strong>User Story:</strong> When I press start, the game will play out.",
"<strong>User Story:</strong> Each time the board changes, I can see how many generations have gone by.",
"<strong>Hint:</strong> Here's an explanation of Conway's Game of Life from John Conway himself: <a href='https://www.youtube.com/watch?v=E8kUJL04ELA' target='_blank'>https://www.youtube.com/watch?v=E8kUJL04ELA</a>",
"<strong>Hint:</strong> Here's an overview of Conway's Game of Life with rules for your reference: <a href='https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life' target='_blank'>https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life</a>",
"Remember to use <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/FreeCodeCamp-Get-Help' target='_blank'>Read-Search-Ask</a> if you get stuck.",
"When you are finished, click the \"I've completed this challenge\" button and include a link to your CodePen. ",
"You can get feedback on your project by sharing it with your friends on Facebook."
],
"releasedOn": "January 1, 2016",
"challengeSeed": [
"5Ajcjs3OmjA"
],
"tests": [],
"type": "zipline",
"isRequired": false,
"challengeType": 3,
"titleRu": "Создайте игру \"Жизнь\"",
"descriptionRu": [
"<strong>Задание:</strong> Создайте приложение <a href='https://codepen.io' target='_blank'>CodePen.io</a>, функционал которого схож с этим: <a href='https://codepen.io/freeCodeCamp/full/BpwMZv/' target='_blank'>https://codepen.io/freeCodeCamp/full/BpwMZv/</a>.",
"<strong>Правило #1:</strong> Не подсматривайте код приложения-примера. Напишите его самостоятельно.",
"<strong>Правило #2:</strong> Приложение должно удовлетворять нижеприведённым <a href='https://ru.wikipedia.org/wiki/Пользовательскиестории' target='_blank'>пользовательским историям</a>. Используйте любые библиотеки или API, которые потребуются. Придайте ему свой личный стиль.",
"<strong>Правило #3:</strong> Для создания этого проекта вы должны использовать Sass и React.",
"<strong>Пользовательская история:</strong> Когда я впервые запускаю игру, она генерирует доску случайным образом и начинает игру.",
"<strong>Пользовательская история:</strong> Я могу запустить и остановить игру.",
"<strong>Пользовательская история:</strong> Я могу настроить доску.",
"<strong>Пользовательская история:</strong> Я могу очистить доску.",
"<strong>Пользовательская история:</strong> Когда я нажимаю начать, игра начинает воспроизведение.",
"<strong>Пользовательская история:</strong> Каждый раз, когда доска меняется, я могу видеть сколько поколений прошло.",
"<strong>Подсказка:</strong> Вот объяснение игры \"Жизнь\" от её создателя Джона Конвея: <a href='https://www.youtube.com/watch?v=E8kUJL04ELA' target='_blank'>https://www.youtube.com/watch?v=E8kUJL04ELA</a>",
"<strong>Подсказка:</strong> Вот обзор правил игры \"Жизнь\" для вашего сведения: <a href='https://ru.wikipedia.org/wiki/Жизнь_(игра)' target='_blank'>https://ru.wikipedia.org/wiki/Жизнь_(игра)</a>",
"Если что-то не получается, не забывайте пользоваться методом <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/FreeCodeCamp-Get-Help' target='_blank'>Читай-Ищи-Спрашивай</a>.",
"Когда закончите, нажмите кнопку \"I've completed this challenge\" и укажите ссылку на вашу работу на CodePen.",
"Вы можете получить отзыв о вашем проекте от коллег, поделившись ссылкой на него в нашем <a href='//gitter.im/freecodecamp/codereview' target='_blank'>чате для рассмотрения кода</a>. Также вы можете поделиться ею через Twitter и на странице Free Code Camp вашего города на Facebook."
],
"titleEs": "Crea un Juego de la vida",
"descriptionEs": [
"<strong>Objetivo:</strong> Construye una aplicación en <a href='https://codepen.io' target='_blank'>CodePen.io</a> que funcione de forma similar al siguiente ejemplo: <a href='https://codepen.io/freeCodeCamp/full/BpwMZv/' target='_blank'>https://codepen.io/freeCodeCamp/full/BpwMZv/</a>.",
"<strong>Regla #1:</strong> No veas el código del proyecto de ejemplo. Encuentra la forma de hacerlo por tu cuenta.",
"<strong>Regla #2:</strong> Satisface las siguientes <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>historias de usuario</a>. Usa cualquier librería o API que sea necesaria. ¡Ponle un toque personal!.",
"<strong>Rule #3:</strong> Debes utilizar ambos Sass y React para construir este proyecto.",
"<strong>Historia de usuario:</strong> La aplicación debe generar aleatoriamente un tablero y comenzar a jugar cuando entro al juego por primera vez.",
"<strong>Historia de usuario:</strong> Puedo iniciar y detener el tablero.",
"<strong>Historia de usuario:</strong> Puedo preparar el tablero.",
"<strong>Historia de usuario:</strong> Puedo limpiar el tablero.",
"<strong>Historia de usuario:</strong> El juego inicia cuando presiono un botón de inicio.",
"<strong>Historia de usuario:</strong> Puedo ver cuántas generaciones han pasado cada vez que el tablero cambia.",
"<strong>Pista:</strong> Puedes encontrar una explicación del Juego de la vida de Conway de parte del mismísimo John Conway aquí: <a href='https://www.youtube.com/watch?v=E8kUJL04ELA' target='_blank'>https://www.youtube.com/watch?v=E8kUJL04ELA</a>",
"<strong>Pista:</strong> Puedes referirte al siguiente enlace para obtener información general acerca del Juego de la vida de Conway incluyendo las reglas del juego: <a href='https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life' target='_blank'>https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life</a>",
"Recuerda utilizar <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/FreeCodeCamp-Get-Help' target='_blank'>Read-Search-Ask</a> si te sientes atascado.",
"Cuando termines, haz clic en el botón de \"I've completed this challenge\" e incluye el vínculo de tu proyecto en CodePen. ",
"Puedes obtener retroalimentación acerca de tu proyecto de parte de tus compañeros campistas compartiéndolo en nuestro <a href='//gitter.im/freecodecamp/codereview' target='_blank'>Cuarto de revisión de código</a>. También puedes compartirlo en Twitter y en el campamento de tu ciudad (en Facebook)."
]
},
{
"id": "bd7153d8c242eddfaeb5bd13",
"title": "Build a Roguelike Dungeon Crawler Game",
"description": [
"<strong>Objective:</strong> Build a <a href='https://codepen.io' target='_blank'>CodePen.io</a> app that is functionally similar to this: <a href='https://codepen.io/freeCodeCamp/full/apLXEJ/' target='_blank'>https://codepen.io/freeCodeCamp/full/apLXEJ/</a>.",
"Fulfill the below <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>user stories</a>. Use whichever libraries or APIs you need. Give it your own personal style.",
"<strong>User Story:</strong> I have health, a level, and a weapon. I can pick up a better weapon. I can pick up health items.",
"<strong>User Story:</strong> All the items and enemies on the map are arranged at random.",
"<strong>User Story:</strong> I can move throughout a map, discovering items.",
"<strong>User Story:</strong> I can move anywhere within the map's boundaries, but I can't move through an enemy until I've beaten it.",
"<strong>User Story:</strong> Much of the map is hidden. When I take a step, all spaces that are within a certain number of spaces from me are revealed.",
"<strong>User Story:</strong> When I beat an enemy, the enemy goes away and I get XP, which eventually increases my level.",
"<strong>User Story:</strong> When I fight an enemy, we take turns damaging each other until one of us loses. I do damage based off of my level and my weapon. The enemy does damage based off of its level. Damage is somewhat random within a range.",
"<strong>User Story:</strong> When I find and beat the boss, I win.",
"<strong>User Story:</strong> The game should be challenging, but theoretically winnable.",
"Remember to use <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> if you get stuck.",
"When you are finished, click the \"I've completed this challenge\" button and include a link to your CodePen. ",
"You can get feedback on your project by sharing it with your friends on Facebook."
],
"releasedOn": "January 1, 2016",
"challengeSeed": [
"BwyKI9iePUQ"
],
"tests": [],
"type": "zipline",
"isRequired": false,
"challengeType": 3,
"translations": {
"es": {
"title": "Crea un juego de dragones al estilo Rogue",
"description": [
"<strong>Objetivo:</strong> Construye una aplicación en <a href='https://codepen.io' target='_blank'>CodePen.io</a> que funcione de forma similar al siguiente ejemplo: <a href='https://codepen.io/freeCodeCamp/full/apLXEJ/' target='_blank'>https://codepen.io/freeCodeCamp/full/apLXEJ/</a>.",
"Satisface las siguientes <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>historias de usuario</a>. Usa cualquier librería o API que sea necesaria. ¡Ponle un toque personal!.",
"<strong>Historia de usuario:</strong> Tengo energía, nivel de habilidad y un arma. Puedo recoger un arma mejor. Puedo recoger ítems que recuperan mi energía.",
"<strong>Historia de usuario:</strong> Todos los ítems y los enemigos en el mapa están colocados aleatoriamente.",
"<strong>Historia de usuario:</strong> Puedo moverme a lo largo de un mapa y descubrir ítems.",
"<strong>Historia de usuario:</strong> Puedo moverme hacia cualquier parte dentro de los límites del mapa, pero no puedo moverme sobre un enemigo hasta que lo haya vencido.",
"<strong>Historia de usuario:</strong> Gran parte del mapa está escondido. Cuando doy un paso, todos los espacios que están a cierto número de espacios de distancia de mi son revelados.",
"<strong>Historia de usuario:</strong> Cuando venzo un enemigo, este desaparece y yo gano puntos de experiencia (XP), lo que eventualmente me permite aumentar de nivel.",
"<strong>Historia de usuario:</strong> Cuando peleo con un enemigo, tomamos turnos haciéndonos daño hasta que uno de los dos pierde. El daño que hago está basado en mi nivel de experiencia y en el arma que estoy utilizando. El enemigo hace daño basado en su nivel. El daño es aleatorio dentro de cierto márgen.",
"<strong>Historia de usuario:</strong> Gano el juego cuando encuentre y venza al jefe.",
"<strong>Historia de usuario:</strong> El juego debe representar un reto, pero ganar debe ser teóricamente posible.",
"Recuerda utilizar <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> si te sientes atascado.",
"Cuando termines, haz clic en el botón de \"I've completed this challenge\" e incluye el vínculo de tu proyecto en CodePen. ",
"Puedes obtener retroalimentación acerca de tu proyecto de parte de tus compañeros campistas compartiéndolo en nuestro <a href='//gitter.im/freecodecamp/codereview' target='_blank'>Cuarto de revisión de código</a>. También puedes compartirlo en Twitter y en el campamento de tu ciudad (en Facebook)."
]
},
"ru": {
"title": "Создайте Roguelike-подобную игру Подземелье",
"description": [
"<strong>Задание:</strong> Создайте приложение <a href='https://codepen.io' target='_blank'>CodePen.io</a>, функционал которого схож с этим: <a href='https://codepen.io/freeCodeCamp/full/apLXEJ/' target='_blank'>https://codepen.io/freeCodeCamp/full/apLXEJ/</a>.",
"Приложение должно удовлетворять нижеприведённым <a href='https://ru.wikipedia.org/wiki/Пользовательскиестории' target='_blank'>пользовательским историям</a>. Используйте любые библиотеки или API, которые потребуются. Придайте ему свой личный стиль.",
"<strong>Пользовательская история:</strong> У меня есть жизни, уровень и оружие. Я могу подобрать оружие получше. Я могу подобрать очки здоровья.",
"<strong>Пользовательская история:</strong> Все предметы и враги располагаются на карте случайным образом.",
"<strong>Пользовательская история:</strong> Я могу передвигаться по карте, обнаруживая новые предметы.",
"<strong>Пользовательская история:</strong> Я могу двигаться куда угодно в рамках карты, но не могу продвинуться дальше врага, пока он не будет побежден.",
"<strong>Пользовательская история:</strong> Большая часть карты скрыта. Когда я делаю шаг, все клетки в определенном количестве клеток от меня становятся видимы.",
"<strong>Пользовательская история:</strong> Когда я побеждаю врага, враг исчезает, а я получаю очки опыта (XP), что увеличивает мой уровень.",
"<strong>Пользовательская история:</strong> Когда я веду бой с врагом, мы поочередно наносим друг-другу повреждения, до тех пор пока кто-нибудь не победит. Я наношу повреждения, которые зависят от моего уровня и моего оружия. Враг наносит повреждения, которые зависят от его уровня. Значение повреждений распределено случайным образом в некотором диапазоне.",
"<strong>Пользовательская история:</strong> Когад я нахожу и побеждаю босса, я выигрываю игру.",
"<strong>Пользовательская история:</strong> Игра должна быть интересной и достаточно сложной, но теоретически проходимой.",
"Если что-то не получается, не забывайте пользоваться методом <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Читай-Ищи-Спрашивай</a>.",
"Когда закончите, нажмите кнопку \"I've completed this challenge\" и укажите ссылку на вашу работу на CodePen.",
"Вы можете получить отзыв о вашем проекте от коллег, поделившись ссылкой на него в нашем <a href='//gitter.im/freecodecamp/codereview' target='_blank'>чате для рассмотрения кода</a>. Также вы можете поделиться ею через Twitter и на странице freeCodeCamp вашего города на Facebook."
]
}
}
},
{
"id": "bd7150d8c442eddfafb5bd1c",
"title": "P2P Video Chat Application",
"description": [
"<strong>Objective:</strong> Build a <a href='https://glitch.com' target='_blank'>Glitch</a> app that is functionally similar to this: <a href='https://unequaled-cement.glitch.me' target='_blank'>https://unequaled-cement.glitch.me</a>.",
"Fulfill the below <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>user stories</a>. Use whichever libraries or APIs you need. Give it your own personal style.",
"<strong>User Story:</strong> Upon arriving, the browser will prompt me to access my camera and microphone. ",
"<strong>User Story:</strong> After I give it permission, I am prompted to type in a room name.",
"<strong>User Story:</strong> Once I type in the room name, a room will be created if no room of that name existed before. ",
"<strong>User Story:</strong> A friend of mine can subsequently go to the same website, type in the same room I entered, and join the same room, then enter into a video chat with me. ",
"<strong>User Story:</strong> If I type in a room name, and there are already two people in that room, I get a notification that the room is full. ",
"<strong>User Story:</strong> Anyone can create or join any room. And there can be any number of rooms, but all of them must have unique names. ",
"<strong>User Story:</strong> I can choose to not permit the site to access my microphone and webcam. If I choose not to do this, if some other driver problem occurs, I see an error message saying these are required. ",
"<strong>User Story:</strong> When I choose to cancel the room name input step, or if I type in no name, or just spaces, it should again ask me again to type in a valid room name. ",
"<strong>User Story:</strong> If one of the two people in the room get disconnected, they can reconnect to the same room and continue chatting.",
"Remember to use <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> if you get stuck.",
"When you are finished, click the \"I've completed this challenge\" button and include a link to your Glitch App.",
"You can get feedback on your project by sharing it with your friends on Facebook."
],
"challengeSeed": [],
"tests": [],
"type": "zipline",
"challengeType": 3,
"isRequired": false,
"releasedOn": "January 1, 2016"
},
{
"id": "bd7198d8c242eddfaeb5bd13",
"title": "Show National Contiguity with a Force Directed Graph",
"description": [
"<strong>Objective:</strong> Build a <a href='https://codepen.io' target='_blank'>CodePen.io</a> app that is functionally similar to this: <a href='https://codepen.io/freeCodeCamp/full/xVopBo' target='_blank'>https://codepen.io/freeCodeCamp/full/xVopBo</a>.",
"Fulfill the following <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>user stories</a>. Use whichever libraries or APIs you need. Give it your own personal style.",
"<strong>User Story:</strong> I can see a Force-directed Graph that shows which countries share borders.",
"<strong>User Story:</strong> I can see each country's flag on its node.",
"<strong>Hint:</strong> Here's a dataset you can use to build this: <a href='https://raw.githubusercontent.com/DealPete/forceDirected/master/countries.json' target='_blank'>https://raw.githubusercontent.com/DealPete/forceDirected/master/countries.json</a>",
"<strong>Hint:</strong> You can create a spritesheet of national flags at <a href='https://www.flag-sprites.com' target='_blank'>https://www.flag-sprites.com</a>.",
"Remember to use <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> if you get stuck.",
"When you are finished, click the \"I've completed this challenge\" button and include a link to your CodePen. ",
"You can get feedback on your project by sharing it with your friends on Facebook."
],
"challengeSeed": [
"etBaP3IdlIE"
],
"tests": [],
"isRequired": false,
"releasedOn": "January 1, 2016",
"type": "zipline",
"challengeType": 3,
"translations": {
"es": {
"title": "Muestra asociaciones utilizando un gráfico de fuerzas dirigidas",
"description": [
"<strong>Objetivo:</strong> Construye una aplicación en <a href='https://codepen.io' target='_blank'>CodePen.io</a> que funcione de forma similar al siguiente ejemplo: <a href='https://codepen.io/freeCodeCamp/full/KVNNXY' target='_blank'>https://codepen.io/freeCodeCamp/full/KVNNXY</a>.",
"<strong>Regla #1:</strong> No veas el código del proyecto de ejemplo. Encuentra la forma de hacerlo por tu cuenta.",
"<strong>Regla #2:</strong> Satisface las siguientes <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>historias de usuario</a>. Usa cualquier librería o API que sea necesaria. ¡Ponle un toque personal!.",
"<strong>Regla #3:</strong> Debes utilizar D3.js para construir este proyecto.",
"<strong>Historia de usuario:</strong> Puedo ver un gráfico de fuerza dirigida que muestra qué campistas están publicando enlaces en Camper News hacia qué dominios.",
"<strong>Historia de usuario:</strong> Puedo ver el icono de cada campista en su nodo respectivo.",
"<strong>Historia de usuario:</strong> Puedo ver la relación entre los campistas y los dominios que publican.",
"<strong>Historia de usuario:</strong> Puedo conocer aproximadamente cuántas veces los campistas han enlazado un dominio en particular a partir del tamaño del nodo respectivo.",
"<strong>Historia de usuario:</strong> Puedo conocer aproximadamente cuántas veces un campista específico ha publicado un enlace a partir del tamaño de su nodo.",
"<strong>Pista:</strong> La siguiente es la ruta del API de noticias de Camper News: <code>http://www.freeCodeCamp.com/news/hot</code>.",
"Recuerda utilizar <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> si te sientes atascado.",
"Cuando termines, haz clic en el botón de \"I've completed this challenge\" e incluye el vínculo de tu proyecto en CodePen. ",
"Puedes obtener retroalimentación acerca de tu proyecto de parte de tus compañeros campistas compartiéndolo en nuestro <a href='//gitter.im/freecodecamp/codereview' target='_blank'>Cuarto de revisión de código</a>. También puedes compartirlo en Twitter y en el campamento de tu ciudad (en Facebook)."
]
}
}
},
{
"id": "bd7108d8c242eddfaeb5bd13",
"title": "Map Data Across the Globe",
"description": [
"<strong>Objective:</strong> Build a <a href='https://codepen.io' target='_blank'>CodePen.io</a> app that is functionally similar to this: <a href='https://codepen.io/freeCodeCamp/full/mVEJag' target='_blank'>https://codepen.io/freeCodeCamp/full/mVEJag</a>.",
"Fulfill the following <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>user stories</a>. Use whichever libraries or APIs you need. Give it your own personal style.",
"<strong>User Story:</strong> I can see where all Meteorites landed on a world map.",
"<strong>User Story:</strong> I can tell the relative size of the meteorite, just by looking at the way it's represented on the map.",
"<strong>User Story:</strong> I can mouse over the meteorite's data point for additional data.",
"<strong>Hint:</strong> Here's a dataset you can use to build this: <a href='https://raw.githubusercontent.com/freeCodeCamp/ProjectReferenceData/master/meteorite-strike-data.json' target='_blank'>https://raw.githubusercontent.com/freeCodeCamp/ProjectReferenceData/master/meteorite-strike-data.json</a>",
"Remember to use <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> if you get stuck.",
"When you are finished, click the \"I've completed this challenge\" button and include a link to your CodePen. ",
"You can get feedback on your project by sharing it with your friends on Facebook."
],
"challengeSeed": [
"kSAqct10gA0"
],
"tests": [],
"isRequired": false,
"releasedOn": "January 1, 2016",
"type": "zipline",
"challengeType": 3,
"translations": {
"es": {
"title": "Mapea datos a lo largo del Globo",
"description": [
"<strong>Objetivo:</strong> Construye una aplicación en <a href='https://codepen.io' target='_blank'>CodePen.io</a> que funcione de forma similar al siguiente ejemplo: <a href='https://codepen.io/freeCodeCamp/full/mVEJag' target='_blank'>https://codepen.io/freeCodeCamp/full/mVEJag</a>.",
"<strong>Regla #1:</strong> No veas el código del proyecto de ejemplo. Encuentra la forma de hacerlo por tu cuenta.",
"<strong>Regla #2:</strong> Satisface las siguientes <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>historias de usuario</a>. Usa cualquier librería o API que sea necesaria. ¡Ponle un toque personal!.",
"<strong>Regla #3:</strong> Debes utilizar D3.js para construir este proyecto.",
"<strong>Historia de usuario:</strong> Puedo ver a dónde cayeron todos los meteoritos en un mapa mundi.",
"<strong>Historia de usuario:</strong> Puedo distinguir el tamaño relativo de cada meteorito simplemente viendo la forma en que está representado en el mapa.",
"<strong>Historia de usuario:</strong> Puedo mover el ratón sobre el dato de cada meteorito para obtener información adicional.",
"<strong>Pista:</strong> Puedes utilizar el siguiente conjunto de datos para construir tu proyecto: <a href='https://raw.githubusercontent.com/freeCodeCamp/ProjectReferenceData/master/meteorite-strike-data.json' target='_blank'>https://raw.githubusercontent.com/freeCodeCamp/ProjectReferenceData/master/meteorite-strike-data.json</a>",
"Recuerda utilizar <a href='http://forum.freeCodeCamp.com/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> si te sientes atascado.",
"Cuando termines, haz clic en el botón de \"I've completed this challenge\" e incluye el vínculo de tu proyecto en CodePen. ",
"Puedes obtener retroalimentación acerca de tu proyecto de parte de tus compañeros campistas compartiéndolo en nuestro <a href='//gitter.im/freecodecamp/codereview' target='_blank'>Cuarto de revisión de código</a>. También puedes compartirlo en Twitter y en el campamento de tu ciudad (en Facebook)."
]
}
}
},
{
"id": "bd7158d8c443eddfaeb5bd0f",
"title": "Manage a Book Trading Club",
"description": [
"<strong>Objective:</strong> Build a full stack JavaScript app that is functionally similar to this: <a href='http://bookjump.herokuapp.com/' target='_blank'>http://bookjump.herokuapp.com/</a> and deploy it to Heroku.",
"Note that for each project, you should create a new GitHub repository and a new Heroku project. If you can't remember how to do this, revisit <a href='/challenges/get-set-for-our-dynamic-web-application-projects'>https://freecodecamp.com/challenges/get-set-for-our-dynamic-web-application-projects</a>.",
"Here are the specific user stories you should implement for this project:",
"<strong>User Story:</strong> I can view all books posted by every user.",
"<strong>User Story:</strong> I can add a new book.",
"<strong>User Story:</strong> I can update my settings to store my full name, city, and state.",
"<strong>User Story:</strong> I can propose a trade and wait for the other user to accept the trade.",
"Once you've finished implementing these user stories, click the \"I've completed this challenge\" button and enter the URLs for both your GitHub repository and your live app running on Heroku.",
"You can get feedback on your project by sharing it with your friends on Facebook."
],
"challengeSeed": [
"mzElFmbGqQI"
],
"tests": [],
"type": "basejump",
"challengeType": 4,
"descriptionEs": [
"<strong>Objetivo:</strong> Construye una aplicación de pila completa (full stack) en JavaScript que funcione de forma similar al siguiente proyecto: <a href='http://bookjump.herokuapp.com/' target='_blank'>http://bookjump.herokuapp.com/</a> y despliégalo en Heroku.",
"Ten en cuenta que para cada proyecto, debes crear un nuevo repositorio en GitHub y un nuevo proyecto en Heroku. Si no recuerdas cómo hacerlo, visita de nuevo <a href='/challenges/get-set-for-our-dynamic-web-application-projects'>https://freecodecamp.com/challenges/get-set-for-our-dynamic-web-application-projects</a>.",
"Estas son las Historias de usuario que debes satisfacer para este Basejump:",
"<strong>Historia de usuario:</strong> Puedo ver todos los libros agregados por cada usuario.",
"<strong>Historia de usuario:</strong> Puedo agregar un nuevo libro.",
"<strong>Historia de usuario:</strong> Puedo actualizar mi configuración para que almacene mi nombre completo, ciudad y Estado.",
"<strong>Historia de usuario:</strong> Puedo proponer un intercambio y esperar a que algún otro usuario acepte el trato.",
"Una vez hayas terminado de implementar estas historias de usuario, pulsa el botón de \"I've completed this challenge\" e incluye las URLs de tu repositorio GitHub y de tu aplicación corriendo en Heroku.",
"Puedes obtener retroalimentación acerca de tu proyecto de parte de tus compañeros campistas compartiéndolo en nuestro <a href='//gitter.im/freecodecamp/codereview' target='_blank'>Cuarto de revisión de código</a>. También puedes compartirlo en Twitter y en el campamento de tu ciudad (en Facebook)."
],
"isRequired": false,
"titleEs": "Administra un club de intercambio de libros"
},
{
"id": "bd7158d8c443eddfaeb5bdee",
"title": "Build a Pinterest Clone",
"description": [
"<strong>Objective:</strong> Build a full stack JavaScript app that is functionally similar to this: <a href='https://midnight-dust.glitch.me' target='_blank'>https://midnight-dust.glitch.me</a> and deploy it to Heroku.",
"Note that for each project, you should create a new GitHub repository and a new Heroku project. If you can't remember how to do this, revisit <a href='/challenges/get-set-for-our-dynamic-web-application-projects'>https://freecodecamp.com/challenges/get-set-for-our-dynamic-web-application-projects</a>.",
"Here are the specific user stories you should implement for this project:",
"<strong>User Story:</strong> As an unauthenticated user, I can login with Twitter.",
"<strong>User Story:</strong> As an authenticated user, I can link to images.",
"<strong>User Story:</strong> As an authenticated user, I can delete images that I've linked to.",
"<strong>User Story:</strong> As an authenticated user, I can see a Pinterest-style wall of all the images I've linked to.",
"<strong>User Story:</strong> As an unauthenticated user, I can browse other users' walls of images.",
"<strong>User Story:</strong> As an authenticated user, if I upload an image that is broken, it will be replaced by a placeholder image. (can use jQuery broken image detection)",
"<strong>Hint:</strong> <a href='http://masonry.desandro.com/' target='_blank'>Masonry.js</a> is a library that allows for Pinterest-style image grids.",
"Once you've finished implementing these user stories, click the \"I've completed this challenge\" button and enter the URLs for both your GitHub repository and your live app running on Heroku.",
"You can get feedback on your project by sharing it with your friends on Facebook."
],
"challengeSeed": [
"adrOtJCVP04"
],
"tests": [],
"type": "basejump",
"challengeType": 4,
"descriptionEs": [
"<strong>Objetivo:</strong> Construye una aplicación de pila completa (full stack) en JavaScript que funcione de forma similar al siguiente proyecto: <a href='https://midnight-dust.glitch.me/' target='_blank'>https://midnight-dust.glitch.me/</a> y despliégalo en Heroku.",
"Ten en cuenta que para cada proyecto, debes crear un nuevo repositorio en GitHub y un nuevo proyecto en Heroku. Si no recuerdas cómo hacerlo, visita de nuevo <a href='/challenges/get-set-for-our-dynamic-web-application-projects'>https://freecodecamp.com/challenges/get-set-for-our-dynamic-web-application-projects</a>.",
"Estas son las Historias de usuario que debes satisfacer para este Basejump:",
"<strong>Historia de usuario:</strong> Como usuario autenticado, puedo acceder a mi cuenta con Twitter.",
"<strong>Historia de usuario:</strong> Como usuario autenticado, puedo agregar enlaces a imágenes.",
"<strong>Historia de usuario:</strong> Como usuario autenticado, puedo elimiar imágenes que he agregado.",
"<strong>Historia de usuario:</strong> Como usuario autenticado, puedo ver un muro al estilo de Pinterest con todas las imágenes para las que he agregado un enlace.",
"<strong>Historia de usuario:</strong> Como usuario no autenticado, puedo navegar los muros de imágenes de otros usuarios.",
"<strong>Historia de usuario:</strong> Como usuario autenticado, si agrego una imagen corrupta, será reemplazada por una imagen predeterminada. (Puedes utilizar la detección de imágenes corruptas de jQuery)",
"<strong>Pista:</strong> <a href='http://masonry.desandro.com/' target='_blank'>Masonry.js</a> es una librería que permite crear cuadrículas de imágenes al estilo de Pinterest.",
"Una vez hayas terminado de implementar estas historias de usuario, pulsa el botón de \"I've completed this challenge\" e incluye las URLs de tu repositorio GitHub y de tu aplicación corriendo en Heroku.",
"Puedes obtener retroalimentación acerca de tu proyecto de parte de tus compañeros campistas compartiéndolo en nuestro <a href='//gitter.im/freecodecamp/codereview' target='_blank'>Cuarto de revisión de código</a>. También puedes compartirlo en Twitter y en el campamento de tu ciudad (en Facebook)."
],
"isRequired": false,
"titleEs": "Crea un clon de Pinterest"
}
]
}

View File

@ -0,0 +1,58 @@
{
"name": "Add and Subtract Decimals",
"order": 18,
"challenges": [
{
"id": "59a5801209a6acac5983b428",
"title": "Add and Subtract Decimal Numbers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836409",
"title": "Mental Math to Add and Subtract Decimals",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836410",
"title": "Add and Subtract Decimals with Front-End Estimation",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836411",
"title": "Round Decimals to Estimate Sums and Differences",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,84 @@
{
"name": "Add and Subtract Fractions",
"order": 11,
"challenges": [
{
"id": "59a5801209a6acac5983b421",
"title": "Add Fractions with Common Denominators",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836370",
"title": "Subtract Fractions with Common Denominators",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836371",
"title": "Add and Subtract with Common Denominators",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836372",
"title": "Add and Subtract Fractions with Common Denominators Word Problems",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836373",
"title": "Add Fractions with Different Denominators",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836374",
"title": "Subtract Fractions with Different Denominators",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,71 @@
{
"name": "Add and Subtract Mixed Numbers",
"order": 12,
"challenges": [
{
"id": "59a5801209a6acac5983b422",
"title": "Add Mixed Numbers with Common Denominators",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836376",
"title": "Subtract Mixed Numbers with Common Denominators",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836377",
"title": "Subtract Mixed Numbers with Different Denominators",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836378",
"title": "Add and Subtract Three Mixed Numbers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836379",
"title": "Add and Subtract Mixed Numbers Word Problems",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,45 @@
{
"name": "Additon and Subtraction",
"order": 2,
"challenges": [
{
"id": "59a5801209a6acac5983b411",
"title": "Add Whole Numbers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836306",
"title": "Subtract Whole Numbers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836307",
"title": "Estimate Whole Number Sums and Differences",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,71 @@
{
"name": "Basic Decimals",
"order": 15,
"challenges": [
{
"id": "59a5801209a6acac5983b425",
"title": "Place Value Charts and Decimals to Thousandths",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836398",
"title": "Equivalent Decimals Ending in Zero",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836399",
"title": "Decimals in Words",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836400",
"title": "Decimal Place Value",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836401",
"title": "Decimals in Expanded Form",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,58 @@
{
"name": "Basic Place Value",
"order": 1,
"challenges": [
{
"id": "59a5801209a6acac59836300",
"title": "Recognize Place Values to 10,000,000",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836301",
"title": "Greatest and Least Values of Given Digits to 10,000,000",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836303",
"title": "Higher Order Place Value and Number Placement Problems",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836304",
"title": "Round Large Numbers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,45 @@
{
"name": "Compare Decimals",
"order": 16,
"challenges": [
{
"id": "59a5801209a6acac5983b426",
"title": "Compare and Order Decimals",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836403",
"title": "Compare and Compose Decimals and Fractions",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836404",
"title": "Compare, Order and Identify Decimal Inequalities",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,71 @@
{
"name": "Converting Decimals",
"order": 25,
"challenges": [
{
"id": "59a5801209a6acac5983b435",
"title": "Convert Decimals to Fractions",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836444",
"title": "Convert Decimals into Simplified Mixed Numbers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836445",
"title": "Decimals as Percents",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836446",
"title": "Compare and Order Fractions and Decimals",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836447",
"title": "Convert between Decimals, Fractions, and Percents",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,84 @@
{
"name": "Converting Fractions",
"order": 24,
"challenges": [
{
"id": "59a5801209a6acac5983b434",
"title": "Fraction and Decimal Conversion",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836438",
"title": "Convert Mixed Numbers to Decimals",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836439",
"title": "Compare Mixed Numbers and Decimals",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836440",
"title": "Convert Between Fractions or Mixed Numbers and Decimals",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836441",
"title": "Add Fractions and Convert to Decimals",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836442",
"title": "Fractions as Percents",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,32 @@
{
"name": "Converting Percentages",
"order": 23,
"challenges": [
{
"id": "59a5801209a6acac5983b433",
"title": "Percents as Decimals",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836436",
"title": "Percents as Fractions",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,71 @@
{
"name": "Division",
"order": 4,
"challenges": [
{
"id": "59a5801209a6acac5983b413",
"title": "Divide Two Digits by One or Two Digits Without Remainders",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836319",
"title": "Higher Order Division to 1000 by One Digit",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836320",
"title": "Divide More than Two Digits by One Digit with Remainders",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836321",
"title": "Relate Division to Multiplication",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836322",
"title": "Estimate Whole Number Products and Quotients",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,58 @@
{
"name": "Exponents and Roots",
"order": 7,
"challenges": [
{
"id": "59a5801209a6acac5983b417",
"title": "Exponents",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836338",
"title": "Evaluate and Compare Powers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836339",
"title": "Perfect Square Roots",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836340",
"title": "Evaluate Square Roots",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,97 @@
{
"name": "Factors",
"order": 8,
"challenges": [
{
"id": "59a5801209a6acac5983b418",
"title": "Prime and Composite Numbers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836342",
"title": "Prime Factorization",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836343",
"title": "Identify Factor Pairs",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836344",
"title": "Divisibility Rules to Find Factors",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836345",
"title": "GCF Greatest Common Factor",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836346",
"title": "Common Multiples",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836347",
"title": "LCM Least Common Multiple",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,136 @@
{
"name": "Fractions",
"order": 10,
"challenges": [
{
"id": "59a5801209a6acac5983b420",
"title": "Equivalent Fractions",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836360",
"title": "Simplify Fractions",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836361",
"title": "Simplify Fractions Word Problems",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836362",
"title": "Compare Fractions",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836363",
"title": "Compare Fractions using Pictures",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836364",
"title": "Compare Fractions that have Common Numerators or Denominators",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836365",
"title": "Compare Fractions without Common Numerators or Denominators",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836366",
"title": "Compare Fractions without Common Numerators or Denominators Word Problems",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836367",
"title": "Estimate and Round Fractions and Mixed Numbers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836368",
"title": "Convert and Compare Mixed Numbers and Improper Fractions",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,149 @@
{
"name": "Integer Operations",
"order": 9,
"challenges": [
{
"id": "59a5801209a6acac5983b419",
"title": "Integers in the Real World",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836349",
"title": "Integers on a Number Line",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836350",
"title": "Absolute Value of Integers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836351",
"title": "Add Integers with the Same Signs",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836352",
"title": "Add Integers with Different Signs",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836353",
"title": "Integer Addition",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836354",
"title": "Subtract Integers with the Same Sign",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836355",
"title": "Subtract Integers with Different Signs",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836356",
"title": "Integer Subtraction",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836357",
"title": "Multiply Integers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836358",
"title": "Divide Integers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,71 @@
{
"name": "Long Division",
"order": 5,
"challenges": [
{
"id": "59a5801209a6acac5983b415",
"title": "Long Division Without Remainders",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836324",
"title": "Divide up to Four Digits by Two Digits with Remainders",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836325",
"title": "Groups and Remainders Word Problems",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836326",
"title": "Long Division Word Problems",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836327",
"title": "Divide Whole Numbers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,136 @@
{
"name": "Multiplication",
"order": 3,
"challenges": [
{
"id": "59a5801209a6acac5983b412",
"title": "Multiply Multiple Digits by One Digit",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836309",
"title": "Higher Order One Digit Multiplication Word Problems",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836310",
"title": "Relate One Digit Number Patterns to Multiplication",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836311",
"title": "Multiply Numbers with the Associative Property",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836312",
"title": "Multiply Two Digits by Two or More Digits",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836313",
"title": "Multiply and Compare with Greater/Less Than",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836314",
"title": "Relate Number Patterns to Multiplication",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836315",
"title": "Higher Order Multiplication Word Problems",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836316",
"title": "Multiply Whole Numbers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836317",
"title": "Mental Multiplication",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,58 @@
{
"name": "Multiply and Divide Decimals",
"order": 19,
"challenges": [
{
"id": "59a5801209a6acac5983b429",
"title": "Decimal Multiplication",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836413",
"title": "Decimal Division",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836414",
"title": "Multiply Decimals and Whole Numbers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836415",
"title": "Estimate Products and Quotients of Decimals",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,162 @@
{
"name": "Multiply and Divide Fractions",
"order": 13,
"challenges": [
{
"id": "59a5801209a6acac5983b423",
"title": "Multiply Whole Numbers and Fractions",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836381",
"title": "Multiply Two Fractions",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836382",
"title": "Multiply Three or More Fractions and Whole Numbers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836383",
"title": "Multiply Mixed Numbers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836384",
"title": "Multiply Mixed Numbers Word Problems",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836385",
"title": "Reciprocal Fractions",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836386",
"title": "Divide Fractions and Whole Numbers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836387",
"title": "Divide Fractions",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836388",
"title": "Divide Whole Numbers by Mixed Numbers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836389",
"title": "Divide Mixed Numbers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836390",
"title": "Multiply and Divide Fractions and Mixed Numbers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836391",
"title": "Estimate Products of Whole Numbers and Fractions",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,123 @@
{
"name": "Order of Operations",
"order": 6,
"challenges": [
{
"id": "59a5801209a6acac5983b416",
"title": "Introduction to Order of Operations",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836329",
"title": "Divide and Subtract with Remainders in Word Problems",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836330",
"title": "Division and Subtraction Word Problems",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836331",
"title": "Higher Order Division and Subtraction Word Problems",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836332",
"title": "Multiply and Add Word Problems",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836333",
"title": "Multiply and Add or Subtract Word Problems",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836334",
"title": "Place Operators to Make True Statements",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836335",
"title": "Place Operators to Make True Statements that Include Parentheses",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836336",
"title": "Place Parentheses to Make True Statements",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,110 @@
{
"name": "Percentages",
"order": 22,
"challenges": [
{
"id": "59a5801209a6acac5983b432",
"title": "Overview of Percentages",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836428",
"title": "Percent of a Number",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836429",
"title": "Simple Interest",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836430",
"title": "Percent of Change",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836431",
"title": "Percent of Increase",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836432",
"title": "Percent of Decrease",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836433",
"title": "Prices Involving Discounts",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836434",
"title": "Total Bill Including Tip and Tax",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,58 @@
{
"name": "Powers of Ten and Scientific Notation",
"order": 20,
"challenges": [
{
"id": "59a5801209a6acac5983b430",
"title": "Multiply Decimals by Powers of Ten",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836417",
"title": "Multiplication and Powers of Ten",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836418",
"title": "Division and Powers of Ten",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836419",
"title": "Scientific Notation",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,97 @@
{
"name": "Rational and Irrational numbers",
"order": 21,
"challenges": [
{
"id": "59a5801209a6acac5983b431",
"title": "Rational Numbers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836421",
"title": "Add Rational Numbers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836422",
"title": "Subtract Rational Numbers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836423",
"title": "Multiply Rational Numbers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836424",
"title": "Divide Rational Numbers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836425",
"title": "Irrational Numbers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836426",
"title": "Irrational Square Roots",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,71 @@
{
"name": "Ratios",
"order": 14,
"challenges": [
{
"id": "59a5801209a6acac5983b424",
"title": "Definition of a Ratio",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836393",
"title": "Equivalent Ratios",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836394",
"title": "Ratios in Simplest Form",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836395",
"title": "Compare Ratios in Decimal Form",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836396",
"title": "Unit Rates",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,32 @@
{
"name": "Round Decimals",
"order": 17,
"challenges": [
{
"id": "59a5801209a6acac5983b427",
"title": "Round Decimal Numbers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836407",
"title": "Round Decimals with Place Value",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,84 @@
{
"name": "Algebra Expressions and Variables",
"order": 29,
"challenges": [
{
"id": "59a5801209a6acac5983b439",
"title": "Expressions and Variables",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836461",
"title": "Evaluate Single Variable Expressions",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836462",
"title": "Evaluate Expressions with One or More Variables",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836463",
"title": "Words that Describe Mathematical Operations",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836464",
"title": "Translate Between English Phrases and Algebraic Expressions",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836465",
"title": "Calculator Use with Algebra Expressions",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,71 @@
{
"name": "Integers",
"order": 27,
"challenges": [
{
"id": "59a5801209a6acac5983b437",
"title": "Absolute Value of Integers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836451",
"title": "Integer Addition",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836452",
"title": "Integer Subtraction",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836453",
"title": "Integer Multiplication",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836454",
"title": "Integer Division",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,136 @@
{
"name": "Properties and Axioms of Real Numbers",
"order": 30,
"challenges": [
{
"id": "59a5801209a6acac5983b440",
"title": "Real Number Properties and Axioms",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836467",
"title": "Distributive Property",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836468",
"title": "Expressions and the Distributive Property",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836469",
"title": "When to Use the Distributive Property",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836470",
"title": "Distributive Property to Evaluate Formulas with Decimals",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836471",
"title": "Additive inverses and Absolute Values",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836472",
"title": "Associative and Commutative Property with Decimals",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836473",
"title": "Associative and Commutative Property with Fractions",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836474",
"title": "Addition and Multiplication Properties with Real Numbers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836475",
"title": "Fraction and Mixed Number Applications",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,32 @@
{
"name": "Real Number Variables and Expressions",
"order": 26,
"challenges": [
{
"id": "59a5801209a6acac5983b436",
"title": "The Real Numbers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836449",
"title": "Order Real Numbers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,58 @@
{
"name": "Simplifying Expressions",
"order": 31,
"challenges": [
{
"id": "59a5801209a6acac5983b441",
"title": "Simplify Variable Expressions Involving Addition and Subtraction",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836477",
"title": "Simplify Variable Expressions Involving Multiplication and Division",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836478",
"title": "Simplify Variable Expressions Involving Multiple Operations",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836479",
"title": "Simplify Algebraic Expressions",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,71 @@
{
"name": "The Order of Operations",
"order": 28,
"challenges": [
{
"id": "59a5801209a6acac5983b438",
"title": "Order of Operations",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836456",
"title": "PEMDAS in Numerical Expressions",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836457",
"title": "Algebra Expressions with Exponents",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836458",
"title": "Algebra Expressions with Fraction Bars",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836459",
"title": "Order of Operations and Variable Substitution",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,45 @@
{
"name": "Add and Subtract Rational Expressions",
"order": 27,
"challenges": [
{
"id": "59a5801209a6acac5983b472",
"title": "Addition and Subtraction of Rational Expressions",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a051",
"title": "Adding and Subtracting Rational Expressions where One Denominator is the LCD",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a052",
"title": "Applications of Adding and Subtracting Rational Expressions",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,97 @@
{
"name": "Basic Equations",
"order": 1,
"challenges": [
{
"id": "59a5801209a6acac5983b442",
"title": "Writing Basic Equations",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836481",
"title": "Sentences as Single Variable Equations",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836482",
"title": "Addition and Subtraction Phrases as Equations",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836483",
"title": "Multiplication and Division Phrases as Equations",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836484",
"title": "Input-Output Tables",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836485",
"title": "Function Rules for Input-Output Tables",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836486",
"title": "Input-Output Tables for Function Rules",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,45 @@
{
"name": "Direct Variations",
"order": 31,
"challenges": [
{
"id": "59a5801209a6acac5983b476",
"title": "Direct Variation",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a065",
"title": "Applications Using Direct Variation",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a066",
"title": "Graphs of Linear Models of Direct Variation",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,97 @@
{
"name": "Distance, Rate, and Time",
"order": 6,
"challenges": [
{
"id": "59a5801209a6acac5983b448",
"title": "D = RT",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836514",
"title": "Solving for Elapsed Time Related to Rate",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836515",
"title": "Finding the Total Time Given a Distance between Two Objects",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836516",
"title": "Applications of Finding Time Using Multiple Steps",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836517",
"title": "Finding Total Distance Using Multiple Steps Word Problems",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836518",
"title": "Find the Rate, Given Time and Distance",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836519",
"title": "Solving Length and Distance Problems Involving Time",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,110 @@
{
"name": "Exponential Growth and Decay Functions",
"order": 40,
"challenges": [
{
"id": "59a5801209a6acac5983b486",
"title": "Exponential Functions",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a223",
"title": "Solving Equations with Exponents",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a224",
"title": "Exponential Growth and Decay",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a225",
"title": "Exponential Growth",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a226",
"title": "Exponential Decay",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a227",
"title": "Geometric Sequences and Exponential Functions",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a228",
"title": "Graphs of Exponential Functions",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a229",
"title": "Applications of Exponential Functions",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,58 @@
{
"name": "Exponents and Irrational Numbers",
"order": 33,
"challenges": [
{
"id": "59a5801209a6acac5983b479",
"title": "Negative and Zero Exponents",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a079",
"title": "Fractional Exponents",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a080",
"title": "Zero, Negative, and Fractional Exponents",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a081",
"title": "Operations with Roots and Irrational Numbers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,97 @@
{
"name": "Functions and Function Notation",
"order": 9,
"challenges": [
{
"id": "59a5801209a6acac5983b451",
"title": "Function Notation",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836541",
"title": "Domain and Range of a Function",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836543",
"title": "Applications of Functions",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836544",
"title": "Identify Functions and the Vertical Line Test",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836545",
"title": "Even and Odd Functions and Function Symmetry",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836546",
"title": "Operations on Functions",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836547",
"title": "Composition of Functions",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,123 @@
{
"name": "Graphing in the Coordinate Plane",
"order": 8,
"challenges": [
{
"id": "59a5801209a6acac5983b450",
"title": "Graphs in the Coordinate Plane",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836533",
"title": "Points in the Coordinate Plane",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836534",
"title": "Ordered Pairs in Four Quadrants",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836535",
"title": "Coordinate Locations on a Map",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836536",
"title": "Graphs on a Coordinate Plane",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836537",
"title": "Graphs Based on Rules",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836538",
"title": "Rules Based on Graphs",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836539",
"title": "Identify Types of Linear and Nonlinear Graphs",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836540",
"title": "Function Families",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,97 @@
{
"name": "Graph Linear Equations",
"order": 10,
"challenges": [
{
"id": "59a5801209a6acac5983b452",
"title": "Graph of a Linear Equation in Two Variables",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836549",
"title": "Graphs of Linear Equations",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836550",
"title": "Horizontal and Vertical Line Graphs",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836551",
"title": "Graph Using Intercepts",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836552",
"title": "Problem Solving with Linear Graphs",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836553",
"title": "Graphs of Absolute Value Equations",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836554",
"title": "Linear and Absolute Value Function Families",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,58 @@
{
"name": "Graphing Polynomials",
"order": 24,
"challenges": [
{
"id": "59a5801209a6acac5983b469",
"title": "Identify Parts of Polynomial Graphs",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a039",
"title": "Graphs of Polynomials Using Transformations",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a040",
"title": "Graphs of Polynomials Using Zeros",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a041",
"title": "Graphing Calculator to Analyze Polynomial Functions",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,71 @@
{
"name": "Graphing Quadratic Functions and Equations",
"order": 38,
"challenges": [
{
"id": "59a5801209a6acac5983b484",
"title": "Graph Quadratic Functions and Equations",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a214",
"title": "Graphing with the Vertex Form of Quadratic Functions",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a215",
"title": "Graphs of Quadratic Functions in Intercept Form",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a216",
"title": "Roots to Determine a Quadratic Function",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a217",
"title": "Quadratic Functions and Equations",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,58 @@
{
"name": "Graphing Slope",
"order": 11,
"challenges": [
{
"id": "59a5801209a6acac5983b453",
"title": "Slope",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836556",
"title": "Rates of Change",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836557",
"title": "Slope of a Line Using Two Points",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836558",
"title": "Graph Using Slope-Intercept Form",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,45 @@
{
"name": "Introduction to Polynomials",
"order": 18,
"challenges": [
{
"id": "59a5801209a6acac5983b461",
"title": "Monomials, Binomials, and Trinomials",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a015",
"title": "Polynomials in Standard Form",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a016",
"title": "Addition and Subtraction of Polynomials",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,58 @@
{
"name": "Introduction to Rational Expressions",
"order": 25,
"challenges": [
{
"id": "59a5801209a6acac5983b470",
"title": "Working with Rational Expressions",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a043",
"title": "Simplifying Rational Expressions",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a044",
"title": "Excluded Values for Rational Expressions",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a045",
"title": "Restricted Domain and Range",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,149 @@
{
"name": "Inverse Variation and Rational Functions",
"order": 32,
"challenges": [
{
"id": "59a5801209a6acac5983b478",
"title": "Direct and Inverse Variation",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a068",
"title": "Inverse Variation Models",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a069",
"title": "Estimate Graphs of Rational Functions",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a070",
"title": "Horizontal and Vertical Asymptotes",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a071",
"title": "Vertical Asymptotes",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a072",
"title": "Horizontal Asymptotes",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a073",
"title": "Oblique Asymptotes",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a074",
"title": "Determining Asymptotes by Division",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a075",
"title": "Inverse Variation Problems",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a076",
"title": "Joint and Combined Variation",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a077",
"title": "Applications Using Rational Equations",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,58 @@
{
"name": "Linear Equations in the Real World",
"order": 5,
"challenges": [
{
"id": "59a5801209a6acac5983b447",
"title": "Applications of Linear Equations",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836510",
"title": "Problem-Solving Models",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836511",
"title": "Guess and Check, Work Backward",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836512",
"title": "Applications Using Linear Models",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,58 @@
{
"name": "Linear, Exponential and Quadratic Models",
"order": 42,
"challenges": [
{
"id": "59a5801209a6acac5983b488",
"title": "Identifying Linear, Exponential, and Quadratic Models",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a239",
"title": "Linear, Quadratic, and Cubic Models",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a240",
"title": "Cubic Models",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a241",
"title": "Applications of Function Models",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,162 @@
{
"name": "Linear Inequalities",
"order": 7,
"challenges": [
{
"id": "59a5801209a6acac5983b449",
"title": "Solve One Step Linear Inequalities",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836521",
"title": "Inequalities on a Number Line",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836522",
"title": "Inequalities that Describe Patterns",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836523",
"title": "Inequality Expressions",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836524",
"title": "Inequalities with Addition and Subtraction",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836525",
"title": "Inequalities with Multiplication and Division",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836526",
"title": "Multi-Step Inequalities",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836527",
"title": "Checking Solutions to Inequalities",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836528",
"title": "Compound Inequalities",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836529",
"title": "Graph and Solve Absolute Value Inequalities",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836530",
"title": "Intervals and Interval Notation",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836531",
"title": "Applications with Inequalities",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,58 @@
{
"name": "Linear Systems",
"order": 15,
"challenges": [
{
"id": "59a5801209a6acac5983b458",
"title": "Consistent and Inconsistent Linear Systems",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a587af21a188128bc4071a",
"title": "Checking a Solution for a Linear System",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a587af21a188128bc4071c",
"title": "Graphs of Linear Systems",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a587af21a188128bc4071d",
"title": "Systems of Linear Equations in Two Variables",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,110 @@
{
"name": "Logarithms",
"order": 41,
"challenges": [
{
"id": "59a5801209a6acac5983b487",
"title": "Common and Natural Logarithms",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a231",
"title": "Analysis of Logarithmic Graphs",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a232",
"title": "Logarithm Properties",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a233",
"title": "Change of Base",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a234",
"title": "Product and Quotient Properties of Logarithms",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a235",
"title": "Power Property of Logarithms",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a236",
"title": "Inverse Properties of Logarithms",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a237",
"title": "Logistic Functions",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,97 @@
{
"name": "Matrix Algebra",
"order": 43,
"challenges": [
{
"id": "59a5801209a6acac5983b489",
"title": "Introduction to Matrices",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a243",
"title": "Adding and Subtracting Matrices",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a244",
"title": "Multiplying Matrices by a Scalar",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a245",
"title": "Matrix Multiplication",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a246",
"title": "Matrix Operations",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a247",
"title": "Determinants",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a248",
"title": "Cramer's Rule",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,110 @@
{
"name": "Matrix Equations",
"order": 44,
"challenges": [
{
"id": "59a5801209a6acac5983b490",
"title": "Solving Matrix Equations",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a250",
"title": "Augmented Matrices",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a251",
"title": "Row Operations and Row Echelon Forms",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a252",
"title": "Writing and Solving a Matrix Equation for a Linear System",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a253",
"title": "Solving Linear Systems Using Matrices and Technology",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a254",
"title": "Inverse Matrices",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a255",
"title": "Applications of Matrices",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac5983a256",
"title": "Partial Fraction Expansions",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

Some files were not shown because too many files have changed in this diff Show More