From f2025dc32c24cee468cc8eafc0b5673b6c282567 Mon Sep 17 00:00:00 2001 From: Creighton Magoun Date: Tue, 16 Oct 2018 05:23:45 +0000 Subject: [PATCH 01/37] Testing packages for scraping FreeCodeCamp --- hello.js | 22 ++++++++++++++++++++++ package.json | 25 +++++++++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 hello.js create mode 100644 package.json diff --git a/hello.js b/hello.js new file mode 100644 index 0000000..a365bf6 --- /dev/null +++ b/hello.js @@ -0,0 +1,22 @@ +const puppeteer = require('puppeteer'); + +// Fetch html using puppeteer +let getHTML = async (url) => { + const browser = await puppeteer.launch(); + const page = await browser.newPage(); + await page.goto(url); + const html = await page.content(); + + await browser.close(); + return html; +}; + + +const url = 'https://learn.freecodecamp.org'; +getHTML(url).then( (html) => { + const $ = require('cheerio').load(html); + $('li').each(function () { + console.log($(this).text()); + }); +}); + diff --git a/package.json b/package.json new file mode 100644 index 0000000..487e978 --- /dev/null +++ b/package.json @@ -0,0 +1,25 @@ +{ + "name": "fcc-progress", + "version": "1.0.0", + "description": "Scrape FreeCodeCamp.org to track student progress through the Greenville Codes program.", + "main": "fcc-progress.js", + "dependencies": { + "cheerio": "^1.0.0-rc.2", + "puppeteer": "^1.9.0", + "request-promise": "^4.2.2" + }, + "devDependencies": {}, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/magoun/fcc-progress.git" + }, + "author": "", + "license": "ISC", + "bugs": { + "url": "https://github.com/magoun/fcc-progress/issues" + }, + "homepage": "https://github.com/magoun/fcc-progress#readme" +} From 8cac83cbbac48cf1f85f543328928cfba7b1ec6d Mon Sep 17 00:00:00 2001 From: Creighton Magoun Date: Tue, 16 Oct 2018 19:22:48 +0000 Subject: [PATCH 02/37] Fix unfolding of FCC curriculum map before scraping html --- hello.js | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/hello.js b/hello.js index a365bf6..24209cc 100644 --- a/hello.js +++ b/hello.js @@ -5,8 +5,24 @@ let getHTML = async (url) => { const browser = await puppeteer.launch(); const page = await browser.newPage(); await page.goto(url); + + // Need to click links to fully expand map + // Outer level uses superblock class + let superblock = await page.$("li[class='superblock ']"); + while (superblock) { + await superblock.click(); + superblock = await page.$("li[class='superblock ']"); + } + + // Inner level uses block class + let block = await page.$("li[class='block ']"); + while (block) { + await block.click(); + block = await page.$("li[class='block ']"); + } + + // Map is now fully expanded. Get content and close browser. const html = await page.content(); - await browser.close(); return html; }; @@ -15,8 +31,8 @@ let getHTML = async (url) => { const url = 'https://learn.freecodecamp.org'; getHTML(url).then( (html) => { const $ = require('cheerio').load(html); - $('li').each(function () { - console.log($(this).text()); + $("li[class='map-challenge-title'] > a").each(function () { + // console.log($(this).text()); }); }); From bc264317962cd4f2b7eef69d9b454b2a0eb88662 Mon Sep 17 00:00:00 2001 From: Creighton Magoun Date: Wed, 17 Oct 2018 00:49:04 +0000 Subject: [PATCH 03/37] Flesh out scraping logic for mapping FreeCodeCamp curriculum --- hello.js | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/hello.js b/hello.js index 24209cc..1c6e131 100644 --- a/hello.js +++ b/hello.js @@ -31,8 +31,31 @@ let getHTML = async (url) => { const url = 'https://learn.freecodecamp.org'; getHTML(url).then( (html) => { const $ = require('cheerio').load(html); - $("li[class='map-challenge-title'] > a").each(function () { - // console.log($(this).text()); - }); + let jsonObj = {}; + + // Assemble the data to convert to JSON + // Crawl the major sections in .superblock + $('.superblock').each(function (index, element) { + // Get the major section titles + let section = $(this).find('h4').text(); + // Crawl the subsections in .block + $(this).find('.block') + .each(function (index, element) { + // Get the minor section titles + let subsection = $(this).find('h5').text(); + console.log(subsection); + $(this).find('a') + .each(function (index, element) { + let exercise = $(this).text(); + console.log(' ' + exercise); + }); + }); + // console.log(testArray); + }); + // console.log(jsonArray); + + // $("li[class='map-challenge-title'] > a").each(function () { + // console.log($(this).text()); + // }); }); From 8ca5df60ae5838120a3de1384741d68b6bd55b9b Mon Sep 17 00:00:00 2001 From: Creighton Magoun Date: Wed, 17 Oct 2018 03:40:35 +0000 Subject: [PATCH 04/37] Clean intro items from each subsection --- hello.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/hello.js b/hello.js index 1c6e131..c9b08b1 100644 --- a/hello.js +++ b/hello.js @@ -31,23 +31,27 @@ let getHTML = async (url) => { const url = 'https://learn.freecodecamp.org'; getHTML(url).then( (html) => { const $ = require('cheerio').load(html); - let jsonObj = {}; + let jsonArray = []; // Assemble the data to convert to JSON // Crawl the major sections in .superblock $('.superblock').each(function (index, element) { // Get the major section titles let section = $(this).find('h4').text(); + jsonArray[index] = // Crawl the subsections in .block $(this).find('.block') .each(function (index, element) { // Get the minor section titles let subsection = $(this).find('h5').text(); - console.log(subsection); + console.log(' ' + subsection); $(this).find('a') .each(function (index, element) { - let exercise = $(this).text(); - console.log(' ' + exercise); + // First item is an 'Intro item', which we can ignore + if (index != 0) { + let exercise = $(this).text(); + console.log(' ' + exercise); + } }); }); // console.log(testArray); From a5790225cdd9f4468852564da0f6f364e3ae5d32 Mon Sep 17 00:00:00 2001 From: Creighton Magoun Date: Wed, 17 Oct 2018 15:16:21 +0000 Subject: [PATCH 05/37] Refactor curriculum mapper into function call --- hello.js | 61 ++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 50 insertions(+), 11 deletions(-) diff --git a/hello.js b/hello.js index c9b08b1..78a864d 100644 --- a/hello.js +++ b/hello.js @@ -27,39 +27,78 @@ let getHTML = async (url) => { return html; }; - -const url = 'https://learn.freecodecamp.org'; -getHTML(url).then( (html) => { +let createMap = (html) => { const $ = require('cheerio').load(html); - let jsonArray = []; + let jsonObj = {}; // Assemble the data to convert to JSON // Crawl the major sections in .superblock $('.superblock').each(function (index, element) { // Get the major section titles let section = $(this).find('h4').text(); - jsonArray[index] = + console.log(section); + + let sectionObj = {}; // Crawl the subsections in .block $(this).find('.block') .each(function (index, element) { // Get the minor section titles let subsection = $(this).find('h5').text(); console.log(' ' + subsection); + + let exercises = []; + // Get the individual exercises for the subsection $(this).find('a') .each(function (index, element) { // First item is an 'Intro item', which we can ignore if (index != 0) { let exercise = $(this).text(); + exercises.push(exercise); console.log(' ' + exercise); } }); + + // Store the exercise array as 'subsection' => exercises + sectionObj[subsection] = exercises; }); - // console.log(testArray); + + // Store the section object as + // 'section' => {subsection1 => exercises, + // subsection2 => exercise, ...} + jsonObj[section] = sectionObj; }); - // console.log(jsonArray); - // $("li[class='map-challenge-title'] > a").each(function () { - // console.log($(this).text()); - // }); -}); + // console.log(JSON.stringify(jsonObj)); + return JSON.stringify(jsonObj); +} + +const url = 'https://learn.freecodecamp.org'; +getHTML(url).then(createMap); +// getHTML(url).then( (html) => { +// const $ = require('cheerio').load(html); +// let jsonArray = []; + +// // Assemble the data to convert to JSON +// // Crawl the major sections in .superblock +// $('.superblock').each(function (index, element) { +// // Get the major section titles +// let section = $(this).find('h4').text(); +// jsonArray[index] = +// // Crawl the subsections in .block +// $(this).find('.block') +// .each(function (index, element) { +// // Get the minor section titles +// let subsection = $(this).find('h5').text(); +// console.log(' ' + subsection); +// $(this).find('a') +// .each(function (index, element) { +// // First item is an 'Intro item', which we can ignore +// if (index != 0) { +// let exercise = $(this).text(); +// console.log(' ' + exercise); +// } +// }); +// }); +// }); +// }); From 87344abb351f1aca18c5c8c236a0139016455204 Mon Sep 17 00:00:00 2001 From: Creighton Magoun Date: Wed, 17 Oct 2018 16:06:19 +0000 Subject: [PATCH 06/37] Move curriculum mapping into lesson_map.js and refactor --- hello.js | 61 +- lesson_map.js | 119 +++- lesson_map.json | 1507 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1638 insertions(+), 49 deletions(-) create mode 100644 lesson_map.json diff --git a/hello.js b/hello.js index 78a864d..47040c5 100644 --- a/hello.js +++ b/hello.js @@ -1,7 +1,7 @@ -const puppeteer = require('puppeteer'); - // Fetch html using puppeteer let getHTML = async (url) => { + const puppeteer = require('puppeteer'); + const browser = await puppeteer.launch(); const page = await browser.newPage(); await page.goto(url); @@ -27,6 +27,7 @@ let getHTML = async (url) => { return html; }; +// Create map of curriculum as JSON object let createMap = (html) => { const $ = require('cheerio').load(html); let jsonObj = {}; @@ -36,7 +37,6 @@ let createMap = (html) => { $('.superblock').each(function (index, element) { // Get the major section titles let section = $(this).find('h4').text(); - console.log(section); let sectionObj = {}; // Crawl the subsections in .block @@ -44,7 +44,6 @@ let createMap = (html) => { .each(function (index, element) { // Get the minor section titles let subsection = $(this).find('h5').text(); - console.log(' ' + subsection); let exercises = []; // Get the individual exercises for the subsection @@ -54,7 +53,6 @@ let createMap = (html) => { if (index != 0) { let exercise = $(this).text(); exercises.push(exercise); - console.log(' ' + exercise); } }); @@ -68,37 +66,30 @@ let createMap = (html) => { jsonObj[section] = sectionObj; }); - // console.log(JSON.stringify(jsonObj)); - return JSON.stringify(jsonObj); + return jsonObj; } -const url = 'https://learn.freecodecamp.org'; -getHTML(url).then(createMap); -// getHTML(url).then( (html) => { -// const $ = require('cheerio').load(html); -// let jsonArray = []; +// Writes the JSON object to a file +let writeJSON = (json) => { + const fs = require('fs'); + const outputFile = 'lesson_map.json'; + // Format the json for readability + const jsonString = JSON.stringify(json, null, 2); + + fs.writeFile(outputFile, jsonString, (err) => { + // Report success / failure + const successMessage = 'FCC curriculum was written to ' + outputFile; + err ? console.log(err) : console.log(successMessage); + }); +}; + +// Runs the program +let run = () => { + const url = 'https://learn.freecodecamp.org'; -// // Assemble the data to convert to JSON -// // Crawl the major sections in .superblock -// $('.superblock').each(function (index, element) { -// // Get the major section titles -// let section = $(this).find('h4').text(); -// jsonArray[index] = -// // Crawl the subsections in .block -// $(this).find('.block') -// .each(function (index, element) { -// // Get the minor section titles -// let subsection = $(this).find('h5').text(); -// console.log(' ' + subsection); -// $(this).find('a') -// .each(function (index, element) { -// // First item is an 'Intro item', which we can ignore -// if (index != 0) { -// let exercise = $(this).text(); -// console.log(' ' + exercise); -// } -// }); -// }); -// }); -// }); + getHTML(url) + .then(createMap) + .then(writeJSON); +}; +run(); \ No newline at end of file diff --git a/lesson_map.js b/lesson_map.js index 9e9fc62..e3bed78 100644 --- a/lesson_map.js +++ b/lesson_map.js @@ -1,22 +1,113 @@ /** - * scrapes the lesson list from https://www.freecodecamp.org/map into - * a 3d array and copies a json string of the result, e.g. + * Scrapes the lesson list from https://learn.freecodecamp.org into + * a JSON Object, then writes that object to lesson_map.json * - * - * [ - * [ - * "section1", ["asg1", "asg2", ...], - * "section2", ["asg1", "asg2", ...], - ... - * ] - * ] + * { 'section1': { + * 'subsection1': [ + * 'exercise1', + * 'exercise2', + * ... + * ], + * 'subsection2': [...], + * ... + * }, + * 'section2': {...}, + * ... + * } */ -const certification = document.querySelector('#collapseFront-End-Development-Certification>#nested') +// Fetch html using puppeteer +let getHTML = async (url) => { + const puppeteer = require('puppeteer'); + + const browser = await puppeteer.launch(); + const page = await browser.newPage(); + await page.goto(url); + + // Need to click links to fully expand map + // Outer level uses superblock class + let superblock = await page.$("li[class='superblock ']"); + while (superblock) { + await superblock.click(); + superblock = await page.$("li[class='superblock ']"); + } + + // Inner level uses block class + let block = await page.$("li[class='block ']"); + while (block) { + await block.click(); + block = await page.$("li[class='block ']"); + } + + // Map is now fully expanded. Get content and close browser. + const html = await page.content(); + await browser.close(); + return html; +}; -const sections = Array.from(certification.querySelectorAll('h3>a')) +// Create map of curriculum as JSON object +let createMap = (html) => { + const $ = require('cheerio').load(html); + let jsonObj = {}; + + // Assemble the data to convert to JSON + // Crawl the major sections in .superblock + $('.superblock').each(function (index, element) { + // Get the major section titles + let section = $(this).find('h4').text(); + + let sectionObj = {}; + // Crawl the subsections in .block + $(this).find('.block') + .each(function (index, element) { + // Get the minor section titles + let subsection = $(this).find('h5').text(); + + let exercises = []; + // Get the individual exercises for the subsection + $(this).find('a') + .each(function (index, element) { + // First item is an 'Intro item', which we can ignore + if (index != 0) { + let exercise = $(this).text(); + exercises.push(exercise); + } + }); + + // Store the exercise array as 'subsection' => exercises + sectionObj[subsection] = exercises; + }); + + // Store the section object as + // 'section' => {subsection1 => exercises, + // subsection2 => exercise, ...} + jsonObj[section] = sectionObj; + }); + + return jsonObj; +} -const sectionData = sections.map(el => [el.innerText, Array.from(certification.querySelectorAll(`${el.href.slice(el.href.indexOf('#'))}>p>a`)).map(x => x.innerText.replace(/ (in)?complete$/gi, ''))]); +// Writes the JSON object to a file +let writeJSON = (json) => { + const fs = require('fs'); + const outputFile = 'lesson_map.json'; + // Format the json for readability + const jsonString = JSON.stringify(json, null, 2); + + fs.writeFile(outputFile, jsonString, (err) => { + // Report success / failure + const successMessage = 'FCC curriculum was written to ' + outputFile; + err ? console.log(err) : console.log(successMessage); + }); +}; -copy(JSON.stringify(sectionData)) +// Runs the program +let run = () => { + const url = 'https://learn.freecodecamp.org'; + + getHTML(url) + .then(createMap) + .then(writeJSON); +}; +run(); \ No newline at end of file diff --git a/lesson_map.json b/lesson_map.json new file mode 100644 index 0000000..14e2656 --- /dev/null +++ b/lesson_map.json @@ -0,0 +1,1507 @@ +{ + "Responsive Web Design Certification (300 hours)": { + "Basic HTML and HTML5": [ + "Say Hello to HTML Elements", + "Headline with the h2 Element", + "Inform with the Paragraph Element", + "Fill in the Blank with Placeholder Text", + "Uncomment HTML", + "Comment out HTML", + "Delete HTML Elements", + "Introduction to HTML5 Elements", + "Add Images to Your Website", + "Link to External Pages with Anchor Elements", + "Link to Internal Sections of a Page with Anchor Elements", + "Nest an Anchor Element within a Paragraph", + "Make Dead Links Using the Hash Symbol", + "Turn an Image into a Link", + "Create a Bulleted Unordered List", + "Create an Ordered List", + "Create a Text Field", + "Add Placeholder Text to a Text Field", + "Create a Form Element", + "Add a Submit Button to a Form", + "Use HTML5 to Require a Field", + "Create a Set of Radio Buttons", + "Create a Set of Checkboxes", + "Check Radio Buttons and Checkboxes by Default", + "Nest Many Elements within a Single div Element", + "Declare the Doctype of an HTML Document", + "Define the Head and Body of an HTML Document" + ], + "Basic CSS": [ + "Change the Color of Text", + "Use CSS Selectors to Style Elements", + "Use a CSS Class to Style an Element", + "Style Multiple Elements with a CSS Class", + "Change the Font Size of an Element", + "Set the Font Family of an Element", + "Import a Google Font", + "Specify How Fonts Should Degrade", + "Size Your Images", + "Add Borders Around Your Elements", + "Add Rounded Corners with border-radius", + "Make Circular Images with a border-radius", + "Give a Background Color to a div Element", + "Set the id of an Element", + "Use an id Attribute to Style an Element", + "Adjust the Padding of an Element", + "Adjust the Margin of an Element", + "Add a Negative Margin to an Element", + "Add Different Padding to Each Side of an Element", + "Add Different Margins to Each Side of an Element", + "Use Clockwise Notation to Specify the Padding of an Element", + "Use Clockwise Notation to Specify the Margin of an Element", + "Use Attribute Selectors to Style Elements", + "Understand Absolute versus Relative Units", + "Style the HTML Body Element", + "Inherit Styles from the Body Element", + "Prioritize One Style Over Another", + "Override Styles in Subsequent CSS", + "Override Class Declarations by Styling ID Attributes", + "Override Class Declarations with Inline Styles", + "Override All Other Styles by using Important", + "Use Hex Code for Specific Colors", + "Use Hex Code to Mix Colors", + "Use Abbreviated Hex Code", + "Use RGB values to Color Elements", + "Use RGB to Mix Colors", + "Use CSS Variables to change several elements at once", + "Create a custom CSS Variable", + "Use a custom CSS Variable", + "Attach a Fallback value to a CSS Variable", + "Improve Compatibility with Browser Fallbacks", + "Cascading CSS variables", + "Change a variable for a specific area", + "Use a media query to change a variable" + ], + "Applied Visual Design": [ + "Create Visual Balance Using the text-align Property", + "Adjust the Width of an Element Using the width Property", + "Adjust the Height of an Element Using the height Property", + "Use the strong Tag to Make Text Bold", + "Use the u Tag to Underline Text", + "Use the em Tag to Italicize Text", + "Use the s Tag to Strikethrough Text", + "Create a Horizontal Line Using the hr Element", + "Adjust the background-color Property of Text", + "Adjust the Size of a Header Versus a Paragraph Tag", + "Add a box-shadow to a Card-like Element", + "Decrease the Opacity of an Element", + "Use the text-transform Property to Make Text Uppercase", + "Set the font-size for Multiple Heading Elements", + "Set the font-weight for Multiple Heading Elements", + "Set the font-size of Paragraph Text", + "Set the line-height of Paragraphs", + "Adjust the Hover State of an Anchor Tag", + "Change an Element's Relative Position", + "Move a Relatively Positioned Element with CSS Offsets", + "Lock an Element to its Parent with Absolute Positioning", + "Lock an Element to the Browser Window with Fixed Positioning", + "Push Elements Left or Right with the float Property", + "Change the Position of Overlapping Elements with the z-index Property", + "Center an Element Horizontally Using the margin Property", + "Learn about Complementary Colors", + "Learn about Tertiary Colors", + "Adjust the Color of Various Elements to Complementary Colors", + "Adjust the Hue of a Color", + "Adjust the Tone of a Color", + "Create a Gradual CSS Linear Gradient", + "Use a CSS Linear Gradient to Create a Striped Element", + "Create Texture by Adding a Subtle Pattern as a Background Image", + "Use the CSS Transform scale Property to Change the Size of an Element", + "Use the CSS Transform scale Property to Scale an Element on Hover", + "Use the CSS Transform Property skewX to Skew an Element Along the X-Axis", + "Use the CSS Transform Property skewY to Skew an Element Along the Y-Axis", + "Create a Graphic Using CSS", + "Create a More Complex Shape Using CSS and HTML", + "Learn How the CSS @keyframes and animation Properties Work", + "Use CSS Animation to Change the Hover State of a Button", + "Modify Fill Mode of an Animation", + "Create Movement Using CSS Animation", + "Create Visual Direction by Fading an Element from Left to Right", + "Animate Elements Continually Using an Infinite Animation Count", + "Make a CSS Heartbeat using an Infinite Animation Count", + "Animate Elements at Variable Rates", + "Animate Multiple Elements at Variable Rates", + "Change Animation Timing with Keywords", + "Learn How Bezier Curves Work", + "Use a Bezier Curve to Move a Graphic", + "Make Motion More Natural Using a Bezier Curve" + ], + "Applied Accessibility": [ + "Add a Text Alternative to Images for Visually Impaired Accessibility", + "Know When Alt Text Should be Left Blank", + "Use Headings to Show Hierarchical Relationships of Content", + "Jump Straight to the Content Using the main Element", + "Wrap Content in the article Element", + "Make Screen Reader Navigation Easier with the header Landmark", + "Make Screen Reader Navigation Easier with the nav Landmark", + "Make Screen Reader Navigation Easier with the footer Landmark", + "Improve Accessibility of Audio Content with the audio Element", + "Improve Chart Accessibility with the figure Element", + "Improve Form Field Accessibility with the label Element", + "Wrap Radio Buttons in a fieldset Element for Better Accessibility", + "Add an Accessible Date Picker", + "Standardize Times with the HTML5 datetime Attribute", + "Make Elements Only Visible to a Screen Reader by Using Custom CSS", + "Improve Readability with High Contrast Text", + "Avoid Colorblindness Issues by Using Sufficient Contrast", + "Avoid Colorblindness Issues by Carefully Choosing Colors that Convey Information", + "Give Links Meaning by Using Descriptive Link Text", + "Make Links Navigatable with HTML Access Keys", + "Use tabindex to Add Keyboard Focus to an Element", + "Use tabindex to Specify the Order of Keyboard Focus for Several Elements" + ], + "Responsive Web Design Principles": [ + "Create a Media Query", + "Make an Image Responsive", + "Use a Retina Image for Higher Resolution Displays", + "Make Typography Responsive" + ], + "CSS Flexbox": [ + "Use display: flex to Position Two Boxes", + "Add Flex Superpowers to the Tweet Embed", + "Use the flex-direction Property to Make a Row", + "Apply the flex-direction Property to Create Rows in the Tweet Embed", + "Use the flex-direction Property to Make a Column", + "Apply the flex-direction Property to Create a Column in the Tweet Embed", + "Align Elements Using the justify-content Property", + "Use the justify-content Property in the Tweet Embed", + "Align Elements Using the align-items Property", + "Use the align-items Property in the Tweet Embed", + "Use the flex-wrap Property to Wrap a Row or Column", + "Use the flex-shrink Property to Shrink Items", + "Use the flex-grow Property to Expand Items", + "Use the flex-basis Property to Set the Initial Size of an Item", + "Use the flex Shorthand Property", + "Use the order Property to Rearrange Items", + "Use the align-self Property" + ], + "CSS Grid": [ + "Create Your First CSS Grid", + "Add Columns with grid-template-columns", + "Add Rows with grid-template-rows", + "Use CSS Grid units to Change the Size of Columns and Rows", + "Create a Column Gap Using grid-column-gap", + "Create a Row Gap using grid-row-gap", + "Add Gaps Faster with grid-gap", + "Use grid-column to Control Spacing", + "Use grid-row to Control Spacing", + "Align an Item Horizontally using justify-self", + "Align an Item Vertically using align-self", + "Align All Items Horizontally using justify-items", + "Align All Items Vertically using align-items", + "Divide the Grid Into an Area Template", + "Place Items in Grid Areas Using the grid-area Property", + "Use grid-area Without Creating an Areas Template", + "Reduce Repetition Using the repeat Function", + "Limit Item Size Using the minmax Function", + "Create Flexible Layouts Using auto-fill", + "Create Flexible Layouts Using auto-fit", + "Use Media Queries to Create Responsive Layouts", + "Create Grids within Grids" + ], + "Responsive Web Design Projects": [ + "Build a Tribute Page", + "Build a Survey Form", + "Build a Product Landing Page", + "Build a Technical Documentation Page", + "Build a Personal Portfolio Webpage" + ] + }, + "Javascript Algorithms And Data Structures Certification (300 hours)": { + "Basic JavaScript": [ + "Comment Your JavaScript Code", + "Declare JavaScript Variables", + "Storing Values with the Assignment Operator", + "Initializing Variables with the Assignment Operator", + "Understanding Uninitialized Variables", + "Understanding Case Sensitivity in Variables", + "Add Two Numbers with JavaScript", + "Subtract One Number from Another with JavaScript", + "Multiply Two Numbers with JavaScript", + "Divide One Number by Another with JavaScript", + "Increment a Number with JavaScript", + "Decrement a Number with JavaScript", + "Create Decimal Numbers with JavaScript", + "Multiply Two Decimals with JavaScript", + "Divide One Decimal by Another with JavaScript", + "Finding a Remainder in JavaScript", + "Compound Assignment With Augmented Addition", + "Compound Assignment With Augmented Subtraction", + "Compound Assignment With Augmented Multiplication", + "Compound Assignment With Augmented Division", + "Declare String Variables", + "Escaping Literal Quotes in Strings", + "Quoting Strings with Single Quotes", + "Escape Sequences in Strings", + "Concatenating Strings with Plus Operator", + "Concatenating Strings with the Plus Equals Operator", + "Constructing Strings with Variables", + "Appending Variables to Strings", + "Find the Length of a String", + "Use Bracket Notation to Find the First Character in a String", + "Understand String Immutability", + "Use Bracket Notation to Find the Nth Character in a String", + "Use Bracket Notation to Find the Last Character in a String", + "Use Bracket Notation to Find the Nth-to-Last Character in a String", + "Word Blanks", + "Store Multiple Values in one Variable using JavaScript Arrays", + "Nest one Array within Another Array", + "Access Array Data with Indexes", + "Modify Array Data With Indexes", + "Access Multi-Dimensional Arrays With Indexes", + "Manipulate Arrays With push()", + "Manipulate Arrays With pop()", + "Manipulate Arrays With shift()", + "Manipulate Arrays With unshift()", + "Shopping List", + "Write Reusable JavaScript with Functions", + "Passing Values to Functions with Arguments", + "Global Scope and Functions", + "Local Scope and Functions", + "Global vs. Local Scope in Functions", + "Return a Value from a Function with Return", + "Understanding Undefined Value returned from a Function", + "Assignment with a Returned Value", + "Stand in Line", + "Understanding Boolean Values", + "Use Conditional Logic with If Statements", + "Comparison with the Equality Operator", + "Comparison with the Strict Equality Operator", + "Practice comparing different values", + "Comparison with the Inequality Operator", + "Comparison with the Strict Inequality Operator", + "Comparison with the Greater Than Operator", + "Comparison with the Greater Than Or Equal To Operator", + "Comparison with the Less Than Operator", + "Comparison with the Less Than Or Equal To Operator", + "Comparisons with the Logical And Operator", + "Comparisons with the Logical Or Operator", + "Introducing Else Statements", + "Introducing Else If Statements", + "Logical Order in If Else Statements", + "Chaining If Else Statements", + "Golf Code", + "Selecting from Many Options with Switch Statements", + "Adding a Default Option in Switch Statements", + "Multiple Identical Options in Switch Statements", + "Replacing If Else Chains with Switch", + "Returning Boolean Values from Functions", + "Return Early Pattern for Functions", + "Counting Cards", + "Build JavaScript Objects", + "Accessing Object Properties with Dot Notation", + "Accessing Object Properties with Bracket Notation", + "Accessing Object Properties with Variables", + "Updating Object Properties", + "Add New Properties to a JavaScript Object", + "Delete Properties from a JavaScript Object", + "Using Objects for Lookups", + "Testing Objects for Properties", + "Manipulating Complex Objects", + "Accessing Nested Objects", + "Accessing Nested Arrays", + "Record Collection", + "Iterate with JavaScript While Loops", + "Iterate with JavaScript For Loops", + "Iterate Odd Numbers With a For Loop", + "Count Backwards With a For Loop", + "Iterate Through an Array with a For Loop", + "Nesting For Loops", + "Iterate with JavaScript Do...While Loops", + "Profile Lookup", + "Generate Random Fractions with JavaScript", + "Generate Random Whole Numbers with JavaScript", + "Generate Random Whole Numbers within a Range", + "Use the parseInt Function", + "Use the parseInt Function with a Radix", + "Use the Conditional (Ternary) Operator", + "Use Multiple Conditional (Ternary) Operators" + ], + "ES6": [ + "Explore Differences Between the var and let Keywords", + "Compare Scopes of the var and let Keywords", + "Declare a Read-Only Variable with the const Keyword", + "Mutate an Array Declared with const", + "Prevent Object Mutation", + "Use Arrow Functions to Write Concise Anonymous Functions", + "Write Arrow Functions with Parameters", + "Write Higher Order Arrow Functions", + "Set Default Parameters for Your Functions", + "Use the Rest Operator with Function Parameters", + "Use the Spread Operator to Evaluate Arrays In-Place", + "Use Destructuring Assignment to Assign Variables from Objects", + "Use Destructuring Assignment to Assign Variables from Nested Objects", + "Use Destructuring Assignment to Assign Variables from Arrays", + "Use Destructuring Assignment with the Rest Operator to Reassign Array Elements", + "Use Destructuring Assignment to Pass an Object as a Function's Parameters", + "Create Strings using Template Literals", + "Write Concise Object Literal Declarations Using Simple Fields", + "Write Concise Declarative Functions with ES6", + "Use class Syntax to Define a Constructor Function", + "Use getters and setters to Control Access to an Object", + "Understand the Differences Between import and require", + "Use export to Reuse a Code Block", + "Use * to Import Everything from a File", + "Create an Export Fallback with export default", + "Import a Default Export" + ], + "Regular Expressions": [ + "Using the Test Method", + "Match Literal Strings", + "Match a Literal String with Different Possibilities", + "Ignore Case While Matching", + "Extract Matches", + "Find More Than the First Match", + "Match Anything with Wildcard Period", + "Match Single Character with Multiple Possibilities", + "Match Letters of the Alphabet", + "Match Numbers and Letters of the Alphabet", + "Match Single Characters Not Specified", + "Match Characters that Occur One or More Times", + "Match Characters that Occur Zero or More Times", + "Find Characters with Lazy Matching", + "Find One or More Criminals in a Hunt", + "Match Beginning String Patterns", + "Match Ending String Patterns", + "Match All Letters and Numbers", + "Match Everything But Letters and Numbers", + "Match All Numbers", + "Match All Non-Numbers", + "Restrict Possible Usernames", + "Match Whitespace", + "Match Non-Whitespace Characters", + "Specify Upper and Lower Number of Matches", + "Specify Only the Lower Number of Matches", + "Specify Exact Number of Matches", + "Check for All or None", + "Positive and Negative Lookahead", + "Reuse Patterns Using Capture Groups", + "Use Capture Groups to Search and Replace", + "Remove Whitespace from Start and End" + ], + "Debugging": [ + "Use the JavaScript Console to Check the Value of a Variable", + "Understanding the Differences between the freeCodeCamp and Browser Console", + "Use typeof to Check the Type of a Variable", + "Catch Misspelled Variable and Function Names", + "Catch Unclosed Parentheses, Brackets, Braces and Quotes", + "Catch Mixed Usage of Single and Double Quotes", + "Catch Use of Assignment Operator Instead of Equality Operator", + "Catch Missing Open and Closing Parenthesis After a Function Call", + "Catch Arguments Passed in the Wrong Order When Calling a Function", + "Catch Off By One Errors When Using Indexing", + "Use Caution When Reinitializing Variables Inside a Loop", + "Prevent Infinite Loops with a Valid Terminal Condition" + ], + "Basic Data Structures": [ + "Use an Array to Store a Collection of Data", + "Access an Array's Contents Using Bracket Notation", + "Add Items to an Array with push() and unshift()", + "Remove Items from an Array with pop() and shift()", + "Remove Items Using splice()", + "Add Items Using splice()", + "Copy Array Items Using slice()", + "Copy an Array with the Spread Operator", + "Combine Arrays with the Spread Operator", + "Check For The Presence of an Element With indexOf()", + "Iterate Through All an Array's Items Using For Loops", + "Create complex multi-dimensional arrays", + "Add Key-Value Pairs to JavaScript Objects", + "Modify an Object Nested Within an Object", + "Access Property Names with Bracket Notation", + "Use the delete Keyword to Remove Object Properties", + "Check if an Object has a Property", + " Iterate Through the Keys of an Object with a for...in Statement", + "Generate an Array of All Object Keys with Object.keys()", + "Modify an Array Stored in an Object" + ], + "Basic Algorithm Scripting": [ + "Convert Celsius to Fahrenheit", + "Reverse a String", + "Factorialize a Number", + "Find the Longest Word in a String", + "Return Largest Numbers in Arrays", + "Confirm the Ending", + "Repeat a String Repeat a String", + "Truncate a String", + "Finders Keepers", + "Boo who", + "Title Case a Sentence", + "Slice and Splice", + "Falsy Bouncer", + "Where do I Belong", + "Mutations", + "Chunky Monkey" + ], + "Object Oriented Programming": [ + "Create a Basic JavaScript Object", + "Use Dot Notation to Access the Properties of an Object", + "Create a Method on an Object", + "Make Code More Reusable with the this Keyword", + "Define a Constructor Function", + "Use a Constructor to Create Objects", + "Extend Constructors to Receive Arguments", + "Verify an Object's Constructor with instanceof", + "Understand Own Properties", + "Use Prototype Properties to Reduce Duplicate Code", + "Iterate Over All Properties", + "Understand the Constructor Property", + "Change the Prototype to a New Object", + "Remember to Set the Constructor Property when Changing the Prototype", + "Understand Where an Object’s Prototype Comes From", + "Understand the Prototype Chain", + "Use Inheritance So You Don't Repeat Yourself", + "Inherit Behaviors from a Supertype", + "Set the Child's Prototype to an Instance of the Parent", + "Reset an Inherited Constructor Property", + "Add Methods After Inheritance", + "Override Inherited Methods", + "Use a Mixin to Add Common Behavior Between Unrelated Objects", + "Use Closure to Protect Properties Within an Object from Being Modified Externally", + "Understand the Immediately Invoked Function Expression (IIFE)", + "Use an IIFE to Create a Module" + ], + "Functional Programming": [ + "Learn About Functional Programming", + "Understand Functional Programming Terminology", + "Understand the Hazards of Using Imperative Code", + "Avoid Mutations and Side Effects Using Functional Programming", + "Pass Arguments to Avoid External Dependence in a Function", + "Refactor Global Variables Out of Functions", + "Use the map Method to Extract Data from an Array", + "Implement map on a Prototype", + "Use the filter Method to Extract Data from an Array", + "Implement the filter Method on a Prototype", + "Return Part of an Array Using the slice Method", + "Remove Elements from an Array Using slice Instead of splice", + "Combine Two Arrays Using the concat Method", + "Add Elements to the End of an Array Using concat Instead of push", + "Use the reduce Method to Analyze Data", + "Sort an Array Alphabetically using the sort Method", + "Return a Sorted Array Without Changing the Original Array", + "Split a String into an Array Using the split Method", + "Combine an Array into a String Using the join Method", + "Apply Functional Programming to Convert Strings to URL Slugs", + "Use the every Method to Check that Every Element in an Array Meets a Criteria", + "Use the some Method to Check that Any Elements in an Array Meet a Criteria", + "Introduction to Currying and Partial Application" + ], + "Intermediate Algorithm Scripting": [ + "Sum All Numbers in a Range", + "Diff Two Arrays", + "Seek and Destroy", + "Wherefore art thou", + "Spinal Tap Case", + "Pig Latin", + "Search and Replace", + "DNA Pairing", + "Missing letters", + "Sorted Union", + "Convert HTML Entities", + "Sum All Odd Fibonacci Numbers", + "Sum All Primes", + "Smallest Common Multiple", + "Drop it", + "Steamroller", + "Binary Agents", + "Everything Be True", + "Arguments Optional", + "Make a Person", + "Map the Debris" + ], + "JavaScript Algorithms and Data Structures Projects": [ + "Palindrome Checker", + "Roman Numeral Converter", + "Caesars Cipher", + "Telephone Number Validator", + "Cash Register" + ] + }, + "Front End Libraries Certification (300 hours)": { + "Bootstrap": [ + "Use Responsive Design with Bootstrap Fluid Containers", + "Make Images Mobile Responsive", + "Center Text with Bootstrap", + "Create a Bootstrap Button", + "Create a Block Element Bootstrap Button", + "Taste the Bootstrap Button Color Rainbow", + "Call out Optional Actions with btn-info", + "Warn Your Users of a Dangerous Action with btn-danger", + "Use the Bootstrap Grid to Put Elements Side By Side", + "Ditch Custom CSS for Bootstrap", + "Use a span to Target Inline Elements", + "Create a Custom Heading", + "Add Font Awesome Icons to our Buttons", + "Add Font Awesome Icons to all of our Buttons", + "Responsively Style Radio Buttons", + "Responsively Style Checkboxes", + "Style Text Inputs as Form Controls", + "Line up Form Elements Responsively with Bootstrap", + "Create a Bootstrap Headline", + "House our page within a Bootstrap container-fluid div", + "Create a Bootstrap Row", + "Split Your Bootstrap Row", + "Create Bootstrap Wells", + "Add Elements within Your Bootstrap Wells", + "Apply the Default Bootstrap Button Style", + "Create a Class to Target with jQuery Selectors", + "Add id Attributes to Bootstrap Elements", + "Label Bootstrap Wells", + "Give Each Element a Unique id", + "Label Bootstrap Buttons", + "Use Comments to Clarify Code" + ], + "jQuery": [ + "Learn How Script Tags and Document Ready Work", + "Target HTML Elements with Selectors Using jQuery", + "Target Elements by Class Using jQuery", + "Target Elements by id Using jQuery", + "Delete Your jQuery Functions", + "Target the Same Element with Multiple jQuery Selectors", + "Remove Classes from an Element with jQuery", + "Change the CSS of an Element Using jQuery", + "Disable an Element Using jQuery", + "Change Text Inside an Element Using jQuery", + "Remove an Element Using jQuery", + "Use appendTo to Move Elements with jQuery", + "Clone an Element Using jQuery", + "Target the Parent of an Element Using jQuery", + "Target the Children of an Element Using jQuery", + "Target a Specific Child of an Element Using jQuery", + "Target Even Elements Using jQuery", + "Use jQuery to Modify the Entire Page" + ], + "Sass": [ + "Store Data with Sass Variables", + "Nest CSS with Sass", + "Create Reusable CSS with Mixins", + "Use @if and @else to Add Logic To Your Styles", + "Use @for to Create a Sass Loop", + "Use @each to Map Over Items in a List", + "Apply a Style Until a Condition is Met with @while", + "Split Your Styles into Smaller Chunks with Partials", + "Extend One Set of CSS Styles to Another Element" + ], + "React": [ + "Create a Simple JSX Element", + "Create a Complex JSX Element", + "Add Comments in JSX", + "Render HTML Elements to the DOM", + "Define an HTML Class in JSX", + "Learn About Self-Closing JSX Tags", + "Create a Stateless Functional Component", + "Create a React Component", + "Create a Component with Composition", + "Use React to Render Nested Components", + "Compose React Components", + "Render a Class Component to the DOM", + "Write a React Component from Scratch", + "Pass Props to a Stateless Functional Component", + "Pass an Array as Props", + "Use Default Props", + "Override Default Props", + "Use PropTypes to Define the Props You Expect", + "Access Props Using this.props", + "Review Using Props with Stateless Functional Components", + "Create a Stateful Component", + "Render State in the User Interface", + "Render State in the User Interface Another Way", + "Set State with this.setState", + "Bind 'this' to a Class Method", + "Use State to Toggle an Element", + "Write a Simple Counter", + "Create a Controlled Input", + "Create a Controlled Form", + "Pass State as Props to Child Components", + "Pass a Callback as Props", + "Use the Lifecycle Method componentWillMount", + "Use the Lifecycle Method componentDidMount", + "Add Event Listeners", + "Manage Updates with Lifecycle Methods", + "Optimize Re-Renders with shouldComponentUpdate", + "Introducing Inline Styles", + "Add Inline Styles in React", + "Use Advanced JavaScript in React Render Method", + "Render with an If/Else Condition", + "Use && for a More Concise Conditional", + "Use a Ternary Expression for Conditional Rendering", + "Render Conditionally from Props", + "Change Inline CSS Conditionally Based on Component State", + "Use Array.map() to Dynamically Render Elements", + "Give Sibling Elements a Unique Key Attribute", + "Use Array.filter() to Dynamically Filter an Array", + "Render React on the Server with renderToString" + ], + "Redux": [ + "Create a Redux Store", + "Get State from the Redux Store", + "Define a Redux Action", + "Define an Action Creator", + "Dispatch an Action Event", + "Handle an Action in the Store", + "Use a Switch Statement to Handle Multiple Actions", + "Use const for Action Types", + "Register a Store Listener", + "Combine Multiple Reducers", + "Send Action Data to the Store", + "Use Middleware to Handle Asynchronous Actions", + "Write a Counter with Redux", + "Never Mutate State", + "Use the Spread Operator on Arrays", + "Remove an Item from an Array", + "Copy an Object with Object.assign" + ], + "React and Redux": [ + "Getting Started with React Redux", + "Manage State Locally First", + "Extract State Logic to Redux", + "Use Provider to Connect Redux to React", + "Map State to Props", + "Map Dispatch to Props", + "Connect Redux to React", + "Connect Redux to the Messages App", + "Extract Local State into Redux", + "Moving Forward From Here" + ], + "Front End Libraries Projects": [ + "Build a Random Quote Machine", + "Build a Markdown Previewer", + "Build a Drum Machine", + "Build a JavaScript Calculator", + "Build a Pomodoro Clock" + ] + }, + "Data Visualization Certification (300 hours)": { + "Data Visualization with D3": [ + "Add Document Elements with D3", + "Select a Group of Elements with D3", + "Work with Data in D3", + "Work with Dynamic Data in D3", + "Add Inline Styling to Elements", + "Change Styles Based on Data", + "Add Classes with D3", + "Update the Height of an Element Dynamically", + "Change the Presentation of a Bar Chart", + "Learn About SVG in D3", + "Display Shapes with SVG", + "Create a Bar for Each Data Point in the Set", + "Dynamically Set the Coordinates for Each Bar", + "Dynamically Change the Height of Each Bar", + "Invert SVG Elements", + "Change the Color of an SVG Element", + "Add Labels to D3 Elements", + "Style D3 Labels", + "Add a Hover Effect to a D3 Element", + "Add a Tooltip to a D3 Element", + "Create a Scatterplot with SVG Circles", + "Add Attributes to the Circle Elements", + "Add Labels to Scatter Plot Circles", + "Create a Linear Scale with D3", + "Set a Domain and a Range on a Scale", + "Use the d3.max and d3.min Functions to Find Minimum and Maximum Values in a Dataset", + "Use Dynamic Scales", + "Use a Pre-Defined Scale to Place Elements", + "Add Axes to a Visualization" + ], + "JSON APIs and Ajax": [ + "Handle Click Events with JavaScript using the onclick property", + "Change Text with click Events", + "Get JSON with the JavaScript XMLHttpRequest Method", + "Access the JSON Data from an API", + "Convert JSON Data to HTML", + "Render Images from Data Sources", + "Pre-filter JSON to Get the Data You Need", + "Get Geolocation Data to Find A User's GPS Coordinates", + "Post Data with the JavaScript XMLHttpRequest Method" + ], + "Data Visualization Projects": [ + "Visualize Data with a Bar Chart", + "Visualize Data with a Scatterplot Graph", + "Visualize Data with a Heat Map", + "Visualize Data with a Choropleth Map", + "Visualize Data with a Treemap Diagram" + ] + }, + "Apis And Microservices Certification (300 hours)": { + "Managing Packages with Npm": [ + "How to Use package.json, the Core of Any Node.js Project or npm Package", + "Add a Description to Your package.json", + "Add Keywords to Your package.json", + "Add a License to Your package.json", + "Add a Version to Your package.json", + "Expand Your Project with External Packages from npm", + "Manage npm Dependencies By Understanding Semantic Versioning", + "Use the Tilde-Character to Always Use the Latest Patch Version of a Dependency", + "Use the Caret-Character to Use the Latest Minor Version of a Dependency", + "Remove a Package from Your Dependencies" + ], + "Basic Node and Express": [ + "Meet the Node console", + "Start a Working Express Server", + "Serve an HTML File", + "Serve Static Assets", + "Serve JSON on a Specific Route", + "Use the .env File", + "Implement a Root-Level Request Logger Middleware", + "Chain Middleware to Create a Time Server", + "Get Route Parameter Input from the Client", + "Get Query Parameter Input from the Client", + "Use body-parser to Parse POST Requests", + "Get Data from POST Requests" + ], + "MongoDB and Mongoose": [ + "Install and Set Up Mongoose", + "Create a Model", + "Create and Save a Record of a Model", + "Create Many Records with model.create()", + "Use model.find() to Search Your Database", + "Use model.findOne() to Return a Single Matching Document from Your Database", + "Use model.findById() to Search Your Database By _id", + "Perform Classic Updates by Running Find, Edit, then Save", + "Perform New Updates on a Document Using model.findOneAndUpdate()", + "Delete One Document Using model.findByIdAndRemove", + "Delete Many Documents with model.remove()", + "Chain Search Query Helpers to Narrow Search Results" + ], + "Apis and Microservices Projects": [ + "Timestamp Microservice", + "Request Header Parser Microservice", + "URL Shortener Microservice", + "Exercise Tracker", + "File Metadata Microservice" + ] + }, + "Information Security And Quality Assurance Certification (300 hours)": { + "Information Security with HelmetJS": [ + "Install and Require Helmet", + "Hide Potentially Dangerous Information Using helmet.hidePoweredBy()", + "Mitigate the Risk of Clickjacking with helmet.frameguard()", + "Mitigate the Risk of Cross Site Scripting (XSS) Attacks with helmet.xssFilter()", + "Avoid Inferring the Response MIME Type with helmet.noSniff()", + "Prevent IE from Opening Untrusted HTML with helmet.ieNoOpen()", + "Ask Browsers to Access Your Site via HTTPS Only with helmet.hsts()", + "Disable DNS Prefetching with helmet.dnsPrefetchControl()", + "Disable Client-Side Caching with helmet.noCache()", + "Set a Content Security Policy with helmet.contentSecurityPolicy()", + "Configure Helmet Using the ‘parent’ helmet() Middleware", + "Understand BCrypt Hashes", + "Hash and Compare Passwords Asynchronously", + "Hash and Compare Passwords Synchronously" + ], + "Quality Assurance and Testing with Chai": [ + "Learn How JavaScript Assertions Work", + "Test if a Variable or Function is Defined", + "Use Assert.isOK and Assert.isNotOK", + "Test for Truthiness", + "Use the Double Equals to Assert Equality", + "Use the Triple Equals to Assert Strict Equality", + "Assert Deep Equality with .deepEqual and .notDeepEqual", + "Compare the Properties of Two Elements", + "Test if One Value is Below or At Least as Large as Another", + "Test if a Value Falls within a Specific Range", + "Test if a Value is an Array", + "Test if an Array Contains an Item", + "Test if a Value is a String", + "Test if a String Contains a Substring", + "Use Regular Expressions to Test a String", + "Test if an Object has a Property", + "Test if a Value is of a Specific Data Structure Type", + "Test if an Object is an Instance of a Constructor", + "Run Functional Tests on API Endpoints using Chai-HTTP", + "Run Functional Tests on API Endpoints using Chai-HTTP II", + "Run Functional Tests on an API Response using Chai-HTTP III - PUT method", + "Run Functional Tests on an API Response using Chai-HTTP IV - PUT method", + "Run Functional Tests using a Headless Browser", + "Run Functional Tests using a Headless Browser II" + ], + "Advanced Node and Express": [ + "Set up a Template Engine", + "Use a Template Engine's Powers", + "Set up Passport", + "Serialization of a User Object", + "Implement the Serialization of a Passport User", + "Authentication Strategies", + "How to Use Passport Strategies", + "Create New Middleware", + "How to Put a Profile Together", + "Logging a User Out", + "Registration of New Users", + "Hashing Your Passwords", + "Clean Up Your Project with Modules", + "Implementation of Social Authentication", + "Implementation of Social Authentication II", + "Implementation of Social Authentication III", + "Set up the Environment", + "Communicate by Emitting", + "Handle a Disconnect", + "Authentication with Socket.IO", + "Announce New Users", + "Send and Display Chat Messages" + ], + "Information Security and Quality Assurance Projects": [ + "Metric-Imperial Converter", + "Issue Tracker", + "Personal Library", + "Stock Price Checker", + "Anonymous Message Board" + ] + }, + "Coding Interview Prep (Thousands of hours of challenges)": { + "Algorithms": [ + "Find the Symmetric Difference", + "Inventory Update", + "No Repeats Please", + "Pairwise", + "Implement Bubble Sort", + "Implement Selection Sort", + "Implement Insertion Sort", + "Implement Quick Sort", + "Implement Merge Sort" + ], + "Data Structures": [ + "Typed Arrays", + "Learn how a Stack Works", + "Create a Stack Class", + "Create a Queue Class", + "Create a Priority Queue Class", + "Create a Circular Queue", + "Create a Set Class", + "Remove from a Set", + "Size of the Set", + "Perform a Union on Two Sets", + "Perform an Intersection on Two Sets of Data", + "Perform a Difference on Two Sets of Data", + "Perform a Subset Check on Two Sets of Data", + "Create and Add to Sets in ES6", + "Remove items from a set in ES6", + "Use .has and .size on an ES6 Set", + "Use Spread and Notes for ES5 Set() Integration", + "Create a Map Data Structure", + "Create an ES6 JavaScript Map", + "Create a Hash Table", + "Work with Nodes in a Linked List", + "Create a Linked List Class", + "Remove Elements from a Linked List", + "Search within a Linked List", + "Remove Elements from a Linked List by Index", + "Add Elements at a Specific Index in a Linked List", + "Create a Doubly Linked List", + "Reverse a Doubly Linked List", + "Find the Minimum and Maximum Value in a Binary Search Tree", + "Add a New Element to a Binary Search Tree", + "Check if an Element is Present in a Binary Search Tree", + "Find the Minimum and Maximum Height of a Binary Search Tree", + "Use Depth First Search in a Binary Search Tree", + "Use Breadth First Search in a Binary Search Tree", + "Delete a Leaf Node in a Binary Search Tree", + "Delete a Node with One Child in a Binary Search Tree", + "Delete a Node with Two Children in a Binary Search Tree", + "Invert a Binary Tree", + "Create a Trie Search Tree", + "Insert an Element into a Max Heap", + "Remove an Element from a Max Heap", + "Implement Heap Sort with a Min Heap", + "Adjacency List", + "Adjacency Matrix", + "Incidence Matrix", + "Breadth-First Search", + "Depth-First Search" + ], + "Take Home Projects": [ + "Show the Local Weather", + "Build a Wikipedia Viewer", + "Use the Twitch JSON API", + "Build an Image Search Abstraction Layer", + "Build a Tic Tac Toe Game", + "Build a Simon Game", + "Build a Camper Leaderboard", + "Build a Recipe Box", + "Build the Game of Life", + "Build a Roguelike Dungeon Crawler Game", + "P2P Video Chat Application", + "Show National Contiguity with a Force Directed Graph", + "Map Data Across the Globe", + "Manage a Book Trading Club", + "Build a Pinterest Clone", + "Build a Nightlife Coordination App", + "Chart the Stock Market", + "Build a Voting App", + "Build a Pong Game", + "Build a Light-Bright App" + ], + "Rosetta Code": [ + "100 doors", + "24 game", + "9 billion names of God the integer", + "ABC Problem", + "Abundant, deficient and perfect number classifications", + "Accumulator factory", + "Ackermann function", + "Align columns", + "Amicable pairs", + "Averages/Mode", + "Averages/Pythagorean means", + "Averages/Root mean square", + "Babbage problem", + "Balanced brackets", + "Circles of given radius through two points", + "Closest-pair problem", + "Combinations", + "Comma quibbling", + "Compare a list of strings", + "Convert seconds to compound duration", + "Count occurrences of a substring", + "Count the coins", + "Cramer's rule", + "Date format", + "Date manipulation", + "Day of the week", + "Deal cards for FreeCell", + "Deepcopy", + "Define a primitive data type", + "Department Numbers", + "Discordian date", + "Element-wise operations", + "Emirp primes", + "Entropy", + "Equilibrium index", + "Ethiopian multiplication", + "Euler method", + "Evaluate binomial coefficients", + "Execute a Markov algorithm", + "Execute Brain****", + "Extensible prime generator", + "Factorial", + "Factors of a Mersenne number", + "Factors of an integer", + "Farey sequence", + "Fibonacci n-step number sequences", + "Fibonacci sequence", + "Fibonacci word", + "Fractran", + "Gamma function", + "Gaussian elimination", + "General FizzBuzz", + "Generate lower case ASCII alphabet", + "Generator/Exponential", + "Gray code", + "Greatest common divisor", + "Greatest subsequential sum", + "Hailstone sequence", + "Happy numbers", + "Harshad or Niven series", + "Hash from two arrays", + "Hash join", + "Heronian triangles", + "Hofstadter Figure-Figure sequences", + "Hofstadter Q sequence", + "I before E except after C", + "IBAN", + "Identity matrix", + "Iterated digits squaring", + "Jaro distance", + "JortSort", + "Josephus problem", + "Sailors, coconuts and a monkey problem", + "SEDOLs", + "S-Expressions", + "Taxicab numbers", + "Tokenize a string with escaping", + "Topological sort", + "Top rank per group", + "Towers of Hanoi", + "Vector cross product", + "Vector dot product", + "Word wrap", + "Y combinator", + "Zeckendorf number representation", + "Zhang-Suen thinning algorithm", + "Zig-zag matrix" + ], + "Project Euler": [ + "Problem 1: Multiples of 3 and 5", + "Problem 2: Even Fibonacci Numbers", + "Problem 3: Largest prime factor", + "Problem 4: Largest palindrome product", + "Problem 5: Smallest multiple", + "Problem 6: Sum square difference", + "Problem 7: 10001st prime", + "Problem 8: Largest product in a series", + "Problem 9: Special Pythagorean triplet", + "Problem 10: Summation of primes", + "Problem 11: Largest product in a grid", + "Problem 12: Highly divisible triangular number", + "Problem 13: Large sum", + "Problem 14: Longest Collatz sequence", + "Problem 15: Lattice paths", + "Problem 16: Power digit sum", + "Problem 17: Number letter counts", + "Problem 18: Maximum path sum I", + "Problem 19: Counting Sundays", + "Problem 20: Factorial digit sum", + "Problem 21: Amicable numbers", + "Problem 22: Names scores", + "Problem 23: Non-abundant sums", + "Problem 24: Lexicographic permutations", + "Problem 25: 1000-digit Fibonacci number", + "Problem 26: Reciprocal cycles", + "Problem 27: Quadratic primes", + "Problem 28: Number spiral diagonals", + "Problem 29: Distinct powers", + "Problem 30: Digit n powers", + "Problem 31: Coin sums", + "Problem 32: Pandigital products", + "Problem 33: Digit cancelling fractions", + "Problem 34: Digit factorials", + "Problem 35: Circular primes", + "Problem 36: Double-base palindromes", + "Problem 37: Truncatable primes", + "Problem 38: Pandigital multiples", + "Problem 39: Integer right triangles", + "Problem 40: Champernowne's constant", + "Problem 41: Pandigital prime", + "Problem 42: Coded triangle numbers", + "Problem 43: Sub-string divisibility", + "Problem 44: Pentagon numbers", + "Problem 45: Triangular, pentagonal, and hexagonal", + "Problem 46: Goldbach's other conjecture", + "Problem 47: Distinct primes factors", + "Problem 48: Self powers", + "Problem 49: Prime permutations", + "Problem 50: Consecutive prime sum", + "Problem 51: Prime digit replacements", + "Problem 52: Permuted multiples", + "Problem 53: Combinatoric selections", + "Problem 54: Poker hands", + "Problem 55: Lychrel numbers", + "Problem 56: Powerful digit sum", + "Problem 57: Square root convergents", + "Problem 58: Spiral primes", + "Problem 59: XOR decryption", + "Problem 60: Prime pair sets", + "Problem 61: Cyclical figurate numbers", + "Problem 62: Cubic permutations", + "Problem 63: Powerful digit counts", + "Problem 64: Odd period square roots", + "Problem 65: Convergents of e", + "Problem 66: Diophantine equation", + "Problem 67: Maximum path sum II", + "Problem 68: Magic 5-gon ring", + "Problem 69: Totient maximum", + "Problem 70: Totient permutation", + "Problem 71: Ordered fractions", + "Problem 72: Counting fractions", + "Problem 73: Counting fractions in a range", + "Problem 74: Digit factorial chains", + "Problem 75: Singular integer right triangles", + "Problem 76: Counting summations", + "Problem 77: Prime summations", + "Problem 78: Coin partitions", + "Problem 79: Passcode derivation", + "Problem 80: Square root digital expansion", + "Problem 81: Path sum: two ways", + "Problem 82: Path sum: three ways", + "Problem 83: Path sum: four ways", + "Problem 84: Monopoly odds", + "Problem 85: Counting rectangles", + "Problem 86: Cuboid route", + "Problem 87: Prime power triples", + "Problem 88: Product-sum numbers", + "Problem 89: Roman numerals", + "Problem 90: Cube digit pairs", + "Problem 91: Right triangles with integer coordinates", + "Problem 92: Square digit chains", + "Problem 93: Arithmetic expressions", + "Problem 94: Almost equilateral triangles", + "Problem 95: Amicable chains", + "Problem 96: Su Doku", + "Problem 97: Large non-Mersenne prime", + "Problem 98: Anagramic squares", + "Problem 99: Largest exponential", + "Problem 100: Arranged probability", + "Problem 101: Optimum polynomial", + "Problem 102: Triangle containment", + "Problem 103: Special subset sums: optimum", + "Problem 104: Pandigital Fibonacci ends", + "Problem 105: Special subset sums: testing", + "Problem 106: Special subset sums: meta-testing", + "Problem 107: Minimal network", + "Problem 108: Diophantine Reciprocals I", + "Problem 109: Darts", + "Problem 110: Diophantine Reciprocals II", + "Problem 111: Primes with runs", + "Problem 112: Bouncy numbers", + "Problem 113: Non-bouncy numbers", + "Problem 114: Counting block combinations I", + "Problem 115: Counting block combinations II", + "Problem 116: Red, green or blue tiles", + "Problem 117: Red, green, and blue tiles", + "Problem 118: Pandigital prime sets", + "Problem 119: Digit power sum", + "Problem 120: Square remainders", + "Problem 121: Disc game prize fund", + "Problem 122: Efficient exponentiation", + "Problem 123: Prime square remainders", + "Problem 124: Ordered radicals", + "Problem 125: Palindromic sums", + "Problem 126: Cuboid layers", + "Problem 127: abc-hits", + "Problem 128: Hexagonal tile differences", + "Problem 129: Repunit divisibility", + "Problem 130: Composites with prime repunit property", + "Problem 131: Prime cube partnership", + "Problem 132: Large repunit factors", + "Problem 133: Repunit nonfactors", + "Problem 134: Prime pair connection", + "Problem 135: Same differences", + "Problem 136: Singleton difference", + "Problem 137: Fibonacci golden nuggets", + "Problem 138: Special isosceles triangles", + "Problem 139: Pythagorean tiles", + "Problem 140: Modified Fibonacci golden nuggets", + "Problem 141: Investigating progressive numbers, n, which are also square", + "Problem 142: Perfect Square Collection", + "Problem 143: Investigating the Torricelli point of a triangle", + "Problem 144: Investigating multiple reflections of a laser beam", + "Problem 145: How many reversible numbers are there below one-billion?", + "Problem 146: Investigating a Prime Pattern", + "Problem 147: Rectangles in cross-hatched grids", + "Problem 148: Exploring Pascal's triangle", + "Problem 149: Searching for a maximum-sum subsequence", + "Problem 150: Searching a triangular array for a sub-triangle having minimum-sum", + "Problem 151: Paper sheets of standard sizes: an expected-value problem", + "Problem 152: Writing 1/2 as a sum of inverse squares", + "Problem 153: Investigating Gaussian Integers", + "Problem 154: Exploring Pascal's pyramid", + "Problem 155: Counting Capacitor Circuits", + "Problem 156: Counting Digits", + "Problem 157: Solving the diophantine equation 1/a+1/b= p/10n", + "Problem 158: Exploring strings for which only one character comes lexicographically after its neighbour to the left", + "Problem 159: Digital root sums of factorisations", + "Problem 160: Factorial trailing digits", + "Problem 161: Triominoes", + "Problem 162: Hexadecimal numbers", + "Problem 163: Cross-hatched triangles", + "Problem 164: Numbers for which no three consecutive digits have a sum greater than a given value", + "Problem 165: Intersections", + "Problem 166: Criss Cross", + "Problem 167: Investigating Ulam sequences", + "Problem 168: Number Rotations", + "Problem 169: Exploring the number of different ways a number can be expressed as a sum of powers of 2", + "Problem 170: Find the largest 0 to 9 pandigital that can be formed by concatenating products", + "Problem 171: Finding numbers for which the sum of the squares of the digits is a square", + "Problem 172: Investigating numbers with few repeated digits", + "Problem 173: Using up to one million tiles how many different \"hollow\" square laminae can be formed?", + "Problem 174: Counting the number of \"hollow\" square laminae that can form one, two, three, ... distinct arrangements", + "Problem 175: Fractions involving the number of different ways a number can be expressed as a sum of powers of 2", + "Problem 176: Right-angled triangles that share a cathetus", + "Problem 177: Integer angled Quadrilaterals", + "Problem 178: Step Numbers", + "Problem 179: Consecutive positive divisors", + "Problem 180: Rational zeros of a function of three variables", + "Problem 181: Investigating in how many ways objects of two different colours can be grouped", + "Problem 182: RSA encryption", + "Problem 183: Maximum product of parts", + "Problem 184: Triangles containing the origin", + "Problem 185: Number Mind", + "Problem 186: Connectedness of a network", + "Problem 187: Semiprimes", + "Problem 188: The hyperexponentiation of a number", + "Problem 189: Tri-colouring a triangular grid", + "Problem 190: Maximising a weighted product", + "Problem 191: Prize Strings", + "Problem 192: Best Approximations", + "Problem 193: Squarefree Numbers", + "Problem 194: Coloured Configurations", + "Problem 195: Inscribed circles of triangles with one angle of 60 degrees", + "Problem 196: Prime triplets", + "Problem 197: Investigating the behaviour of a recursively defined sequence", + "Problem 198: Ambiguous Numbers", + "Problem 199: Iterative Circle Packing", + "Problem 200: Find the 200th prime-proof sqube containing the contiguous sub-string \"200\"", + "Problem 201: Subsets with a unique sum", + "Problem 202: Laserbeam", + "Problem 203: Squarefree Binomial Coefficients", + "Problem 204: Generalised Hamming Numbers", + "Problem 205: Dice Game", + "Problem 206: Concealed Square", + "Problem 207: Integer partition equations", + "Problem 208: Robot Walks", + "Problem 209: Circular Logic", + "Problem 210: Obtuse Angled Triangles", + "Problem 211: Divisor Square Sum", + "Problem 212: Combined Volume of Cuboids", + "Problem 213: Flea Circus", + "Problem 214: Totient Chains", + "Problem 215: Crack-free Walls", + "Problem 216: Investigating the primality of numbers of the form 2n2-1", + "Problem 217: Balanced Numbers", + "Problem 218: Perfect right-angled triangles", + "Problem 219: Skew-cost coding", + "Problem 220: Heighway Dragon", + "Problem 221: Alexandrian Integers", + "Problem 222: Sphere Packing", + "Problem 223: Almost right-angled triangles I", + "Problem 224: Almost right-angled triangles II", + "Problem 225: Tribonacci non-divisors", + "Problem 226: A Scoop of Blancmange", + "Problem 227: The Chase", + "Problem 228: Minkowski Sums", + "Problem 229: Four Representations using Squares", + "Problem 230: Fibonacci Words", + "Problem 231: The prime factorisation of binomial coefficients", + "Problem 232: The Race", + "Problem 233: Lattice points on a circle", + "Problem 234: Semidivisible numbers", + "Problem 235: An Arithmetic Geometric sequence", + "Problem 236: Luxury Hampers", + "Problem 237: Tours on a 4 x n playing board", + "Problem 238: Infinite string tour", + "Problem 239: Twenty-two Foolish Primes", + "Problem 240: Top Dice", + "Problem 241: Perfection Quotients", + "Problem 242: Odd Triplets", + "Problem 243: Resilience", + "Problem 244: Sliders", + "Problem 245: Coresilience", + "Problem 246: Tangents to an ellipse", + "Problem 247: Squares under a hyperbola", + "Problem 248: Numbers for which Euler’s totient function equals 13!", + "Problem 249: Prime Subset Sums", + "Problem 250: 250250", + "Problem 251: Cardano Triplets", + "Problem 252: Convex Holes", + "Problem 253: Tidying up", + "Problem 254: Sums of Digit Factorials", + "Problem 255: Rounded Square Roots", + "Problem 256: Tatami-Free Rooms", + "Problem 257: Angular Bisectors", + "Problem 258: A lagged Fibonacci sequence", + "Problem 259: Reachable Numbers", + "Problem 260: Stone Game", + "Problem 261: Pivotal Square Sums", + "Problem 262: Mountain Range", + "Problem 263: An engineers' dream come true", + "Problem 264: Triangle Centres", + "Problem 265: Binary Circles", + "Problem 266: Pseudo Square Root", + "Problem 267: Billionaire", + "Problem 268: Counting numbers with at least four distinct prime factors less than 100", + "Problem 269: Polynomials with at least one integer root", + "Problem 270: Cutting Squares", + "Problem 271: Modular Cubes, part 1", + "Problem 272: Modular Cubes, part 2", + "Problem 273: Sum of Squares", + "Problem 274: Divisibility Multipliers", + "Problem 275: Balanced Sculptures", + "Problem 276: Primitive Triangles", + "Problem 277: A Modified Collatz sequence", + "Problem 278: Linear Combinations of Semiprimes", + "Problem 279: Triangles with integral sides and an integral angle", + "Problem 280: Ant and seeds", + "Problem 281: Pizza Toppings", + "Problem 282: The Ackermann function", + "Problem 283: Integer sided triangles for which the area/perimeter ratio is integral", + "Problem 284: Steady Squares", + "Problem 285: Pythagorean odds", + "Problem 286: Scoring probabilities", + "Problem 287: Quadtree encoding (a simple compression algorithm)", + "Problem 288: An enormous factorial", + "Problem 289: Eulerian Cycles", + "Problem 290: Digital Signature", + "Problem 291: Panaitopol Primes", + "Problem 292: Pythagorean Polygons", + "Problem 293: Pseudo-Fortunate Numbers", + "Problem 294: Sum of digits - experience #23", + "Problem 295: Lenticular holes", + "Problem 296: Angular Bisector and Tangent", + "Problem 297: Zeckendorf Representation", + "Problem 298: Selective Amnesia", + "Problem 299: Three similar triangles", + "Problem 300: Protein folding", + "Problem 301: Nim", + "Problem 302: Strong Achilles Numbers", + "Problem 303: Multiples with small digits", + "Problem 304: Primonacci", + "Problem 305: Reflexive Position", + "Problem 306: Paper-strip Game", + "Problem 307: Chip Defects", + "Problem 308: An amazing Prime-generating Automaton", + "Problem 309: Integer Ladders", + "Problem 310: Nim Square", + "Problem 311: Biclinic Integral Quadrilaterals", + "Problem 312: Cyclic paths on Sierpiński graphs", + "Problem 313: Sliding game", + "Problem 314: The Mouse on the Moon", + "Problem 315: Digital root clocks", + "Problem 316: Numbers in decimal expansions", + "Problem 317: Firecracker", + "Problem 318: 2011 nines", + "Problem 319: Bounded Sequences", + "Problem 320: Factorials divisible by a huge integer", + "Problem 321: Swapping Counters", + "Problem 322: Binomial coefficients divisible by 10", + "Problem 323: Bitwise-OR operations on random integers", + "Problem 324: Building a tower", + "Problem 325: Stone Game II", + "Problem 326: Modulo Summations", + "Problem 327: Rooms of Doom", + "Problem 328: Lowest-cost Search", + "Problem 329: Prime Frog", + "Problem 330: Euler's Number", + "Problem 331: Cross flips", + "Problem 332: Spherical triangles", + "Problem 333: Special partitions", + "Problem 334: Spilling the beans", + "Problem 335: Gathering the beans", + "Problem 336: Maximix Arrangements", + "Problem 337: Totient Stairstep Sequences", + "Problem 338: Cutting Rectangular Grid Paper", + "Problem 339: Peredur fab Efrawg", + "Problem 340: Crazy Function", + "Problem 341: Golomb's self-describing sequence", + "Problem 342: The totient of a square is a cube", + "Problem 343: Fractional Sequences", + "Problem 344: Silver dollar game", + "Problem 345: Matrix Sum", + "Problem 346: Strong Repunits", + "Problem 347: Largest integer divisible by two primes", + "Problem 348: Sum of a square and a cube", + "Problem 349: Langton's ant", + "Problem 350: Constraining the least greatest and the greatest least", + "Problem 351: Hexagonal orchards", + "Problem 352: Blood tests", + "Problem 353: Risky moon", + "Problem 354: Distances in a bee's honeycomb", + "Problem 355: Maximal coprime subset", + "Problem 356: Largest roots of cubic polynomials", + "Problem 357: Prime generating integers", + "Problem 358: Cyclic numbers", + "Problem 359: Hilbert's New Hotel", + "Problem 360: Scary Sphere", + "Problem 361: Subsequence of Thue-Morse sequence", + "Problem 362: Squarefree factors", + "Problem 363: Bézier Curves", + "Problem 364: Comfortable distance", + "Problem 365: A huge binomial coefficient", + "Problem 366: Stone Game III", + "Problem 367: Bozo sort", + "Problem 368: A Kempner-like series", + "Problem 369: Badugi", + "Problem 370: Geometric triangles", + "Problem 371: Licence plates", + "Problem 372: Pencils of rays", + "Problem 373: Circumscribed Circles", + "Problem 374: Maximum Integer Partition Product", + "Problem 375: Minimum of subsequences", + "Problem 376: Nontransitive sets of dice", + "Problem 377: Sum of digits, experience 13", + "Problem 378: Triangle Triples", + "Problem 379: Least common multiple count", + "Problem 380: Amazing Mazes!", + "Problem 381: (prime-k) factorial", + "Problem 382: Generating polygons", + "Problem 383: Divisibility comparison between factorials", + "Problem 384: Rudin-Shapiro sequence", + "Problem 385: Ellipses inside triangles", + "Problem 386: Maximum length of an antichain", + "Problem 387: Harshad Numbers", + "Problem 388: Distinct Lines", + "Problem 389: Platonic Dice", + "Problem 390: Triangles with non rational sides and integral area", + "Problem 391: Hopping Game", + "Problem 392: Enmeshed unit circle", + "Problem 393: Migrating ants", + "Problem 394: Eating pie", + "Problem 395: Pythagorean tree", + "Problem 396: Weak Goodstein sequence", + "Problem 397: Triangle on parabola", + "Problem 398: Cutting rope", + "Problem 399: Squarefree Fibonacci Numbers", + "Problem 400: Fibonacci tree game", + "Problem 401: Sum of squares of divisors", + "Problem 402: Integer-valued polynomials", + "Problem 403: Lattice points enclosed by parabola and line", + "Problem 404: Crisscross Ellipses", + "Problem 405: A rectangular tiling", + "Problem 406: Guessing Game", + "Problem 407: Idempotents", + "Problem 408: Admissible paths through a grid", + "Problem 409: Nim Extreme", + "Problem 410: Circle and tangent line", + "Problem 411: Uphill paths", + "Problem 412: Gnomon numbering", + "Problem 413: One-child Numbers", + "Problem 414: Kaprekar constant", + "Problem 415: Titanic sets", + "Problem 416: A frog's trip", + "Problem 417: Reciprocal cycles II", + "Problem 418: Factorisation triples", + "Problem 419: Look and say sequence", + "Problem 420: 2x2 positive integer matrix", + "Problem 421: Prime factors of n15+1", + "Problem 422: Sequence of points on a hyperbola", + "Problem 423: Consecutive die throws", + "Problem 424: Kakuro", + "Problem 425: Prime connection", + "Problem 426: Box-ball system", + "Problem 427: n-sequences", + "Problem 428: Necklace of Circles", + "Problem 429: Sum of squares of unitary divisors", + "Problem 430: Range flips", + "Problem 431: Square Space Silo", + "Problem 432: Totient sum", + "Problem 433: Steps in Euclid's algorithm", + "Problem 434: Rigid graphs", + "Problem 435: Polynomials of Fibonacci numbers", + "Problem 436: Unfair wager", + "Problem 437: Fibonacci primitive roots", + "Problem 438: Integer part of polynomial equation's solutions", + "Problem 439: Sum of sum of divisors", + "Problem 440: GCD and Tiling", + "Problem 441: The inverse summation of coprime couples", + "Problem 442: Eleven-free integers", + "Problem 443: GCD sequence", + "Problem 444: The Roundtable Lottery", + "Problem 445: Retractions A", + "Problem 446: Retractions B", + "Problem 447: Retractions C", + "Problem 448: Average least common multiple", + "Problem 449: Chocolate covered candy", + "Problem 450: Hypocycloid and Lattice points", + "Problem 451: Modular inverses", + "Problem 452: Long Products", + "Problem 453: Lattice Quadrilaterals", + "Problem 454: Diophantine reciprocals III", + "Problem 455: Powers With Trailing Digits", + "Problem 456: Triangles containing the origin II", + "Problem 457: A polynomial modulo the square of a prime", + "Problem 458: Permutations of Project", + "Problem 459: Flipping game", + "Problem 460: An ant on the move", + "Problem 461: Almost Pi", + "Problem 462: Permutation of 3-smooth numbers", + "Problem 463: A weird recurrence relation", + "Problem 464: Möbius function and intervals", + "Problem 465: Polar polygons", + "Problem 466: Distinct terms in a multiplication table", + "Problem 467: Superinteger", + "Problem 468: Smooth divisors of binomial coefficients", + "Problem 469: Empty chairs", + "Problem 470: Super Ramvok", + "Problem 471: Triangle inscribed in ellipse", + "Problem 472: Comfortable Distance II", + "Problem 473: Phigital number base", + "Problem 474: Last digits of divisors", + "Problem 475: Music festival", + "Problem 476: Circle Packing II", + "Problem 477: Number Sequence Game", + "Problem 478: Mixtures", + "Problem 479: Roots on the Rise", + "Problem 480: The Last Question" + ] + } +} \ No newline at end of file From 4d2d00ef0afcdb09416af1235811cd3a493c284d Mon Sep 17 00:00:00 2001 From: Creighton Magoun Date: Wed, 17 Oct 2018 16:09:00 +0000 Subject: [PATCH 07/37] Add usage note in header --- lesson_map.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lesson_map.js b/lesson_map.js index e3bed78..c731851 100644 --- a/lesson_map.js +++ b/lesson_map.js @@ -2,6 +2,8 @@ * Scrapes the lesson list from https://learn.freecodecamp.org into * a JSON Object, then writes that object to lesson_map.json * + * Usage: node lesson_map.js + * * { 'section1': { * 'subsection1': [ * 'exercise1', From 05a5cbb1dafddefd4063c7e6483762ee8dec9b9a Mon Sep 17 00:00:00 2001 From: Creighton Magoun Date: Wed, 17 Oct 2018 16:09:28 +0000 Subject: [PATCH 08/37] Rename playground file to wip (work in progress) --- hello.js => wip.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename hello.js => wip.js (100%) diff --git a/hello.js b/wip.js similarity index 100% rename from hello.js rename to wip.js From 92013ddde0d9607f55071bd0e78afff22bbb54b8 Mon Sep 17 00:00:00 2001 From: Creighton Magoun Date: Wed, 17 Oct 2018 16:32:50 +0000 Subject: [PATCH 09/37] Begin rewriting instructions for new scraper --- README.md | 14 ++++++++------ assets/install.gif | Bin 440889 -> 0 bytes 2 files changed, 8 insertions(+), 6 deletions(-) delete mode 100644 assets/install.gif diff --git a/README.md b/README.md index dd4a99b..a08b608 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,19 @@ ## Overview +_Note: To Edit_ This script takes a newline-delimited list of FreeCodeCamp profile URLs and returns a report on their progress as a newline-delimited list of tab-delimited percentages. ## Installation +Requires Node v7.6 or higher (testing done with v10.1.0). +Clone the repo and cd into it. +Install the dependencies with `npm install`. -1. [Install Tampermonkey.](https://chrome.google.com/webstore/detail/tampermonkey/dhdgffkkebhmkfjojejmpbldmpobfkfo) -2. Navigate to the Utilities tab in Tampermonkey options. -3. Paste the following address into the input marked "URL" and click "Import" -4. Confirm the installation. +## Usage +Create the curriculum map with `node lesson_map.js`. +It will create lesson_map.json or overwrite the existing file. -![Installation](assets/install.gif) -## Usage +#### OLD README BELOW #### _Note: This script sends a request for all these URLs essentially at the same time, so and hasn't been tested for more than ~30 at a time. Too many more and their serers might not appreciate it._ diff --git a/assets/install.gif b/assets/install.gif deleted file mode 100644 index 807a4d4c01211b882768f02b24ba76a044e0d580..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 440889 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 N@$HBI^X-S?{|7?rp;rI^ From 61dec3244cee96401b33a9e21e9ac0e3287616b4 Mon Sep 17 00:00:00 2001 From: Creighton Magoun Date: Wed, 17 Oct 2018 18:24:22 +0000 Subject: [PATCH 10/37] Add check for React components loading, just in case --- lesson_map.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lesson_map.js b/lesson_map.js index c731851..f120b1b 100644 --- a/lesson_map.js +++ b/lesson_map.js @@ -24,7 +24,8 @@ let getHTML = async (url) => { const browser = await puppeteer.launch(); const page = await browser.newPage(); - await page.goto(url); + // Wait for React components to load + await page.goto(url, { waitUntil: 'networkidle0'}); // Need to click links to fully expand map // Outer level uses superblock class From 2135837e90855e5281b1c6b63a27511331fe8739 Mon Sep 17 00:00:00 2001 From: Creighton Magoun Date: Wed, 17 Oct 2018 20:53:01 +0000 Subject: [PATCH 11/37] Refactor student completion parsing --- wip.js | 1608 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 1551 insertions(+), 57 deletions(-) diff --git a/wip.js b/wip.js index 47040c5..d26083d 100644 --- a/wip.js +++ b/wip.js @@ -4,91 +4,1585 @@ let getHTML = async (url) => { const browser = await puppeteer.launch(); const page = await browser.newPage(); - await page.goto(url); - // Need to click links to fully expand map - // Outer level uses superblock class - let superblock = await page.$("li[class='superblock ']"); - while (superblock) { - await superblock.click(); - superblock = await page.$("li[class='superblock ']"); - } - - // Inner level uses block class - let block = await page.$("li[class='block ']"); - while (block) { - await block.click(); - block = await page.$("li[class='block ']"); - } + // Wait for React components to load + await page.goto(url, { waitUntil: 'networkidle0'}); - // Map is now fully expanded. Get content and close browser. const html = await page.content(); await browser.close(); return html; }; -// Create map of curriculum as JSON object -let createMap = (html) => { +// Parse the HTML for completed challenges +// Returns an array of challenge names +let parseHTML = (html) => { const $ = require('cheerio').load(html); - let jsonObj = {}; + let challenges = []; - // Assemble the data to convert to JSON - // Crawl the major sections in .superblock - $('.superblock').each(function (index, element) { - // Get the major section titles - let section = $(this).find('h4').text(); - - let sectionObj = {}; - // Crawl the subsections in .block - $(this).find('.block') - .each(function (index, element) { - // Get the minor section titles - let subsection = $(this).find('h5').text(); - - let exercises = []; - // Get the individual exercises for the subsection - $(this).find('a') - .each(function (index, element) { - // First item is an 'Intro item', which we can ignore - if (index != 0) { - let exercise = $(this).text(); - exercises.push(exercise); - } - }); - - // Store the exercise array as 'subsection' => exercises - sectionObj[subsection] = exercises; - }); - - // Store the section object as - // 'section' => {subsection1 => exercises, - // subsection2 => exercise, ...} - jsonObj[section] = sectionObj; + $('tr', 'tbody').each(function (index, element) { + let challenge = $(this).find('a').text(); + challenges.push(challenge); }); - return jsonObj; -} + return challenges; +}; + +// Compare progress to overall curriculum +// Returns a JSON object +let getProgress = (completedChallenges) => { + // Hard coded, but can be pulled dynamically with lesson_map.js + const lesson_map = { + "Responsive Web Design Certification (300 hours)": { + "Basic HTML and HTML5": [ + "Say Hello to HTML Elements", + "Headline with the h2 Element", + "Inform with the Paragraph Element", + "Fill in the Blank with Placeholder Text", + "Uncomment HTML", + "Comment out HTML", + "Delete HTML Elements", + "Introduction to HTML5 Elements", + "Add Images to Your Website", + "Link to External Pages with Anchor Elements", + "Link to Internal Sections of a Page with Anchor Elements", + "Nest an Anchor Element within a Paragraph", + "Make Dead Links Using the Hash Symbol", + "Turn an Image into a Link", + "Create a Bulleted Unordered List", + "Create an Ordered List", + "Create a Text Field", + "Add Placeholder Text to a Text Field", + "Create a Form Element", + "Add a Submit Button to a Form", + "Use HTML5 to Require a Field", + "Create a Set of Radio Buttons", + "Create a Set of Checkboxes", + "Check Radio Buttons and Checkboxes by Default", + "Nest Many Elements within a Single div Element", + "Declare the Doctype of an HTML Document", + "Define the Head and Body of an HTML Document" + ], + "Basic CSS": [ + "Change the Color of Text", + "Use CSS Selectors to Style Elements", + "Use a CSS Class to Style an Element", + "Style Multiple Elements with a CSS Class", + "Change the Font Size of an Element", + "Set the Font Family of an Element", + "Import a Google Font", + "Specify How Fonts Should Degrade", + "Size Your Images", + "Add Borders Around Your Elements", + "Add Rounded Corners with border-radius", + "Make Circular Images with a border-radius", + "Give a Background Color to a div Element", + "Set the id of an Element", + "Use an id Attribute to Style an Element", + "Adjust the Padding of an Element", + "Adjust the Margin of an Element", + "Add a Negative Margin to an Element", + "Add Different Padding to Each Side of an Element", + "Add Different Margins to Each Side of an Element", + "Use Clockwise Notation to Specify the Padding of an Element", + "Use Clockwise Notation to Specify the Margin of an Element", + "Use Attribute Selectors to Style Elements", + "Understand Absolute versus Relative Units", + "Style the HTML Body Element", + "Inherit Styles from the Body Element", + "Prioritize One Style Over Another", + "Override Styles in Subsequent CSS", + "Override Class Declarations by Styling ID Attributes", + "Override Class Declarations with Inline Styles", + "Override All Other Styles by using Important", + "Use Hex Code for Specific Colors", + "Use Hex Code to Mix Colors", + "Use Abbreviated Hex Code", + "Use RGB values to Color Elements", + "Use RGB to Mix Colors", + "Use CSS Variables to change several elements at once", + "Create a custom CSS Variable", + "Use a custom CSS Variable", + "Attach a Fallback value to a CSS Variable", + "Improve Compatibility with Browser Fallbacks", + "Cascading CSS variables", + "Change a variable for a specific area", + "Use a media query to change a variable" + ], + "Applied Visual Design": [ + "Create Visual Balance Using the text-align Property", + "Adjust the Width of an Element Using the width Property", + "Adjust the Height of an Element Using the height Property", + "Use the strong Tag to Make Text Bold", + "Use the u Tag to Underline Text", + "Use the em Tag to Italicize Text", + "Use the s Tag to Strikethrough Text", + "Create a Horizontal Line Using the hr Element", + "Adjust the background-color Property of Text", + "Adjust the Size of a Header Versus a Paragraph Tag", + "Add a box-shadow to a Card-like Element", + "Decrease the Opacity of an Element", + "Use the text-transform Property to Make Text Uppercase", + "Set the font-size for Multiple Heading Elements", + "Set the font-weight for Multiple Heading Elements", + "Set the font-size of Paragraph Text", + "Set the line-height of Paragraphs", + "Adjust the Hover State of an Anchor Tag", + "Change an Element's Relative Position", + "Move a Relatively Positioned Element with CSS Offsets", + "Lock an Element to its Parent with Absolute Positioning", + "Lock an Element to the Browser Window with Fixed Positioning", + "Push Elements Left or Right with the float Property", + "Change the Position of Overlapping Elements with the z-index Property", + "Center an Element Horizontally Using the margin Property", + "Learn about Complementary Colors", + "Learn about Tertiary Colors", + "Adjust the Color of Various Elements to Complementary Colors", + "Adjust the Hue of a Color", + "Adjust the Tone of a Color", + "Create a Gradual CSS Linear Gradient", + "Use a CSS Linear Gradient to Create a Striped Element", + "Create Texture by Adding a Subtle Pattern as a Background Image", + "Use the CSS Transform scale Property to Change the Size of an Element", + "Use the CSS Transform scale Property to Scale an Element on Hover", + "Use the CSS Transform Property skewX to Skew an Element Along the X-Axis", + "Use the CSS Transform Property skewY to Skew an Element Along the Y-Axis", + "Create a Graphic Using CSS", + "Create a More Complex Shape Using CSS and HTML", + "Learn How the CSS @keyframes and animation Properties Work", + "Use CSS Animation to Change the Hover State of a Button", + "Modify Fill Mode of an Animation", + "Create Movement Using CSS Animation", + "Create Visual Direction by Fading an Element from Left to Right", + "Animate Elements Continually Using an Infinite Animation Count", + "Make a CSS Heartbeat using an Infinite Animation Count", + "Animate Elements at Variable Rates", + "Animate Multiple Elements at Variable Rates", + "Change Animation Timing with Keywords", + "Learn How Bezier Curves Work", + "Use a Bezier Curve to Move a Graphic", + "Make Motion More Natural Using a Bezier Curve" + ], + "Applied Accessibility": [ + "Add a Text Alternative to Images for Visually Impaired Accessibility", + "Know When Alt Text Should be Left Blank", + "Use Headings to Show Hierarchical Relationships of Content", + "Jump Straight to the Content Using the main Element", + "Wrap Content in the article Element", + "Make Screen Reader Navigation Easier with the header Landmark", + "Make Screen Reader Navigation Easier with the nav Landmark", + "Make Screen Reader Navigation Easier with the footer Landmark", + "Improve Accessibility of Audio Content with the audio Element", + "Improve Chart Accessibility with the figure Element", + "Improve Form Field Accessibility with the label Element", + "Wrap Radio Buttons in a fieldset Element for Better Accessibility", + "Add an Accessible Date Picker", + "Standardize Times with the HTML5 datetime Attribute", + "Make Elements Only Visible to a Screen Reader by Using Custom CSS", + "Improve Readability with High Contrast Text", + "Avoid Colorblindness Issues by Using Sufficient Contrast", + "Avoid Colorblindness Issues by Carefully Choosing Colors that Convey Information", + "Give Links Meaning by Using Descriptive Link Text", + "Make Links Navigatable with HTML Access Keys", + "Use tabindex to Add Keyboard Focus to an Element", + "Use tabindex to Specify the Order of Keyboard Focus for Several Elements" + ], + "Responsive Web Design Principles": [ + "Create a Media Query", + "Make an Image Responsive", + "Use a Retina Image for Higher Resolution Displays", + "Make Typography Responsive" + ], + "CSS Flexbox": [ + "Use display: flex to Position Two Boxes", + "Add Flex Superpowers to the Tweet Embed", + "Use the flex-direction Property to Make a Row", + "Apply the flex-direction Property to Create Rows in the Tweet Embed", + "Use the flex-direction Property to Make a Column", + "Apply the flex-direction Property to Create a Column in the Tweet Embed", + "Align Elements Using the justify-content Property", + "Use the justify-content Property in the Tweet Embed", + "Align Elements Using the align-items Property", + "Use the align-items Property in the Tweet Embed", + "Use the flex-wrap Property to Wrap a Row or Column", + "Use the flex-shrink Property to Shrink Items", + "Use the flex-grow Property to Expand Items", + "Use the flex-basis Property to Set the Initial Size of an Item", + "Use the flex Shorthand Property", + "Use the order Property to Rearrange Items", + "Use the align-self Property" + ], + "CSS Grid": [ + "Create Your First CSS Grid", + "Add Columns with grid-template-columns", + "Add Rows with grid-template-rows", + "Use CSS Grid units to Change the Size of Columns and Rows", + "Create a Column Gap Using grid-column-gap", + "Create a Row Gap using grid-row-gap", + "Add Gaps Faster with grid-gap", + "Use grid-column to Control Spacing", + "Use grid-row to Control Spacing", + "Align an Item Horizontally using justify-self", + "Align an Item Vertically using align-self", + "Align All Items Horizontally using justify-items", + "Align All Items Vertically using align-items", + "Divide the Grid Into an Area Template", + "Place Items in Grid Areas Using the grid-area Property", + "Use grid-area Without Creating an Areas Template", + "Reduce Repetition Using the repeat Function", + "Limit Item Size Using the minmax Function", + "Create Flexible Layouts Using auto-fill", + "Create Flexible Layouts Using auto-fit", + "Use Media Queries to Create Responsive Layouts", + "Create Grids within Grids" + ], + "Responsive Web Design Projects": [ + "Build a Tribute Page", + "Build a Survey Form", + "Build a Product Landing Page", + "Build a Technical Documentation Page", + "Build a Personal Portfolio Webpage" + ] + }, + "Javascript Algorithms And Data Structures Certification (300 hours)": { + "Basic JavaScript": [ + "Comment Your JavaScript Code", + "Declare JavaScript Variables", + "Storing Values with the Assignment Operator", + "Initializing Variables with the Assignment Operator", + "Understanding Uninitialized Variables", + "Understanding Case Sensitivity in Variables", + "Add Two Numbers with JavaScript", + "Subtract One Number from Another with JavaScript", + "Multiply Two Numbers with JavaScript", + "Divide One Number by Another with JavaScript", + "Increment a Number with JavaScript", + "Decrement a Number with JavaScript", + "Create Decimal Numbers with JavaScript", + "Multiply Two Decimals with JavaScript", + "Divide One Decimal by Another with JavaScript", + "Finding a Remainder in JavaScript", + "Compound Assignment With Augmented Addition", + "Compound Assignment With Augmented Subtraction", + "Compound Assignment With Augmented Multiplication", + "Compound Assignment With Augmented Division", + "Declare String Variables", + "Escaping Literal Quotes in Strings", + "Quoting Strings with Single Quotes", + "Escape Sequences in Strings", + "Concatenating Strings with Plus Operator", + "Concatenating Strings with the Plus Equals Operator", + "Constructing Strings with Variables", + "Appending Variables to Strings", + "Find the Length of a String", + "Use Bracket Notation to Find the First Character in a String", + "Understand String Immutability", + "Use Bracket Notation to Find the Nth Character in a String", + "Use Bracket Notation to Find the Last Character in a String", + "Use Bracket Notation to Find the Nth-to-Last Character in a String", + "Word Blanks", + "Store Multiple Values in one Variable using JavaScript Arrays", + "Nest one Array within Another Array", + "Access Array Data with Indexes", + "Modify Array Data With Indexes", + "Access Multi-Dimensional Arrays With Indexes", + "Manipulate Arrays With push()", + "Manipulate Arrays With pop()", + "Manipulate Arrays With shift()", + "Manipulate Arrays With unshift()", + "Shopping List", + "Write Reusable JavaScript with Functions", + "Passing Values to Functions with Arguments", + "Global Scope and Functions", + "Local Scope and Functions", + "Global vs. Local Scope in Functions", + "Return a Value from a Function with Return", + "Understanding Undefined Value returned from a Function", + "Assignment with a Returned Value", + "Stand in Line", + "Understanding Boolean Values", + "Use Conditional Logic with If Statements", + "Comparison with the Equality Operator", + "Comparison with the Strict Equality Operator", + "Practice comparing different values", + "Comparison with the Inequality Operator", + "Comparison with the Strict Inequality Operator", + "Comparison with the Greater Than Operator", + "Comparison with the Greater Than Or Equal To Operator", + "Comparison with the Less Than Operator", + "Comparison with the Less Than Or Equal To Operator", + "Comparisons with the Logical And Operator", + "Comparisons with the Logical Or Operator", + "Introducing Else Statements", + "Introducing Else If Statements", + "Logical Order in If Else Statements", + "Chaining If Else Statements", + "Golf Code", + "Selecting from Many Options with Switch Statements", + "Adding a Default Option in Switch Statements", + "Multiple Identical Options in Switch Statements", + "Replacing If Else Chains with Switch", + "Returning Boolean Values from Functions", + "Return Early Pattern for Functions", + "Counting Cards", + "Build JavaScript Objects", + "Accessing Object Properties with Dot Notation", + "Accessing Object Properties with Bracket Notation", + "Accessing Object Properties with Variables", + "Updating Object Properties", + "Add New Properties to a JavaScript Object", + "Delete Properties from a JavaScript Object", + "Using Objects for Lookups", + "Testing Objects for Properties", + "Manipulating Complex Objects", + "Accessing Nested Objects", + "Accessing Nested Arrays", + "Record Collection", + "Iterate with JavaScript While Loops", + "Iterate with JavaScript For Loops", + "Iterate Odd Numbers With a For Loop", + "Count Backwards With a For Loop", + "Iterate Through an Array with a For Loop", + "Nesting For Loops", + "Iterate with JavaScript Do...While Loops", + "Profile Lookup", + "Generate Random Fractions with JavaScript", + "Generate Random Whole Numbers with JavaScript", + "Generate Random Whole Numbers within a Range", + "Use the parseInt Function", + "Use the parseInt Function with a Radix", + "Use the Conditional (Ternary) Operator", + "Use Multiple Conditional (Ternary) Operators" + ], + "ES6": [ + "Explore Differences Between the var and let Keywords", + "Compare Scopes of the var and let Keywords", + "Declare a Read-Only Variable with the const Keyword", + "Mutate an Array Declared with const", + "Prevent Object Mutation", + "Use Arrow Functions to Write Concise Anonymous Functions", + "Write Arrow Functions with Parameters", + "Write Higher Order Arrow Functions", + "Set Default Parameters for Your Functions", + "Use the Rest Operator with Function Parameters", + "Use the Spread Operator to Evaluate Arrays In-Place", + "Use Destructuring Assignment to Assign Variables from Objects", + "Use Destructuring Assignment to Assign Variables from Nested Objects", + "Use Destructuring Assignment to Assign Variables from Arrays", + "Use Destructuring Assignment with the Rest Operator to Reassign Array Elements", + "Use Destructuring Assignment to Pass an Object as a Function's Parameters", + "Create Strings using Template Literals", + "Write Concise Object Literal Declarations Using Simple Fields", + "Write Concise Declarative Functions with ES6", + "Use class Syntax to Define a Constructor Function", + "Use getters and setters to Control Access to an Object", + "Understand the Differences Between import and require", + "Use export to Reuse a Code Block", + "Use * to Import Everything from a File", + "Create an Export Fallback with export default", + "Import a Default Export" + ], + "Regular Expressions": [ + "Using the Test Method", + "Match Literal Strings", + "Match a Literal String with Different Possibilities", + "Ignore Case While Matching", + "Extract Matches", + "Find More Than the First Match", + "Match Anything with Wildcard Period", + "Match Single Character with Multiple Possibilities", + "Match Letters of the Alphabet", + "Match Numbers and Letters of the Alphabet", + "Match Single Characters Not Specified", + "Match Characters that Occur One or More Times", + "Match Characters that Occur Zero or More Times", + "Find Characters with Lazy Matching", + "Find One or More Criminals in a Hunt", + "Match Beginning String Patterns", + "Match Ending String Patterns", + "Match All Letters and Numbers", + "Match Everything But Letters and Numbers", + "Match All Numbers", + "Match All Non-Numbers", + "Restrict Possible Usernames", + "Match Whitespace", + "Match Non-Whitespace Characters", + "Specify Upper and Lower Number of Matches", + "Specify Only the Lower Number of Matches", + "Specify Exact Number of Matches", + "Check for All or None", + "Positive and Negative Lookahead", + "Reuse Patterns Using Capture Groups", + "Use Capture Groups to Search and Replace", + "Remove Whitespace from Start and End" + ], + "Debugging": [ + "Use the JavaScript Console to Check the Value of a Variable", + "Understanding the Differences between the freeCodeCamp and Browser Console", + "Use typeof to Check the Type of a Variable", + "Catch Misspelled Variable and Function Names", + "Catch Unclosed Parentheses, Brackets, Braces and Quotes", + "Catch Mixed Usage of Single and Double Quotes", + "Catch Use of Assignment Operator Instead of Equality Operator", + "Catch Missing Open and Closing Parenthesis After a Function Call", + "Catch Arguments Passed in the Wrong Order When Calling a Function", + "Catch Off By One Errors When Using Indexing", + "Use Caution When Reinitializing Variables Inside a Loop", + "Prevent Infinite Loops with a Valid Terminal Condition" + ], + "Basic Data Structures": [ + "Use an Array to Store a Collection of Data", + "Access an Array's Contents Using Bracket Notation", + "Add Items to an Array with push() and unshift()", + "Remove Items from an Array with pop() and shift()", + "Remove Items Using splice()", + "Add Items Using splice()", + "Copy Array Items Using slice()", + "Copy an Array with the Spread Operator", + "Combine Arrays with the Spread Operator", + "Check For The Presence of an Element With indexOf()", + "Iterate Through All an Array's Items Using For Loops", + "Create complex multi-dimensional arrays", + "Add Key-Value Pairs to JavaScript Objects", + "Modify an Object Nested Within an Object", + "Access Property Names with Bracket Notation", + "Use the delete Keyword to Remove Object Properties", + "Check if an Object has a Property", + " Iterate Through the Keys of an Object with a for...in Statement", + "Generate an Array of All Object Keys with Object.keys()", + "Modify an Array Stored in an Object" + ], + "Basic Algorithm Scripting": [ + "Convert Celsius to Fahrenheit", + "Reverse a String", + "Factorialize a Number", + "Find the Longest Word in a String", + "Return Largest Numbers in Arrays", + "Confirm the Ending", + "Repeat a String Repeat a String", + "Truncate a String", + "Finders Keepers", + "Boo who", + "Title Case a Sentence", + "Slice and Splice", + "Falsy Bouncer", + "Where do I Belong", + "Mutations", + "Chunky Monkey" + ], + "Object Oriented Programming": [ + "Create a Basic JavaScript Object", + "Use Dot Notation to Access the Properties of an Object", + "Create a Method on an Object", + "Make Code More Reusable with the this Keyword", + "Define a Constructor Function", + "Use a Constructor to Create Objects", + "Extend Constructors to Receive Arguments", + "Verify an Object's Constructor with instanceof", + "Understand Own Properties", + "Use Prototype Properties to Reduce Duplicate Code", + "Iterate Over All Properties", + "Understand the Constructor Property", + "Change the Prototype to a New Object", + "Remember to Set the Constructor Property when Changing the Prototype", + "Understand Where an Object’s Prototype Comes From", + "Understand the Prototype Chain", + "Use Inheritance So You Don't Repeat Yourself", + "Inherit Behaviors from a Supertype", + "Set the Child's Prototype to an Instance of the Parent", + "Reset an Inherited Constructor Property", + "Add Methods After Inheritance", + "Override Inherited Methods", + "Use a Mixin to Add Common Behavior Between Unrelated Objects", + "Use Closure to Protect Properties Within an Object from Being Modified Externally", + "Understand the Immediately Invoked Function Expression (IIFE)", + "Use an IIFE to Create a Module" + ], + "Functional Programming": [ + "Learn About Functional Programming", + "Understand Functional Programming Terminology", + "Understand the Hazards of Using Imperative Code", + "Avoid Mutations and Side Effects Using Functional Programming", + "Pass Arguments to Avoid External Dependence in a Function", + "Refactor Global Variables Out of Functions", + "Use the map Method to Extract Data from an Array", + "Implement map on a Prototype", + "Use the filter Method to Extract Data from an Array", + "Implement the filter Method on a Prototype", + "Return Part of an Array Using the slice Method", + "Remove Elements from an Array Using slice Instead of splice", + "Combine Two Arrays Using the concat Method", + "Add Elements to the End of an Array Using concat Instead of push", + "Use the reduce Method to Analyze Data", + "Sort an Array Alphabetically using the sort Method", + "Return a Sorted Array Without Changing the Original Array", + "Split a String into an Array Using the split Method", + "Combine an Array into a String Using the join Method", + "Apply Functional Programming to Convert Strings to URL Slugs", + "Use the every Method to Check that Every Element in an Array Meets a Criteria", + "Use the some Method to Check that Any Elements in an Array Meet a Criteria", + "Introduction to Currying and Partial Application" + ], + "Intermediate Algorithm Scripting": [ + "Sum All Numbers in a Range", + "Diff Two Arrays", + "Seek and Destroy", + "Wherefore art thou", + "Spinal Tap Case", + "Pig Latin", + "Search and Replace", + "DNA Pairing", + "Missing letters", + "Sorted Union", + "Convert HTML Entities", + "Sum All Odd Fibonacci Numbers", + "Sum All Primes", + "Smallest Common Multiple", + "Drop it", + "Steamroller", + "Binary Agents", + "Everything Be True", + "Arguments Optional", + "Make a Person", + "Map the Debris" + ], + "JavaScript Algorithms and Data Structures Projects": [ + "Palindrome Checker", + "Roman Numeral Converter", + "Caesars Cipher", + "Telephone Number Validator", + "Cash Register" + ] + }, + "Front End Libraries Certification (300 hours)": { + "Bootstrap": [ + "Use Responsive Design with Bootstrap Fluid Containers", + "Make Images Mobile Responsive", + "Center Text with Bootstrap", + "Create a Bootstrap Button", + "Create a Block Element Bootstrap Button", + "Taste the Bootstrap Button Color Rainbow", + "Call out Optional Actions with btn-info", + "Warn Your Users of a Dangerous Action with btn-danger", + "Use the Bootstrap Grid to Put Elements Side By Side", + "Ditch Custom CSS for Bootstrap", + "Use a span to Target Inline Elements", + "Create a Custom Heading", + "Add Font Awesome Icons to our Buttons", + "Add Font Awesome Icons to all of our Buttons", + "Responsively Style Radio Buttons", + "Responsively Style Checkboxes", + "Style Text Inputs as Form Controls", + "Line up Form Elements Responsively with Bootstrap", + "Create a Bootstrap Headline", + "House our page within a Bootstrap container-fluid div", + "Create a Bootstrap Row", + "Split Your Bootstrap Row", + "Create Bootstrap Wells", + "Add Elements within Your Bootstrap Wells", + "Apply the Default Bootstrap Button Style", + "Create a Class to Target with jQuery Selectors", + "Add id Attributes to Bootstrap Elements", + "Label Bootstrap Wells", + "Give Each Element a Unique id", + "Label Bootstrap Buttons", + "Use Comments to Clarify Code" + ], + "jQuery": [ + "Learn How Script Tags and Document Ready Work", + "Target HTML Elements with Selectors Using jQuery", + "Target Elements by Class Using jQuery", + "Target Elements by id Using jQuery", + "Delete Your jQuery Functions", + "Target the Same Element with Multiple jQuery Selectors", + "Remove Classes from an Element with jQuery", + "Change the CSS of an Element Using jQuery", + "Disable an Element Using jQuery", + "Change Text Inside an Element Using jQuery", + "Remove an Element Using jQuery", + "Use appendTo to Move Elements with jQuery", + "Clone an Element Using jQuery", + "Target the Parent of an Element Using jQuery", + "Target the Children of an Element Using jQuery", + "Target a Specific Child of an Element Using jQuery", + "Target Even Elements Using jQuery", + "Use jQuery to Modify the Entire Page" + ], + "Sass": [ + "Store Data with Sass Variables", + "Nest CSS with Sass", + "Create Reusable CSS with Mixins", + "Use @if and @else to Add Logic To Your Styles", + "Use @for to Create a Sass Loop", + "Use @each to Map Over Items in a List", + "Apply a Style Until a Condition is Met with @while", + "Split Your Styles into Smaller Chunks with Partials", + "Extend One Set of CSS Styles to Another Element" + ], + "React": [ + "Create a Simple JSX Element", + "Create a Complex JSX Element", + "Add Comments in JSX", + "Render HTML Elements to the DOM", + "Define an HTML Class in JSX", + "Learn About Self-Closing JSX Tags", + "Create a Stateless Functional Component", + "Create a React Component", + "Create a Component with Composition", + "Use React to Render Nested Components", + "Compose React Components", + "Render a Class Component to the DOM", + "Write a React Component from Scratch", + "Pass Props to a Stateless Functional Component", + "Pass an Array as Props", + "Use Default Props", + "Override Default Props", + "Use PropTypes to Define the Props You Expect", + "Access Props Using this.props", + "Review Using Props with Stateless Functional Components", + "Create a Stateful Component", + "Render State in the User Interface", + "Render State in the User Interface Another Way", + "Set State with this.setState", + "Bind 'this' to a Class Method", + "Use State to Toggle an Element", + "Write a Simple Counter", + "Create a Controlled Input", + "Create a Controlled Form", + "Pass State as Props to Child Components", + "Pass a Callback as Props", + "Use the Lifecycle Method componentWillMount", + "Use the Lifecycle Method componentDidMount", + "Add Event Listeners", + "Manage Updates with Lifecycle Methods", + "Optimize Re-Renders with shouldComponentUpdate", + "Introducing Inline Styles", + "Add Inline Styles in React", + "Use Advanced JavaScript in React Render Method", + "Render with an If/Else Condition", + "Use && for a More Concise Conditional", + "Use a Ternary Expression for Conditional Rendering", + "Render Conditionally from Props", + "Change Inline CSS Conditionally Based on Component State", + "Use Array.map() to Dynamically Render Elements", + "Give Sibling Elements a Unique Key Attribute", + "Use Array.filter() to Dynamically Filter an Array", + "Render React on the Server with renderToString" + ], + "Redux": [ + "Create a Redux Store", + "Get State from the Redux Store", + "Define a Redux Action", + "Define an Action Creator", + "Dispatch an Action Event", + "Handle an Action in the Store", + "Use a Switch Statement to Handle Multiple Actions", + "Use const for Action Types", + "Register a Store Listener", + "Combine Multiple Reducers", + "Send Action Data to the Store", + "Use Middleware to Handle Asynchronous Actions", + "Write a Counter with Redux", + "Never Mutate State", + "Use the Spread Operator on Arrays", + "Remove an Item from an Array", + "Copy an Object with Object.assign" + ], + "React and Redux": [ + "Getting Started with React Redux", + "Manage State Locally First", + "Extract State Logic to Redux", + "Use Provider to Connect Redux to React", + "Map State to Props", + "Map Dispatch to Props", + "Connect Redux to React", + "Connect Redux to the Messages App", + "Extract Local State into Redux", + "Moving Forward From Here" + ], + "Front End Libraries Projects": [ + "Build a Random Quote Machine", + "Build a Markdown Previewer", + "Build a Drum Machine", + "Build a JavaScript Calculator", + "Build a Pomodoro Clock" + ] + }, + "Data Visualization Certification (300 hours)": { + "Data Visualization with D3": [ + "Add Document Elements with D3", + "Select a Group of Elements with D3", + "Work with Data in D3", + "Work with Dynamic Data in D3", + "Add Inline Styling to Elements", + "Change Styles Based on Data", + "Add Classes with D3", + "Update the Height of an Element Dynamically", + "Change the Presentation of a Bar Chart", + "Learn About SVG in D3", + "Display Shapes with SVG", + "Create a Bar for Each Data Point in the Set", + "Dynamically Set the Coordinates for Each Bar", + "Dynamically Change the Height of Each Bar", + "Invert SVG Elements", + "Change the Color of an SVG Element", + "Add Labels to D3 Elements", + "Style D3 Labels", + "Add a Hover Effect to a D3 Element", + "Add a Tooltip to a D3 Element", + "Create a Scatterplot with SVG Circles", + "Add Attributes to the Circle Elements", + "Add Labels to Scatter Plot Circles", + "Create a Linear Scale with D3", + "Set a Domain and a Range on a Scale", + "Use the d3.max and d3.min Functions to Find Minimum and Maximum Values in a Dataset", + "Use Dynamic Scales", + "Use a Pre-Defined Scale to Place Elements", + "Add Axes to a Visualization" + ], + "JSON APIs and Ajax": [ + "Handle Click Events with JavaScript using the onclick property", + "Change Text with click Events", + "Get JSON with the JavaScript XMLHttpRequest Method", + "Access the JSON Data from an API", + "Convert JSON Data to HTML", + "Render Images from Data Sources", + "Pre-filter JSON to Get the Data You Need", + "Get Geolocation Data to Find A User's GPS Coordinates", + "Post Data with the JavaScript XMLHttpRequest Method" + ], + "Data Visualization Projects": [ + "Visualize Data with a Bar Chart", + "Visualize Data with a Scatterplot Graph", + "Visualize Data with a Heat Map", + "Visualize Data with a Choropleth Map", + "Visualize Data with a Treemap Diagram" + ] + }, + "Apis And Microservices Certification (300 hours)": { + "Managing Packages with Npm": [ + "How to Use package.json, the Core of Any Node.js Project or npm Package", + "Add a Description to Your package.json", + "Add Keywords to Your package.json", + "Add a License to Your package.json", + "Add a Version to Your package.json", + "Expand Your Project with External Packages from npm", + "Manage npm Dependencies By Understanding Semantic Versioning", + "Use the Tilde-Character to Always Use the Latest Patch Version of a Dependency", + "Use the Caret-Character to Use the Latest Minor Version of a Dependency", + "Remove a Package from Your Dependencies" + ], + "Basic Node and Express": [ + "Meet the Node console", + "Start a Working Express Server", + "Serve an HTML File", + "Serve Static Assets", + "Serve JSON on a Specific Route", + "Use the .env File", + "Implement a Root-Level Request Logger Middleware", + "Chain Middleware to Create a Time Server", + "Get Route Parameter Input from the Client", + "Get Query Parameter Input from the Client", + "Use body-parser to Parse POST Requests", + "Get Data from POST Requests" + ], + "MongoDB and Mongoose": [ + "Install and Set Up Mongoose", + "Create a Model", + "Create and Save a Record of a Model", + "Create Many Records with model.create()", + "Use model.find() to Search Your Database", + "Use model.findOne() to Return a Single Matching Document from Your Database", + "Use model.findById() to Search Your Database By _id", + "Perform Classic Updates by Running Find, Edit, then Save", + "Perform New Updates on a Document Using model.findOneAndUpdate()", + "Delete One Document Using model.findByIdAndRemove", + "Delete Many Documents with model.remove()", + "Chain Search Query Helpers to Narrow Search Results" + ], + "Apis and Microservices Projects": [ + "Timestamp Microservice", + "Request Header Parser Microservice", + "URL Shortener Microservice", + "Exercise Tracker", + "File Metadata Microservice" + ] + }, + "Information Security And Quality Assurance Certification (300 hours)": { + "Information Security with HelmetJS": [ + "Install and Require Helmet", + "Hide Potentially Dangerous Information Using helmet.hidePoweredBy()", + "Mitigate the Risk of Clickjacking with helmet.frameguard()", + "Mitigate the Risk of Cross Site Scripting (XSS) Attacks with helmet.xssFilter()", + "Avoid Inferring the Response MIME Type with helmet.noSniff()", + "Prevent IE from Opening Untrusted HTML with helmet.ieNoOpen()", + "Ask Browsers to Access Your Site via HTTPS Only with helmet.hsts()", + "Disable DNS Prefetching with helmet.dnsPrefetchControl()", + "Disable Client-Side Caching with helmet.noCache()", + "Set a Content Security Policy with helmet.contentSecurityPolicy()", + "Configure Helmet Using the ‘parent’ helmet() Middleware", + "Understand BCrypt Hashes", + "Hash and Compare Passwords Asynchronously", + "Hash and Compare Passwords Synchronously" + ], + "Quality Assurance and Testing with Chai": [ + "Learn How JavaScript Assertions Work", + "Test if a Variable or Function is Defined", + "Use Assert.isOK and Assert.isNotOK", + "Test for Truthiness", + "Use the Double Equals to Assert Equality", + "Use the Triple Equals to Assert Strict Equality", + "Assert Deep Equality with .deepEqual and .notDeepEqual", + "Compare the Properties of Two Elements", + "Test if One Value is Below or At Least as Large as Another", + "Test if a Value Falls within a Specific Range", + "Test if a Value is an Array", + "Test if an Array Contains an Item", + "Test if a Value is a String", + "Test if a String Contains a Substring", + "Use Regular Expressions to Test a String", + "Test if an Object has a Property", + "Test if a Value is of a Specific Data Structure Type", + "Test if an Object is an Instance of a Constructor", + "Run Functional Tests on API Endpoints using Chai-HTTP", + "Run Functional Tests on API Endpoints using Chai-HTTP II", + "Run Functional Tests on an API Response using Chai-HTTP III - PUT method", + "Run Functional Tests on an API Response using Chai-HTTP IV - PUT method", + "Run Functional Tests using a Headless Browser", + "Run Functional Tests using a Headless Browser II" + ], + "Advanced Node and Express": [ + "Set up a Template Engine", + "Use a Template Engine's Powers", + "Set up Passport", + "Serialization of a User Object", + "Implement the Serialization of a Passport User", + "Authentication Strategies", + "How to Use Passport Strategies", + "Create New Middleware", + "How to Put a Profile Together", + "Logging a User Out", + "Registration of New Users", + "Hashing Your Passwords", + "Clean Up Your Project with Modules", + "Implementation of Social Authentication", + "Implementation of Social Authentication II", + "Implementation of Social Authentication III", + "Set up the Environment", + "Communicate by Emitting", + "Handle a Disconnect", + "Authentication with Socket.IO", + "Announce New Users", + "Send and Display Chat Messages" + ], + "Information Security and Quality Assurance Projects": [ + "Metric-Imperial Converter", + "Issue Tracker", + "Personal Library", + "Stock Price Checker", + "Anonymous Message Board" + ] + }, + "Coding Interview Prep (Thousands of hours of challenges)": { + "Algorithms": [ + "Find the Symmetric Difference", + "Inventory Update", + "No Repeats Please", + "Pairwise", + "Implement Bubble Sort", + "Implement Selection Sort", + "Implement Insertion Sort", + "Implement Quick Sort", + "Implement Merge Sort" + ], + "Data Structures": [ + "Typed Arrays", + "Learn how a Stack Works", + "Create a Stack Class", + "Create a Queue Class", + "Create a Priority Queue Class", + "Create a Circular Queue", + "Create a Set Class", + "Remove from a Set", + "Size of the Set", + "Perform a Union on Two Sets", + "Perform an Intersection on Two Sets of Data", + "Perform a Difference on Two Sets of Data", + "Perform a Subset Check on Two Sets of Data", + "Create and Add to Sets in ES6", + "Remove items from a set in ES6", + "Use .has and .size on an ES6 Set", + "Use Spread and Notes for ES5 Set() Integration", + "Create a Map Data Structure", + "Create an ES6 JavaScript Map", + "Create a Hash Table", + "Work with Nodes in a Linked List", + "Create a Linked List Class", + "Remove Elements from a Linked List", + "Search within a Linked List", + "Remove Elements from a Linked List by Index", + "Add Elements at a Specific Index in a Linked List", + "Create a Doubly Linked List", + "Reverse a Doubly Linked List", + "Find the Minimum and Maximum Value in a Binary Search Tree", + "Add a New Element to a Binary Search Tree", + "Check if an Element is Present in a Binary Search Tree", + "Find the Minimum and Maximum Height of a Binary Search Tree", + "Use Depth First Search in a Binary Search Tree", + "Use Breadth First Search in a Binary Search Tree", + "Delete a Leaf Node in a Binary Search Tree", + "Delete a Node with One Child in a Binary Search Tree", + "Delete a Node with Two Children in a Binary Search Tree", + "Invert a Binary Tree", + "Create a Trie Search Tree", + "Insert an Element into a Max Heap", + "Remove an Element from a Max Heap", + "Implement Heap Sort with a Min Heap", + "Adjacency List", + "Adjacency Matrix", + "Incidence Matrix", + "Breadth-First Search", + "Depth-First Search" + ], + "Take Home Projects": [ + "Show the Local Weather", + "Build a Wikipedia Viewer", + "Use the Twitch JSON API", + "Build an Image Search Abstraction Layer", + "Build a Tic Tac Toe Game", + "Build a Simon Game", + "Build a Camper Leaderboard", + "Build a Recipe Box", + "Build the Game of Life", + "Build a Roguelike Dungeon Crawler Game", + "P2P Video Chat Application", + "Show National Contiguity with a Force Directed Graph", + "Map Data Across the Globe", + "Manage a Book Trading Club", + "Build a Pinterest Clone", + "Build a Nightlife Coordination App", + "Chart the Stock Market", + "Build a Voting App", + "Build a Pong Game", + "Build a Light-Bright App" + ], + "Rosetta Code": [ + "100 doors", + "24 game", + "9 billion names of God the integer", + "ABC Problem", + "Abundant, deficient and perfect number classifications", + "Accumulator factory", + "Ackermann function", + "Align columns", + "Amicable pairs", + "Averages/Mode", + "Averages/Pythagorean means", + "Averages/Root mean square", + "Babbage problem", + "Balanced brackets", + "Circles of given radius through two points", + "Closest-pair problem", + "Combinations", + "Comma quibbling", + "Compare a list of strings", + "Convert seconds to compound duration", + "Count occurrences of a substring", + "Count the coins", + "Cramer's rule", + "Date format", + "Date manipulation", + "Day of the week", + "Deal cards for FreeCell", + "Deepcopy", + "Define a primitive data type", + "Department Numbers", + "Discordian date", + "Element-wise operations", + "Emirp primes", + "Entropy", + "Equilibrium index", + "Ethiopian multiplication", + "Euler method", + "Evaluate binomial coefficients", + "Execute a Markov algorithm", + "Execute Brain****", + "Extensible prime generator", + "Factorial", + "Factors of a Mersenne number", + "Factors of an integer", + "Farey sequence", + "Fibonacci n-step number sequences", + "Fibonacci sequence", + "Fibonacci word", + "Fractran", + "Gamma function", + "Gaussian elimination", + "General FizzBuzz", + "Generate lower case ASCII alphabet", + "Generator/Exponential", + "Gray code", + "Greatest common divisor", + "Greatest subsequential sum", + "Hailstone sequence", + "Happy numbers", + "Harshad or Niven series", + "Hash from two arrays", + "Hash join", + "Heronian triangles", + "Hofstadter Figure-Figure sequences", + "Hofstadter Q sequence", + "I before E except after C", + "IBAN", + "Identity matrix", + "Iterated digits squaring", + "Jaro distance", + "JortSort", + "Josephus problem", + "Sailors, coconuts and a monkey problem", + "SEDOLs", + "S-Expressions", + "Taxicab numbers", + "Tokenize a string with escaping", + "Topological sort", + "Top rank per group", + "Towers of Hanoi", + "Vector cross product", + "Vector dot product", + "Word wrap", + "Y combinator", + "Zeckendorf number representation", + "Zhang-Suen thinning algorithm", + "Zig-zag matrix" + ], + "Project Euler": [ + "Problem 1: Multiples of 3 and 5", + "Problem 2: Even Fibonacci Numbers", + "Problem 3: Largest prime factor", + "Problem 4: Largest palindrome product", + "Problem 5: Smallest multiple", + "Problem 6: Sum square difference", + "Problem 7: 10001st prime", + "Problem 8: Largest product in a series", + "Problem 9: Special Pythagorean triplet", + "Problem 10: Summation of primes", + "Problem 11: Largest product in a grid", + "Problem 12: Highly divisible triangular number", + "Problem 13: Large sum", + "Problem 14: Longest Collatz sequence", + "Problem 15: Lattice paths", + "Problem 16: Power digit sum", + "Problem 17: Number letter counts", + "Problem 18: Maximum path sum I", + "Problem 19: Counting Sundays", + "Problem 20: Factorial digit sum", + "Problem 21: Amicable numbers", + "Problem 22: Names scores", + "Problem 23: Non-abundant sums", + "Problem 24: Lexicographic permutations", + "Problem 25: 1000-digit Fibonacci number", + "Problem 26: Reciprocal cycles", + "Problem 27: Quadratic primes", + "Problem 28: Number spiral diagonals", + "Problem 29: Distinct powers", + "Problem 30: Digit n powers", + "Problem 31: Coin sums", + "Problem 32: Pandigital products", + "Problem 33: Digit cancelling fractions", + "Problem 34: Digit factorials", + "Problem 35: Circular primes", + "Problem 36: Double-base palindromes", + "Problem 37: Truncatable primes", + "Problem 38: Pandigital multiples", + "Problem 39: Integer right triangles", + "Problem 40: Champernowne's constant", + "Problem 41: Pandigital prime", + "Problem 42: Coded triangle numbers", + "Problem 43: Sub-string divisibility", + "Problem 44: Pentagon numbers", + "Problem 45: Triangular, pentagonal, and hexagonal", + "Problem 46: Goldbach's other conjecture", + "Problem 47: Distinct primes factors", + "Problem 48: Self powers", + "Problem 49: Prime permutations", + "Problem 50: Consecutive prime sum", + "Problem 51: Prime digit replacements", + "Problem 52: Permuted multiples", + "Problem 53: Combinatoric selections", + "Problem 54: Poker hands", + "Problem 55: Lychrel numbers", + "Problem 56: Powerful digit sum", + "Problem 57: Square root convergents", + "Problem 58: Spiral primes", + "Problem 59: XOR decryption", + "Problem 60: Prime pair sets", + "Problem 61: Cyclical figurate numbers", + "Problem 62: Cubic permutations", + "Problem 63: Powerful digit counts", + "Problem 64: Odd period square roots", + "Problem 65: Convergents of e", + "Problem 66: Diophantine equation", + "Problem 67: Maximum path sum II", + "Problem 68: Magic 5-gon ring", + "Problem 69: Totient maximum", + "Problem 70: Totient permutation", + "Problem 71: Ordered fractions", + "Problem 72: Counting fractions", + "Problem 73: Counting fractions in a range", + "Problem 74: Digit factorial chains", + "Problem 75: Singular integer right triangles", + "Problem 76: Counting summations", + "Problem 77: Prime summations", + "Problem 78: Coin partitions", + "Problem 79: Passcode derivation", + "Problem 80: Square root digital expansion", + "Problem 81: Path sum: two ways", + "Problem 82: Path sum: three ways", + "Problem 83: Path sum: four ways", + "Problem 84: Monopoly odds", + "Problem 85: Counting rectangles", + "Problem 86: Cuboid route", + "Problem 87: Prime power triples", + "Problem 88: Product-sum numbers", + "Problem 89: Roman numerals", + "Problem 90: Cube digit pairs", + "Problem 91: Right triangles with integer coordinates", + "Problem 92: Square digit chains", + "Problem 93: Arithmetic expressions", + "Problem 94: Almost equilateral triangles", + "Problem 95: Amicable chains", + "Problem 96: Su Doku", + "Problem 97: Large non-Mersenne prime", + "Problem 98: Anagramic squares", + "Problem 99: Largest exponential", + "Problem 100: Arranged probability", + "Problem 101: Optimum polynomial", + "Problem 102: Triangle containment", + "Problem 103: Special subset sums: optimum", + "Problem 104: Pandigital Fibonacci ends", + "Problem 105: Special subset sums: testing", + "Problem 106: Special subset sums: meta-testing", + "Problem 107: Minimal network", + "Problem 108: Diophantine Reciprocals I", + "Problem 109: Darts", + "Problem 110: Diophantine Reciprocals II", + "Problem 111: Primes with runs", + "Problem 112: Bouncy numbers", + "Problem 113: Non-bouncy numbers", + "Problem 114: Counting block combinations I", + "Problem 115: Counting block combinations II", + "Problem 116: Red, green or blue tiles", + "Problem 117: Red, green, and blue tiles", + "Problem 118: Pandigital prime sets", + "Problem 119: Digit power sum", + "Problem 120: Square remainders", + "Problem 121: Disc game prize fund", + "Problem 122: Efficient exponentiation", + "Problem 123: Prime square remainders", + "Problem 124: Ordered radicals", + "Problem 125: Palindromic sums", + "Problem 126: Cuboid layers", + "Problem 127: abc-hits", + "Problem 128: Hexagonal tile differences", + "Problem 129: Repunit divisibility", + "Problem 130: Composites with prime repunit property", + "Problem 131: Prime cube partnership", + "Problem 132: Large repunit factors", + "Problem 133: Repunit nonfactors", + "Problem 134: Prime pair connection", + "Problem 135: Same differences", + "Problem 136: Singleton difference", + "Problem 137: Fibonacci golden nuggets", + "Problem 138: Special isosceles triangles", + "Problem 139: Pythagorean tiles", + "Problem 140: Modified Fibonacci golden nuggets", + "Problem 141: Investigating progressive numbers, n, which are also square", + "Problem 142: Perfect Square Collection", + "Problem 143: Investigating the Torricelli point of a triangle", + "Problem 144: Investigating multiple reflections of a laser beam", + "Problem 145: How many reversible numbers are there below one-billion?", + "Problem 146: Investigating a Prime Pattern", + "Problem 147: Rectangles in cross-hatched grids", + "Problem 148: Exploring Pascal's triangle", + "Problem 149: Searching for a maximum-sum subsequence", + "Problem 150: Searching a triangular array for a sub-triangle having minimum-sum", + "Problem 151: Paper sheets of standard sizes: an expected-value problem", + "Problem 152: Writing 1/2 as a sum of inverse squares", + "Problem 153: Investigating Gaussian Integers", + "Problem 154: Exploring Pascal's pyramid", + "Problem 155: Counting Capacitor Circuits", + "Problem 156: Counting Digits", + "Problem 157: Solving the diophantine equation 1/a+1/b= p/10n", + "Problem 158: Exploring strings for which only one character comes lexicographically after its neighbour to the left", + "Problem 159: Digital root sums of factorisations", + "Problem 160: Factorial trailing digits", + "Problem 161: Triominoes", + "Problem 162: Hexadecimal numbers", + "Problem 163: Cross-hatched triangles", + "Problem 164: Numbers for which no three consecutive digits have a sum greater than a given value", + "Problem 165: Intersections", + "Problem 166: Criss Cross", + "Problem 167: Investigating Ulam sequences", + "Problem 168: Number Rotations", + "Problem 169: Exploring the number of different ways a number can be expressed as a sum of powers of 2", + "Problem 170: Find the largest 0 to 9 pandigital that can be formed by concatenating products", + "Problem 171: Finding numbers for which the sum of the squares of the digits is a square", + "Problem 172: Investigating numbers with few repeated digits", + "Problem 173: Using up to one million tiles how many different \"hollow\" square laminae can be formed?", + "Problem 174: Counting the number of \"hollow\" square laminae that can form one, two, three, ... distinct arrangements", + "Problem 175: Fractions involving the number of different ways a number can be expressed as a sum of powers of 2", + "Problem 176: Right-angled triangles that share a cathetus", + "Problem 177: Integer angled Quadrilaterals", + "Problem 178: Step Numbers", + "Problem 179: Consecutive positive divisors", + "Problem 180: Rational zeros of a function of three variables", + "Problem 181: Investigating in how many ways objects of two different colours can be grouped", + "Problem 182: RSA encryption", + "Problem 183: Maximum product of parts", + "Problem 184: Triangles containing the origin", + "Problem 185: Number Mind", + "Problem 186: Connectedness of a network", + "Problem 187: Semiprimes", + "Problem 188: The hyperexponentiation of a number", + "Problem 189: Tri-colouring a triangular grid", + "Problem 190: Maximising a weighted product", + "Problem 191: Prize Strings", + "Problem 192: Best Approximations", + "Problem 193: Squarefree Numbers", + "Problem 194: Coloured Configurations", + "Problem 195: Inscribed circles of triangles with one angle of 60 degrees", + "Problem 196: Prime triplets", + "Problem 197: Investigating the behaviour of a recursively defined sequence", + "Problem 198: Ambiguous Numbers", + "Problem 199: Iterative Circle Packing", + "Problem 200: Find the 200th prime-proof sqube containing the contiguous sub-string \"200\"", + "Problem 201: Subsets with a unique sum", + "Problem 202: Laserbeam", + "Problem 203: Squarefree Binomial Coefficients", + "Problem 204: Generalised Hamming Numbers", + "Problem 205: Dice Game", + "Problem 206: Concealed Square", + "Problem 207: Integer partition equations", + "Problem 208: Robot Walks", + "Problem 209: Circular Logic", + "Problem 210: Obtuse Angled Triangles", + "Problem 211: Divisor Square Sum", + "Problem 212: Combined Volume of Cuboids", + "Problem 213: Flea Circus", + "Problem 214: Totient Chains", + "Problem 215: Crack-free Walls", + "Problem 216: Investigating the primality of numbers of the form 2n2-1", + "Problem 217: Balanced Numbers", + "Problem 218: Perfect right-angled triangles", + "Problem 219: Skew-cost coding", + "Problem 220: Heighway Dragon", + "Problem 221: Alexandrian Integers", + "Problem 222: Sphere Packing", + "Problem 223: Almost right-angled triangles I", + "Problem 224: Almost right-angled triangles II", + "Problem 225: Tribonacci non-divisors", + "Problem 226: A Scoop of Blancmange", + "Problem 227: The Chase", + "Problem 228: Minkowski Sums", + "Problem 229: Four Representations using Squares", + "Problem 230: Fibonacci Words", + "Problem 231: The prime factorisation of binomial coefficients", + "Problem 232: The Race", + "Problem 233: Lattice points on a circle", + "Problem 234: Semidivisible numbers", + "Problem 235: An Arithmetic Geometric sequence", + "Problem 236: Luxury Hampers", + "Problem 237: Tours on a 4 x n playing board", + "Problem 238: Infinite string tour", + "Problem 239: Twenty-two Foolish Primes", + "Problem 240: Top Dice", + "Problem 241: Perfection Quotients", + "Problem 242: Odd Triplets", + "Problem 243: Resilience", + "Problem 244: Sliders", + "Problem 245: Coresilience", + "Problem 246: Tangents to an ellipse", + "Problem 247: Squares under a hyperbola", + "Problem 248: Numbers for which Euler’s totient function equals 13!", + "Problem 249: Prime Subset Sums", + "Problem 250: 250250", + "Problem 251: Cardano Triplets", + "Problem 252: Convex Holes", + "Problem 253: Tidying up", + "Problem 254: Sums of Digit Factorials", + "Problem 255: Rounded Square Roots", + "Problem 256: Tatami-Free Rooms", + "Problem 257: Angular Bisectors", + "Problem 258: A lagged Fibonacci sequence", + "Problem 259: Reachable Numbers", + "Problem 260: Stone Game", + "Problem 261: Pivotal Square Sums", + "Problem 262: Mountain Range", + "Problem 263: An engineers' dream come true", + "Problem 264: Triangle Centres", + "Problem 265: Binary Circles", + "Problem 266: Pseudo Square Root", + "Problem 267: Billionaire", + "Problem 268: Counting numbers with at least four distinct prime factors less than 100", + "Problem 269: Polynomials with at least one integer root", + "Problem 270: Cutting Squares", + "Problem 271: Modular Cubes, part 1", + "Problem 272: Modular Cubes, part 2", + "Problem 273: Sum of Squares", + "Problem 274: Divisibility Multipliers", + "Problem 275: Balanced Sculptures", + "Problem 276: Primitive Triangles", + "Problem 277: A Modified Collatz sequence", + "Problem 278: Linear Combinations of Semiprimes", + "Problem 279: Triangles with integral sides and an integral angle", + "Problem 280: Ant and seeds", + "Problem 281: Pizza Toppings", + "Problem 282: The Ackermann function", + "Problem 283: Integer sided triangles for which the area/perimeter ratio is integral", + "Problem 284: Steady Squares", + "Problem 285: Pythagorean odds", + "Problem 286: Scoring probabilities", + "Problem 287: Quadtree encoding (a simple compression algorithm)", + "Problem 288: An enormous factorial", + "Problem 289: Eulerian Cycles", + "Problem 290: Digital Signature", + "Problem 291: Panaitopol Primes", + "Problem 292: Pythagorean Polygons", + "Problem 293: Pseudo-Fortunate Numbers", + "Problem 294: Sum of digits - experience #23", + "Problem 295: Lenticular holes", + "Problem 296: Angular Bisector and Tangent", + "Problem 297: Zeckendorf Representation", + "Problem 298: Selective Amnesia", + "Problem 299: Three similar triangles", + "Problem 300: Protein folding", + "Problem 301: Nim", + "Problem 302: Strong Achilles Numbers", + "Problem 303: Multiples with small digits", + "Problem 304: Primonacci", + "Problem 305: Reflexive Position", + "Problem 306: Paper-strip Game", + "Problem 307: Chip Defects", + "Problem 308: An amazing Prime-generating Automaton", + "Problem 309: Integer Ladders", + "Problem 310: Nim Square", + "Problem 311: Biclinic Integral Quadrilaterals", + "Problem 312: Cyclic paths on Sierpiński graphs", + "Problem 313: Sliding game", + "Problem 314: The Mouse on the Moon", + "Problem 315: Digital root clocks", + "Problem 316: Numbers in decimal expansions", + "Problem 317: Firecracker", + "Problem 318: 2011 nines", + "Problem 319: Bounded Sequences", + "Problem 320: Factorials divisible by a huge integer", + "Problem 321: Swapping Counters", + "Problem 322: Binomial coefficients divisible by 10", + "Problem 323: Bitwise-OR operations on random integers", + "Problem 324: Building a tower", + "Problem 325: Stone Game II", + "Problem 326: Modulo Summations", + "Problem 327: Rooms of Doom", + "Problem 328: Lowest-cost Search", + "Problem 329: Prime Frog", + "Problem 330: Euler's Number", + "Problem 331: Cross flips", + "Problem 332: Spherical triangles", + "Problem 333: Special partitions", + "Problem 334: Spilling the beans", + "Problem 335: Gathering the beans", + "Problem 336: Maximix Arrangements", + "Problem 337: Totient Stairstep Sequences", + "Problem 338: Cutting Rectangular Grid Paper", + "Problem 339: Peredur fab Efrawg", + "Problem 340: Crazy Function", + "Problem 341: Golomb's self-describing sequence", + "Problem 342: The totient of a square is a cube", + "Problem 343: Fractional Sequences", + "Problem 344: Silver dollar game", + "Problem 345: Matrix Sum", + "Problem 346: Strong Repunits", + "Problem 347: Largest integer divisible by two primes", + "Problem 348: Sum of a square and a cube", + "Problem 349: Langton's ant", + "Problem 350: Constraining the least greatest and the greatest least", + "Problem 351: Hexagonal orchards", + "Problem 352: Blood tests", + "Problem 353: Risky moon", + "Problem 354: Distances in a bee's honeycomb", + "Problem 355: Maximal coprime subset", + "Problem 356: Largest roots of cubic polynomials", + "Problem 357: Prime generating integers", + "Problem 358: Cyclic numbers", + "Problem 359: Hilbert's New Hotel", + "Problem 360: Scary Sphere", + "Problem 361: Subsequence of Thue-Morse sequence", + "Problem 362: Squarefree factors", + "Problem 363: Bézier Curves", + "Problem 364: Comfortable distance", + "Problem 365: A huge binomial coefficient", + "Problem 366: Stone Game III", + "Problem 367: Bozo sort", + "Problem 368: A Kempner-like series", + "Problem 369: Badugi", + "Problem 370: Geometric triangles", + "Problem 371: Licence plates", + "Problem 372: Pencils of rays", + "Problem 373: Circumscribed Circles", + "Problem 374: Maximum Integer Partition Product", + "Problem 375: Minimum of subsequences", + "Problem 376: Nontransitive sets of dice", + "Problem 377: Sum of digits, experience 13", + "Problem 378: Triangle Triples", + "Problem 379: Least common multiple count", + "Problem 380: Amazing Mazes!", + "Problem 381: (prime-k) factorial", + "Problem 382: Generating polygons", + "Problem 383: Divisibility comparison between factorials", + "Problem 384: Rudin-Shapiro sequence", + "Problem 385: Ellipses inside triangles", + "Problem 386: Maximum length of an antichain", + "Problem 387: Harshad Numbers", + "Problem 388: Distinct Lines", + "Problem 389: Platonic Dice", + "Problem 390: Triangles with non rational sides and integral area", + "Problem 391: Hopping Game", + "Problem 392: Enmeshed unit circle", + "Problem 393: Migrating ants", + "Problem 394: Eating pie", + "Problem 395: Pythagorean tree", + "Problem 396: Weak Goodstein sequence", + "Problem 397: Triangle on parabola", + "Problem 398: Cutting rope", + "Problem 399: Squarefree Fibonacci Numbers", + "Problem 400: Fibonacci tree game", + "Problem 401: Sum of squares of divisors", + "Problem 402: Integer-valued polynomials", + "Problem 403: Lattice points enclosed by parabola and line", + "Problem 404: Crisscross Ellipses", + "Problem 405: A rectangular tiling", + "Problem 406: Guessing Game", + "Problem 407: Idempotents", + "Problem 408: Admissible paths through a grid", + "Problem 409: Nim Extreme", + "Problem 410: Circle and tangent line", + "Problem 411: Uphill paths", + "Problem 412: Gnomon numbering", + "Problem 413: One-child Numbers", + "Problem 414: Kaprekar constant", + "Problem 415: Titanic sets", + "Problem 416: A frog's trip", + "Problem 417: Reciprocal cycles II", + "Problem 418: Factorisation triples", + "Problem 419: Look and say sequence", + "Problem 420: 2x2 positive integer matrix", + "Problem 421: Prime factors of n15+1", + "Problem 422: Sequence of points on a hyperbola", + "Problem 423: Consecutive die throws", + "Problem 424: Kakuro", + "Problem 425: Prime connection", + "Problem 426: Box-ball system", + "Problem 427: n-sequences", + "Problem 428: Necklace of Circles", + "Problem 429: Sum of squares of unitary divisors", + "Problem 430: Range flips", + "Problem 431: Square Space Silo", + "Problem 432: Totient sum", + "Problem 433: Steps in Euclid's algorithm", + "Problem 434: Rigid graphs", + "Problem 435: Polynomials of Fibonacci numbers", + "Problem 436: Unfair wager", + "Problem 437: Fibonacci primitive roots", + "Problem 438: Integer part of polynomial equation's solutions", + "Problem 439: Sum of sum of divisors", + "Problem 440: GCD and Tiling", + "Problem 441: The inverse summation of coprime couples", + "Problem 442: Eleven-free integers", + "Problem 443: GCD sequence", + "Problem 444: The Roundtable Lottery", + "Problem 445: Retractions A", + "Problem 446: Retractions B", + "Problem 447: Retractions C", + "Problem 448: Average least common multiple", + "Problem 449: Chocolate covered candy", + "Problem 450: Hypocycloid and Lattice points", + "Problem 451: Modular inverses", + "Problem 452: Long Products", + "Problem 453: Lattice Quadrilaterals", + "Problem 454: Diophantine reciprocals III", + "Problem 455: Powers With Trailing Digits", + "Problem 456: Triangles containing the origin II", + "Problem 457: A polynomial modulo the square of a prime", + "Problem 458: Permutations of Project", + "Problem 459: Flipping game", + "Problem 460: An ant on the move", + "Problem 461: Almost Pi", + "Problem 462: Permutation of 3-smooth numbers", + "Problem 463: A weird recurrence relation", + "Problem 464: Möbius function and intervals", + "Problem 465: Polar polygons", + "Problem 466: Distinct terms in a multiplication table", + "Problem 467: Superinteger", + "Problem 468: Smooth divisors of binomial coefficients", + "Problem 469: Empty chairs", + "Problem 470: Super Ramvok", + "Problem 471: Triangle inscribed in ellipse", + "Problem 472: Comfortable Distance II", + "Problem 473: Phigital number base", + "Problem 474: Last digits of divisors", + "Problem 475: Music festival", + "Problem 476: Circle Packing II", + "Problem 477: Number Sequence Game", + "Problem 478: Mixtures", + "Problem 479: Roots on the Rise", + "Problem 480: The Last Question" + ] + } +}; + let challengeMap = lesson_map; + + // Inconsistent capitalization, thus map to lower case + completedChallenges = completedChallenges.map(x => x.toLowerCase()); + + // Loop through curriculum JSON + for (let section of Object.keys(challengeMap)) { + for (let subsection of Object.keys(challengeMap[section])) { + let numChallenges = challengeMap[section][subsection].length; + + // Inconsistent capitalization, thus map to lower case + let subsectionArray = challengeMap[section][subsection].map(x => x.toLowerCase()); + + let numCompleted = subsectionArray.reduce((acc, val) => { + return completedChallenges.indexOf(val) != -1 ? ++acc : acc; + }, 0); + + challengeMap[section][subsection] = `${Math.round(100 * numCompleted / numChallenges)}%`; + } + } + + return challengeMap; +}; // Writes the JSON object to a file let writeJSON = (json) => { const fs = require('fs'); - const outputFile = 'lesson_map.json'; + const outputFile = 'test.json'; // Format the json for readability const jsonString = JSON.stringify(json, null, 2); fs.writeFile(outputFile, jsonString, (err) => { // Report success / failure - const successMessage = 'FCC curriculum was written to ' + outputFile; + const successMessage = 'FCC progress was written to ' + outputFile; err ? console.log(err) : console.log(successMessage); }); }; // Runs the program let run = () => { - const url = 'https://learn.freecodecamp.org'; + const url = 'https://www.freecodecamp.org/magoun'; getHTML(url) - .then(createMap) + .then(parseHTML) + .then(getProgress) .then(writeJSON); }; From 855e7f007c44f1fc2ca77e6ab165cf0270c18bdc Mon Sep 17 00:00:00 2001 From: Creighton Magoun Date: Wed, 17 Oct 2018 20:54:34 +0000 Subject: [PATCH 12/37] Move logic for student progress shaping from wip.js to fcc_progress.js --- fcc-progress.js | 404 ------------ fcc_progress.js | 1603 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1603 insertions(+), 404 deletions(-) delete mode 100644 fcc-progress.js create mode 100644 fcc_progress.js diff --git a/fcc-progress.js b/fcc-progress.js deleted file mode 100644 index 9818ff7..0000000 --- a/fcc-progress.js +++ /dev/null @@ -1,404 +0,0 @@ -// ==UserScript== -// @name Get FCC Progress -// @namespace http://tampermonkey.net/ -// @version 0.1 -// @description try to take over the world! -// @author David Cohen -// @match https://www.freecodecamp.org/* -// @match https://www.freecodecamp.com/* -// @grant GM_registerMenuCommand -// @grant GM_setClipboard -// ==/UserScript== - -(function() { - function sanitizeText(text) { - return text.split('').map(char => char.toLowerCase()).filter(char => /[a-z]/.test(char)).join(''); - } - - Set.prototype.intersection = function(setB) { - var intersection = new Set(); - for (var elem of setB) { - if (this.has(elem)) { - intersection.add(elem); - } - } - return intersection; - } - - const sections = [ - [ - "HTML5 and CSS", - [ - "Learn How freeCodeCamp Works", - "Say Hello to HTML Elements", - "Headline with the h2 Element", - "Inform with the Paragraph Element", - "Uncomment HTML", - "Comment out HTML", - "Fill in the Blank with Placeholder Text", - "Delete HTML Elements", - "Change the Color of Text", - "Join a freeCodeCamp Study Group in Your City", - "Become a Supporter", - "Use CSS Selectors to Style Elements", - "Use a CSS Class to Style an Element", - "Style Multiple Elements with a CSS Class", - "Change the Font Size of an Element", - "Set the Font Family of an Element", - "Import a Google Font", - "Specify How Fonts Should Degrade", - "Add Images to your Website", - "Size your Images", - "Add Borders Around your Elements", - "Add Rounded Corners with a Border Radius", - "Make Circular Images with a Border Radius", - "Link to External Pages with Anchor Elements", - "Nest an Anchor Element within a Paragraph", - "Make Dead Links using the Hash Symbol", - "Turn an Image into a Link", - "Create a Bulleted Unordered List", - "Create an Ordered List", - "Create a Text Field", - "Add Placeholder Text to a Text Field", - "Create a Form Element", - "Add a Submit Button to a Form", - "Use HTML5 to Require a Field", - "Create a Set of Radio Buttons", - "Create a Set of Checkboxes", - "Check Radio Buttons and Checkboxes by Default", - "Nest Many Elements within a Single Div Element", - "Give a Background Color to a Div Element", - "Set the ID of an Element", - "Use an ID Attribute to Style an Element", - "Adjusting the Padding of an Element", - "Adjust the Margin of an Element", - "Add a Negative Margin to an Element", - "Add Different Padding to Each Side of an Element", - "Add Different Margins to Each Side of an Element", - "Use Clockwise Notation to Specify the Padding of an Element", - "Use Clockwise Notation to Specify the Margin of an Element", - "Style the HTML Body Element", - "Inherit Styles from the Body Element", - "Prioritize One Style Over Another", - "Override Styles in Subsequent CSS", - "Override Class Declarations by Styling ID Attributes", - "Override Class Declarations with Inline Styles", - "Override All Other Styles by using Important", - "Use Hex Code for Specific Colors", - "Use Hex Code to Mix Colors", - "Use Abbreviated Hex Code", - "Use RGB values to Color Elements", - "Use RGB to Mix Colors" - ] - ], - [ - "Responsive Design with Bootstrap", - [ - "Use Responsive Design with Bootstrap Fluid Containers", - "Make Images Mobile Responsive", - "Center Text with Bootstrap", - "Create a Bootstrap Button", - "Create a Block Element Bootstrap Button", - "Taste the Bootstrap Button Color Rainbow", - "Call out Optional Actions with Button Info", - "Warn your Users of a Dangerous Action", - "Use the Bootstrap Grid to Put Elements Side By Side", - "Ditch Custom CSS for Bootstrap", - "Use Spans for Inline Elements", - "Create a Custom Heading", - "Add Font Awesome Icons to our Buttons", - "Add Font Awesome Icons to all of our Buttons", - "Responsively Style Radio Buttons", - "Responsively Style Checkboxes", - "Style Text Inputs as Form Controls", - "Line up Form Elements Responsively with Bootstrap", - "Create a Bootstrap Headline", - "House our page within a Bootstrap Container Fluid Div", - "Create a Bootstrap Row", - "Split your Bootstrap Row", - "Create Bootstrap Wells", - "Add Elements within your Bootstrap Wells", - "Apply the Default Bootstrap Button Style", - "Create a Class to Target with jQuery Selectors", - "Add ID Attributes to Bootstrap Elements", - "Label Bootstrap Wells", - "Give Each Element a Unique ID", - "Label Bootstrap Buttons", - "Use Comments to Clarify Code" - ] - ], - [ - "jQuery", - [ - "Learn how Script Tags and Document Ready Work", - "Target HTML Elements with Selectors Using jQuery", - "Target Elements by Class Using jQuery", - "Target Elements by ID Using jQuery", - "Delete your jQuery Functions", - "Target the same element with multiple jQuery Selectors", - "Remove Classes from an element with jQuery", - "Change the CSS of an Element Using jQuery", - "Disable an Element Using jQuery", - "Change Text Inside an Element Using jQuery", - "Remove an Element Using jQuery", - "Use appendTo to Move Elements with jQuery", - "Clone an Element Using jQuery", - "Target the Parent of an Element Using jQuery", - "Target the Children of an Element Using jQuery", - "Target a Specific Child of an Element Using jQuery", - "Target Even Numbered Elements Using jQuery", - "Use jQuery to Modify the Entire Page" - ] - ], - [ - "Basic Front End Development Projects", - [ - "Get Set for our Front End Development Projects", - "Build a Tribute Page", - "Build a Personal Portfolio Webpage" - ] - ], - [ - "Basic JavaScript", - [ - "Comment your JavaScript Code", - "Declare JavaScript Variables", - "Storing Values with the Assignment Operator", - "Initializing Variables with the Assignment Operator", - "Understanding Uninitialized Variables", - "Understanding Case Sensitivity in Variables", - "Add Two Numbers with JavaScript", - "Subtract One Number from Another with JavaScript", - "Multiply Two Numbers with JavaScript", - "Divide One Number by Another with JavaScript", - "Increment a Number with JavaScript", - "Decrement a Number with JavaScript", - "Create Decimal Numbers with JavaScript", - "Multiply Two Decimals with JavaScript", - "Divide one Decimal by Another with JavaScript", - "Finding a Remainder in JavaScript", - "Compound Assignment With Augmented Addition", - "Compound Assignment With Augmented Subtraction", - "Compound Assignment With Augmented Multiplication", - "Compound Assignment With Augmented Division", - "Convert Celsius to Fahrenheit", - "Declare String Variables", - "Escaping Literal Quotes in Strings", - "Quoting Strings with Single Quotes", - "Escape Sequences in Strings", - "Concatenating Strings with Plus Operator", - "Concatenating Strings with the Plus Equals Operator", - "Constructing Strings with Variables", - "Appending Variables to Strings", - "Find the Length of a String", - "Use Bracket Notation to Find the First Character in a String", - "Understand String Immutability", - "Use Bracket Notation to Find the Nth Character in a String", - "Use Bracket Notation to Find the Last Character in a String", - "Use Bracket Notation to Find the Nth-to-Last Character in a String", - "Word Blanks", - "Store Multiple Values in one Variable using JavaScript Arrays", - "Nest one Array within Another Array", - "Access Array Data with Indexes", - "Modify Array Data With Indexes", - "Access Multi-Dimensional Arrays With Indexes", - "Manipulate Arrays With push()", - "Manipulate Arrays With pop()", - "Manipulate Arrays With shift()", - "Manipulate Arrays With unshift()", - "Shopping List", - "Write Reusable JavaScript with Functions", - "Passing Values to Functions with Arguments", - "Global Scope and Functions", - "Local Scope and Functions", - "Global vs. Local Scope in Functions", - "Return a Value from a Function with Return", - "Assignment with a Returned Value", - "Stand in Line", - "Understanding Boolean Values", - "Use Conditional Logic with If Statements", - "Comparison with the Equality Operator", - "Comparison with the Strict Equality Operator", - "Comparison with the Inequality Operator", - "Comparison with the Strict Inequality Operator", - "Comparison with the Greater Than Operator", - "Comparison with the Greater Than Or Equal To Operator", - "Comparison with the Less Than Operator", - "Comparison with the Less Than Or Equal To Operator", - "Comparisons with the Logical And Operator", - "Comparisons with the Logical Or Operator", - "Introducing Else Statements", - "Introducing Else If Statements", - "Logical Order in If Else Statements", - "Chaining If Else Statements", - "Golf Code", - "Selecting from many options with Switch Statements", - "Adding a default option in Switch statements", - "Multiple Identical Options in Switch Statements", - "Replacing If Else Chains with Switch", - "Returning Boolean Values from Functions", - "Return Early Pattern for Functions", - "Counting Cards", - "Build JavaScript Objects", - "Accessing Objects Properties with the Dot Operator", - "Accessing Objects Properties with Bracket Notation", - "Accessing Objects Properties with Variables", - "Updating Object Properties", - "Add New Properties to a JavaScript Object", - "Delete Properties from a JavaScript Object", - "Using Objects for Lookups", - "Testing Objects for Properties", - "Manipulating Complex Objects", - "Accessing Nested Objects", - "Accessing Nested Arrays", - "Iterate with JavaScript For Loops", - "Iterate Odd Numbers With a For Loop", - "Count Backwards With a For Loop", - "Iterate Through an Array with a For Loop", - "Nesting For Loops", - "Iterate with JavaScript While Loops", - "Profile Lookup", - "Generate Random Fractions with JavaScript", - "Generate Random Whole Numbers with JavaScript", - "Generate Random Whole Numbers within a Range", - "Sift through Text with Regular Expressions", - "Find Numbers with Regular Expressions", - "Find Whitespace with Regular Expressions", - "Invert Regular Expression Matches with JavaScript" - ] - ], - [ - "Object Oriented and Functional Programming", - [ - "Declare JavaScript Objects as Variables", - "Construct JavaScript Objects with Functions", - "Make Instances of Objects with a Constructor Function", - "Make Unique Objects by Passing Parameters to our Constructor", - "Make Object Properties Private", - "Iterate over Arrays with map", - "Condense arrays with reduce", - "Filter Arrays with filter", - "Sort Arrays with sort", - "Reverse Arrays with reverse", - "Concatenate Arrays with concat", - "Split Strings with split", - "Join Strings with join" - ] - ], - [ - "Basic Algorithm Scripting", - [ - "Get Set for our Algorithm Challenges", - "Reverse a String", - "Factorialize a Number", - "Check for Palindromes", - "Find the Longest Word in a String", - "Title Case a Sentence", - "Return Largest Numbers in Arrays", - "Confirm the Ending", - "Repeat a string repeat a string", - "Truncate a string", - "Chunky Monkey", - "Slasher Flick", - "Mutations", - "Falsy Bouncer", - "Seek and Destroy", - "Where do I belong", - "Caesars Cipher" - ] - ], - [ - "JSON APIs and Ajax", - [ - "Trigger Click Events with jQuery", - "Change Text with Click Events", - "Get JSON with the jQuery getJSON Method", - "Convert JSON Data to HTML", - "Render Images from Data Sources", - "Prefilter JSON", - "Get Geo-location Data" - ] - ], - [ - "Intermediate Front End Development Projects", - [ - "Build a Random Quote Machine", - "Show the Local Weather", - "Build a Wikipedia Viewer", - "Use the Twitch.tv JSON API" - ] - ], - [ - "Intermediate Algorithm Scripting", - [ - "Sum All Numbers in a Range", - "Diff Two Arrays", - "Roman Numeral Converter", - "Wherefore art thou", - "Search and Replace", - "Pig Latin", - "DNA Pairing", - "Missing letters", - "Boo who", - "Sorted Union", - "Convert HTML Entities", - "Spinal Tap Case", - "Sum All Odd Fibonacci Numbers", - "Sum All Primes", - "Smallest Common Multiple", - "Finders Keepers", - "Drop it", - "Steamroller", - "Binary Agents", - "Everything Be True", - "Arguments Optional" - ] - ], - [ - "Advanced Algorithm Scripting", - [ - "Validate US Telephone Numbers", - "Record Collection", - "Symmetric Difference", - "Exact Change", - "Inventory Update", - "No repeats please", - "Make a Person", - "Map the Debris", - "Pairwise" - ] - ], - [ - "Advanced Front End Development Projects", - [ - "Build a JavaScript Calculator", - "Build a Pomodoro Clock", - "Build a Tic Tac Toe Game", - "Build a Simon Game" - ] - ] - ]; - - - // total complete over all sections - const arrComplete = Array.from(document.querySelectorAll('body > div:nth-child(10) > div.col-md-12 > div > table > tbody > tr > td:nth-child(1)')).map(x => sanitizeText(x.innerText)); - const setComplete = new Set(arrComplete); - - const allSectionsProgress = sections.map(section => { - const assignments = section[1].map(sanitizeText); - // this is the important part... - const sectionProgress = setComplete.intersection(assignments).size; - - // expressed as a percentage: - return `${Math.round(100 * sectionProgress / assignments.length)}%`; - }); - - function copyProgressRow(){ - // join w/ tab to copy text suitable for pasting into a spreadsheet - const row = allSectionsProgress.join('\t'); - GM_setClipboard(row, { type: 'text', mimetype: 'text/plain'}); - } - - GM_registerMenuCommand("Copy Student Progress", copyProgressRow); - -})(); \ No newline at end of file diff --git a/fcc_progress.js b/fcc_progress.js new file mode 100644 index 0000000..3c1679b --- /dev/null +++ b/fcc_progress.js @@ -0,0 +1,1603 @@ +/** + * Scrapes a user profile from https://www.freecodecamp.org/{username} and + * compares completed challenges against the FCC curriculum. The results are + * output in JSON format to fcc_progress.json + * + * The FCC curriculum is gathered using lesson_map.js. + * + * Usage: node fcc_progress.js + * + * Set output file in writeJSON() + * Set user to scrape in run() + * + */ + +// Fetch html using puppeteer +let getHTML = async (url) => { + const puppeteer = require('puppeteer'); + + const browser = await puppeteer.launch(); + const page = await browser.newPage(); + + // Wait for React components to load + await page.goto(url, { waitUntil: 'networkidle0'}); + + const html = await page.content(); + await browser.close(); + return html; +}; + +// Parse the HTML for completed challenges +// Returns an array of challenge names +let parseHTML = (html) => { + const $ = require('cheerio').load(html); + let challenges = []; + + $('tr', 'tbody').each(function (index, element) { + let challenge = $(this).find('a').text(); + challenges.push(challenge); + }); + + return challenges; +}; + +// Compare progress to overall curriculum +// Returns a JSON object +let getProgress = (completedChallenges) => { + // Hard coded, but can be pulled dynamically with lesson_map.js + const lesson_map = { + "Responsive Web Design Certification (300 hours)": { + "Basic HTML and HTML5": [ + "Say Hello to HTML Elements", + "Headline with the h2 Element", + "Inform with the Paragraph Element", + "Fill in the Blank with Placeholder Text", + "Uncomment HTML", + "Comment out HTML", + "Delete HTML Elements", + "Introduction to HTML5 Elements", + "Add Images to Your Website", + "Link to External Pages with Anchor Elements", + "Link to Internal Sections of a Page with Anchor Elements", + "Nest an Anchor Element within a Paragraph", + "Make Dead Links Using the Hash Symbol", + "Turn an Image into a Link", + "Create a Bulleted Unordered List", + "Create an Ordered List", + "Create a Text Field", + "Add Placeholder Text to a Text Field", + "Create a Form Element", + "Add a Submit Button to a Form", + "Use HTML5 to Require a Field", + "Create a Set of Radio Buttons", + "Create a Set of Checkboxes", + "Check Radio Buttons and Checkboxes by Default", + "Nest Many Elements within a Single div Element", + "Declare the Doctype of an HTML Document", + "Define the Head and Body of an HTML Document" + ], + "Basic CSS": [ + "Change the Color of Text", + "Use CSS Selectors to Style Elements", + "Use a CSS Class to Style an Element", + "Style Multiple Elements with a CSS Class", + "Change the Font Size of an Element", + "Set the Font Family of an Element", + "Import a Google Font", + "Specify How Fonts Should Degrade", + "Size Your Images", + "Add Borders Around Your Elements", + "Add Rounded Corners with border-radius", + "Make Circular Images with a border-radius", + "Give a Background Color to a div Element", + "Set the id of an Element", + "Use an id Attribute to Style an Element", + "Adjust the Padding of an Element", + "Adjust the Margin of an Element", + "Add a Negative Margin to an Element", + "Add Different Padding to Each Side of an Element", + "Add Different Margins to Each Side of an Element", + "Use Clockwise Notation to Specify the Padding of an Element", + "Use Clockwise Notation to Specify the Margin of an Element", + "Use Attribute Selectors to Style Elements", + "Understand Absolute versus Relative Units", + "Style the HTML Body Element", + "Inherit Styles from the Body Element", + "Prioritize One Style Over Another", + "Override Styles in Subsequent CSS", + "Override Class Declarations by Styling ID Attributes", + "Override Class Declarations with Inline Styles", + "Override All Other Styles by using Important", + "Use Hex Code for Specific Colors", + "Use Hex Code to Mix Colors", + "Use Abbreviated Hex Code", + "Use RGB values to Color Elements", + "Use RGB to Mix Colors", + "Use CSS Variables to change several elements at once", + "Create a custom CSS Variable", + "Use a custom CSS Variable", + "Attach a Fallback value to a CSS Variable", + "Improve Compatibility with Browser Fallbacks", + "Cascading CSS variables", + "Change a variable for a specific area", + "Use a media query to change a variable" + ], + "Applied Visual Design": [ + "Create Visual Balance Using the text-align Property", + "Adjust the Width of an Element Using the width Property", + "Adjust the Height of an Element Using the height Property", + "Use the strong Tag to Make Text Bold", + "Use the u Tag to Underline Text", + "Use the em Tag to Italicize Text", + "Use the s Tag to Strikethrough Text", + "Create a Horizontal Line Using the hr Element", + "Adjust the background-color Property of Text", + "Adjust the Size of a Header Versus a Paragraph Tag", + "Add a box-shadow to a Card-like Element", + "Decrease the Opacity of an Element", + "Use the text-transform Property to Make Text Uppercase", + "Set the font-size for Multiple Heading Elements", + "Set the font-weight for Multiple Heading Elements", + "Set the font-size of Paragraph Text", + "Set the line-height of Paragraphs", + "Adjust the Hover State of an Anchor Tag", + "Change an Element's Relative Position", + "Move a Relatively Positioned Element with CSS Offsets", + "Lock an Element to its Parent with Absolute Positioning", + "Lock an Element to the Browser Window with Fixed Positioning", + "Push Elements Left or Right with the float Property", + "Change the Position of Overlapping Elements with the z-index Property", + "Center an Element Horizontally Using the margin Property", + "Learn about Complementary Colors", + "Learn about Tertiary Colors", + "Adjust the Color of Various Elements to Complementary Colors", + "Adjust the Hue of a Color", + "Adjust the Tone of a Color", + "Create a Gradual CSS Linear Gradient", + "Use a CSS Linear Gradient to Create a Striped Element", + "Create Texture by Adding a Subtle Pattern as a Background Image", + "Use the CSS Transform scale Property to Change the Size of an Element", + "Use the CSS Transform scale Property to Scale an Element on Hover", + "Use the CSS Transform Property skewX to Skew an Element Along the X-Axis", + "Use the CSS Transform Property skewY to Skew an Element Along the Y-Axis", + "Create a Graphic Using CSS", + "Create a More Complex Shape Using CSS and HTML", + "Learn How the CSS @keyframes and animation Properties Work", + "Use CSS Animation to Change the Hover State of a Button", + "Modify Fill Mode of an Animation", + "Create Movement Using CSS Animation", + "Create Visual Direction by Fading an Element from Left to Right", + "Animate Elements Continually Using an Infinite Animation Count", + "Make a CSS Heartbeat using an Infinite Animation Count", + "Animate Elements at Variable Rates", + "Animate Multiple Elements at Variable Rates", + "Change Animation Timing with Keywords", + "Learn How Bezier Curves Work", + "Use a Bezier Curve to Move a Graphic", + "Make Motion More Natural Using a Bezier Curve" + ], + "Applied Accessibility": [ + "Add a Text Alternative to Images for Visually Impaired Accessibility", + "Know When Alt Text Should be Left Blank", + "Use Headings to Show Hierarchical Relationships of Content", + "Jump Straight to the Content Using the main Element", + "Wrap Content in the article Element", + "Make Screen Reader Navigation Easier with the header Landmark", + "Make Screen Reader Navigation Easier with the nav Landmark", + "Make Screen Reader Navigation Easier with the footer Landmark", + "Improve Accessibility of Audio Content with the audio Element", + "Improve Chart Accessibility with the figure Element", + "Improve Form Field Accessibility with the label Element", + "Wrap Radio Buttons in a fieldset Element for Better Accessibility", + "Add an Accessible Date Picker", + "Standardize Times with the HTML5 datetime Attribute", + "Make Elements Only Visible to a Screen Reader by Using Custom CSS", + "Improve Readability with High Contrast Text", + "Avoid Colorblindness Issues by Using Sufficient Contrast", + "Avoid Colorblindness Issues by Carefully Choosing Colors that Convey Information", + "Give Links Meaning by Using Descriptive Link Text", + "Make Links Navigatable with HTML Access Keys", + "Use tabindex to Add Keyboard Focus to an Element", + "Use tabindex to Specify the Order of Keyboard Focus for Several Elements" + ], + "Responsive Web Design Principles": [ + "Create a Media Query", + "Make an Image Responsive", + "Use a Retina Image for Higher Resolution Displays", + "Make Typography Responsive" + ], + "CSS Flexbox": [ + "Use display: flex to Position Two Boxes", + "Add Flex Superpowers to the Tweet Embed", + "Use the flex-direction Property to Make a Row", + "Apply the flex-direction Property to Create Rows in the Tweet Embed", + "Use the flex-direction Property to Make a Column", + "Apply the flex-direction Property to Create a Column in the Tweet Embed", + "Align Elements Using the justify-content Property", + "Use the justify-content Property in the Tweet Embed", + "Align Elements Using the align-items Property", + "Use the align-items Property in the Tweet Embed", + "Use the flex-wrap Property to Wrap a Row or Column", + "Use the flex-shrink Property to Shrink Items", + "Use the flex-grow Property to Expand Items", + "Use the flex-basis Property to Set the Initial Size of an Item", + "Use the flex Shorthand Property", + "Use the order Property to Rearrange Items", + "Use the align-self Property" + ], + "CSS Grid": [ + "Create Your First CSS Grid", + "Add Columns with grid-template-columns", + "Add Rows with grid-template-rows", + "Use CSS Grid units to Change the Size of Columns and Rows", + "Create a Column Gap Using grid-column-gap", + "Create a Row Gap using grid-row-gap", + "Add Gaps Faster with grid-gap", + "Use grid-column to Control Spacing", + "Use grid-row to Control Spacing", + "Align an Item Horizontally using justify-self", + "Align an Item Vertically using align-self", + "Align All Items Horizontally using justify-items", + "Align All Items Vertically using align-items", + "Divide the Grid Into an Area Template", + "Place Items in Grid Areas Using the grid-area Property", + "Use grid-area Without Creating an Areas Template", + "Reduce Repetition Using the repeat Function", + "Limit Item Size Using the minmax Function", + "Create Flexible Layouts Using auto-fill", + "Create Flexible Layouts Using auto-fit", + "Use Media Queries to Create Responsive Layouts", + "Create Grids within Grids" + ], + "Responsive Web Design Projects": [ + "Build a Tribute Page", + "Build a Survey Form", + "Build a Product Landing Page", + "Build a Technical Documentation Page", + "Build a Personal Portfolio Webpage" + ] + }, + "Javascript Algorithms And Data Structures Certification (300 hours)": { + "Basic JavaScript": [ + "Comment Your JavaScript Code", + "Declare JavaScript Variables", + "Storing Values with the Assignment Operator", + "Initializing Variables with the Assignment Operator", + "Understanding Uninitialized Variables", + "Understanding Case Sensitivity in Variables", + "Add Two Numbers with JavaScript", + "Subtract One Number from Another with JavaScript", + "Multiply Two Numbers with JavaScript", + "Divide One Number by Another with JavaScript", + "Increment a Number with JavaScript", + "Decrement a Number with JavaScript", + "Create Decimal Numbers with JavaScript", + "Multiply Two Decimals with JavaScript", + "Divide One Decimal by Another with JavaScript", + "Finding a Remainder in JavaScript", + "Compound Assignment With Augmented Addition", + "Compound Assignment With Augmented Subtraction", + "Compound Assignment With Augmented Multiplication", + "Compound Assignment With Augmented Division", + "Declare String Variables", + "Escaping Literal Quotes in Strings", + "Quoting Strings with Single Quotes", + "Escape Sequences in Strings", + "Concatenating Strings with Plus Operator", + "Concatenating Strings with the Plus Equals Operator", + "Constructing Strings with Variables", + "Appending Variables to Strings", + "Find the Length of a String", + "Use Bracket Notation to Find the First Character in a String", + "Understand String Immutability", + "Use Bracket Notation to Find the Nth Character in a String", + "Use Bracket Notation to Find the Last Character in a String", + "Use Bracket Notation to Find the Nth-to-Last Character in a String", + "Word Blanks", + "Store Multiple Values in one Variable using JavaScript Arrays", + "Nest one Array within Another Array", + "Access Array Data with Indexes", + "Modify Array Data With Indexes", + "Access Multi-Dimensional Arrays With Indexes", + "Manipulate Arrays With push()", + "Manipulate Arrays With pop()", + "Manipulate Arrays With shift()", + "Manipulate Arrays With unshift()", + "Shopping List", + "Write Reusable JavaScript with Functions", + "Passing Values to Functions with Arguments", + "Global Scope and Functions", + "Local Scope and Functions", + "Global vs. Local Scope in Functions", + "Return a Value from a Function with Return", + "Understanding Undefined Value returned from a Function", + "Assignment with a Returned Value", + "Stand in Line", + "Understanding Boolean Values", + "Use Conditional Logic with If Statements", + "Comparison with the Equality Operator", + "Comparison with the Strict Equality Operator", + "Practice comparing different values", + "Comparison with the Inequality Operator", + "Comparison with the Strict Inequality Operator", + "Comparison with the Greater Than Operator", + "Comparison with the Greater Than Or Equal To Operator", + "Comparison with the Less Than Operator", + "Comparison with the Less Than Or Equal To Operator", + "Comparisons with the Logical And Operator", + "Comparisons with the Logical Or Operator", + "Introducing Else Statements", + "Introducing Else If Statements", + "Logical Order in If Else Statements", + "Chaining If Else Statements", + "Golf Code", + "Selecting from Many Options with Switch Statements", + "Adding a Default Option in Switch Statements", + "Multiple Identical Options in Switch Statements", + "Replacing If Else Chains with Switch", + "Returning Boolean Values from Functions", + "Return Early Pattern for Functions", + "Counting Cards", + "Build JavaScript Objects", + "Accessing Object Properties with Dot Notation", + "Accessing Object Properties with Bracket Notation", + "Accessing Object Properties with Variables", + "Updating Object Properties", + "Add New Properties to a JavaScript Object", + "Delete Properties from a JavaScript Object", + "Using Objects for Lookups", + "Testing Objects for Properties", + "Manipulating Complex Objects", + "Accessing Nested Objects", + "Accessing Nested Arrays", + "Record Collection", + "Iterate with JavaScript While Loops", + "Iterate with JavaScript For Loops", + "Iterate Odd Numbers With a For Loop", + "Count Backwards With a For Loop", + "Iterate Through an Array with a For Loop", + "Nesting For Loops", + "Iterate with JavaScript Do...While Loops", + "Profile Lookup", + "Generate Random Fractions with JavaScript", + "Generate Random Whole Numbers with JavaScript", + "Generate Random Whole Numbers within a Range", + "Use the parseInt Function", + "Use the parseInt Function with a Radix", + "Use the Conditional (Ternary) Operator", + "Use Multiple Conditional (Ternary) Operators" + ], + "ES6": [ + "Explore Differences Between the var and let Keywords", + "Compare Scopes of the var and let Keywords", + "Declare a Read-Only Variable with the const Keyword", + "Mutate an Array Declared with const", + "Prevent Object Mutation", + "Use Arrow Functions to Write Concise Anonymous Functions", + "Write Arrow Functions with Parameters", + "Write Higher Order Arrow Functions", + "Set Default Parameters for Your Functions", + "Use the Rest Operator with Function Parameters", + "Use the Spread Operator to Evaluate Arrays In-Place", + "Use Destructuring Assignment to Assign Variables from Objects", + "Use Destructuring Assignment to Assign Variables from Nested Objects", + "Use Destructuring Assignment to Assign Variables from Arrays", + "Use Destructuring Assignment with the Rest Operator to Reassign Array Elements", + "Use Destructuring Assignment to Pass an Object as a Function's Parameters", + "Create Strings using Template Literals", + "Write Concise Object Literal Declarations Using Simple Fields", + "Write Concise Declarative Functions with ES6", + "Use class Syntax to Define a Constructor Function", + "Use getters and setters to Control Access to an Object", + "Understand the Differences Between import and require", + "Use export to Reuse a Code Block", + "Use * to Import Everything from a File", + "Create an Export Fallback with export default", + "Import a Default Export" + ], + "Regular Expressions": [ + "Using the Test Method", + "Match Literal Strings", + "Match a Literal String with Different Possibilities", + "Ignore Case While Matching", + "Extract Matches", + "Find More Than the First Match", + "Match Anything with Wildcard Period", + "Match Single Character with Multiple Possibilities", + "Match Letters of the Alphabet", + "Match Numbers and Letters of the Alphabet", + "Match Single Characters Not Specified", + "Match Characters that Occur One or More Times", + "Match Characters that Occur Zero or More Times", + "Find Characters with Lazy Matching", + "Find One or More Criminals in a Hunt", + "Match Beginning String Patterns", + "Match Ending String Patterns", + "Match All Letters and Numbers", + "Match Everything But Letters and Numbers", + "Match All Numbers", + "Match All Non-Numbers", + "Restrict Possible Usernames", + "Match Whitespace", + "Match Non-Whitespace Characters", + "Specify Upper and Lower Number of Matches", + "Specify Only the Lower Number of Matches", + "Specify Exact Number of Matches", + "Check for All or None", + "Positive and Negative Lookahead", + "Reuse Patterns Using Capture Groups", + "Use Capture Groups to Search and Replace", + "Remove Whitespace from Start and End" + ], + "Debugging": [ + "Use the JavaScript Console to Check the Value of a Variable", + "Understanding the Differences between the freeCodeCamp and Browser Console", + "Use typeof to Check the Type of a Variable", + "Catch Misspelled Variable and Function Names", + "Catch Unclosed Parentheses, Brackets, Braces and Quotes", + "Catch Mixed Usage of Single and Double Quotes", + "Catch Use of Assignment Operator Instead of Equality Operator", + "Catch Missing Open and Closing Parenthesis After a Function Call", + "Catch Arguments Passed in the Wrong Order When Calling a Function", + "Catch Off By One Errors When Using Indexing", + "Use Caution When Reinitializing Variables Inside a Loop", + "Prevent Infinite Loops with a Valid Terminal Condition" + ], + "Basic Data Structures": [ + "Use an Array to Store a Collection of Data", + "Access an Array's Contents Using Bracket Notation", + "Add Items to an Array with push() and unshift()", + "Remove Items from an Array with pop() and shift()", + "Remove Items Using splice()", + "Add Items Using splice()", + "Copy Array Items Using slice()", + "Copy an Array with the Spread Operator", + "Combine Arrays with the Spread Operator", + "Check For The Presence of an Element With indexOf()", + "Iterate Through All an Array's Items Using For Loops", + "Create complex multi-dimensional arrays", + "Add Key-Value Pairs to JavaScript Objects", + "Modify an Object Nested Within an Object", + "Access Property Names with Bracket Notation", + "Use the delete Keyword to Remove Object Properties", + "Check if an Object has a Property", + " Iterate Through the Keys of an Object with a for...in Statement", + "Generate an Array of All Object Keys with Object.keys()", + "Modify an Array Stored in an Object" + ], + "Basic Algorithm Scripting": [ + "Convert Celsius to Fahrenheit", + "Reverse a String", + "Factorialize a Number", + "Find the Longest Word in a String", + "Return Largest Numbers in Arrays", + "Confirm the Ending", + "Repeat a String Repeat a String", + "Truncate a String", + "Finders Keepers", + "Boo who", + "Title Case a Sentence", + "Slice and Splice", + "Falsy Bouncer", + "Where do I Belong", + "Mutations", + "Chunky Monkey" + ], + "Object Oriented Programming": [ + "Create a Basic JavaScript Object", + "Use Dot Notation to Access the Properties of an Object", + "Create a Method on an Object", + "Make Code More Reusable with the this Keyword", + "Define a Constructor Function", + "Use a Constructor to Create Objects", + "Extend Constructors to Receive Arguments", + "Verify an Object's Constructor with instanceof", + "Understand Own Properties", + "Use Prototype Properties to Reduce Duplicate Code", + "Iterate Over All Properties", + "Understand the Constructor Property", + "Change the Prototype to a New Object", + "Remember to Set the Constructor Property when Changing the Prototype", + "Understand Where an Object’s Prototype Comes From", + "Understand the Prototype Chain", + "Use Inheritance So You Don't Repeat Yourself", + "Inherit Behaviors from a Supertype", + "Set the Child's Prototype to an Instance of the Parent", + "Reset an Inherited Constructor Property", + "Add Methods After Inheritance", + "Override Inherited Methods", + "Use a Mixin to Add Common Behavior Between Unrelated Objects", + "Use Closure to Protect Properties Within an Object from Being Modified Externally", + "Understand the Immediately Invoked Function Expression (IIFE)", + "Use an IIFE to Create a Module" + ], + "Functional Programming": [ + "Learn About Functional Programming", + "Understand Functional Programming Terminology", + "Understand the Hazards of Using Imperative Code", + "Avoid Mutations and Side Effects Using Functional Programming", + "Pass Arguments to Avoid External Dependence in a Function", + "Refactor Global Variables Out of Functions", + "Use the map Method to Extract Data from an Array", + "Implement map on a Prototype", + "Use the filter Method to Extract Data from an Array", + "Implement the filter Method on a Prototype", + "Return Part of an Array Using the slice Method", + "Remove Elements from an Array Using slice Instead of splice", + "Combine Two Arrays Using the concat Method", + "Add Elements to the End of an Array Using concat Instead of push", + "Use the reduce Method to Analyze Data", + "Sort an Array Alphabetically using the sort Method", + "Return a Sorted Array Without Changing the Original Array", + "Split a String into an Array Using the split Method", + "Combine an Array into a String Using the join Method", + "Apply Functional Programming to Convert Strings to URL Slugs", + "Use the every Method to Check that Every Element in an Array Meets a Criteria", + "Use the some Method to Check that Any Elements in an Array Meet a Criteria", + "Introduction to Currying and Partial Application" + ], + "Intermediate Algorithm Scripting": [ + "Sum All Numbers in a Range", + "Diff Two Arrays", + "Seek and Destroy", + "Wherefore art thou", + "Spinal Tap Case", + "Pig Latin", + "Search and Replace", + "DNA Pairing", + "Missing letters", + "Sorted Union", + "Convert HTML Entities", + "Sum All Odd Fibonacci Numbers", + "Sum All Primes", + "Smallest Common Multiple", + "Drop it", + "Steamroller", + "Binary Agents", + "Everything Be True", + "Arguments Optional", + "Make a Person", + "Map the Debris" + ], + "JavaScript Algorithms and Data Structures Projects": [ + "Palindrome Checker", + "Roman Numeral Converter", + "Caesars Cipher", + "Telephone Number Validator", + "Cash Register" + ] + }, + "Front End Libraries Certification (300 hours)": { + "Bootstrap": [ + "Use Responsive Design with Bootstrap Fluid Containers", + "Make Images Mobile Responsive", + "Center Text with Bootstrap", + "Create a Bootstrap Button", + "Create a Block Element Bootstrap Button", + "Taste the Bootstrap Button Color Rainbow", + "Call out Optional Actions with btn-info", + "Warn Your Users of a Dangerous Action with btn-danger", + "Use the Bootstrap Grid to Put Elements Side By Side", + "Ditch Custom CSS for Bootstrap", + "Use a span to Target Inline Elements", + "Create a Custom Heading", + "Add Font Awesome Icons to our Buttons", + "Add Font Awesome Icons to all of our Buttons", + "Responsively Style Radio Buttons", + "Responsively Style Checkboxes", + "Style Text Inputs as Form Controls", + "Line up Form Elements Responsively with Bootstrap", + "Create a Bootstrap Headline", + "House our page within a Bootstrap container-fluid div", + "Create a Bootstrap Row", + "Split Your Bootstrap Row", + "Create Bootstrap Wells", + "Add Elements within Your Bootstrap Wells", + "Apply the Default Bootstrap Button Style", + "Create a Class to Target with jQuery Selectors", + "Add id Attributes to Bootstrap Elements", + "Label Bootstrap Wells", + "Give Each Element a Unique id", + "Label Bootstrap Buttons", + "Use Comments to Clarify Code" + ], + "jQuery": [ + "Learn How Script Tags and Document Ready Work", + "Target HTML Elements with Selectors Using jQuery", + "Target Elements by Class Using jQuery", + "Target Elements by id Using jQuery", + "Delete Your jQuery Functions", + "Target the Same Element with Multiple jQuery Selectors", + "Remove Classes from an Element with jQuery", + "Change the CSS of an Element Using jQuery", + "Disable an Element Using jQuery", + "Change Text Inside an Element Using jQuery", + "Remove an Element Using jQuery", + "Use appendTo to Move Elements with jQuery", + "Clone an Element Using jQuery", + "Target the Parent of an Element Using jQuery", + "Target the Children of an Element Using jQuery", + "Target a Specific Child of an Element Using jQuery", + "Target Even Elements Using jQuery", + "Use jQuery to Modify the Entire Page" + ], + "Sass": [ + "Store Data with Sass Variables", + "Nest CSS with Sass", + "Create Reusable CSS with Mixins", + "Use @if and @else to Add Logic To Your Styles", + "Use @for to Create a Sass Loop", + "Use @each to Map Over Items in a List", + "Apply a Style Until a Condition is Met with @while", + "Split Your Styles into Smaller Chunks with Partials", + "Extend One Set of CSS Styles to Another Element" + ], + "React": [ + "Create a Simple JSX Element", + "Create a Complex JSX Element", + "Add Comments in JSX", + "Render HTML Elements to the DOM", + "Define an HTML Class in JSX", + "Learn About Self-Closing JSX Tags", + "Create a Stateless Functional Component", + "Create a React Component", + "Create a Component with Composition", + "Use React to Render Nested Components", + "Compose React Components", + "Render a Class Component to the DOM", + "Write a React Component from Scratch", + "Pass Props to a Stateless Functional Component", + "Pass an Array as Props", + "Use Default Props", + "Override Default Props", + "Use PropTypes to Define the Props You Expect", + "Access Props Using this.props", + "Review Using Props with Stateless Functional Components", + "Create a Stateful Component", + "Render State in the User Interface", + "Render State in the User Interface Another Way", + "Set State with this.setState", + "Bind 'this' to a Class Method", + "Use State to Toggle an Element", + "Write a Simple Counter", + "Create a Controlled Input", + "Create a Controlled Form", + "Pass State as Props to Child Components", + "Pass a Callback as Props", + "Use the Lifecycle Method componentWillMount", + "Use the Lifecycle Method componentDidMount", + "Add Event Listeners", + "Manage Updates with Lifecycle Methods", + "Optimize Re-Renders with shouldComponentUpdate", + "Introducing Inline Styles", + "Add Inline Styles in React", + "Use Advanced JavaScript in React Render Method", + "Render with an If/Else Condition", + "Use && for a More Concise Conditional", + "Use a Ternary Expression for Conditional Rendering", + "Render Conditionally from Props", + "Change Inline CSS Conditionally Based on Component State", + "Use Array.map() to Dynamically Render Elements", + "Give Sibling Elements a Unique Key Attribute", + "Use Array.filter() to Dynamically Filter an Array", + "Render React on the Server with renderToString" + ], + "Redux": [ + "Create a Redux Store", + "Get State from the Redux Store", + "Define a Redux Action", + "Define an Action Creator", + "Dispatch an Action Event", + "Handle an Action in the Store", + "Use a Switch Statement to Handle Multiple Actions", + "Use const for Action Types", + "Register a Store Listener", + "Combine Multiple Reducers", + "Send Action Data to the Store", + "Use Middleware to Handle Asynchronous Actions", + "Write a Counter with Redux", + "Never Mutate State", + "Use the Spread Operator on Arrays", + "Remove an Item from an Array", + "Copy an Object with Object.assign" + ], + "React and Redux": [ + "Getting Started with React Redux", + "Manage State Locally First", + "Extract State Logic to Redux", + "Use Provider to Connect Redux to React", + "Map State to Props", + "Map Dispatch to Props", + "Connect Redux to React", + "Connect Redux to the Messages App", + "Extract Local State into Redux", + "Moving Forward From Here" + ], + "Front End Libraries Projects": [ + "Build a Random Quote Machine", + "Build a Markdown Previewer", + "Build a Drum Machine", + "Build a JavaScript Calculator", + "Build a Pomodoro Clock" + ] + }, + "Data Visualization Certification (300 hours)": { + "Data Visualization with D3": [ + "Add Document Elements with D3", + "Select a Group of Elements with D3", + "Work with Data in D3", + "Work with Dynamic Data in D3", + "Add Inline Styling to Elements", + "Change Styles Based on Data", + "Add Classes with D3", + "Update the Height of an Element Dynamically", + "Change the Presentation of a Bar Chart", + "Learn About SVG in D3", + "Display Shapes with SVG", + "Create a Bar for Each Data Point in the Set", + "Dynamically Set the Coordinates for Each Bar", + "Dynamically Change the Height of Each Bar", + "Invert SVG Elements", + "Change the Color of an SVG Element", + "Add Labels to D3 Elements", + "Style D3 Labels", + "Add a Hover Effect to a D3 Element", + "Add a Tooltip to a D3 Element", + "Create a Scatterplot with SVG Circles", + "Add Attributes to the Circle Elements", + "Add Labels to Scatter Plot Circles", + "Create a Linear Scale with D3", + "Set a Domain and a Range on a Scale", + "Use the d3.max and d3.min Functions to Find Minimum and Maximum Values in a Dataset", + "Use Dynamic Scales", + "Use a Pre-Defined Scale to Place Elements", + "Add Axes to a Visualization" + ], + "JSON APIs and Ajax": [ + "Handle Click Events with JavaScript using the onclick property", + "Change Text with click Events", + "Get JSON with the JavaScript XMLHttpRequest Method", + "Access the JSON Data from an API", + "Convert JSON Data to HTML", + "Render Images from Data Sources", + "Pre-filter JSON to Get the Data You Need", + "Get Geolocation Data to Find A User's GPS Coordinates", + "Post Data with the JavaScript XMLHttpRequest Method" + ], + "Data Visualization Projects": [ + "Visualize Data with a Bar Chart", + "Visualize Data with a Scatterplot Graph", + "Visualize Data with a Heat Map", + "Visualize Data with a Choropleth Map", + "Visualize Data with a Treemap Diagram" + ] + }, + "Apis And Microservices Certification (300 hours)": { + "Managing Packages with Npm": [ + "How to Use package.json, the Core of Any Node.js Project or npm Package", + "Add a Description to Your package.json", + "Add Keywords to Your package.json", + "Add a License to Your package.json", + "Add a Version to Your package.json", + "Expand Your Project with External Packages from npm", + "Manage npm Dependencies By Understanding Semantic Versioning", + "Use the Tilde-Character to Always Use the Latest Patch Version of a Dependency", + "Use the Caret-Character to Use the Latest Minor Version of a Dependency", + "Remove a Package from Your Dependencies" + ], + "Basic Node and Express": [ + "Meet the Node console", + "Start a Working Express Server", + "Serve an HTML File", + "Serve Static Assets", + "Serve JSON on a Specific Route", + "Use the .env File", + "Implement a Root-Level Request Logger Middleware", + "Chain Middleware to Create a Time Server", + "Get Route Parameter Input from the Client", + "Get Query Parameter Input from the Client", + "Use body-parser to Parse POST Requests", + "Get Data from POST Requests" + ], + "MongoDB and Mongoose": [ + "Install and Set Up Mongoose", + "Create a Model", + "Create and Save a Record of a Model", + "Create Many Records with model.create()", + "Use model.find() to Search Your Database", + "Use model.findOne() to Return a Single Matching Document from Your Database", + "Use model.findById() to Search Your Database By _id", + "Perform Classic Updates by Running Find, Edit, then Save", + "Perform New Updates on a Document Using model.findOneAndUpdate()", + "Delete One Document Using model.findByIdAndRemove", + "Delete Many Documents with model.remove()", + "Chain Search Query Helpers to Narrow Search Results" + ], + "Apis and Microservices Projects": [ + "Timestamp Microservice", + "Request Header Parser Microservice", + "URL Shortener Microservice", + "Exercise Tracker", + "File Metadata Microservice" + ] + }, + "Information Security And Quality Assurance Certification (300 hours)": { + "Information Security with HelmetJS": [ + "Install and Require Helmet", + "Hide Potentially Dangerous Information Using helmet.hidePoweredBy()", + "Mitigate the Risk of Clickjacking with helmet.frameguard()", + "Mitigate the Risk of Cross Site Scripting (XSS) Attacks with helmet.xssFilter()", + "Avoid Inferring the Response MIME Type with helmet.noSniff()", + "Prevent IE from Opening Untrusted HTML with helmet.ieNoOpen()", + "Ask Browsers to Access Your Site via HTTPS Only with helmet.hsts()", + "Disable DNS Prefetching with helmet.dnsPrefetchControl()", + "Disable Client-Side Caching with helmet.noCache()", + "Set a Content Security Policy with helmet.contentSecurityPolicy()", + "Configure Helmet Using the ‘parent’ helmet() Middleware", + "Understand BCrypt Hashes", + "Hash and Compare Passwords Asynchronously", + "Hash and Compare Passwords Synchronously" + ], + "Quality Assurance and Testing with Chai": [ + "Learn How JavaScript Assertions Work", + "Test if a Variable or Function is Defined", + "Use Assert.isOK and Assert.isNotOK", + "Test for Truthiness", + "Use the Double Equals to Assert Equality", + "Use the Triple Equals to Assert Strict Equality", + "Assert Deep Equality with .deepEqual and .notDeepEqual", + "Compare the Properties of Two Elements", + "Test if One Value is Below or At Least as Large as Another", + "Test if a Value Falls within a Specific Range", + "Test if a Value is an Array", + "Test if an Array Contains an Item", + "Test if a Value is a String", + "Test if a String Contains a Substring", + "Use Regular Expressions to Test a String", + "Test if an Object has a Property", + "Test if a Value is of a Specific Data Structure Type", + "Test if an Object is an Instance of a Constructor", + "Run Functional Tests on API Endpoints using Chai-HTTP", + "Run Functional Tests on API Endpoints using Chai-HTTP II", + "Run Functional Tests on an API Response using Chai-HTTP III - PUT method", + "Run Functional Tests on an API Response using Chai-HTTP IV - PUT method", + "Run Functional Tests using a Headless Browser", + "Run Functional Tests using a Headless Browser II" + ], + "Advanced Node and Express": [ + "Set up a Template Engine", + "Use a Template Engine's Powers", + "Set up Passport", + "Serialization of a User Object", + "Implement the Serialization of a Passport User", + "Authentication Strategies", + "How to Use Passport Strategies", + "Create New Middleware", + "How to Put a Profile Together", + "Logging a User Out", + "Registration of New Users", + "Hashing Your Passwords", + "Clean Up Your Project with Modules", + "Implementation of Social Authentication", + "Implementation of Social Authentication II", + "Implementation of Social Authentication III", + "Set up the Environment", + "Communicate by Emitting", + "Handle a Disconnect", + "Authentication with Socket.IO", + "Announce New Users", + "Send and Display Chat Messages" + ], + "Information Security and Quality Assurance Projects": [ + "Metric-Imperial Converter", + "Issue Tracker", + "Personal Library", + "Stock Price Checker", + "Anonymous Message Board" + ] + }, + "Coding Interview Prep (Thousands of hours of challenges)": { + "Algorithms": [ + "Find the Symmetric Difference", + "Inventory Update", + "No Repeats Please", + "Pairwise", + "Implement Bubble Sort", + "Implement Selection Sort", + "Implement Insertion Sort", + "Implement Quick Sort", + "Implement Merge Sort" + ], + "Data Structures": [ + "Typed Arrays", + "Learn how a Stack Works", + "Create a Stack Class", + "Create a Queue Class", + "Create a Priority Queue Class", + "Create a Circular Queue", + "Create a Set Class", + "Remove from a Set", + "Size of the Set", + "Perform a Union on Two Sets", + "Perform an Intersection on Two Sets of Data", + "Perform a Difference on Two Sets of Data", + "Perform a Subset Check on Two Sets of Data", + "Create and Add to Sets in ES6", + "Remove items from a set in ES6", + "Use .has and .size on an ES6 Set", + "Use Spread and Notes for ES5 Set() Integration", + "Create a Map Data Structure", + "Create an ES6 JavaScript Map", + "Create a Hash Table", + "Work with Nodes in a Linked List", + "Create a Linked List Class", + "Remove Elements from a Linked List", + "Search within a Linked List", + "Remove Elements from a Linked List by Index", + "Add Elements at a Specific Index in a Linked List", + "Create a Doubly Linked List", + "Reverse a Doubly Linked List", + "Find the Minimum and Maximum Value in a Binary Search Tree", + "Add a New Element to a Binary Search Tree", + "Check if an Element is Present in a Binary Search Tree", + "Find the Minimum and Maximum Height of a Binary Search Tree", + "Use Depth First Search in a Binary Search Tree", + "Use Breadth First Search in a Binary Search Tree", + "Delete a Leaf Node in a Binary Search Tree", + "Delete a Node with One Child in a Binary Search Tree", + "Delete a Node with Two Children in a Binary Search Tree", + "Invert a Binary Tree", + "Create a Trie Search Tree", + "Insert an Element into a Max Heap", + "Remove an Element from a Max Heap", + "Implement Heap Sort with a Min Heap", + "Adjacency List", + "Adjacency Matrix", + "Incidence Matrix", + "Breadth-First Search", + "Depth-First Search" + ], + "Take Home Projects": [ + "Show the Local Weather", + "Build a Wikipedia Viewer", + "Use the Twitch JSON API", + "Build an Image Search Abstraction Layer", + "Build a Tic Tac Toe Game", + "Build a Simon Game", + "Build a Camper Leaderboard", + "Build a Recipe Box", + "Build the Game of Life", + "Build a Roguelike Dungeon Crawler Game", + "P2P Video Chat Application", + "Show National Contiguity with a Force Directed Graph", + "Map Data Across the Globe", + "Manage a Book Trading Club", + "Build a Pinterest Clone", + "Build a Nightlife Coordination App", + "Chart the Stock Market", + "Build a Voting App", + "Build a Pong Game", + "Build a Light-Bright App" + ], + "Rosetta Code": [ + "100 doors", + "24 game", + "9 billion names of God the integer", + "ABC Problem", + "Abundant, deficient and perfect number classifications", + "Accumulator factory", + "Ackermann function", + "Align columns", + "Amicable pairs", + "Averages/Mode", + "Averages/Pythagorean means", + "Averages/Root mean square", + "Babbage problem", + "Balanced brackets", + "Circles of given radius through two points", + "Closest-pair problem", + "Combinations", + "Comma quibbling", + "Compare a list of strings", + "Convert seconds to compound duration", + "Count occurrences of a substring", + "Count the coins", + "Cramer's rule", + "Date format", + "Date manipulation", + "Day of the week", + "Deal cards for FreeCell", + "Deepcopy", + "Define a primitive data type", + "Department Numbers", + "Discordian date", + "Element-wise operations", + "Emirp primes", + "Entropy", + "Equilibrium index", + "Ethiopian multiplication", + "Euler method", + "Evaluate binomial coefficients", + "Execute a Markov algorithm", + "Execute Brain****", + "Extensible prime generator", + "Factorial", + "Factors of a Mersenne number", + "Factors of an integer", + "Farey sequence", + "Fibonacci n-step number sequences", + "Fibonacci sequence", + "Fibonacci word", + "Fractran", + "Gamma function", + "Gaussian elimination", + "General FizzBuzz", + "Generate lower case ASCII alphabet", + "Generator/Exponential", + "Gray code", + "Greatest common divisor", + "Greatest subsequential sum", + "Hailstone sequence", + "Happy numbers", + "Harshad or Niven series", + "Hash from two arrays", + "Hash join", + "Heronian triangles", + "Hofstadter Figure-Figure sequences", + "Hofstadter Q sequence", + "I before E except after C", + "IBAN", + "Identity matrix", + "Iterated digits squaring", + "Jaro distance", + "JortSort", + "Josephus problem", + "Sailors, coconuts and a monkey problem", + "SEDOLs", + "S-Expressions", + "Taxicab numbers", + "Tokenize a string with escaping", + "Topological sort", + "Top rank per group", + "Towers of Hanoi", + "Vector cross product", + "Vector dot product", + "Word wrap", + "Y combinator", + "Zeckendorf number representation", + "Zhang-Suen thinning algorithm", + "Zig-zag matrix" + ], + "Project Euler": [ + "Problem 1: Multiples of 3 and 5", + "Problem 2: Even Fibonacci Numbers", + "Problem 3: Largest prime factor", + "Problem 4: Largest palindrome product", + "Problem 5: Smallest multiple", + "Problem 6: Sum square difference", + "Problem 7: 10001st prime", + "Problem 8: Largest product in a series", + "Problem 9: Special Pythagorean triplet", + "Problem 10: Summation of primes", + "Problem 11: Largest product in a grid", + "Problem 12: Highly divisible triangular number", + "Problem 13: Large sum", + "Problem 14: Longest Collatz sequence", + "Problem 15: Lattice paths", + "Problem 16: Power digit sum", + "Problem 17: Number letter counts", + "Problem 18: Maximum path sum I", + "Problem 19: Counting Sundays", + "Problem 20: Factorial digit sum", + "Problem 21: Amicable numbers", + "Problem 22: Names scores", + "Problem 23: Non-abundant sums", + "Problem 24: Lexicographic permutations", + "Problem 25: 1000-digit Fibonacci number", + "Problem 26: Reciprocal cycles", + "Problem 27: Quadratic primes", + "Problem 28: Number spiral diagonals", + "Problem 29: Distinct powers", + "Problem 30: Digit n powers", + "Problem 31: Coin sums", + "Problem 32: Pandigital products", + "Problem 33: Digit cancelling fractions", + "Problem 34: Digit factorials", + "Problem 35: Circular primes", + "Problem 36: Double-base palindromes", + "Problem 37: Truncatable primes", + "Problem 38: Pandigital multiples", + "Problem 39: Integer right triangles", + "Problem 40: Champernowne's constant", + "Problem 41: Pandigital prime", + "Problem 42: Coded triangle numbers", + "Problem 43: Sub-string divisibility", + "Problem 44: Pentagon numbers", + "Problem 45: Triangular, pentagonal, and hexagonal", + "Problem 46: Goldbach's other conjecture", + "Problem 47: Distinct primes factors", + "Problem 48: Self powers", + "Problem 49: Prime permutations", + "Problem 50: Consecutive prime sum", + "Problem 51: Prime digit replacements", + "Problem 52: Permuted multiples", + "Problem 53: Combinatoric selections", + "Problem 54: Poker hands", + "Problem 55: Lychrel numbers", + "Problem 56: Powerful digit sum", + "Problem 57: Square root convergents", + "Problem 58: Spiral primes", + "Problem 59: XOR decryption", + "Problem 60: Prime pair sets", + "Problem 61: Cyclical figurate numbers", + "Problem 62: Cubic permutations", + "Problem 63: Powerful digit counts", + "Problem 64: Odd period square roots", + "Problem 65: Convergents of e", + "Problem 66: Diophantine equation", + "Problem 67: Maximum path sum II", + "Problem 68: Magic 5-gon ring", + "Problem 69: Totient maximum", + "Problem 70: Totient permutation", + "Problem 71: Ordered fractions", + "Problem 72: Counting fractions", + "Problem 73: Counting fractions in a range", + "Problem 74: Digit factorial chains", + "Problem 75: Singular integer right triangles", + "Problem 76: Counting summations", + "Problem 77: Prime summations", + "Problem 78: Coin partitions", + "Problem 79: Passcode derivation", + "Problem 80: Square root digital expansion", + "Problem 81: Path sum: two ways", + "Problem 82: Path sum: three ways", + "Problem 83: Path sum: four ways", + "Problem 84: Monopoly odds", + "Problem 85: Counting rectangles", + "Problem 86: Cuboid route", + "Problem 87: Prime power triples", + "Problem 88: Product-sum numbers", + "Problem 89: Roman numerals", + "Problem 90: Cube digit pairs", + "Problem 91: Right triangles with integer coordinates", + "Problem 92: Square digit chains", + "Problem 93: Arithmetic expressions", + "Problem 94: Almost equilateral triangles", + "Problem 95: Amicable chains", + "Problem 96: Su Doku", + "Problem 97: Large non-Mersenne prime", + "Problem 98: Anagramic squares", + "Problem 99: Largest exponential", + "Problem 100: Arranged probability", + "Problem 101: Optimum polynomial", + "Problem 102: Triangle containment", + "Problem 103: Special subset sums: optimum", + "Problem 104: Pandigital Fibonacci ends", + "Problem 105: Special subset sums: testing", + "Problem 106: Special subset sums: meta-testing", + "Problem 107: Minimal network", + "Problem 108: Diophantine Reciprocals I", + "Problem 109: Darts", + "Problem 110: Diophantine Reciprocals II", + "Problem 111: Primes with runs", + "Problem 112: Bouncy numbers", + "Problem 113: Non-bouncy numbers", + "Problem 114: Counting block combinations I", + "Problem 115: Counting block combinations II", + "Problem 116: Red, green or blue tiles", + "Problem 117: Red, green, and blue tiles", + "Problem 118: Pandigital prime sets", + "Problem 119: Digit power sum", + "Problem 120: Square remainders", + "Problem 121: Disc game prize fund", + "Problem 122: Efficient exponentiation", + "Problem 123: Prime square remainders", + "Problem 124: Ordered radicals", + "Problem 125: Palindromic sums", + "Problem 126: Cuboid layers", + "Problem 127: abc-hits", + "Problem 128: Hexagonal tile differences", + "Problem 129: Repunit divisibility", + "Problem 130: Composites with prime repunit property", + "Problem 131: Prime cube partnership", + "Problem 132: Large repunit factors", + "Problem 133: Repunit nonfactors", + "Problem 134: Prime pair connection", + "Problem 135: Same differences", + "Problem 136: Singleton difference", + "Problem 137: Fibonacci golden nuggets", + "Problem 138: Special isosceles triangles", + "Problem 139: Pythagorean tiles", + "Problem 140: Modified Fibonacci golden nuggets", + "Problem 141: Investigating progressive numbers, n, which are also square", + "Problem 142: Perfect Square Collection", + "Problem 143: Investigating the Torricelli point of a triangle", + "Problem 144: Investigating multiple reflections of a laser beam", + "Problem 145: How many reversible numbers are there below one-billion?", + "Problem 146: Investigating a Prime Pattern", + "Problem 147: Rectangles in cross-hatched grids", + "Problem 148: Exploring Pascal's triangle", + "Problem 149: Searching for a maximum-sum subsequence", + "Problem 150: Searching a triangular array for a sub-triangle having minimum-sum", + "Problem 151: Paper sheets of standard sizes: an expected-value problem", + "Problem 152: Writing 1/2 as a sum of inverse squares", + "Problem 153: Investigating Gaussian Integers", + "Problem 154: Exploring Pascal's pyramid", + "Problem 155: Counting Capacitor Circuits", + "Problem 156: Counting Digits", + "Problem 157: Solving the diophantine equation 1/a+1/b= p/10n", + "Problem 158: Exploring strings for which only one character comes lexicographically after its neighbour to the left", + "Problem 159: Digital root sums of factorisations", + "Problem 160: Factorial trailing digits", + "Problem 161: Triominoes", + "Problem 162: Hexadecimal numbers", + "Problem 163: Cross-hatched triangles", + "Problem 164: Numbers for which no three consecutive digits have a sum greater than a given value", + "Problem 165: Intersections", + "Problem 166: Criss Cross", + "Problem 167: Investigating Ulam sequences", + "Problem 168: Number Rotations", + "Problem 169: Exploring the number of different ways a number can be expressed as a sum of powers of 2", + "Problem 170: Find the largest 0 to 9 pandigital that can be formed by concatenating products", + "Problem 171: Finding numbers for which the sum of the squares of the digits is a square", + "Problem 172: Investigating numbers with few repeated digits", + "Problem 173: Using up to one million tiles how many different \"hollow\" square laminae can be formed?", + "Problem 174: Counting the number of \"hollow\" square laminae that can form one, two, three, ... distinct arrangements", + "Problem 175: Fractions involving the number of different ways a number can be expressed as a sum of powers of 2", + "Problem 176: Right-angled triangles that share a cathetus", + "Problem 177: Integer angled Quadrilaterals", + "Problem 178: Step Numbers", + "Problem 179: Consecutive positive divisors", + "Problem 180: Rational zeros of a function of three variables", + "Problem 181: Investigating in how many ways objects of two different colours can be grouped", + "Problem 182: RSA encryption", + "Problem 183: Maximum product of parts", + "Problem 184: Triangles containing the origin", + "Problem 185: Number Mind", + "Problem 186: Connectedness of a network", + "Problem 187: Semiprimes", + "Problem 188: The hyperexponentiation of a number", + "Problem 189: Tri-colouring a triangular grid", + "Problem 190: Maximising a weighted product", + "Problem 191: Prize Strings", + "Problem 192: Best Approximations", + "Problem 193: Squarefree Numbers", + "Problem 194: Coloured Configurations", + "Problem 195: Inscribed circles of triangles with one angle of 60 degrees", + "Problem 196: Prime triplets", + "Problem 197: Investigating the behaviour of a recursively defined sequence", + "Problem 198: Ambiguous Numbers", + "Problem 199: Iterative Circle Packing", + "Problem 200: Find the 200th prime-proof sqube containing the contiguous sub-string \"200\"", + "Problem 201: Subsets with a unique sum", + "Problem 202: Laserbeam", + "Problem 203: Squarefree Binomial Coefficients", + "Problem 204: Generalised Hamming Numbers", + "Problem 205: Dice Game", + "Problem 206: Concealed Square", + "Problem 207: Integer partition equations", + "Problem 208: Robot Walks", + "Problem 209: Circular Logic", + "Problem 210: Obtuse Angled Triangles", + "Problem 211: Divisor Square Sum", + "Problem 212: Combined Volume of Cuboids", + "Problem 213: Flea Circus", + "Problem 214: Totient Chains", + "Problem 215: Crack-free Walls", + "Problem 216: Investigating the primality of numbers of the form 2n2-1", + "Problem 217: Balanced Numbers", + "Problem 218: Perfect right-angled triangles", + "Problem 219: Skew-cost coding", + "Problem 220: Heighway Dragon", + "Problem 221: Alexandrian Integers", + "Problem 222: Sphere Packing", + "Problem 223: Almost right-angled triangles I", + "Problem 224: Almost right-angled triangles II", + "Problem 225: Tribonacci non-divisors", + "Problem 226: A Scoop of Blancmange", + "Problem 227: The Chase", + "Problem 228: Minkowski Sums", + "Problem 229: Four Representations using Squares", + "Problem 230: Fibonacci Words", + "Problem 231: The prime factorisation of binomial coefficients", + "Problem 232: The Race", + "Problem 233: Lattice points on a circle", + "Problem 234: Semidivisible numbers", + "Problem 235: An Arithmetic Geometric sequence", + "Problem 236: Luxury Hampers", + "Problem 237: Tours on a 4 x n playing board", + "Problem 238: Infinite string tour", + "Problem 239: Twenty-two Foolish Primes", + "Problem 240: Top Dice", + "Problem 241: Perfection Quotients", + "Problem 242: Odd Triplets", + "Problem 243: Resilience", + "Problem 244: Sliders", + "Problem 245: Coresilience", + "Problem 246: Tangents to an ellipse", + "Problem 247: Squares under a hyperbola", + "Problem 248: Numbers for which Euler’s totient function equals 13!", + "Problem 249: Prime Subset Sums", + "Problem 250: 250250", + "Problem 251: Cardano Triplets", + "Problem 252: Convex Holes", + "Problem 253: Tidying up", + "Problem 254: Sums of Digit Factorials", + "Problem 255: Rounded Square Roots", + "Problem 256: Tatami-Free Rooms", + "Problem 257: Angular Bisectors", + "Problem 258: A lagged Fibonacci sequence", + "Problem 259: Reachable Numbers", + "Problem 260: Stone Game", + "Problem 261: Pivotal Square Sums", + "Problem 262: Mountain Range", + "Problem 263: An engineers' dream come true", + "Problem 264: Triangle Centres", + "Problem 265: Binary Circles", + "Problem 266: Pseudo Square Root", + "Problem 267: Billionaire", + "Problem 268: Counting numbers with at least four distinct prime factors less than 100", + "Problem 269: Polynomials with at least one integer root", + "Problem 270: Cutting Squares", + "Problem 271: Modular Cubes, part 1", + "Problem 272: Modular Cubes, part 2", + "Problem 273: Sum of Squares", + "Problem 274: Divisibility Multipliers", + "Problem 275: Balanced Sculptures", + "Problem 276: Primitive Triangles", + "Problem 277: A Modified Collatz sequence", + "Problem 278: Linear Combinations of Semiprimes", + "Problem 279: Triangles with integral sides and an integral angle", + "Problem 280: Ant and seeds", + "Problem 281: Pizza Toppings", + "Problem 282: The Ackermann function", + "Problem 283: Integer sided triangles for which the area/perimeter ratio is integral", + "Problem 284: Steady Squares", + "Problem 285: Pythagorean odds", + "Problem 286: Scoring probabilities", + "Problem 287: Quadtree encoding (a simple compression algorithm)", + "Problem 288: An enormous factorial", + "Problem 289: Eulerian Cycles", + "Problem 290: Digital Signature", + "Problem 291: Panaitopol Primes", + "Problem 292: Pythagorean Polygons", + "Problem 293: Pseudo-Fortunate Numbers", + "Problem 294: Sum of digits - experience #23", + "Problem 295: Lenticular holes", + "Problem 296: Angular Bisector and Tangent", + "Problem 297: Zeckendorf Representation", + "Problem 298: Selective Amnesia", + "Problem 299: Three similar triangles", + "Problem 300: Protein folding", + "Problem 301: Nim", + "Problem 302: Strong Achilles Numbers", + "Problem 303: Multiples with small digits", + "Problem 304: Primonacci", + "Problem 305: Reflexive Position", + "Problem 306: Paper-strip Game", + "Problem 307: Chip Defects", + "Problem 308: An amazing Prime-generating Automaton", + "Problem 309: Integer Ladders", + "Problem 310: Nim Square", + "Problem 311: Biclinic Integral Quadrilaterals", + "Problem 312: Cyclic paths on Sierpiński graphs", + "Problem 313: Sliding game", + "Problem 314: The Mouse on the Moon", + "Problem 315: Digital root clocks", + "Problem 316: Numbers in decimal expansions", + "Problem 317: Firecracker", + "Problem 318: 2011 nines", + "Problem 319: Bounded Sequences", + "Problem 320: Factorials divisible by a huge integer", + "Problem 321: Swapping Counters", + "Problem 322: Binomial coefficients divisible by 10", + "Problem 323: Bitwise-OR operations on random integers", + "Problem 324: Building a tower", + "Problem 325: Stone Game II", + "Problem 326: Modulo Summations", + "Problem 327: Rooms of Doom", + "Problem 328: Lowest-cost Search", + "Problem 329: Prime Frog", + "Problem 330: Euler's Number", + "Problem 331: Cross flips", + "Problem 332: Spherical triangles", + "Problem 333: Special partitions", + "Problem 334: Spilling the beans", + "Problem 335: Gathering the beans", + "Problem 336: Maximix Arrangements", + "Problem 337: Totient Stairstep Sequences", + "Problem 338: Cutting Rectangular Grid Paper", + "Problem 339: Peredur fab Efrawg", + "Problem 340: Crazy Function", + "Problem 341: Golomb's self-describing sequence", + "Problem 342: The totient of a square is a cube", + "Problem 343: Fractional Sequences", + "Problem 344: Silver dollar game", + "Problem 345: Matrix Sum", + "Problem 346: Strong Repunits", + "Problem 347: Largest integer divisible by two primes", + "Problem 348: Sum of a square and a cube", + "Problem 349: Langton's ant", + "Problem 350: Constraining the least greatest and the greatest least", + "Problem 351: Hexagonal orchards", + "Problem 352: Blood tests", + "Problem 353: Risky moon", + "Problem 354: Distances in a bee's honeycomb", + "Problem 355: Maximal coprime subset", + "Problem 356: Largest roots of cubic polynomials", + "Problem 357: Prime generating integers", + "Problem 358: Cyclic numbers", + "Problem 359: Hilbert's New Hotel", + "Problem 360: Scary Sphere", + "Problem 361: Subsequence of Thue-Morse sequence", + "Problem 362: Squarefree factors", + "Problem 363: Bézier Curves", + "Problem 364: Comfortable distance", + "Problem 365: A huge binomial coefficient", + "Problem 366: Stone Game III", + "Problem 367: Bozo sort", + "Problem 368: A Kempner-like series", + "Problem 369: Badugi", + "Problem 370: Geometric triangles", + "Problem 371: Licence plates", + "Problem 372: Pencils of rays", + "Problem 373: Circumscribed Circles", + "Problem 374: Maximum Integer Partition Product", + "Problem 375: Minimum of subsequences", + "Problem 376: Nontransitive sets of dice", + "Problem 377: Sum of digits, experience 13", + "Problem 378: Triangle Triples", + "Problem 379: Least common multiple count", + "Problem 380: Amazing Mazes!", + "Problem 381: (prime-k) factorial", + "Problem 382: Generating polygons", + "Problem 383: Divisibility comparison between factorials", + "Problem 384: Rudin-Shapiro sequence", + "Problem 385: Ellipses inside triangles", + "Problem 386: Maximum length of an antichain", + "Problem 387: Harshad Numbers", + "Problem 388: Distinct Lines", + "Problem 389: Platonic Dice", + "Problem 390: Triangles with non rational sides and integral area", + "Problem 391: Hopping Game", + "Problem 392: Enmeshed unit circle", + "Problem 393: Migrating ants", + "Problem 394: Eating pie", + "Problem 395: Pythagorean tree", + "Problem 396: Weak Goodstein sequence", + "Problem 397: Triangle on parabola", + "Problem 398: Cutting rope", + "Problem 399: Squarefree Fibonacci Numbers", + "Problem 400: Fibonacci tree game", + "Problem 401: Sum of squares of divisors", + "Problem 402: Integer-valued polynomials", + "Problem 403: Lattice points enclosed by parabola and line", + "Problem 404: Crisscross Ellipses", + "Problem 405: A rectangular tiling", + "Problem 406: Guessing Game", + "Problem 407: Idempotents", + "Problem 408: Admissible paths through a grid", + "Problem 409: Nim Extreme", + "Problem 410: Circle and tangent line", + "Problem 411: Uphill paths", + "Problem 412: Gnomon numbering", + "Problem 413: One-child Numbers", + "Problem 414: Kaprekar constant", + "Problem 415: Titanic sets", + "Problem 416: A frog's trip", + "Problem 417: Reciprocal cycles II", + "Problem 418: Factorisation triples", + "Problem 419: Look and say sequence", + "Problem 420: 2x2 positive integer matrix", + "Problem 421: Prime factors of n15+1", + "Problem 422: Sequence of points on a hyperbola", + "Problem 423: Consecutive die throws", + "Problem 424: Kakuro", + "Problem 425: Prime connection", + "Problem 426: Box-ball system", + "Problem 427: n-sequences", + "Problem 428: Necklace of Circles", + "Problem 429: Sum of squares of unitary divisors", + "Problem 430: Range flips", + "Problem 431: Square Space Silo", + "Problem 432: Totient sum", + "Problem 433: Steps in Euclid's algorithm", + "Problem 434: Rigid graphs", + "Problem 435: Polynomials of Fibonacci numbers", + "Problem 436: Unfair wager", + "Problem 437: Fibonacci primitive roots", + "Problem 438: Integer part of polynomial equation's solutions", + "Problem 439: Sum of sum of divisors", + "Problem 440: GCD and Tiling", + "Problem 441: The inverse summation of coprime couples", + "Problem 442: Eleven-free integers", + "Problem 443: GCD sequence", + "Problem 444: The Roundtable Lottery", + "Problem 445: Retractions A", + "Problem 446: Retractions B", + "Problem 447: Retractions C", + "Problem 448: Average least common multiple", + "Problem 449: Chocolate covered candy", + "Problem 450: Hypocycloid and Lattice points", + "Problem 451: Modular inverses", + "Problem 452: Long Products", + "Problem 453: Lattice Quadrilaterals", + "Problem 454: Diophantine reciprocals III", + "Problem 455: Powers With Trailing Digits", + "Problem 456: Triangles containing the origin II", + "Problem 457: A polynomial modulo the square of a prime", + "Problem 458: Permutations of Project", + "Problem 459: Flipping game", + "Problem 460: An ant on the move", + "Problem 461: Almost Pi", + "Problem 462: Permutation of 3-smooth numbers", + "Problem 463: A weird recurrence relation", + "Problem 464: Möbius function and intervals", + "Problem 465: Polar polygons", + "Problem 466: Distinct terms in a multiplication table", + "Problem 467: Superinteger", + "Problem 468: Smooth divisors of binomial coefficients", + "Problem 469: Empty chairs", + "Problem 470: Super Ramvok", + "Problem 471: Triangle inscribed in ellipse", + "Problem 472: Comfortable Distance II", + "Problem 473: Phigital number base", + "Problem 474: Last digits of divisors", + "Problem 475: Music festival", + "Problem 476: Circle Packing II", + "Problem 477: Number Sequence Game", + "Problem 478: Mixtures", + "Problem 479: Roots on the Rise", + "Problem 480: The Last Question" + ] + } +}; + let challengeMap = lesson_map; + + // Inconsistent capitalization, thus map to lower case + completedChallenges = completedChallenges.map(x => x.toLowerCase()); + + // Loop through curriculum JSON + for (let section of Object.keys(challengeMap)) { + for (let subsection of Object.keys(challengeMap[section])) { + let numChallenges = challengeMap[section][subsection].length; + + // Inconsistent capitalization, thus map to lower case + let subsectionArray = challengeMap[section][subsection].map(x => x.toLowerCase()); + + let numCompleted = subsectionArray.reduce((acc, val) => { + return completedChallenges.indexOf(val) != -1 ? ++acc : acc; + }, 0); + + challengeMap[section][subsection] = `${Math.round(100 * numCompleted / numChallenges)}%`; + } + } + + return challengeMap; +}; + +// Writes the JSON object to a file +let writeJSON = (json) => { + const fs = require('fs'); + const outputFile = 'fcc_progress.json'; + // Format the json for readability + const jsonString = JSON.stringify(json, null, 2); + + fs.writeFile(outputFile, jsonString, (err) => { + // Report success / failure + const successMessage = 'FCC progress was written to ' + outputFile; + err ? console.log(err) : console.log(successMessage); + }); +}; + +// Runs the program +let run = () => { + const url = 'https://www.freecodecamp.org/magoun'; + + getHTML(url) + .then(parseHTML) + .then(getProgress) + .then(writeJSON); +}; + +run(); \ No newline at end of file From c969cf0bfd49d866d5e9339f605556182476dd95 Mon Sep 17 00:00:00 2001 From: Creighton Magoun Date: Wed, 17 Oct 2018 20:55:09 +0000 Subject: [PATCH 13/37] Scraped curriculum from 17 Oct 2018 --- lesson_map.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lesson_map.js b/lesson_map.js index f120b1b..06e0e34 100644 --- a/lesson_map.js +++ b/lesson_map.js @@ -16,7 +16,8 @@ * 'section2': {...}, * ... * } -*/ + * + */ // Fetch html using puppeteer let getHTML = async (url) => { From 413cb987a61dd7638e472772cfc231a8f9dae2fc Mon Sep 17 00:00:00 2001 From: Creighton Magoun Date: Wed, 17 Oct 2018 21:02:28 +0000 Subject: [PATCH 14/37] Rename output file for clarity --- lesson_map.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lesson_map.js b/lesson_map.js index 06e0e34..14a4a53 100644 --- a/lesson_map.js +++ b/lesson_map.js @@ -1,6 +1,6 @@ /** * Scrapes the lesson list from https://learn.freecodecamp.org into - * a JSON Object, then writes that object to lesson_map.json + * a JSON Object, then writes that object to fcc_curriculum.json * * Usage: node lesson_map.js * @@ -94,7 +94,7 @@ let createMap = (html) => { // Writes the JSON object to a file let writeJSON = (json) => { const fs = require('fs'); - const outputFile = 'lesson_map.json'; + const outputFile = 'fcc_curriculum.json'; // Format the json for readability const jsonString = JSON.stringify(json, null, 2); From c8778ccdc9e0c6003eb2da886257d47bba62059f Mon Sep 17 00:00:00 2001 From: Creighton Magoun Date: Wed, 17 Oct 2018 21:02:59 +0000 Subject: [PATCH 15/37] Rename output file and store scraped curriculum --- lesson_map.json => fcc_curriculum.json | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename lesson_map.json => fcc_curriculum.json (100%) diff --git a/lesson_map.json b/fcc_curriculum.json similarity index 100% rename from lesson_map.json rename to fcc_curriculum.json From 546b0bdf106c6681ecfa36ded391f2ae3e6431f4 Mon Sep 17 00:00:00 2001 From: Creighton Magoun Date: Thu, 18 Oct 2018 04:12:20 +0000 Subject: [PATCH 16/37] Add a file to accept a list of fcc profiles for checking --- fcc_profiles.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 fcc_profiles.txt diff --git a/fcc_profiles.txt b/fcc_profiles.txt new file mode 100644 index 0000000..d145b02 --- /dev/null +++ b/fcc_profiles.txt @@ -0,0 +1,3 @@ +https://www.freecodecamp.org/magoun +https://www.freecodecamp.org/thirtythreeb +https://www.freecodecamp.org/jaaron0606 \ No newline at end of file From 9c1eab1c0cd809291c1538e6d4d747dabed560c5 Mon Sep 17 00:00:00 2001 From: Creighton Magoun Date: Thu, 18 Oct 2018 04:12:54 +0000 Subject: [PATCH 17/37] Begin speccing out logic for multiple profile scrapes with a single call --- wip.js | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/wip.js b/wip.js index d26083d..5bb48dd 100644 --- a/wip.js +++ b/wip.js @@ -1,7 +1,16 @@ +const fs = require('fs'); +const puppeteer = require('puppeteer'); + +// Read list of profile urls +let readURLs = () => { + let file = 'fcc_profiles.txt'; + let profiles = fs.readFileSync(file, 'utf8'); + + console.log(profiles.split('\n')); +}; + // Fetch html using puppeteer let getHTML = async (url) => { - const puppeteer = require('puppeteer'); - const browser = await puppeteer.launch(); const page = await browser.newPage(); @@ -1564,7 +1573,6 @@ let getProgress = (completedChallenges) => { // Writes the JSON object to a file let writeJSON = (json) => { - const fs = require('fs'); const outputFile = 'test.json'; // Format the json for readability const jsonString = JSON.stringify(json, null, 2); @@ -1578,12 +1586,14 @@ let writeJSON = (json) => { // Runs the program let run = () => { - const url = 'https://www.freecodecamp.org/magoun'; + // const url = 'https://www.freecodecamp.org/magoun'; + + // getHTML(url) + // .then(parseHTML) + // .then(getProgress) + // .then(writeJSON); - getHTML(url) - .then(parseHTML) - .then(getProgress) - .then(writeJSON); + readURLs(); }; run(); \ No newline at end of file From 977d2b0d393f0715a1346a1ea53a5b87b1a3da71 Mon Sep 17 00:00:00 2001 From: Creighton Magoun Date: Thu, 18 Oct 2018 18:07:02 +0000 Subject: [PATCH 18/37] Do not track progress reports pulled from fcc_progress.js --- .gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d3c5d85 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +fcc_progress.json From cc03be216829a9cd70dae12ad31eac57a51e0503 Mon Sep 17 00:00:00 2001 From: Creighton Magoun Date: Thu, 18 Oct 2018 18:07:39 +0000 Subject: [PATCH 19/37] Add comment to split call --- wip.js | 1 + 1 file changed, 1 insertion(+) diff --git a/wip.js b/wip.js index 5bb48dd..77b2b61 100644 --- a/wip.js +++ b/wip.js @@ -6,6 +6,7 @@ let readURLs = () => { let file = 'fcc_profiles.txt'; let profiles = fs.readFileSync(file, 'utf8'); + // Splitting the return on new line yields an array console.log(profiles.split('\n')); }; From ff49443ea9ea38457c84fd928bd26e0eb08727ca Mon Sep 17 00:00:00 2001 From: Creighton Magoun Date: Thu, 18 Oct 2018 22:53:21 +0000 Subject: [PATCH 20/37] Add JSON for new Greenville codes Curriculum --- gvl_codes_path.json | 564 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 564 insertions(+) create mode 100644 gvl_codes_path.json diff --git a/gvl_codes_path.json b/gvl_codes_path.json new file mode 100644 index 0000000..9c8d507 --- /dev/null +++ b/gvl_codes_path.json @@ -0,0 +1,564 @@ +{ + "Pre-Work Part 1": { + "Basic HTML and HTML5": [ + "Say Hello to HTML Elements", + "Headline with the h2 Element", + "Inform with the Paragraph Element", + "Fill in the Blank with Placeholder Text", + "Uncomment HTML", + "Comment out HTML", + "Delete HTML Elements", + "Introduction to HTML5 Elements", + "Add Images to Your Website", + "Link to External Pages with Anchor Elements", + "Link to Internal Sections of a Page with Anchor Elements", + "Nest an Anchor Element within a Paragraph", + "Make Dead Links Using the Hash Symbol", + "Turn an Image into a Link", + "Create a Bulleted Unordered List", + "Create an Ordered List", + "Create a Text Field", + "Add Placeholder Text to a Text Field", + "Create a Form Element", + "Add a Submit Button to a Form", + "Use HTML5 to Require a Field", + "Create a Set of Radio Buttons", + "Create a Set of Checkboxes", + "Check Radio Buttons and Checkboxes by Default", + "Nest Many Elements within a Single div Element", + "Declare the Doctype of an HTML Document", + "Define the Head and Body of an HTML Document" + ], + "Basic CSS": [ + "Change the Color of Text", + "Use CSS Selectors to Style Elements", + "Use a CSS Class to Style an Element", + "Style Multiple Elements with a CSS Class", + "Change the Font Size of an Element", + "Set the Font Family of an Element", + "Import a Google Font", + "Specify How Fonts Should Degrade", + "Size Your Images", + "Add Borders Around Your Elements", + "Add Rounded Corners with border-radius", + "Make Circular Images with a border-radius", + "Give a Background Color to a div Element", + "Set the id of an Element", + "Use an id Attribute to Style an Element", + "Adjust the Padding of an Element", + "Adjust the Margin of an Element", + "Add a Negative Margin to an Element", + "Add Different Padding to Each Side of an Element", + "Add Different Margins to Each Side of an Element", + "Use Clockwise Notation to Specify the Padding of an Element", + "Use Clockwise Notation to Specify the Margin of an Element", + "Use Attribute Selectors to Style Elements", + "Understand Absolute versus Relative Units", + "Style the HTML Body Element", + "Inherit Styles from the Body Element", + "Prioritize One Style Over Another", + "Override Styles in Subsequent CSS", + "Override Class Declarations by Styling ID Attributes", + "Override Class Declarations with Inline Styles", + "Override All Other Styles by using Important", + "Use Hex Code for Specific Colors", + "Use Hex Code to Mix Colors", + "Use Abbreviated Hex Code", + "Use RGB values to Color Elements", + "Use RGB to Mix Colors", + "Use CSS Variables to change several elements at once", + "Create a custom CSS Variable", + "Use a custom CSS Variable", + "Attach a Fallback value to a CSS Variable", + "Improve Compatibility with Browser Fallbacks", + "Cascading CSS variables", + "Change a variable for a specific area", + "Use a media query to change a variable" + ], + "Tribute Page Project": [ + "Build a Tribute Page" + ], + "Basic JavaScript": [ + "Comment Your JavaScript Code", + "Declare JavaScript Variables", + "Storing Values with the Assignment Operator", + "Initializing Variables with the Assignment Operator", + "Understanding Uninitialized Variables", + "Understanding Case Sensitivity in Variables", + "Add Two Numbers with JavaScript", + "Subtract One Number from Another with JavaScript", + "Multiply Two Numbers with JavaScript", + "Divide One Number by Another with JavaScript", + "Increment a Number with JavaScript", + "Decrement a Number with JavaScript", + "Create Decimal Numbers with JavaScript", + "Multiply Two Decimals with JavaScript", + "Divide One Decimal by Another with JavaScript", + "Finding a Remainder in JavaScript", + "Compound Assignment With Augmented Addition", + "Compound Assignment With Augmented Subtraction", + "Compound Assignment With Augmented Multiplication", + "Compound Assignment With Augmented Division", + "Declare String Variables", + "Escaping Literal Quotes in Strings", + "Quoting Strings with Single Quotes", + "Escape Sequences in Strings", + "Concatenating Strings with Plus Operator", + "Concatenating Strings with the Plus Equals Operator", + "Constructing Strings with Variables", + "Appending Variables to Strings", + "Find the Length of a String", + "Use Bracket Notation to Find the First Character in a String", + "Understand String Immutability", + "Use Bracket Notation to Find the Nth Character in a String", + "Use Bracket Notation to Find the Last Character in a String", + "Use Bracket Notation to Find the Nth-to-Last Character in a String", + "Word Blanks", + "Store Multiple Values in one Variable using JavaScript Arrays", + "Nest one Array within Another Array", + "Access Array Data with Indexes", + "Modify Array Data With Indexes", + "Access Multi-Dimensional Arrays With Indexes", + "Manipulate Arrays With push()", + "Manipulate Arrays With pop()", + "Manipulate Arrays With shift()", + "Manipulate Arrays With unshift()", + "Shopping List", + "Write Reusable JavaScript with Functions", + "Passing Values to Functions with Arguments", + "Global Scope and Functions", + "Local Scope and Functions", + "Global vs. Local Scope in Functions", + "Return a Value from a Function with Return", + "Understanding Undefined Value returned from a Function", + "Assignment with a Returned Value", + "Stand in Line", + "Understanding Boolean Values", + "Use Conditional Logic with If Statements", + "Comparison with the Equality Operator", + "Comparison with the Strict Equality Operator", + "Practice comparing different values", + "Comparison with the Inequality Operator", + "Comparison with the Strict Inequality Operator", + "Comparison with the Greater Than Operator", + "Comparison with the Greater Than Or Equal To Operator", + "Comparison with the Less Than Operator", + "Comparison with the Less Than Or Equal To Operator", + "Comparisons with the Logical And Operator", + "Comparisons with the Logical Or Operator", + "Introducing Else Statements", + "Introducing Else If Statements", + "Logical Order in If Else Statements", + "Chaining If Else Statements", + "Golf Code", + "Selecting from Many Options with Switch Statements", + "Adding a Default Option in Switch Statements", + "Multiple Identical Options in Switch Statements", + "Replacing If Else Chains with Switch", + "Returning Boolean Values from Functions", + "Return Early Pattern for Functions", + "Counting Cards", + "Build JavaScript Objects", + "Accessing Object Properties with Dot Notation", + "Accessing Object Properties with Bracket Notation", + "Accessing Object Properties with Variables", + "Updating Object Properties", + "Add New Properties to a JavaScript Object", + "Delete Properties from a JavaScript Object", + "Using Objects for Lookups", + "Testing Objects for Properties", + "Manipulating Complex Objects", + "Accessing Nested Objects", + "Accessing Nested Arrays", + "Record Collection", + "Iterate with JavaScript While Loops", + "Iterate with JavaScript For Loops", + "Iterate Odd Numbers With a For Loop", + "Count Backwards With a For Loop", + "Iterate Through an Array with a For Loop", + "Nesting For Loops", + "Iterate with JavaScript Do...While Loops", + "Profile Lookup", + "Generate Random Fractions with JavaScript", + "Generate Random Whole Numbers with JavaScript", + "Generate Random Whole Numbers within a Range", + "Use the parseInt Function", + "Use the parseInt Function with a Radix", + "Use the Conditional (Ternary) Operator", + "Use Multiple Conditional (Ternary) Operators" + ] + }, + "Pre-Work Part 2": { + "ES6": [ + "Explore Differences Between the var and let Keywords", + "Compare Scopes of the var and let Keywords", + "Declare a Read-Only Variable with the const Keyword", + "Mutate an Array Declared with const", + "Prevent Object Mutation", + "Use Arrow Functions to Write Concise Anonymous Functions", + "Write Arrow Functions with Parameters", + "Write Higher Order Arrow Functions", + "Set Default Parameters for Your Functions", + "Use the Rest Operator with Function Parameters", + "Use the Spread Operator to Evaluate Arrays In-Place", + "Use Destructuring Assignment to Assign Variables from Objects", + "Use Destructuring Assignment to Assign Variables from Nested Objects", + "Use Destructuring Assignment to Assign Variables from Arrays", + "Use Destructuring Assignment with the Rest Operator to Reassign Array Elements", + "Use Destructuring Assignment to Pass an Object as a Function's Parameters", + "Create Strings using Template Literals", + "Write Concise Object Literal Declarations Using Simple Fields", + "Write Concise Declarative Functions with ES6", + "Use class Syntax to Define a Constructor Function", + "Use getters and setters to Control Access to an Object", + "Understand the Differences Between import and require", + "Use export to Reuse a Code Block", + "Use * to Import Everything from a File", + "Create an Export Fallback with export default", + "Import a Default Export" + ], + "Regular Expressions": [ + "Using the Test Method", + "Match Literal Strings", + "Match a Literal String with Different Possibilities", + "Ignore Case While Matching", + "Extract Matches", + "Find More Than the First Match", + "Match Anything with Wildcard Period", + "Match Single Character with Multiple Possibilities", + "Match Letters of the Alphabet", + "Match Numbers and Letters of the Alphabet", + "Match Single Characters Not Specified", + "Match Characters that Occur One or More Times", + "Match Characters that Occur Zero or More Times", + "Find Characters with Lazy Matching", + "Find One or More Criminals in a Hunt", + "Match Beginning String Patterns", + "Match Ending String Patterns", + "Match All Letters and Numbers", + "Match Everything But Letters and Numbers", + "Match All Numbers", + "Match All Non-Numbers", + "Restrict Possible Usernames", + "Match Whitespace", + "Match Non-Whitespace Characters", + "Specify Upper and Lower Number of Matches", + "Specify Only the Lower Number of Matches", + "Specify Exact Number of Matches", + "Check for All or None", + "Positive and Negative Lookahead", + "Reuse Patterns Using Capture Groups", + "Use Capture Groups to Search and Replace", + "Remove Whitespace from Start and End" + ], + "Debugging": [ + "Use the JavaScript Console to Check the Value of a Variable", + "Understanding the Differences between the freeCodeCamp and Browser Console", + "Use typeof to Check the Type of a Variable", + "Catch Misspelled Variable and Function Names", + "Catch Unclosed Parentheses, Brackets, Braces and Quotes", + "Catch Mixed Usage of Single and Double Quotes", + "Catch Use of Assignment Operator Instead of Equality Operator", + "Catch Missing Open and Closing Parenthesis After a Function Call", + "Catch Arguments Passed in the Wrong Order When Calling a Function", + "Catch Off By One Errors When Using Indexing", + "Use Caution When Reinitializing Variables Inside a Loop", + "Prevent Infinite Loops with a Valid Terminal Condition" + ], + "Basic Data Structures": [ + "Use an Array to Store a Collection of Data", + "Access an Array's Contents Using Bracket Notation", + "Add Items to an Array with push() and unshift()", + "Remove Items from an Array with pop() and shift()", + "Remove Items Using splice()", + "Add Items Using splice()", + "Copy Array Items Using slice()", + "Copy an Array with the Spread Operator", + "Combine Arrays with the Spread Operator", + "Check For The Presence of an Element With indexOf()", + "Iterate Through All an Array's Items Using For Loops", + "Create complex multi-dimensional arrays", + "Add Key-Value Pairs to JavaScript Objects", + "Modify an Object Nested Within an Object", + "Access Property Names with Bracket Notation", + "Use the delete Keyword to Remove Object Properties", + "Check if an Object has a Property", + " Iterate Through the Keys of an Object with a for...in Statement", + "Generate an Array of All Object Keys with Object.keys()", + "Modify an Array Stored in an Object" + ] + }, + "12 Week Session - Part 1": { + "Basic Algorithm Scripting": [ + "Convert Celsius to Fahrenheit", + "Reverse a String", + "Factorialize a Number", + "Find the Longest Word in a String", + "Return Largest Numbers in Arrays", + "Confirm the Ending", + "Repeat a String Repeat a String", + "Truncate a String", + "Finders Keepers", + "Boo who", + "Title Case a Sentence", + "Slice and Splice", + "Falsy Bouncer", + "Where do I Belong", + "Mutations", + "Chunky Monkey" + ], + "Object Oriented Programming": [ + "Create a Basic JavaScript Object", + "Use Dot Notation to Access the Properties of an Object", + "Create a Method on an Object", + "Make Code More Reusable with the this Keyword", + "Define a Constructor Function", + "Use a Constructor to Create Objects", + "Extend Constructors to Receive Arguments", + "Verify an Object's Constructor with instanceof", + "Understand Own Properties", + "Use Prototype Properties to Reduce Duplicate Code", + "Iterate Over All Properties", + "Understand the Constructor Property", + "Change the Prototype to a New Object", + "Remember to Set the Constructor Property when Changing the Prototype", + "Understand Where an Object’s Prototype Comes From", + "Understand the Prototype Chain", + "Use Inheritance So You Don't Repeat Yourself", + "Inherit Behaviors from a Supertype", + "Set the Child's Prototype to an Instance of the Parent", + "Reset an Inherited Constructor Property", + "Add Methods After Inheritance", + "Override Inherited Methods", + "Use a Mixin to Add Common Behavior Between Unrelated Objects", + "Use Closure to Protect Properties Within an Object from Being Modified Externally", + "Understand the Immediately Invoked Function Expression (IIFE)", + "Use an IIFE to Create a Module" + ], + "Functional Programming": [ + "Learn About Functional Programming", + "Understand Functional Programming Terminology", + "Understand the Hazards of Using Imperative Code", + "Avoid Mutations and Side Effects Using Functional Programming", + "Pass Arguments to Avoid External Dependence in a Function", + "Refactor Global Variables Out of Functions", + "Use the map Method to Extract Data from an Array", + "Implement map on a Prototype", + "Use the filter Method to Extract Data from an Array", + "Implement the filter Method on a Prototype", + "Return Part of an Array Using the slice Method", + "Remove Elements from an Array Using slice Instead of splice", + "Combine Two Arrays Using the concat Method", + "Add Elements to the End of an Array Using concat Instead of push", + "Use the reduce Method to Analyze Data", + "Sort an Array Alphabetically using the sort Method", + "Return a Sorted Array Without Changing the Original Array", + "Split a String into an Array Using the split Method", + "Combine an Array into a String Using the join Method", + "Apply Functional Programming to Convert Strings to URL Slugs", + "Use the every Method to Check that Every Element in an Array Meets a Criteria", + "Use the some Method to Check that Any Elements in an Array Meet a Criteria", + "Introduction to Currying and Partial Application" + ], + "Intermediate Algorithm Scripting": [ + "Sum All Numbers in a Range", + "Diff Two Arrays", + "Seek and Destroy", + "Wherefore art thou", + "Spinal Tap Case", + "Pig Latin", + "Search and Replace", + "DNA Pairing", + "Missing letters", + "Sorted Union", + "Convert HTML Entities", + "Sum All Odd Fibonacci Numbers", + "Sum All Primes", + "Smallest Common Multiple", + "Drop it", + "Steamroller", + "Binary Agents", + "Everything Be True", + "Arguments Optional", + "Make a Person", + "Map the Debris" + ], + "Palindrome Checker Project": [ + "Palindrome Checker" + ], + "Roman Numeral Converter Project": [ + "Roman Numeral Converter" + ], + "Caesars Cipher Project": [ + "Caesars Cipher" + ], + "Telephone Number Validator Project": [ + "Telephone Number Validator" + ], + "Cash Register Project": [ + "Cash Register" + ] + }, + "12 Week Session - Part 2 (Advanced Track)": { + "Bootstrap": [ + "Use Responsive Design with Bootstrap Fluid Containers", + "Make Images Mobile Responsive", + "Center Text with Bootstrap", + "Create a Bootstrap Button", + "Create a Block Element Bootstrap Button", + "Taste the Bootstrap Button Color Rainbow", + "Call out Optional Actions with btn-info", + "Warn Your Users of a Dangerous Action with btn-danger", + "Use the Bootstrap Grid to Put Elements Side By Side", + "Ditch Custom CSS for Bootstrap", + "Use a span to Target Inline Elements", + "Create a Custom Heading", + "Add Font Awesome Icons to our Buttons", + "Add Font Awesome Icons to all of our Buttons", + "Responsively Style Radio Buttons", + "Responsively Style Checkboxes", + "Style Text Inputs as Form Controls", + "Line up Form Elements Responsively with Bootstrap", + "Create a Bootstrap Headline", + "House our page within a Bootstrap container-fluid div", + "Create a Bootstrap Row", + "Split Your Bootstrap Row", + "Create Bootstrap Wells", + "Add Elements within Your Bootstrap Wells", + "Apply the Default Bootstrap Button Style", + "Create a Class to Target with jQuery Selectors", + "Add id Attributes to Bootstrap Elements", + "Label Bootstrap Wells", + "Give Each Element a Unique id", + "Label Bootstrap Buttons", + "Use Comments to Clarify Code" + ], + "jQuery": [ + "Learn How Script Tags and Document Ready Work", + "Target HTML Elements with Selectors Using jQuery", + "Target Elements by Class Using jQuery", + "Target Elements by id Using jQuery", + "Delete Your jQuery Functions", + "Target the Same Element with Multiple jQuery Selectors", + "Remove Classes from an Element with jQuery", + "Change the CSS of an Element Using jQuery", + "Disable an Element Using jQuery", + "Change Text Inside an Element Using jQuery", + "Remove an Element Using jQuery", + "Use appendTo to Move Elements with jQuery", + "Clone an Element Using jQuery", + "Target the Parent of an Element Using jQuery", + "Target the Children of an Element Using jQuery", + "Target a Specific Child of an Element Using jQuery", + "Target Even Elements Using jQuery", + "Use jQuery to Modify the Entire Page" + ], + "Sass": [ + "Store Data with Sass Variables", + "Nest CSS with Sass", + "Create Reusable CSS with Mixins", + "Use @if and @else to Add Logic To Your Styles", + "Use @for to Create a Sass Loop", + "Use @each to Map Over Items in a List", + "Apply a Style Until a Condition is Met with @while", + "Split Your Styles into Smaller Chunks with Partials", + "Extend One Set of CSS Styles to Another Element" + ], + "React": [ + "Create a Simple JSX Element", + "Create a Complex JSX Element", + "Add Comments in JSX", + "Render HTML Elements to the DOM", + "Define an HTML Class in JSX", + "Learn About Self-Closing JSX Tags", + "Create a Stateless Functional Component", + "Create a React Component", + "Create a Component with Composition", + "Use React to Render Nested Components", + "Compose React Components", + "Render a Class Component to the DOM", + "Write a React Component from Scratch", + "Pass Props to a Stateless Functional Component", + "Pass an Array as Props", + "Use Default Props", + "Override Default Props", + "Use PropTypes to Define the Props You Expect", + "Access Props Using this.props", + "Review Using Props with Stateless Functional Components", + "Create a Stateful Component", + "Render State in the User Interface", + "Render State in the User Interface Another Way", + "Set State with this.setState", + "Bind 'this' to a Class Method", + "Use State to Toggle an Element", + "Write a Simple Counter", + "Create a Controlled Input", + "Create a Controlled Form", + "Pass State as Props to Child Components", + "Pass a Callback as Props", + "Use the Lifecycle Method componentWillMount", + "Use the Lifecycle Method componentDidMount", + "Add Event Listeners", + "Manage Updates with Lifecycle Methods", + "Optimize Re-Renders with shouldComponentUpdate", + "Introducing Inline Styles", + "Add Inline Styles in React", + "Use Advanced JavaScript in React Render Method", + "Render with an If/Else Condition", + "Use && for a More Concise Conditional", + "Use a Ternary Expression for Conditional Rendering", + "Render Conditionally from Props", + "Change Inline CSS Conditionally Based on Component State", + "Use Array.map() to Dynamically Render Elements", + "Give Sibling Elements a Unique Key Attribute", + "Use Array.filter() to Dynamically Filter an Array", + "Render React on the Server with renderToString" + ], + "Redux": [ + "Create a Redux Store", + "Get State from the Redux Store", + "Define a Redux Action", + "Define an Action Creator", + "Dispatch an Action Event", + "Handle an Action in the Store", + "Use a Switch Statement to Handle Multiple Actions", + "Use const for Action Types", + "Register a Store Listener", + "Combine Multiple Reducers", + "Send Action Data to the Store", + "Use Middleware to Handle Asynchronous Actions", + "Write a Counter with Redux", + "Never Mutate State", + "Use the Spread Operator on Arrays", + "Remove an Item from an Array", + "Copy an Object with Object.assign" + ], + "React and Redux": [ + "Getting Started with React Redux", + "Manage State Locally First", + "Extract State Logic to Redux", + "Use Provider to Connect Redux to React", + "Map State to Props", + "Map Dispatch to Props", + "Connect Redux to React", + "Connect Redux to the Messages App", + "Extract Local State into Redux", + "Moving Forward From Here" + ], + "Random Quote Machine Project": [ + "Build a Random Quote Machine" + ], + "Markdown Previewer Project": [ + "Build a Markdown Previewer" + ], + "Drum Machine Project": [ + "Build a Drum Machine" + ], + "Javascript Calculator Project": [ + "Build a JavaScript Calculator" + ], + "Pomodoro Clock Project": [ + "Build a Pomodoro Clock" + ] + } +} \ No newline at end of file From bf0842a9e651ce5b1cc2a7b758179abbe7875412 Mon Sep 17 00:00:00 2001 From: Creighton Magoun Date: Thu, 18 Oct 2018 22:54:20 +0000 Subject: [PATCH 21/37] Update progress checker to use Greenville Codes curriculum --- fcc_progress.js | 1519 +---------------------------------------------- 1 file changed, 7 insertions(+), 1512 deletions(-) diff --git a/fcc_progress.js b/fcc_progress.js index 3c1679b..005eab2 100644 --- a/fcc_progress.js +++ b/fcc_progress.js @@ -11,11 +11,12 @@ * Set user to scrape in run() * */ + +const fs = require('fs'); +const puppeteer = require('puppeteer'); // Fetch html using puppeteer let getHTML = async (url) => { - const puppeteer = require('puppeteer'); - const browser = await puppeteer.launch(); const page = await browser.newPage(); @@ -45,1514 +46,9 @@ let parseHTML = (html) => { // Returns a JSON object let getProgress = (completedChallenges) => { // Hard coded, but can be pulled dynamically with lesson_map.js - const lesson_map = { - "Responsive Web Design Certification (300 hours)": { - "Basic HTML and HTML5": [ - "Say Hello to HTML Elements", - "Headline with the h2 Element", - "Inform with the Paragraph Element", - "Fill in the Blank with Placeholder Text", - "Uncomment HTML", - "Comment out HTML", - "Delete HTML Elements", - "Introduction to HTML5 Elements", - "Add Images to Your Website", - "Link to External Pages with Anchor Elements", - "Link to Internal Sections of a Page with Anchor Elements", - "Nest an Anchor Element within a Paragraph", - "Make Dead Links Using the Hash Symbol", - "Turn an Image into a Link", - "Create a Bulleted Unordered List", - "Create an Ordered List", - "Create a Text Field", - "Add Placeholder Text to a Text Field", - "Create a Form Element", - "Add a Submit Button to a Form", - "Use HTML5 to Require a Field", - "Create a Set of Radio Buttons", - "Create a Set of Checkboxes", - "Check Radio Buttons and Checkboxes by Default", - "Nest Many Elements within a Single div Element", - "Declare the Doctype of an HTML Document", - "Define the Head and Body of an HTML Document" - ], - "Basic CSS": [ - "Change the Color of Text", - "Use CSS Selectors to Style Elements", - "Use a CSS Class to Style an Element", - "Style Multiple Elements with a CSS Class", - "Change the Font Size of an Element", - "Set the Font Family of an Element", - "Import a Google Font", - "Specify How Fonts Should Degrade", - "Size Your Images", - "Add Borders Around Your Elements", - "Add Rounded Corners with border-radius", - "Make Circular Images with a border-radius", - "Give a Background Color to a div Element", - "Set the id of an Element", - "Use an id Attribute to Style an Element", - "Adjust the Padding of an Element", - "Adjust the Margin of an Element", - "Add a Negative Margin to an Element", - "Add Different Padding to Each Side of an Element", - "Add Different Margins to Each Side of an Element", - "Use Clockwise Notation to Specify the Padding of an Element", - "Use Clockwise Notation to Specify the Margin of an Element", - "Use Attribute Selectors to Style Elements", - "Understand Absolute versus Relative Units", - "Style the HTML Body Element", - "Inherit Styles from the Body Element", - "Prioritize One Style Over Another", - "Override Styles in Subsequent CSS", - "Override Class Declarations by Styling ID Attributes", - "Override Class Declarations with Inline Styles", - "Override All Other Styles by using Important", - "Use Hex Code for Specific Colors", - "Use Hex Code to Mix Colors", - "Use Abbreviated Hex Code", - "Use RGB values to Color Elements", - "Use RGB to Mix Colors", - "Use CSS Variables to change several elements at once", - "Create a custom CSS Variable", - "Use a custom CSS Variable", - "Attach a Fallback value to a CSS Variable", - "Improve Compatibility with Browser Fallbacks", - "Cascading CSS variables", - "Change a variable for a specific area", - "Use a media query to change a variable" - ], - "Applied Visual Design": [ - "Create Visual Balance Using the text-align Property", - "Adjust the Width of an Element Using the width Property", - "Adjust the Height of an Element Using the height Property", - "Use the strong Tag to Make Text Bold", - "Use the u Tag to Underline Text", - "Use the em Tag to Italicize Text", - "Use the s Tag to Strikethrough Text", - "Create a Horizontal Line Using the hr Element", - "Adjust the background-color Property of Text", - "Adjust the Size of a Header Versus a Paragraph Tag", - "Add a box-shadow to a Card-like Element", - "Decrease the Opacity of an Element", - "Use the text-transform Property to Make Text Uppercase", - "Set the font-size for Multiple Heading Elements", - "Set the font-weight for Multiple Heading Elements", - "Set the font-size of Paragraph Text", - "Set the line-height of Paragraphs", - "Adjust the Hover State of an Anchor Tag", - "Change an Element's Relative Position", - "Move a Relatively Positioned Element with CSS Offsets", - "Lock an Element to its Parent with Absolute Positioning", - "Lock an Element to the Browser Window with Fixed Positioning", - "Push Elements Left or Right with the float Property", - "Change the Position of Overlapping Elements with the z-index Property", - "Center an Element Horizontally Using the margin Property", - "Learn about Complementary Colors", - "Learn about Tertiary Colors", - "Adjust the Color of Various Elements to Complementary Colors", - "Adjust the Hue of a Color", - "Adjust the Tone of a Color", - "Create a Gradual CSS Linear Gradient", - "Use a CSS Linear Gradient to Create a Striped Element", - "Create Texture by Adding a Subtle Pattern as a Background Image", - "Use the CSS Transform scale Property to Change the Size of an Element", - "Use the CSS Transform scale Property to Scale an Element on Hover", - "Use the CSS Transform Property skewX to Skew an Element Along the X-Axis", - "Use the CSS Transform Property skewY to Skew an Element Along the Y-Axis", - "Create a Graphic Using CSS", - "Create a More Complex Shape Using CSS and HTML", - "Learn How the CSS @keyframes and animation Properties Work", - "Use CSS Animation to Change the Hover State of a Button", - "Modify Fill Mode of an Animation", - "Create Movement Using CSS Animation", - "Create Visual Direction by Fading an Element from Left to Right", - "Animate Elements Continually Using an Infinite Animation Count", - "Make a CSS Heartbeat using an Infinite Animation Count", - "Animate Elements at Variable Rates", - "Animate Multiple Elements at Variable Rates", - "Change Animation Timing with Keywords", - "Learn How Bezier Curves Work", - "Use a Bezier Curve to Move a Graphic", - "Make Motion More Natural Using a Bezier Curve" - ], - "Applied Accessibility": [ - "Add a Text Alternative to Images for Visually Impaired Accessibility", - "Know When Alt Text Should be Left Blank", - "Use Headings to Show Hierarchical Relationships of Content", - "Jump Straight to the Content Using the main Element", - "Wrap Content in the article Element", - "Make Screen Reader Navigation Easier with the header Landmark", - "Make Screen Reader Navigation Easier with the nav Landmark", - "Make Screen Reader Navigation Easier with the footer Landmark", - "Improve Accessibility of Audio Content with the audio Element", - "Improve Chart Accessibility with the figure Element", - "Improve Form Field Accessibility with the label Element", - "Wrap Radio Buttons in a fieldset Element for Better Accessibility", - "Add an Accessible Date Picker", - "Standardize Times with the HTML5 datetime Attribute", - "Make Elements Only Visible to a Screen Reader by Using Custom CSS", - "Improve Readability with High Contrast Text", - "Avoid Colorblindness Issues by Using Sufficient Contrast", - "Avoid Colorblindness Issues by Carefully Choosing Colors that Convey Information", - "Give Links Meaning by Using Descriptive Link Text", - "Make Links Navigatable with HTML Access Keys", - "Use tabindex to Add Keyboard Focus to an Element", - "Use tabindex to Specify the Order of Keyboard Focus for Several Elements" - ], - "Responsive Web Design Principles": [ - "Create a Media Query", - "Make an Image Responsive", - "Use a Retina Image for Higher Resolution Displays", - "Make Typography Responsive" - ], - "CSS Flexbox": [ - "Use display: flex to Position Two Boxes", - "Add Flex Superpowers to the Tweet Embed", - "Use the flex-direction Property to Make a Row", - "Apply the flex-direction Property to Create Rows in the Tweet Embed", - "Use the flex-direction Property to Make a Column", - "Apply the flex-direction Property to Create a Column in the Tweet Embed", - "Align Elements Using the justify-content Property", - "Use the justify-content Property in the Tweet Embed", - "Align Elements Using the align-items Property", - "Use the align-items Property in the Tweet Embed", - "Use the flex-wrap Property to Wrap a Row or Column", - "Use the flex-shrink Property to Shrink Items", - "Use the flex-grow Property to Expand Items", - "Use the flex-basis Property to Set the Initial Size of an Item", - "Use the flex Shorthand Property", - "Use the order Property to Rearrange Items", - "Use the align-self Property" - ], - "CSS Grid": [ - "Create Your First CSS Grid", - "Add Columns with grid-template-columns", - "Add Rows with grid-template-rows", - "Use CSS Grid units to Change the Size of Columns and Rows", - "Create a Column Gap Using grid-column-gap", - "Create a Row Gap using grid-row-gap", - "Add Gaps Faster with grid-gap", - "Use grid-column to Control Spacing", - "Use grid-row to Control Spacing", - "Align an Item Horizontally using justify-self", - "Align an Item Vertically using align-self", - "Align All Items Horizontally using justify-items", - "Align All Items Vertically using align-items", - "Divide the Grid Into an Area Template", - "Place Items in Grid Areas Using the grid-area Property", - "Use grid-area Without Creating an Areas Template", - "Reduce Repetition Using the repeat Function", - "Limit Item Size Using the minmax Function", - "Create Flexible Layouts Using auto-fill", - "Create Flexible Layouts Using auto-fit", - "Use Media Queries to Create Responsive Layouts", - "Create Grids within Grids" - ], - "Responsive Web Design Projects": [ - "Build a Tribute Page", - "Build a Survey Form", - "Build a Product Landing Page", - "Build a Technical Documentation Page", - "Build a Personal Portfolio Webpage" - ] - }, - "Javascript Algorithms And Data Structures Certification (300 hours)": { - "Basic JavaScript": [ - "Comment Your JavaScript Code", - "Declare JavaScript Variables", - "Storing Values with the Assignment Operator", - "Initializing Variables with the Assignment Operator", - "Understanding Uninitialized Variables", - "Understanding Case Sensitivity in Variables", - "Add Two Numbers with JavaScript", - "Subtract One Number from Another with JavaScript", - "Multiply Two Numbers with JavaScript", - "Divide One Number by Another with JavaScript", - "Increment a Number with JavaScript", - "Decrement a Number with JavaScript", - "Create Decimal Numbers with JavaScript", - "Multiply Two Decimals with JavaScript", - "Divide One Decimal by Another with JavaScript", - "Finding a Remainder in JavaScript", - "Compound Assignment With Augmented Addition", - "Compound Assignment With Augmented Subtraction", - "Compound Assignment With Augmented Multiplication", - "Compound Assignment With Augmented Division", - "Declare String Variables", - "Escaping Literal Quotes in Strings", - "Quoting Strings with Single Quotes", - "Escape Sequences in Strings", - "Concatenating Strings with Plus Operator", - "Concatenating Strings with the Plus Equals Operator", - "Constructing Strings with Variables", - "Appending Variables to Strings", - "Find the Length of a String", - "Use Bracket Notation to Find the First Character in a String", - "Understand String Immutability", - "Use Bracket Notation to Find the Nth Character in a String", - "Use Bracket Notation to Find the Last Character in a String", - "Use Bracket Notation to Find the Nth-to-Last Character in a String", - "Word Blanks", - "Store Multiple Values in one Variable using JavaScript Arrays", - "Nest one Array within Another Array", - "Access Array Data with Indexes", - "Modify Array Data With Indexes", - "Access Multi-Dimensional Arrays With Indexes", - "Manipulate Arrays With push()", - "Manipulate Arrays With pop()", - "Manipulate Arrays With shift()", - "Manipulate Arrays With unshift()", - "Shopping List", - "Write Reusable JavaScript with Functions", - "Passing Values to Functions with Arguments", - "Global Scope and Functions", - "Local Scope and Functions", - "Global vs. Local Scope in Functions", - "Return a Value from a Function with Return", - "Understanding Undefined Value returned from a Function", - "Assignment with a Returned Value", - "Stand in Line", - "Understanding Boolean Values", - "Use Conditional Logic with If Statements", - "Comparison with the Equality Operator", - "Comparison with the Strict Equality Operator", - "Practice comparing different values", - "Comparison with the Inequality Operator", - "Comparison with the Strict Inequality Operator", - "Comparison with the Greater Than Operator", - "Comparison with the Greater Than Or Equal To Operator", - "Comparison with the Less Than Operator", - "Comparison with the Less Than Or Equal To Operator", - "Comparisons with the Logical And Operator", - "Comparisons with the Logical Or Operator", - "Introducing Else Statements", - "Introducing Else If Statements", - "Logical Order in If Else Statements", - "Chaining If Else Statements", - "Golf Code", - "Selecting from Many Options with Switch Statements", - "Adding a Default Option in Switch Statements", - "Multiple Identical Options in Switch Statements", - "Replacing If Else Chains with Switch", - "Returning Boolean Values from Functions", - "Return Early Pattern for Functions", - "Counting Cards", - "Build JavaScript Objects", - "Accessing Object Properties with Dot Notation", - "Accessing Object Properties with Bracket Notation", - "Accessing Object Properties with Variables", - "Updating Object Properties", - "Add New Properties to a JavaScript Object", - "Delete Properties from a JavaScript Object", - "Using Objects for Lookups", - "Testing Objects for Properties", - "Manipulating Complex Objects", - "Accessing Nested Objects", - "Accessing Nested Arrays", - "Record Collection", - "Iterate with JavaScript While Loops", - "Iterate with JavaScript For Loops", - "Iterate Odd Numbers With a For Loop", - "Count Backwards With a For Loop", - "Iterate Through an Array with a For Loop", - "Nesting For Loops", - "Iterate with JavaScript Do...While Loops", - "Profile Lookup", - "Generate Random Fractions with JavaScript", - "Generate Random Whole Numbers with JavaScript", - "Generate Random Whole Numbers within a Range", - "Use the parseInt Function", - "Use the parseInt Function with a Radix", - "Use the Conditional (Ternary) Operator", - "Use Multiple Conditional (Ternary) Operators" - ], - "ES6": [ - "Explore Differences Between the var and let Keywords", - "Compare Scopes of the var and let Keywords", - "Declare a Read-Only Variable with the const Keyword", - "Mutate an Array Declared with const", - "Prevent Object Mutation", - "Use Arrow Functions to Write Concise Anonymous Functions", - "Write Arrow Functions with Parameters", - "Write Higher Order Arrow Functions", - "Set Default Parameters for Your Functions", - "Use the Rest Operator with Function Parameters", - "Use the Spread Operator to Evaluate Arrays In-Place", - "Use Destructuring Assignment to Assign Variables from Objects", - "Use Destructuring Assignment to Assign Variables from Nested Objects", - "Use Destructuring Assignment to Assign Variables from Arrays", - "Use Destructuring Assignment with the Rest Operator to Reassign Array Elements", - "Use Destructuring Assignment to Pass an Object as a Function's Parameters", - "Create Strings using Template Literals", - "Write Concise Object Literal Declarations Using Simple Fields", - "Write Concise Declarative Functions with ES6", - "Use class Syntax to Define a Constructor Function", - "Use getters and setters to Control Access to an Object", - "Understand the Differences Between import and require", - "Use export to Reuse a Code Block", - "Use * to Import Everything from a File", - "Create an Export Fallback with export default", - "Import a Default Export" - ], - "Regular Expressions": [ - "Using the Test Method", - "Match Literal Strings", - "Match a Literal String with Different Possibilities", - "Ignore Case While Matching", - "Extract Matches", - "Find More Than the First Match", - "Match Anything with Wildcard Period", - "Match Single Character with Multiple Possibilities", - "Match Letters of the Alphabet", - "Match Numbers and Letters of the Alphabet", - "Match Single Characters Not Specified", - "Match Characters that Occur One or More Times", - "Match Characters that Occur Zero or More Times", - "Find Characters with Lazy Matching", - "Find One or More Criminals in a Hunt", - "Match Beginning String Patterns", - "Match Ending String Patterns", - "Match All Letters and Numbers", - "Match Everything But Letters and Numbers", - "Match All Numbers", - "Match All Non-Numbers", - "Restrict Possible Usernames", - "Match Whitespace", - "Match Non-Whitespace Characters", - "Specify Upper and Lower Number of Matches", - "Specify Only the Lower Number of Matches", - "Specify Exact Number of Matches", - "Check for All or None", - "Positive and Negative Lookahead", - "Reuse Patterns Using Capture Groups", - "Use Capture Groups to Search and Replace", - "Remove Whitespace from Start and End" - ], - "Debugging": [ - "Use the JavaScript Console to Check the Value of a Variable", - "Understanding the Differences between the freeCodeCamp and Browser Console", - "Use typeof to Check the Type of a Variable", - "Catch Misspelled Variable and Function Names", - "Catch Unclosed Parentheses, Brackets, Braces and Quotes", - "Catch Mixed Usage of Single and Double Quotes", - "Catch Use of Assignment Operator Instead of Equality Operator", - "Catch Missing Open and Closing Parenthesis After a Function Call", - "Catch Arguments Passed in the Wrong Order When Calling a Function", - "Catch Off By One Errors When Using Indexing", - "Use Caution When Reinitializing Variables Inside a Loop", - "Prevent Infinite Loops with a Valid Terminal Condition" - ], - "Basic Data Structures": [ - "Use an Array to Store a Collection of Data", - "Access an Array's Contents Using Bracket Notation", - "Add Items to an Array with push() and unshift()", - "Remove Items from an Array with pop() and shift()", - "Remove Items Using splice()", - "Add Items Using splice()", - "Copy Array Items Using slice()", - "Copy an Array with the Spread Operator", - "Combine Arrays with the Spread Operator", - "Check For The Presence of an Element With indexOf()", - "Iterate Through All an Array's Items Using For Loops", - "Create complex multi-dimensional arrays", - "Add Key-Value Pairs to JavaScript Objects", - "Modify an Object Nested Within an Object", - "Access Property Names with Bracket Notation", - "Use the delete Keyword to Remove Object Properties", - "Check if an Object has a Property", - " Iterate Through the Keys of an Object with a for...in Statement", - "Generate an Array of All Object Keys with Object.keys()", - "Modify an Array Stored in an Object" - ], - "Basic Algorithm Scripting": [ - "Convert Celsius to Fahrenheit", - "Reverse a String", - "Factorialize a Number", - "Find the Longest Word in a String", - "Return Largest Numbers in Arrays", - "Confirm the Ending", - "Repeat a String Repeat a String", - "Truncate a String", - "Finders Keepers", - "Boo who", - "Title Case a Sentence", - "Slice and Splice", - "Falsy Bouncer", - "Where do I Belong", - "Mutations", - "Chunky Monkey" - ], - "Object Oriented Programming": [ - "Create a Basic JavaScript Object", - "Use Dot Notation to Access the Properties of an Object", - "Create a Method on an Object", - "Make Code More Reusable with the this Keyword", - "Define a Constructor Function", - "Use a Constructor to Create Objects", - "Extend Constructors to Receive Arguments", - "Verify an Object's Constructor with instanceof", - "Understand Own Properties", - "Use Prototype Properties to Reduce Duplicate Code", - "Iterate Over All Properties", - "Understand the Constructor Property", - "Change the Prototype to a New Object", - "Remember to Set the Constructor Property when Changing the Prototype", - "Understand Where an Object’s Prototype Comes From", - "Understand the Prototype Chain", - "Use Inheritance So You Don't Repeat Yourself", - "Inherit Behaviors from a Supertype", - "Set the Child's Prototype to an Instance of the Parent", - "Reset an Inherited Constructor Property", - "Add Methods After Inheritance", - "Override Inherited Methods", - "Use a Mixin to Add Common Behavior Between Unrelated Objects", - "Use Closure to Protect Properties Within an Object from Being Modified Externally", - "Understand the Immediately Invoked Function Expression (IIFE)", - "Use an IIFE to Create a Module" - ], - "Functional Programming": [ - "Learn About Functional Programming", - "Understand Functional Programming Terminology", - "Understand the Hazards of Using Imperative Code", - "Avoid Mutations and Side Effects Using Functional Programming", - "Pass Arguments to Avoid External Dependence in a Function", - "Refactor Global Variables Out of Functions", - "Use the map Method to Extract Data from an Array", - "Implement map on a Prototype", - "Use the filter Method to Extract Data from an Array", - "Implement the filter Method on a Prototype", - "Return Part of an Array Using the slice Method", - "Remove Elements from an Array Using slice Instead of splice", - "Combine Two Arrays Using the concat Method", - "Add Elements to the End of an Array Using concat Instead of push", - "Use the reduce Method to Analyze Data", - "Sort an Array Alphabetically using the sort Method", - "Return a Sorted Array Without Changing the Original Array", - "Split a String into an Array Using the split Method", - "Combine an Array into a String Using the join Method", - "Apply Functional Programming to Convert Strings to URL Slugs", - "Use the every Method to Check that Every Element in an Array Meets a Criteria", - "Use the some Method to Check that Any Elements in an Array Meet a Criteria", - "Introduction to Currying and Partial Application" - ], - "Intermediate Algorithm Scripting": [ - "Sum All Numbers in a Range", - "Diff Two Arrays", - "Seek and Destroy", - "Wherefore art thou", - "Spinal Tap Case", - "Pig Latin", - "Search and Replace", - "DNA Pairing", - "Missing letters", - "Sorted Union", - "Convert HTML Entities", - "Sum All Odd Fibonacci Numbers", - "Sum All Primes", - "Smallest Common Multiple", - "Drop it", - "Steamroller", - "Binary Agents", - "Everything Be True", - "Arguments Optional", - "Make a Person", - "Map the Debris" - ], - "JavaScript Algorithms and Data Structures Projects": [ - "Palindrome Checker", - "Roman Numeral Converter", - "Caesars Cipher", - "Telephone Number Validator", - "Cash Register" - ] - }, - "Front End Libraries Certification (300 hours)": { - "Bootstrap": [ - "Use Responsive Design with Bootstrap Fluid Containers", - "Make Images Mobile Responsive", - "Center Text with Bootstrap", - "Create a Bootstrap Button", - "Create a Block Element Bootstrap Button", - "Taste the Bootstrap Button Color Rainbow", - "Call out Optional Actions with btn-info", - "Warn Your Users of a Dangerous Action with btn-danger", - "Use the Bootstrap Grid to Put Elements Side By Side", - "Ditch Custom CSS for Bootstrap", - "Use a span to Target Inline Elements", - "Create a Custom Heading", - "Add Font Awesome Icons to our Buttons", - "Add Font Awesome Icons to all of our Buttons", - "Responsively Style Radio Buttons", - "Responsively Style Checkboxes", - "Style Text Inputs as Form Controls", - "Line up Form Elements Responsively with Bootstrap", - "Create a Bootstrap Headline", - "House our page within a Bootstrap container-fluid div", - "Create a Bootstrap Row", - "Split Your Bootstrap Row", - "Create Bootstrap Wells", - "Add Elements within Your Bootstrap Wells", - "Apply the Default Bootstrap Button Style", - "Create a Class to Target with jQuery Selectors", - "Add id Attributes to Bootstrap Elements", - "Label Bootstrap Wells", - "Give Each Element a Unique id", - "Label Bootstrap Buttons", - "Use Comments to Clarify Code" - ], - "jQuery": [ - "Learn How Script Tags and Document Ready Work", - "Target HTML Elements with Selectors Using jQuery", - "Target Elements by Class Using jQuery", - "Target Elements by id Using jQuery", - "Delete Your jQuery Functions", - "Target the Same Element with Multiple jQuery Selectors", - "Remove Classes from an Element with jQuery", - "Change the CSS of an Element Using jQuery", - "Disable an Element Using jQuery", - "Change Text Inside an Element Using jQuery", - "Remove an Element Using jQuery", - "Use appendTo to Move Elements with jQuery", - "Clone an Element Using jQuery", - "Target the Parent of an Element Using jQuery", - "Target the Children of an Element Using jQuery", - "Target a Specific Child of an Element Using jQuery", - "Target Even Elements Using jQuery", - "Use jQuery to Modify the Entire Page" - ], - "Sass": [ - "Store Data with Sass Variables", - "Nest CSS with Sass", - "Create Reusable CSS with Mixins", - "Use @if and @else to Add Logic To Your Styles", - "Use @for to Create a Sass Loop", - "Use @each to Map Over Items in a List", - "Apply a Style Until a Condition is Met with @while", - "Split Your Styles into Smaller Chunks with Partials", - "Extend One Set of CSS Styles to Another Element" - ], - "React": [ - "Create a Simple JSX Element", - "Create a Complex JSX Element", - "Add Comments in JSX", - "Render HTML Elements to the DOM", - "Define an HTML Class in JSX", - "Learn About Self-Closing JSX Tags", - "Create a Stateless Functional Component", - "Create a React Component", - "Create a Component with Composition", - "Use React to Render Nested Components", - "Compose React Components", - "Render a Class Component to the DOM", - "Write a React Component from Scratch", - "Pass Props to a Stateless Functional Component", - "Pass an Array as Props", - "Use Default Props", - "Override Default Props", - "Use PropTypes to Define the Props You Expect", - "Access Props Using this.props", - "Review Using Props with Stateless Functional Components", - "Create a Stateful Component", - "Render State in the User Interface", - "Render State in the User Interface Another Way", - "Set State with this.setState", - "Bind 'this' to a Class Method", - "Use State to Toggle an Element", - "Write a Simple Counter", - "Create a Controlled Input", - "Create a Controlled Form", - "Pass State as Props to Child Components", - "Pass a Callback as Props", - "Use the Lifecycle Method componentWillMount", - "Use the Lifecycle Method componentDidMount", - "Add Event Listeners", - "Manage Updates with Lifecycle Methods", - "Optimize Re-Renders with shouldComponentUpdate", - "Introducing Inline Styles", - "Add Inline Styles in React", - "Use Advanced JavaScript in React Render Method", - "Render with an If/Else Condition", - "Use && for a More Concise Conditional", - "Use a Ternary Expression for Conditional Rendering", - "Render Conditionally from Props", - "Change Inline CSS Conditionally Based on Component State", - "Use Array.map() to Dynamically Render Elements", - "Give Sibling Elements a Unique Key Attribute", - "Use Array.filter() to Dynamically Filter an Array", - "Render React on the Server with renderToString" - ], - "Redux": [ - "Create a Redux Store", - "Get State from the Redux Store", - "Define a Redux Action", - "Define an Action Creator", - "Dispatch an Action Event", - "Handle an Action in the Store", - "Use a Switch Statement to Handle Multiple Actions", - "Use const for Action Types", - "Register a Store Listener", - "Combine Multiple Reducers", - "Send Action Data to the Store", - "Use Middleware to Handle Asynchronous Actions", - "Write a Counter with Redux", - "Never Mutate State", - "Use the Spread Operator on Arrays", - "Remove an Item from an Array", - "Copy an Object with Object.assign" - ], - "React and Redux": [ - "Getting Started with React Redux", - "Manage State Locally First", - "Extract State Logic to Redux", - "Use Provider to Connect Redux to React", - "Map State to Props", - "Map Dispatch to Props", - "Connect Redux to React", - "Connect Redux to the Messages App", - "Extract Local State into Redux", - "Moving Forward From Here" - ], - "Front End Libraries Projects": [ - "Build a Random Quote Machine", - "Build a Markdown Previewer", - "Build a Drum Machine", - "Build a JavaScript Calculator", - "Build a Pomodoro Clock" - ] - }, - "Data Visualization Certification (300 hours)": { - "Data Visualization with D3": [ - "Add Document Elements with D3", - "Select a Group of Elements with D3", - "Work with Data in D3", - "Work with Dynamic Data in D3", - "Add Inline Styling to Elements", - "Change Styles Based on Data", - "Add Classes with D3", - "Update the Height of an Element Dynamically", - "Change the Presentation of a Bar Chart", - "Learn About SVG in D3", - "Display Shapes with SVG", - "Create a Bar for Each Data Point in the Set", - "Dynamically Set the Coordinates for Each Bar", - "Dynamically Change the Height of Each Bar", - "Invert SVG Elements", - "Change the Color of an SVG Element", - "Add Labels to D3 Elements", - "Style D3 Labels", - "Add a Hover Effect to a D3 Element", - "Add a Tooltip to a D3 Element", - "Create a Scatterplot with SVG Circles", - "Add Attributes to the Circle Elements", - "Add Labels to Scatter Plot Circles", - "Create a Linear Scale with D3", - "Set a Domain and a Range on a Scale", - "Use the d3.max and d3.min Functions to Find Minimum and Maximum Values in a Dataset", - "Use Dynamic Scales", - "Use a Pre-Defined Scale to Place Elements", - "Add Axes to a Visualization" - ], - "JSON APIs and Ajax": [ - "Handle Click Events with JavaScript using the onclick property", - "Change Text with click Events", - "Get JSON with the JavaScript XMLHttpRequest Method", - "Access the JSON Data from an API", - "Convert JSON Data to HTML", - "Render Images from Data Sources", - "Pre-filter JSON to Get the Data You Need", - "Get Geolocation Data to Find A User's GPS Coordinates", - "Post Data with the JavaScript XMLHttpRequest Method" - ], - "Data Visualization Projects": [ - "Visualize Data with a Bar Chart", - "Visualize Data with a Scatterplot Graph", - "Visualize Data with a Heat Map", - "Visualize Data with a Choropleth Map", - "Visualize Data with a Treemap Diagram" - ] - }, - "Apis And Microservices Certification (300 hours)": { - "Managing Packages with Npm": [ - "How to Use package.json, the Core of Any Node.js Project or npm Package", - "Add a Description to Your package.json", - "Add Keywords to Your package.json", - "Add a License to Your package.json", - "Add a Version to Your package.json", - "Expand Your Project with External Packages from npm", - "Manage npm Dependencies By Understanding Semantic Versioning", - "Use the Tilde-Character to Always Use the Latest Patch Version of a Dependency", - "Use the Caret-Character to Use the Latest Minor Version of a Dependency", - "Remove a Package from Your Dependencies" - ], - "Basic Node and Express": [ - "Meet the Node console", - "Start a Working Express Server", - "Serve an HTML File", - "Serve Static Assets", - "Serve JSON on a Specific Route", - "Use the .env File", - "Implement a Root-Level Request Logger Middleware", - "Chain Middleware to Create a Time Server", - "Get Route Parameter Input from the Client", - "Get Query Parameter Input from the Client", - "Use body-parser to Parse POST Requests", - "Get Data from POST Requests" - ], - "MongoDB and Mongoose": [ - "Install and Set Up Mongoose", - "Create a Model", - "Create and Save a Record of a Model", - "Create Many Records with model.create()", - "Use model.find() to Search Your Database", - "Use model.findOne() to Return a Single Matching Document from Your Database", - "Use model.findById() to Search Your Database By _id", - "Perform Classic Updates by Running Find, Edit, then Save", - "Perform New Updates on a Document Using model.findOneAndUpdate()", - "Delete One Document Using model.findByIdAndRemove", - "Delete Many Documents with model.remove()", - "Chain Search Query Helpers to Narrow Search Results" - ], - "Apis and Microservices Projects": [ - "Timestamp Microservice", - "Request Header Parser Microservice", - "URL Shortener Microservice", - "Exercise Tracker", - "File Metadata Microservice" - ] - }, - "Information Security And Quality Assurance Certification (300 hours)": { - "Information Security with HelmetJS": [ - "Install and Require Helmet", - "Hide Potentially Dangerous Information Using helmet.hidePoweredBy()", - "Mitigate the Risk of Clickjacking with helmet.frameguard()", - "Mitigate the Risk of Cross Site Scripting (XSS) Attacks with helmet.xssFilter()", - "Avoid Inferring the Response MIME Type with helmet.noSniff()", - "Prevent IE from Opening Untrusted HTML with helmet.ieNoOpen()", - "Ask Browsers to Access Your Site via HTTPS Only with helmet.hsts()", - "Disable DNS Prefetching with helmet.dnsPrefetchControl()", - "Disable Client-Side Caching with helmet.noCache()", - "Set a Content Security Policy with helmet.contentSecurityPolicy()", - "Configure Helmet Using the ‘parent’ helmet() Middleware", - "Understand BCrypt Hashes", - "Hash and Compare Passwords Asynchronously", - "Hash and Compare Passwords Synchronously" - ], - "Quality Assurance and Testing with Chai": [ - "Learn How JavaScript Assertions Work", - "Test if a Variable or Function is Defined", - "Use Assert.isOK and Assert.isNotOK", - "Test for Truthiness", - "Use the Double Equals to Assert Equality", - "Use the Triple Equals to Assert Strict Equality", - "Assert Deep Equality with .deepEqual and .notDeepEqual", - "Compare the Properties of Two Elements", - "Test if One Value is Below or At Least as Large as Another", - "Test if a Value Falls within a Specific Range", - "Test if a Value is an Array", - "Test if an Array Contains an Item", - "Test if a Value is a String", - "Test if a String Contains a Substring", - "Use Regular Expressions to Test a String", - "Test if an Object has a Property", - "Test if a Value is of a Specific Data Structure Type", - "Test if an Object is an Instance of a Constructor", - "Run Functional Tests on API Endpoints using Chai-HTTP", - "Run Functional Tests on API Endpoints using Chai-HTTP II", - "Run Functional Tests on an API Response using Chai-HTTP III - PUT method", - "Run Functional Tests on an API Response using Chai-HTTP IV - PUT method", - "Run Functional Tests using a Headless Browser", - "Run Functional Tests using a Headless Browser II" - ], - "Advanced Node and Express": [ - "Set up a Template Engine", - "Use a Template Engine's Powers", - "Set up Passport", - "Serialization of a User Object", - "Implement the Serialization of a Passport User", - "Authentication Strategies", - "How to Use Passport Strategies", - "Create New Middleware", - "How to Put a Profile Together", - "Logging a User Out", - "Registration of New Users", - "Hashing Your Passwords", - "Clean Up Your Project with Modules", - "Implementation of Social Authentication", - "Implementation of Social Authentication II", - "Implementation of Social Authentication III", - "Set up the Environment", - "Communicate by Emitting", - "Handle a Disconnect", - "Authentication with Socket.IO", - "Announce New Users", - "Send and Display Chat Messages" - ], - "Information Security and Quality Assurance Projects": [ - "Metric-Imperial Converter", - "Issue Tracker", - "Personal Library", - "Stock Price Checker", - "Anonymous Message Board" - ] - }, - "Coding Interview Prep (Thousands of hours of challenges)": { - "Algorithms": [ - "Find the Symmetric Difference", - "Inventory Update", - "No Repeats Please", - "Pairwise", - "Implement Bubble Sort", - "Implement Selection Sort", - "Implement Insertion Sort", - "Implement Quick Sort", - "Implement Merge Sort" - ], - "Data Structures": [ - "Typed Arrays", - "Learn how a Stack Works", - "Create a Stack Class", - "Create a Queue Class", - "Create a Priority Queue Class", - "Create a Circular Queue", - "Create a Set Class", - "Remove from a Set", - "Size of the Set", - "Perform a Union on Two Sets", - "Perform an Intersection on Two Sets of Data", - "Perform a Difference on Two Sets of Data", - "Perform a Subset Check on Two Sets of Data", - "Create and Add to Sets in ES6", - "Remove items from a set in ES6", - "Use .has and .size on an ES6 Set", - "Use Spread and Notes for ES5 Set() Integration", - "Create a Map Data Structure", - "Create an ES6 JavaScript Map", - "Create a Hash Table", - "Work with Nodes in a Linked List", - "Create a Linked List Class", - "Remove Elements from a Linked List", - "Search within a Linked List", - "Remove Elements from a Linked List by Index", - "Add Elements at a Specific Index in a Linked List", - "Create a Doubly Linked List", - "Reverse a Doubly Linked List", - "Find the Minimum and Maximum Value in a Binary Search Tree", - "Add a New Element to a Binary Search Tree", - "Check if an Element is Present in a Binary Search Tree", - "Find the Minimum and Maximum Height of a Binary Search Tree", - "Use Depth First Search in a Binary Search Tree", - "Use Breadth First Search in a Binary Search Tree", - "Delete a Leaf Node in a Binary Search Tree", - "Delete a Node with One Child in a Binary Search Tree", - "Delete a Node with Two Children in a Binary Search Tree", - "Invert a Binary Tree", - "Create a Trie Search Tree", - "Insert an Element into a Max Heap", - "Remove an Element from a Max Heap", - "Implement Heap Sort with a Min Heap", - "Adjacency List", - "Adjacency Matrix", - "Incidence Matrix", - "Breadth-First Search", - "Depth-First Search" - ], - "Take Home Projects": [ - "Show the Local Weather", - "Build a Wikipedia Viewer", - "Use the Twitch JSON API", - "Build an Image Search Abstraction Layer", - "Build a Tic Tac Toe Game", - "Build a Simon Game", - "Build a Camper Leaderboard", - "Build a Recipe Box", - "Build the Game of Life", - "Build a Roguelike Dungeon Crawler Game", - "P2P Video Chat Application", - "Show National Contiguity with a Force Directed Graph", - "Map Data Across the Globe", - "Manage a Book Trading Club", - "Build a Pinterest Clone", - "Build a Nightlife Coordination App", - "Chart the Stock Market", - "Build a Voting App", - "Build a Pong Game", - "Build a Light-Bright App" - ], - "Rosetta Code": [ - "100 doors", - "24 game", - "9 billion names of God the integer", - "ABC Problem", - "Abundant, deficient and perfect number classifications", - "Accumulator factory", - "Ackermann function", - "Align columns", - "Amicable pairs", - "Averages/Mode", - "Averages/Pythagorean means", - "Averages/Root mean square", - "Babbage problem", - "Balanced brackets", - "Circles of given radius through two points", - "Closest-pair problem", - "Combinations", - "Comma quibbling", - "Compare a list of strings", - "Convert seconds to compound duration", - "Count occurrences of a substring", - "Count the coins", - "Cramer's rule", - "Date format", - "Date manipulation", - "Day of the week", - "Deal cards for FreeCell", - "Deepcopy", - "Define a primitive data type", - "Department Numbers", - "Discordian date", - "Element-wise operations", - "Emirp primes", - "Entropy", - "Equilibrium index", - "Ethiopian multiplication", - "Euler method", - "Evaluate binomial coefficients", - "Execute a Markov algorithm", - "Execute Brain****", - "Extensible prime generator", - "Factorial", - "Factors of a Mersenne number", - "Factors of an integer", - "Farey sequence", - "Fibonacci n-step number sequences", - "Fibonacci sequence", - "Fibonacci word", - "Fractran", - "Gamma function", - "Gaussian elimination", - "General FizzBuzz", - "Generate lower case ASCII alphabet", - "Generator/Exponential", - "Gray code", - "Greatest common divisor", - "Greatest subsequential sum", - "Hailstone sequence", - "Happy numbers", - "Harshad or Niven series", - "Hash from two arrays", - "Hash join", - "Heronian triangles", - "Hofstadter Figure-Figure sequences", - "Hofstadter Q sequence", - "I before E except after C", - "IBAN", - "Identity matrix", - "Iterated digits squaring", - "Jaro distance", - "JortSort", - "Josephus problem", - "Sailors, coconuts and a monkey problem", - "SEDOLs", - "S-Expressions", - "Taxicab numbers", - "Tokenize a string with escaping", - "Topological sort", - "Top rank per group", - "Towers of Hanoi", - "Vector cross product", - "Vector dot product", - "Word wrap", - "Y combinator", - "Zeckendorf number representation", - "Zhang-Suen thinning algorithm", - "Zig-zag matrix" - ], - "Project Euler": [ - "Problem 1: Multiples of 3 and 5", - "Problem 2: Even Fibonacci Numbers", - "Problem 3: Largest prime factor", - "Problem 4: Largest palindrome product", - "Problem 5: Smallest multiple", - "Problem 6: Sum square difference", - "Problem 7: 10001st prime", - "Problem 8: Largest product in a series", - "Problem 9: Special Pythagorean triplet", - "Problem 10: Summation of primes", - "Problem 11: Largest product in a grid", - "Problem 12: Highly divisible triangular number", - "Problem 13: Large sum", - "Problem 14: Longest Collatz sequence", - "Problem 15: Lattice paths", - "Problem 16: Power digit sum", - "Problem 17: Number letter counts", - "Problem 18: Maximum path sum I", - "Problem 19: Counting Sundays", - "Problem 20: Factorial digit sum", - "Problem 21: Amicable numbers", - "Problem 22: Names scores", - "Problem 23: Non-abundant sums", - "Problem 24: Lexicographic permutations", - "Problem 25: 1000-digit Fibonacci number", - "Problem 26: Reciprocal cycles", - "Problem 27: Quadratic primes", - "Problem 28: Number spiral diagonals", - "Problem 29: Distinct powers", - "Problem 30: Digit n powers", - "Problem 31: Coin sums", - "Problem 32: Pandigital products", - "Problem 33: Digit cancelling fractions", - "Problem 34: Digit factorials", - "Problem 35: Circular primes", - "Problem 36: Double-base palindromes", - "Problem 37: Truncatable primes", - "Problem 38: Pandigital multiples", - "Problem 39: Integer right triangles", - "Problem 40: Champernowne's constant", - "Problem 41: Pandigital prime", - "Problem 42: Coded triangle numbers", - "Problem 43: Sub-string divisibility", - "Problem 44: Pentagon numbers", - "Problem 45: Triangular, pentagonal, and hexagonal", - "Problem 46: Goldbach's other conjecture", - "Problem 47: Distinct primes factors", - "Problem 48: Self powers", - "Problem 49: Prime permutations", - "Problem 50: Consecutive prime sum", - "Problem 51: Prime digit replacements", - "Problem 52: Permuted multiples", - "Problem 53: Combinatoric selections", - "Problem 54: Poker hands", - "Problem 55: Lychrel numbers", - "Problem 56: Powerful digit sum", - "Problem 57: Square root convergents", - "Problem 58: Spiral primes", - "Problem 59: XOR decryption", - "Problem 60: Prime pair sets", - "Problem 61: Cyclical figurate numbers", - "Problem 62: Cubic permutations", - "Problem 63: Powerful digit counts", - "Problem 64: Odd period square roots", - "Problem 65: Convergents of e", - "Problem 66: Diophantine equation", - "Problem 67: Maximum path sum II", - "Problem 68: Magic 5-gon ring", - "Problem 69: Totient maximum", - "Problem 70: Totient permutation", - "Problem 71: Ordered fractions", - "Problem 72: Counting fractions", - "Problem 73: Counting fractions in a range", - "Problem 74: Digit factorial chains", - "Problem 75: Singular integer right triangles", - "Problem 76: Counting summations", - "Problem 77: Prime summations", - "Problem 78: Coin partitions", - "Problem 79: Passcode derivation", - "Problem 80: Square root digital expansion", - "Problem 81: Path sum: two ways", - "Problem 82: Path sum: three ways", - "Problem 83: Path sum: four ways", - "Problem 84: Monopoly odds", - "Problem 85: Counting rectangles", - "Problem 86: Cuboid route", - "Problem 87: Prime power triples", - "Problem 88: Product-sum numbers", - "Problem 89: Roman numerals", - "Problem 90: Cube digit pairs", - "Problem 91: Right triangles with integer coordinates", - "Problem 92: Square digit chains", - "Problem 93: Arithmetic expressions", - "Problem 94: Almost equilateral triangles", - "Problem 95: Amicable chains", - "Problem 96: Su Doku", - "Problem 97: Large non-Mersenne prime", - "Problem 98: Anagramic squares", - "Problem 99: Largest exponential", - "Problem 100: Arranged probability", - "Problem 101: Optimum polynomial", - "Problem 102: Triangle containment", - "Problem 103: Special subset sums: optimum", - "Problem 104: Pandigital Fibonacci ends", - "Problem 105: Special subset sums: testing", - "Problem 106: Special subset sums: meta-testing", - "Problem 107: Minimal network", - "Problem 108: Diophantine Reciprocals I", - "Problem 109: Darts", - "Problem 110: Diophantine Reciprocals II", - "Problem 111: Primes with runs", - "Problem 112: Bouncy numbers", - "Problem 113: Non-bouncy numbers", - "Problem 114: Counting block combinations I", - "Problem 115: Counting block combinations II", - "Problem 116: Red, green or blue tiles", - "Problem 117: Red, green, and blue tiles", - "Problem 118: Pandigital prime sets", - "Problem 119: Digit power sum", - "Problem 120: Square remainders", - "Problem 121: Disc game prize fund", - "Problem 122: Efficient exponentiation", - "Problem 123: Prime square remainders", - "Problem 124: Ordered radicals", - "Problem 125: Palindromic sums", - "Problem 126: Cuboid layers", - "Problem 127: abc-hits", - "Problem 128: Hexagonal tile differences", - "Problem 129: Repunit divisibility", - "Problem 130: Composites with prime repunit property", - "Problem 131: Prime cube partnership", - "Problem 132: Large repunit factors", - "Problem 133: Repunit nonfactors", - "Problem 134: Prime pair connection", - "Problem 135: Same differences", - "Problem 136: Singleton difference", - "Problem 137: Fibonacci golden nuggets", - "Problem 138: Special isosceles triangles", - "Problem 139: Pythagorean tiles", - "Problem 140: Modified Fibonacci golden nuggets", - "Problem 141: Investigating progressive numbers, n, which are also square", - "Problem 142: Perfect Square Collection", - "Problem 143: Investigating the Torricelli point of a triangle", - "Problem 144: Investigating multiple reflections of a laser beam", - "Problem 145: How many reversible numbers are there below one-billion?", - "Problem 146: Investigating a Prime Pattern", - "Problem 147: Rectangles in cross-hatched grids", - "Problem 148: Exploring Pascal's triangle", - "Problem 149: Searching for a maximum-sum subsequence", - "Problem 150: Searching a triangular array for a sub-triangle having minimum-sum", - "Problem 151: Paper sheets of standard sizes: an expected-value problem", - "Problem 152: Writing 1/2 as a sum of inverse squares", - "Problem 153: Investigating Gaussian Integers", - "Problem 154: Exploring Pascal's pyramid", - "Problem 155: Counting Capacitor Circuits", - "Problem 156: Counting Digits", - "Problem 157: Solving the diophantine equation 1/a+1/b= p/10n", - "Problem 158: Exploring strings for which only one character comes lexicographically after its neighbour to the left", - "Problem 159: Digital root sums of factorisations", - "Problem 160: Factorial trailing digits", - "Problem 161: Triominoes", - "Problem 162: Hexadecimal numbers", - "Problem 163: Cross-hatched triangles", - "Problem 164: Numbers for which no three consecutive digits have a sum greater than a given value", - "Problem 165: Intersections", - "Problem 166: Criss Cross", - "Problem 167: Investigating Ulam sequences", - "Problem 168: Number Rotations", - "Problem 169: Exploring the number of different ways a number can be expressed as a sum of powers of 2", - "Problem 170: Find the largest 0 to 9 pandigital that can be formed by concatenating products", - "Problem 171: Finding numbers for which the sum of the squares of the digits is a square", - "Problem 172: Investigating numbers with few repeated digits", - "Problem 173: Using up to one million tiles how many different \"hollow\" square laminae can be formed?", - "Problem 174: Counting the number of \"hollow\" square laminae that can form one, two, three, ... distinct arrangements", - "Problem 175: Fractions involving the number of different ways a number can be expressed as a sum of powers of 2", - "Problem 176: Right-angled triangles that share a cathetus", - "Problem 177: Integer angled Quadrilaterals", - "Problem 178: Step Numbers", - "Problem 179: Consecutive positive divisors", - "Problem 180: Rational zeros of a function of three variables", - "Problem 181: Investigating in how many ways objects of two different colours can be grouped", - "Problem 182: RSA encryption", - "Problem 183: Maximum product of parts", - "Problem 184: Triangles containing the origin", - "Problem 185: Number Mind", - "Problem 186: Connectedness of a network", - "Problem 187: Semiprimes", - "Problem 188: The hyperexponentiation of a number", - "Problem 189: Tri-colouring a triangular grid", - "Problem 190: Maximising a weighted product", - "Problem 191: Prize Strings", - "Problem 192: Best Approximations", - "Problem 193: Squarefree Numbers", - "Problem 194: Coloured Configurations", - "Problem 195: Inscribed circles of triangles with one angle of 60 degrees", - "Problem 196: Prime triplets", - "Problem 197: Investigating the behaviour of a recursively defined sequence", - "Problem 198: Ambiguous Numbers", - "Problem 199: Iterative Circle Packing", - "Problem 200: Find the 200th prime-proof sqube containing the contiguous sub-string \"200\"", - "Problem 201: Subsets with a unique sum", - "Problem 202: Laserbeam", - "Problem 203: Squarefree Binomial Coefficients", - "Problem 204: Generalised Hamming Numbers", - "Problem 205: Dice Game", - "Problem 206: Concealed Square", - "Problem 207: Integer partition equations", - "Problem 208: Robot Walks", - "Problem 209: Circular Logic", - "Problem 210: Obtuse Angled Triangles", - "Problem 211: Divisor Square Sum", - "Problem 212: Combined Volume of Cuboids", - "Problem 213: Flea Circus", - "Problem 214: Totient Chains", - "Problem 215: Crack-free Walls", - "Problem 216: Investigating the primality of numbers of the form 2n2-1", - "Problem 217: Balanced Numbers", - "Problem 218: Perfect right-angled triangles", - "Problem 219: Skew-cost coding", - "Problem 220: Heighway Dragon", - "Problem 221: Alexandrian Integers", - "Problem 222: Sphere Packing", - "Problem 223: Almost right-angled triangles I", - "Problem 224: Almost right-angled triangles II", - "Problem 225: Tribonacci non-divisors", - "Problem 226: A Scoop of Blancmange", - "Problem 227: The Chase", - "Problem 228: Minkowski Sums", - "Problem 229: Four Representations using Squares", - "Problem 230: Fibonacci Words", - "Problem 231: The prime factorisation of binomial coefficients", - "Problem 232: The Race", - "Problem 233: Lattice points on a circle", - "Problem 234: Semidivisible numbers", - "Problem 235: An Arithmetic Geometric sequence", - "Problem 236: Luxury Hampers", - "Problem 237: Tours on a 4 x n playing board", - "Problem 238: Infinite string tour", - "Problem 239: Twenty-two Foolish Primes", - "Problem 240: Top Dice", - "Problem 241: Perfection Quotients", - "Problem 242: Odd Triplets", - "Problem 243: Resilience", - "Problem 244: Sliders", - "Problem 245: Coresilience", - "Problem 246: Tangents to an ellipse", - "Problem 247: Squares under a hyperbola", - "Problem 248: Numbers for which Euler’s totient function equals 13!", - "Problem 249: Prime Subset Sums", - "Problem 250: 250250", - "Problem 251: Cardano Triplets", - "Problem 252: Convex Holes", - "Problem 253: Tidying up", - "Problem 254: Sums of Digit Factorials", - "Problem 255: Rounded Square Roots", - "Problem 256: Tatami-Free Rooms", - "Problem 257: Angular Bisectors", - "Problem 258: A lagged Fibonacci sequence", - "Problem 259: Reachable Numbers", - "Problem 260: Stone Game", - "Problem 261: Pivotal Square Sums", - "Problem 262: Mountain Range", - "Problem 263: An engineers' dream come true", - "Problem 264: Triangle Centres", - "Problem 265: Binary Circles", - "Problem 266: Pseudo Square Root", - "Problem 267: Billionaire", - "Problem 268: Counting numbers with at least four distinct prime factors less than 100", - "Problem 269: Polynomials with at least one integer root", - "Problem 270: Cutting Squares", - "Problem 271: Modular Cubes, part 1", - "Problem 272: Modular Cubes, part 2", - "Problem 273: Sum of Squares", - "Problem 274: Divisibility Multipliers", - "Problem 275: Balanced Sculptures", - "Problem 276: Primitive Triangles", - "Problem 277: A Modified Collatz sequence", - "Problem 278: Linear Combinations of Semiprimes", - "Problem 279: Triangles with integral sides and an integral angle", - "Problem 280: Ant and seeds", - "Problem 281: Pizza Toppings", - "Problem 282: The Ackermann function", - "Problem 283: Integer sided triangles for which the area/perimeter ratio is integral", - "Problem 284: Steady Squares", - "Problem 285: Pythagorean odds", - "Problem 286: Scoring probabilities", - "Problem 287: Quadtree encoding (a simple compression algorithm)", - "Problem 288: An enormous factorial", - "Problem 289: Eulerian Cycles", - "Problem 290: Digital Signature", - "Problem 291: Panaitopol Primes", - "Problem 292: Pythagorean Polygons", - "Problem 293: Pseudo-Fortunate Numbers", - "Problem 294: Sum of digits - experience #23", - "Problem 295: Lenticular holes", - "Problem 296: Angular Bisector and Tangent", - "Problem 297: Zeckendorf Representation", - "Problem 298: Selective Amnesia", - "Problem 299: Three similar triangles", - "Problem 300: Protein folding", - "Problem 301: Nim", - "Problem 302: Strong Achilles Numbers", - "Problem 303: Multiples with small digits", - "Problem 304: Primonacci", - "Problem 305: Reflexive Position", - "Problem 306: Paper-strip Game", - "Problem 307: Chip Defects", - "Problem 308: An amazing Prime-generating Automaton", - "Problem 309: Integer Ladders", - "Problem 310: Nim Square", - "Problem 311: Biclinic Integral Quadrilaterals", - "Problem 312: Cyclic paths on Sierpiński graphs", - "Problem 313: Sliding game", - "Problem 314: The Mouse on the Moon", - "Problem 315: Digital root clocks", - "Problem 316: Numbers in decimal expansions", - "Problem 317: Firecracker", - "Problem 318: 2011 nines", - "Problem 319: Bounded Sequences", - "Problem 320: Factorials divisible by a huge integer", - "Problem 321: Swapping Counters", - "Problem 322: Binomial coefficients divisible by 10", - "Problem 323: Bitwise-OR operations on random integers", - "Problem 324: Building a tower", - "Problem 325: Stone Game II", - "Problem 326: Modulo Summations", - "Problem 327: Rooms of Doom", - "Problem 328: Lowest-cost Search", - "Problem 329: Prime Frog", - "Problem 330: Euler's Number", - "Problem 331: Cross flips", - "Problem 332: Spherical triangles", - "Problem 333: Special partitions", - "Problem 334: Spilling the beans", - "Problem 335: Gathering the beans", - "Problem 336: Maximix Arrangements", - "Problem 337: Totient Stairstep Sequences", - "Problem 338: Cutting Rectangular Grid Paper", - "Problem 339: Peredur fab Efrawg", - "Problem 340: Crazy Function", - "Problem 341: Golomb's self-describing sequence", - "Problem 342: The totient of a square is a cube", - "Problem 343: Fractional Sequences", - "Problem 344: Silver dollar game", - "Problem 345: Matrix Sum", - "Problem 346: Strong Repunits", - "Problem 347: Largest integer divisible by two primes", - "Problem 348: Sum of a square and a cube", - "Problem 349: Langton's ant", - "Problem 350: Constraining the least greatest and the greatest least", - "Problem 351: Hexagonal orchards", - "Problem 352: Blood tests", - "Problem 353: Risky moon", - "Problem 354: Distances in a bee's honeycomb", - "Problem 355: Maximal coprime subset", - "Problem 356: Largest roots of cubic polynomials", - "Problem 357: Prime generating integers", - "Problem 358: Cyclic numbers", - "Problem 359: Hilbert's New Hotel", - "Problem 360: Scary Sphere", - "Problem 361: Subsequence of Thue-Morse sequence", - "Problem 362: Squarefree factors", - "Problem 363: Bézier Curves", - "Problem 364: Comfortable distance", - "Problem 365: A huge binomial coefficient", - "Problem 366: Stone Game III", - "Problem 367: Bozo sort", - "Problem 368: A Kempner-like series", - "Problem 369: Badugi", - "Problem 370: Geometric triangles", - "Problem 371: Licence plates", - "Problem 372: Pencils of rays", - "Problem 373: Circumscribed Circles", - "Problem 374: Maximum Integer Partition Product", - "Problem 375: Minimum of subsequences", - "Problem 376: Nontransitive sets of dice", - "Problem 377: Sum of digits, experience 13", - "Problem 378: Triangle Triples", - "Problem 379: Least common multiple count", - "Problem 380: Amazing Mazes!", - "Problem 381: (prime-k) factorial", - "Problem 382: Generating polygons", - "Problem 383: Divisibility comparison between factorials", - "Problem 384: Rudin-Shapiro sequence", - "Problem 385: Ellipses inside triangles", - "Problem 386: Maximum length of an antichain", - "Problem 387: Harshad Numbers", - "Problem 388: Distinct Lines", - "Problem 389: Platonic Dice", - "Problem 390: Triangles with non rational sides and integral area", - "Problem 391: Hopping Game", - "Problem 392: Enmeshed unit circle", - "Problem 393: Migrating ants", - "Problem 394: Eating pie", - "Problem 395: Pythagorean tree", - "Problem 396: Weak Goodstein sequence", - "Problem 397: Triangle on parabola", - "Problem 398: Cutting rope", - "Problem 399: Squarefree Fibonacci Numbers", - "Problem 400: Fibonacci tree game", - "Problem 401: Sum of squares of divisors", - "Problem 402: Integer-valued polynomials", - "Problem 403: Lattice points enclosed by parabola and line", - "Problem 404: Crisscross Ellipses", - "Problem 405: A rectangular tiling", - "Problem 406: Guessing Game", - "Problem 407: Idempotents", - "Problem 408: Admissible paths through a grid", - "Problem 409: Nim Extreme", - "Problem 410: Circle and tangent line", - "Problem 411: Uphill paths", - "Problem 412: Gnomon numbering", - "Problem 413: One-child Numbers", - "Problem 414: Kaprekar constant", - "Problem 415: Titanic sets", - "Problem 416: A frog's trip", - "Problem 417: Reciprocal cycles II", - "Problem 418: Factorisation triples", - "Problem 419: Look and say sequence", - "Problem 420: 2x2 positive integer matrix", - "Problem 421: Prime factors of n15+1", - "Problem 422: Sequence of points on a hyperbola", - "Problem 423: Consecutive die throws", - "Problem 424: Kakuro", - "Problem 425: Prime connection", - "Problem 426: Box-ball system", - "Problem 427: n-sequences", - "Problem 428: Necklace of Circles", - "Problem 429: Sum of squares of unitary divisors", - "Problem 430: Range flips", - "Problem 431: Square Space Silo", - "Problem 432: Totient sum", - "Problem 433: Steps in Euclid's algorithm", - "Problem 434: Rigid graphs", - "Problem 435: Polynomials of Fibonacci numbers", - "Problem 436: Unfair wager", - "Problem 437: Fibonacci primitive roots", - "Problem 438: Integer part of polynomial equation's solutions", - "Problem 439: Sum of sum of divisors", - "Problem 440: GCD and Tiling", - "Problem 441: The inverse summation of coprime couples", - "Problem 442: Eleven-free integers", - "Problem 443: GCD sequence", - "Problem 444: The Roundtable Lottery", - "Problem 445: Retractions A", - "Problem 446: Retractions B", - "Problem 447: Retractions C", - "Problem 448: Average least common multiple", - "Problem 449: Chocolate covered candy", - "Problem 450: Hypocycloid and Lattice points", - "Problem 451: Modular inverses", - "Problem 452: Long Products", - "Problem 453: Lattice Quadrilaterals", - "Problem 454: Diophantine reciprocals III", - "Problem 455: Powers With Trailing Digits", - "Problem 456: Triangles containing the origin II", - "Problem 457: A polynomial modulo the square of a prime", - "Problem 458: Permutations of Project", - "Problem 459: Flipping game", - "Problem 460: An ant on the move", - "Problem 461: Almost Pi", - "Problem 462: Permutation of 3-smooth numbers", - "Problem 463: A weird recurrence relation", - "Problem 464: Möbius function and intervals", - "Problem 465: Polar polygons", - "Problem 466: Distinct terms in a multiplication table", - "Problem 467: Superinteger", - "Problem 468: Smooth divisors of binomial coefficients", - "Problem 469: Empty chairs", - "Problem 470: Super Ramvok", - "Problem 471: Triangle inscribed in ellipse", - "Problem 472: Comfortable Distance II", - "Problem 473: Phigital number base", - "Problem 474: Last digits of divisors", - "Problem 475: Music festival", - "Problem 476: Circle Packing II", - "Problem 477: Number Sequence Game", - "Problem 478: Mixtures", - "Problem 479: Roots on the Rise", - "Problem 480: The Last Question" - ] - } -}; - let challengeMap = lesson_map; + const rawJSON = fs.readFileSync('gvl_codes_path.json'); + let challengeMap = JSON.parse(rawJSON); + console.log(challengeMap); // Inconsistent capitalization, thus map to lower case completedChallenges = completedChallenges.map(x => x.toLowerCase()); @@ -1578,14 +74,13 @@ let getProgress = (completedChallenges) => { // Writes the JSON object to a file let writeJSON = (json) => { - const fs = require('fs'); const outputFile = 'fcc_progress.json'; // Format the json for readability const jsonString = JSON.stringify(json, null, 2); fs.writeFile(outputFile, jsonString, (err) => { // Report success / failure - const successMessage = 'FCC progress was written to ' + outputFile; + const successMessage = 'Greenville Codes progress was written to ' + outputFile; err ? console.log(err) : console.log(successMessage); }); }; From 32359534b1beae01251c3b9c4b56d1917c22e327 Mon Sep 17 00:00:00 2001 From: Creighton Magoun Date: Fri, 19 Oct 2018 02:41:48 +0000 Subject: [PATCH 22/37] Update master curriculum to pull from gvl_codes_path.json --- fcc_progress.js | 1 - 1 file changed, 1 deletion(-) diff --git a/fcc_progress.js b/fcc_progress.js index 005eab2..6cec630 100644 --- a/fcc_progress.js +++ b/fcc_progress.js @@ -48,7 +48,6 @@ let getProgress = (completedChallenges) => { // Hard coded, but can be pulled dynamically with lesson_map.js const rawJSON = fs.readFileSync('gvl_codes_path.json'); let challengeMap = JSON.parse(rawJSON); - console.log(challengeMap); // Inconsistent capitalization, thus map to lower case completedChallenges = completedChallenges.map(x => x.toLowerCase()); From b834a47760bb2ad7ff83f26d97b32a167803c8ae Mon Sep 17 00:00:00 2001 From: Creighton Magoun Date: Fri, 19 Oct 2018 02:42:36 +0000 Subject: [PATCH 23/37] Finish working logic for bulk student progress scraping --- wip.js | 1564 ++------------------------------------------------------ 1 file changed, 35 insertions(+), 1529 deletions(-) diff --git a/wip.js b/wip.js index 77b2b61..e04b1df 100644 --- a/wip.js +++ b/wip.js @@ -2,12 +2,12 @@ const fs = require('fs'); const puppeteer = require('puppeteer'); // Read list of profile urls -let readURLs = () => { - let file = 'fcc_profiles.txt'; +// Returns an array of profile URLs +let readURLs = (file) => { let profiles = fs.readFileSync(file, 'utf8'); // Splitting the return on new line yields an array - console.log(profiles.split('\n')); + return profiles.split('\n'); }; // Fetch html using puppeteer @@ -38,1521 +38,16 @@ let parseHTML = (html) => { }; // Compare progress to overall curriculum -// Returns a JSON object +// Returns a semicolon delimited string let getProgress = (completedChallenges) => { - // Hard coded, but can be pulled dynamically with lesson_map.js - const lesson_map = { - "Responsive Web Design Certification (300 hours)": { - "Basic HTML and HTML5": [ - "Say Hello to HTML Elements", - "Headline with the h2 Element", - "Inform with the Paragraph Element", - "Fill in the Blank with Placeholder Text", - "Uncomment HTML", - "Comment out HTML", - "Delete HTML Elements", - "Introduction to HTML5 Elements", - "Add Images to Your Website", - "Link to External Pages with Anchor Elements", - "Link to Internal Sections of a Page with Anchor Elements", - "Nest an Anchor Element within a Paragraph", - "Make Dead Links Using the Hash Symbol", - "Turn an Image into a Link", - "Create a Bulleted Unordered List", - "Create an Ordered List", - "Create a Text Field", - "Add Placeholder Text to a Text Field", - "Create a Form Element", - "Add a Submit Button to a Form", - "Use HTML5 to Require a Field", - "Create a Set of Radio Buttons", - "Create a Set of Checkboxes", - "Check Radio Buttons and Checkboxes by Default", - "Nest Many Elements within a Single div Element", - "Declare the Doctype of an HTML Document", - "Define the Head and Body of an HTML Document" - ], - "Basic CSS": [ - "Change the Color of Text", - "Use CSS Selectors to Style Elements", - "Use a CSS Class to Style an Element", - "Style Multiple Elements with a CSS Class", - "Change the Font Size of an Element", - "Set the Font Family of an Element", - "Import a Google Font", - "Specify How Fonts Should Degrade", - "Size Your Images", - "Add Borders Around Your Elements", - "Add Rounded Corners with border-radius", - "Make Circular Images with a border-radius", - "Give a Background Color to a div Element", - "Set the id of an Element", - "Use an id Attribute to Style an Element", - "Adjust the Padding of an Element", - "Adjust the Margin of an Element", - "Add a Negative Margin to an Element", - "Add Different Padding to Each Side of an Element", - "Add Different Margins to Each Side of an Element", - "Use Clockwise Notation to Specify the Padding of an Element", - "Use Clockwise Notation to Specify the Margin of an Element", - "Use Attribute Selectors to Style Elements", - "Understand Absolute versus Relative Units", - "Style the HTML Body Element", - "Inherit Styles from the Body Element", - "Prioritize One Style Over Another", - "Override Styles in Subsequent CSS", - "Override Class Declarations by Styling ID Attributes", - "Override Class Declarations with Inline Styles", - "Override All Other Styles by using Important", - "Use Hex Code for Specific Colors", - "Use Hex Code to Mix Colors", - "Use Abbreviated Hex Code", - "Use RGB values to Color Elements", - "Use RGB to Mix Colors", - "Use CSS Variables to change several elements at once", - "Create a custom CSS Variable", - "Use a custom CSS Variable", - "Attach a Fallback value to a CSS Variable", - "Improve Compatibility with Browser Fallbacks", - "Cascading CSS variables", - "Change a variable for a specific area", - "Use a media query to change a variable" - ], - "Applied Visual Design": [ - "Create Visual Balance Using the text-align Property", - "Adjust the Width of an Element Using the width Property", - "Adjust the Height of an Element Using the height Property", - "Use the strong Tag to Make Text Bold", - "Use the u Tag to Underline Text", - "Use the em Tag to Italicize Text", - "Use the s Tag to Strikethrough Text", - "Create a Horizontal Line Using the hr Element", - "Adjust the background-color Property of Text", - "Adjust the Size of a Header Versus a Paragraph Tag", - "Add a box-shadow to a Card-like Element", - "Decrease the Opacity of an Element", - "Use the text-transform Property to Make Text Uppercase", - "Set the font-size for Multiple Heading Elements", - "Set the font-weight for Multiple Heading Elements", - "Set the font-size of Paragraph Text", - "Set the line-height of Paragraphs", - "Adjust the Hover State of an Anchor Tag", - "Change an Element's Relative Position", - "Move a Relatively Positioned Element with CSS Offsets", - "Lock an Element to its Parent with Absolute Positioning", - "Lock an Element to the Browser Window with Fixed Positioning", - "Push Elements Left or Right with the float Property", - "Change the Position of Overlapping Elements with the z-index Property", - "Center an Element Horizontally Using the margin Property", - "Learn about Complementary Colors", - "Learn about Tertiary Colors", - "Adjust the Color of Various Elements to Complementary Colors", - "Adjust the Hue of a Color", - "Adjust the Tone of a Color", - "Create a Gradual CSS Linear Gradient", - "Use a CSS Linear Gradient to Create a Striped Element", - "Create Texture by Adding a Subtle Pattern as a Background Image", - "Use the CSS Transform scale Property to Change the Size of an Element", - "Use the CSS Transform scale Property to Scale an Element on Hover", - "Use the CSS Transform Property skewX to Skew an Element Along the X-Axis", - "Use the CSS Transform Property skewY to Skew an Element Along the Y-Axis", - "Create a Graphic Using CSS", - "Create a More Complex Shape Using CSS and HTML", - "Learn How the CSS @keyframes and animation Properties Work", - "Use CSS Animation to Change the Hover State of a Button", - "Modify Fill Mode of an Animation", - "Create Movement Using CSS Animation", - "Create Visual Direction by Fading an Element from Left to Right", - "Animate Elements Continually Using an Infinite Animation Count", - "Make a CSS Heartbeat using an Infinite Animation Count", - "Animate Elements at Variable Rates", - "Animate Multiple Elements at Variable Rates", - "Change Animation Timing with Keywords", - "Learn How Bezier Curves Work", - "Use a Bezier Curve to Move a Graphic", - "Make Motion More Natural Using a Bezier Curve" - ], - "Applied Accessibility": [ - "Add a Text Alternative to Images for Visually Impaired Accessibility", - "Know When Alt Text Should be Left Blank", - "Use Headings to Show Hierarchical Relationships of Content", - "Jump Straight to the Content Using the main Element", - "Wrap Content in the article Element", - "Make Screen Reader Navigation Easier with the header Landmark", - "Make Screen Reader Navigation Easier with the nav Landmark", - "Make Screen Reader Navigation Easier with the footer Landmark", - "Improve Accessibility of Audio Content with the audio Element", - "Improve Chart Accessibility with the figure Element", - "Improve Form Field Accessibility with the label Element", - "Wrap Radio Buttons in a fieldset Element for Better Accessibility", - "Add an Accessible Date Picker", - "Standardize Times with the HTML5 datetime Attribute", - "Make Elements Only Visible to a Screen Reader by Using Custom CSS", - "Improve Readability with High Contrast Text", - "Avoid Colorblindness Issues by Using Sufficient Contrast", - "Avoid Colorblindness Issues by Carefully Choosing Colors that Convey Information", - "Give Links Meaning by Using Descriptive Link Text", - "Make Links Navigatable with HTML Access Keys", - "Use tabindex to Add Keyboard Focus to an Element", - "Use tabindex to Specify the Order of Keyboard Focus for Several Elements" - ], - "Responsive Web Design Principles": [ - "Create a Media Query", - "Make an Image Responsive", - "Use a Retina Image for Higher Resolution Displays", - "Make Typography Responsive" - ], - "CSS Flexbox": [ - "Use display: flex to Position Two Boxes", - "Add Flex Superpowers to the Tweet Embed", - "Use the flex-direction Property to Make a Row", - "Apply the flex-direction Property to Create Rows in the Tweet Embed", - "Use the flex-direction Property to Make a Column", - "Apply the flex-direction Property to Create a Column in the Tweet Embed", - "Align Elements Using the justify-content Property", - "Use the justify-content Property in the Tweet Embed", - "Align Elements Using the align-items Property", - "Use the align-items Property in the Tweet Embed", - "Use the flex-wrap Property to Wrap a Row or Column", - "Use the flex-shrink Property to Shrink Items", - "Use the flex-grow Property to Expand Items", - "Use the flex-basis Property to Set the Initial Size of an Item", - "Use the flex Shorthand Property", - "Use the order Property to Rearrange Items", - "Use the align-self Property" - ], - "CSS Grid": [ - "Create Your First CSS Grid", - "Add Columns with grid-template-columns", - "Add Rows with grid-template-rows", - "Use CSS Grid units to Change the Size of Columns and Rows", - "Create a Column Gap Using grid-column-gap", - "Create a Row Gap using grid-row-gap", - "Add Gaps Faster with grid-gap", - "Use grid-column to Control Spacing", - "Use grid-row to Control Spacing", - "Align an Item Horizontally using justify-self", - "Align an Item Vertically using align-self", - "Align All Items Horizontally using justify-items", - "Align All Items Vertically using align-items", - "Divide the Grid Into an Area Template", - "Place Items in Grid Areas Using the grid-area Property", - "Use grid-area Without Creating an Areas Template", - "Reduce Repetition Using the repeat Function", - "Limit Item Size Using the minmax Function", - "Create Flexible Layouts Using auto-fill", - "Create Flexible Layouts Using auto-fit", - "Use Media Queries to Create Responsive Layouts", - "Create Grids within Grids" - ], - "Responsive Web Design Projects": [ - "Build a Tribute Page", - "Build a Survey Form", - "Build a Product Landing Page", - "Build a Technical Documentation Page", - "Build a Personal Portfolio Webpage" - ] - }, - "Javascript Algorithms And Data Structures Certification (300 hours)": { - "Basic JavaScript": [ - "Comment Your JavaScript Code", - "Declare JavaScript Variables", - "Storing Values with the Assignment Operator", - "Initializing Variables with the Assignment Operator", - "Understanding Uninitialized Variables", - "Understanding Case Sensitivity in Variables", - "Add Two Numbers with JavaScript", - "Subtract One Number from Another with JavaScript", - "Multiply Two Numbers with JavaScript", - "Divide One Number by Another with JavaScript", - "Increment a Number with JavaScript", - "Decrement a Number with JavaScript", - "Create Decimal Numbers with JavaScript", - "Multiply Two Decimals with JavaScript", - "Divide One Decimal by Another with JavaScript", - "Finding a Remainder in JavaScript", - "Compound Assignment With Augmented Addition", - "Compound Assignment With Augmented Subtraction", - "Compound Assignment With Augmented Multiplication", - "Compound Assignment With Augmented Division", - "Declare String Variables", - "Escaping Literal Quotes in Strings", - "Quoting Strings with Single Quotes", - "Escape Sequences in Strings", - "Concatenating Strings with Plus Operator", - "Concatenating Strings with the Plus Equals Operator", - "Constructing Strings with Variables", - "Appending Variables to Strings", - "Find the Length of a String", - "Use Bracket Notation to Find the First Character in a String", - "Understand String Immutability", - "Use Bracket Notation to Find the Nth Character in a String", - "Use Bracket Notation to Find the Last Character in a String", - "Use Bracket Notation to Find the Nth-to-Last Character in a String", - "Word Blanks", - "Store Multiple Values in one Variable using JavaScript Arrays", - "Nest one Array within Another Array", - "Access Array Data with Indexes", - "Modify Array Data With Indexes", - "Access Multi-Dimensional Arrays With Indexes", - "Manipulate Arrays With push()", - "Manipulate Arrays With pop()", - "Manipulate Arrays With shift()", - "Manipulate Arrays With unshift()", - "Shopping List", - "Write Reusable JavaScript with Functions", - "Passing Values to Functions with Arguments", - "Global Scope and Functions", - "Local Scope and Functions", - "Global vs. Local Scope in Functions", - "Return a Value from a Function with Return", - "Understanding Undefined Value returned from a Function", - "Assignment with a Returned Value", - "Stand in Line", - "Understanding Boolean Values", - "Use Conditional Logic with If Statements", - "Comparison with the Equality Operator", - "Comparison with the Strict Equality Operator", - "Practice comparing different values", - "Comparison with the Inequality Operator", - "Comparison with the Strict Inequality Operator", - "Comparison with the Greater Than Operator", - "Comparison with the Greater Than Or Equal To Operator", - "Comparison with the Less Than Operator", - "Comparison with the Less Than Or Equal To Operator", - "Comparisons with the Logical And Operator", - "Comparisons with the Logical Or Operator", - "Introducing Else Statements", - "Introducing Else If Statements", - "Logical Order in If Else Statements", - "Chaining If Else Statements", - "Golf Code", - "Selecting from Many Options with Switch Statements", - "Adding a Default Option in Switch Statements", - "Multiple Identical Options in Switch Statements", - "Replacing If Else Chains with Switch", - "Returning Boolean Values from Functions", - "Return Early Pattern for Functions", - "Counting Cards", - "Build JavaScript Objects", - "Accessing Object Properties with Dot Notation", - "Accessing Object Properties with Bracket Notation", - "Accessing Object Properties with Variables", - "Updating Object Properties", - "Add New Properties to a JavaScript Object", - "Delete Properties from a JavaScript Object", - "Using Objects for Lookups", - "Testing Objects for Properties", - "Manipulating Complex Objects", - "Accessing Nested Objects", - "Accessing Nested Arrays", - "Record Collection", - "Iterate with JavaScript While Loops", - "Iterate with JavaScript For Loops", - "Iterate Odd Numbers With a For Loop", - "Count Backwards With a For Loop", - "Iterate Through an Array with a For Loop", - "Nesting For Loops", - "Iterate with JavaScript Do...While Loops", - "Profile Lookup", - "Generate Random Fractions with JavaScript", - "Generate Random Whole Numbers with JavaScript", - "Generate Random Whole Numbers within a Range", - "Use the parseInt Function", - "Use the parseInt Function with a Radix", - "Use the Conditional (Ternary) Operator", - "Use Multiple Conditional (Ternary) Operators" - ], - "ES6": [ - "Explore Differences Between the var and let Keywords", - "Compare Scopes of the var and let Keywords", - "Declare a Read-Only Variable with the const Keyword", - "Mutate an Array Declared with const", - "Prevent Object Mutation", - "Use Arrow Functions to Write Concise Anonymous Functions", - "Write Arrow Functions with Parameters", - "Write Higher Order Arrow Functions", - "Set Default Parameters for Your Functions", - "Use the Rest Operator with Function Parameters", - "Use the Spread Operator to Evaluate Arrays In-Place", - "Use Destructuring Assignment to Assign Variables from Objects", - "Use Destructuring Assignment to Assign Variables from Nested Objects", - "Use Destructuring Assignment to Assign Variables from Arrays", - "Use Destructuring Assignment with the Rest Operator to Reassign Array Elements", - "Use Destructuring Assignment to Pass an Object as a Function's Parameters", - "Create Strings using Template Literals", - "Write Concise Object Literal Declarations Using Simple Fields", - "Write Concise Declarative Functions with ES6", - "Use class Syntax to Define a Constructor Function", - "Use getters and setters to Control Access to an Object", - "Understand the Differences Between import and require", - "Use export to Reuse a Code Block", - "Use * to Import Everything from a File", - "Create an Export Fallback with export default", - "Import a Default Export" - ], - "Regular Expressions": [ - "Using the Test Method", - "Match Literal Strings", - "Match a Literal String with Different Possibilities", - "Ignore Case While Matching", - "Extract Matches", - "Find More Than the First Match", - "Match Anything with Wildcard Period", - "Match Single Character with Multiple Possibilities", - "Match Letters of the Alphabet", - "Match Numbers and Letters of the Alphabet", - "Match Single Characters Not Specified", - "Match Characters that Occur One or More Times", - "Match Characters that Occur Zero or More Times", - "Find Characters with Lazy Matching", - "Find One or More Criminals in a Hunt", - "Match Beginning String Patterns", - "Match Ending String Patterns", - "Match All Letters and Numbers", - "Match Everything But Letters and Numbers", - "Match All Numbers", - "Match All Non-Numbers", - "Restrict Possible Usernames", - "Match Whitespace", - "Match Non-Whitespace Characters", - "Specify Upper and Lower Number of Matches", - "Specify Only the Lower Number of Matches", - "Specify Exact Number of Matches", - "Check for All or None", - "Positive and Negative Lookahead", - "Reuse Patterns Using Capture Groups", - "Use Capture Groups to Search and Replace", - "Remove Whitespace from Start and End" - ], - "Debugging": [ - "Use the JavaScript Console to Check the Value of a Variable", - "Understanding the Differences between the freeCodeCamp and Browser Console", - "Use typeof to Check the Type of a Variable", - "Catch Misspelled Variable and Function Names", - "Catch Unclosed Parentheses, Brackets, Braces and Quotes", - "Catch Mixed Usage of Single and Double Quotes", - "Catch Use of Assignment Operator Instead of Equality Operator", - "Catch Missing Open and Closing Parenthesis After a Function Call", - "Catch Arguments Passed in the Wrong Order When Calling a Function", - "Catch Off By One Errors When Using Indexing", - "Use Caution When Reinitializing Variables Inside a Loop", - "Prevent Infinite Loops with a Valid Terminal Condition" - ], - "Basic Data Structures": [ - "Use an Array to Store a Collection of Data", - "Access an Array's Contents Using Bracket Notation", - "Add Items to an Array with push() and unshift()", - "Remove Items from an Array with pop() and shift()", - "Remove Items Using splice()", - "Add Items Using splice()", - "Copy Array Items Using slice()", - "Copy an Array with the Spread Operator", - "Combine Arrays with the Spread Operator", - "Check For The Presence of an Element With indexOf()", - "Iterate Through All an Array's Items Using For Loops", - "Create complex multi-dimensional arrays", - "Add Key-Value Pairs to JavaScript Objects", - "Modify an Object Nested Within an Object", - "Access Property Names with Bracket Notation", - "Use the delete Keyword to Remove Object Properties", - "Check if an Object has a Property", - " Iterate Through the Keys of an Object with a for...in Statement", - "Generate an Array of All Object Keys with Object.keys()", - "Modify an Array Stored in an Object" - ], - "Basic Algorithm Scripting": [ - "Convert Celsius to Fahrenheit", - "Reverse a String", - "Factorialize a Number", - "Find the Longest Word in a String", - "Return Largest Numbers in Arrays", - "Confirm the Ending", - "Repeat a String Repeat a String", - "Truncate a String", - "Finders Keepers", - "Boo who", - "Title Case a Sentence", - "Slice and Splice", - "Falsy Bouncer", - "Where do I Belong", - "Mutations", - "Chunky Monkey" - ], - "Object Oriented Programming": [ - "Create a Basic JavaScript Object", - "Use Dot Notation to Access the Properties of an Object", - "Create a Method on an Object", - "Make Code More Reusable with the this Keyword", - "Define a Constructor Function", - "Use a Constructor to Create Objects", - "Extend Constructors to Receive Arguments", - "Verify an Object's Constructor with instanceof", - "Understand Own Properties", - "Use Prototype Properties to Reduce Duplicate Code", - "Iterate Over All Properties", - "Understand the Constructor Property", - "Change the Prototype to a New Object", - "Remember to Set the Constructor Property when Changing the Prototype", - "Understand Where an Object’s Prototype Comes From", - "Understand the Prototype Chain", - "Use Inheritance So You Don't Repeat Yourself", - "Inherit Behaviors from a Supertype", - "Set the Child's Prototype to an Instance of the Parent", - "Reset an Inherited Constructor Property", - "Add Methods After Inheritance", - "Override Inherited Methods", - "Use a Mixin to Add Common Behavior Between Unrelated Objects", - "Use Closure to Protect Properties Within an Object from Being Modified Externally", - "Understand the Immediately Invoked Function Expression (IIFE)", - "Use an IIFE to Create a Module" - ], - "Functional Programming": [ - "Learn About Functional Programming", - "Understand Functional Programming Terminology", - "Understand the Hazards of Using Imperative Code", - "Avoid Mutations and Side Effects Using Functional Programming", - "Pass Arguments to Avoid External Dependence in a Function", - "Refactor Global Variables Out of Functions", - "Use the map Method to Extract Data from an Array", - "Implement map on a Prototype", - "Use the filter Method to Extract Data from an Array", - "Implement the filter Method on a Prototype", - "Return Part of an Array Using the slice Method", - "Remove Elements from an Array Using slice Instead of splice", - "Combine Two Arrays Using the concat Method", - "Add Elements to the End of an Array Using concat Instead of push", - "Use the reduce Method to Analyze Data", - "Sort an Array Alphabetically using the sort Method", - "Return a Sorted Array Without Changing the Original Array", - "Split a String into an Array Using the split Method", - "Combine an Array into a String Using the join Method", - "Apply Functional Programming to Convert Strings to URL Slugs", - "Use the every Method to Check that Every Element in an Array Meets a Criteria", - "Use the some Method to Check that Any Elements in an Array Meet a Criteria", - "Introduction to Currying and Partial Application" - ], - "Intermediate Algorithm Scripting": [ - "Sum All Numbers in a Range", - "Diff Two Arrays", - "Seek and Destroy", - "Wherefore art thou", - "Spinal Tap Case", - "Pig Latin", - "Search and Replace", - "DNA Pairing", - "Missing letters", - "Sorted Union", - "Convert HTML Entities", - "Sum All Odd Fibonacci Numbers", - "Sum All Primes", - "Smallest Common Multiple", - "Drop it", - "Steamroller", - "Binary Agents", - "Everything Be True", - "Arguments Optional", - "Make a Person", - "Map the Debris" - ], - "JavaScript Algorithms and Data Structures Projects": [ - "Palindrome Checker", - "Roman Numeral Converter", - "Caesars Cipher", - "Telephone Number Validator", - "Cash Register" - ] - }, - "Front End Libraries Certification (300 hours)": { - "Bootstrap": [ - "Use Responsive Design with Bootstrap Fluid Containers", - "Make Images Mobile Responsive", - "Center Text with Bootstrap", - "Create a Bootstrap Button", - "Create a Block Element Bootstrap Button", - "Taste the Bootstrap Button Color Rainbow", - "Call out Optional Actions with btn-info", - "Warn Your Users of a Dangerous Action with btn-danger", - "Use the Bootstrap Grid to Put Elements Side By Side", - "Ditch Custom CSS for Bootstrap", - "Use a span to Target Inline Elements", - "Create a Custom Heading", - "Add Font Awesome Icons to our Buttons", - "Add Font Awesome Icons to all of our Buttons", - "Responsively Style Radio Buttons", - "Responsively Style Checkboxes", - "Style Text Inputs as Form Controls", - "Line up Form Elements Responsively with Bootstrap", - "Create a Bootstrap Headline", - "House our page within a Bootstrap container-fluid div", - "Create a Bootstrap Row", - "Split Your Bootstrap Row", - "Create Bootstrap Wells", - "Add Elements within Your Bootstrap Wells", - "Apply the Default Bootstrap Button Style", - "Create a Class to Target with jQuery Selectors", - "Add id Attributes to Bootstrap Elements", - "Label Bootstrap Wells", - "Give Each Element a Unique id", - "Label Bootstrap Buttons", - "Use Comments to Clarify Code" - ], - "jQuery": [ - "Learn How Script Tags and Document Ready Work", - "Target HTML Elements with Selectors Using jQuery", - "Target Elements by Class Using jQuery", - "Target Elements by id Using jQuery", - "Delete Your jQuery Functions", - "Target the Same Element with Multiple jQuery Selectors", - "Remove Classes from an Element with jQuery", - "Change the CSS of an Element Using jQuery", - "Disable an Element Using jQuery", - "Change Text Inside an Element Using jQuery", - "Remove an Element Using jQuery", - "Use appendTo to Move Elements with jQuery", - "Clone an Element Using jQuery", - "Target the Parent of an Element Using jQuery", - "Target the Children of an Element Using jQuery", - "Target a Specific Child of an Element Using jQuery", - "Target Even Elements Using jQuery", - "Use jQuery to Modify the Entire Page" - ], - "Sass": [ - "Store Data with Sass Variables", - "Nest CSS with Sass", - "Create Reusable CSS with Mixins", - "Use @if and @else to Add Logic To Your Styles", - "Use @for to Create a Sass Loop", - "Use @each to Map Over Items in a List", - "Apply a Style Until a Condition is Met with @while", - "Split Your Styles into Smaller Chunks with Partials", - "Extend One Set of CSS Styles to Another Element" - ], - "React": [ - "Create a Simple JSX Element", - "Create a Complex JSX Element", - "Add Comments in JSX", - "Render HTML Elements to the DOM", - "Define an HTML Class in JSX", - "Learn About Self-Closing JSX Tags", - "Create a Stateless Functional Component", - "Create a React Component", - "Create a Component with Composition", - "Use React to Render Nested Components", - "Compose React Components", - "Render a Class Component to the DOM", - "Write a React Component from Scratch", - "Pass Props to a Stateless Functional Component", - "Pass an Array as Props", - "Use Default Props", - "Override Default Props", - "Use PropTypes to Define the Props You Expect", - "Access Props Using this.props", - "Review Using Props with Stateless Functional Components", - "Create a Stateful Component", - "Render State in the User Interface", - "Render State in the User Interface Another Way", - "Set State with this.setState", - "Bind 'this' to a Class Method", - "Use State to Toggle an Element", - "Write a Simple Counter", - "Create a Controlled Input", - "Create a Controlled Form", - "Pass State as Props to Child Components", - "Pass a Callback as Props", - "Use the Lifecycle Method componentWillMount", - "Use the Lifecycle Method componentDidMount", - "Add Event Listeners", - "Manage Updates with Lifecycle Methods", - "Optimize Re-Renders with shouldComponentUpdate", - "Introducing Inline Styles", - "Add Inline Styles in React", - "Use Advanced JavaScript in React Render Method", - "Render with an If/Else Condition", - "Use && for a More Concise Conditional", - "Use a Ternary Expression for Conditional Rendering", - "Render Conditionally from Props", - "Change Inline CSS Conditionally Based on Component State", - "Use Array.map() to Dynamically Render Elements", - "Give Sibling Elements a Unique Key Attribute", - "Use Array.filter() to Dynamically Filter an Array", - "Render React on the Server with renderToString" - ], - "Redux": [ - "Create a Redux Store", - "Get State from the Redux Store", - "Define a Redux Action", - "Define an Action Creator", - "Dispatch an Action Event", - "Handle an Action in the Store", - "Use a Switch Statement to Handle Multiple Actions", - "Use const for Action Types", - "Register a Store Listener", - "Combine Multiple Reducers", - "Send Action Data to the Store", - "Use Middleware to Handle Asynchronous Actions", - "Write a Counter with Redux", - "Never Mutate State", - "Use the Spread Operator on Arrays", - "Remove an Item from an Array", - "Copy an Object with Object.assign" - ], - "React and Redux": [ - "Getting Started with React Redux", - "Manage State Locally First", - "Extract State Logic to Redux", - "Use Provider to Connect Redux to React", - "Map State to Props", - "Map Dispatch to Props", - "Connect Redux to React", - "Connect Redux to the Messages App", - "Extract Local State into Redux", - "Moving Forward From Here" - ], - "Front End Libraries Projects": [ - "Build a Random Quote Machine", - "Build a Markdown Previewer", - "Build a Drum Machine", - "Build a JavaScript Calculator", - "Build a Pomodoro Clock" - ] - }, - "Data Visualization Certification (300 hours)": { - "Data Visualization with D3": [ - "Add Document Elements with D3", - "Select a Group of Elements with D3", - "Work with Data in D3", - "Work with Dynamic Data in D3", - "Add Inline Styling to Elements", - "Change Styles Based on Data", - "Add Classes with D3", - "Update the Height of an Element Dynamically", - "Change the Presentation of a Bar Chart", - "Learn About SVG in D3", - "Display Shapes with SVG", - "Create a Bar for Each Data Point in the Set", - "Dynamically Set the Coordinates for Each Bar", - "Dynamically Change the Height of Each Bar", - "Invert SVG Elements", - "Change the Color of an SVG Element", - "Add Labels to D3 Elements", - "Style D3 Labels", - "Add a Hover Effect to a D3 Element", - "Add a Tooltip to a D3 Element", - "Create a Scatterplot with SVG Circles", - "Add Attributes to the Circle Elements", - "Add Labels to Scatter Plot Circles", - "Create a Linear Scale with D3", - "Set a Domain and a Range on a Scale", - "Use the d3.max and d3.min Functions to Find Minimum and Maximum Values in a Dataset", - "Use Dynamic Scales", - "Use a Pre-Defined Scale to Place Elements", - "Add Axes to a Visualization" - ], - "JSON APIs and Ajax": [ - "Handle Click Events with JavaScript using the onclick property", - "Change Text with click Events", - "Get JSON with the JavaScript XMLHttpRequest Method", - "Access the JSON Data from an API", - "Convert JSON Data to HTML", - "Render Images from Data Sources", - "Pre-filter JSON to Get the Data You Need", - "Get Geolocation Data to Find A User's GPS Coordinates", - "Post Data with the JavaScript XMLHttpRequest Method" - ], - "Data Visualization Projects": [ - "Visualize Data with a Bar Chart", - "Visualize Data with a Scatterplot Graph", - "Visualize Data with a Heat Map", - "Visualize Data with a Choropleth Map", - "Visualize Data with a Treemap Diagram" - ] - }, - "Apis And Microservices Certification (300 hours)": { - "Managing Packages with Npm": [ - "How to Use package.json, the Core of Any Node.js Project or npm Package", - "Add a Description to Your package.json", - "Add Keywords to Your package.json", - "Add a License to Your package.json", - "Add a Version to Your package.json", - "Expand Your Project with External Packages from npm", - "Manage npm Dependencies By Understanding Semantic Versioning", - "Use the Tilde-Character to Always Use the Latest Patch Version of a Dependency", - "Use the Caret-Character to Use the Latest Minor Version of a Dependency", - "Remove a Package from Your Dependencies" - ], - "Basic Node and Express": [ - "Meet the Node console", - "Start a Working Express Server", - "Serve an HTML File", - "Serve Static Assets", - "Serve JSON on a Specific Route", - "Use the .env File", - "Implement a Root-Level Request Logger Middleware", - "Chain Middleware to Create a Time Server", - "Get Route Parameter Input from the Client", - "Get Query Parameter Input from the Client", - "Use body-parser to Parse POST Requests", - "Get Data from POST Requests" - ], - "MongoDB and Mongoose": [ - "Install and Set Up Mongoose", - "Create a Model", - "Create and Save a Record of a Model", - "Create Many Records with model.create()", - "Use model.find() to Search Your Database", - "Use model.findOne() to Return a Single Matching Document from Your Database", - "Use model.findById() to Search Your Database By _id", - "Perform Classic Updates by Running Find, Edit, then Save", - "Perform New Updates on a Document Using model.findOneAndUpdate()", - "Delete One Document Using model.findByIdAndRemove", - "Delete Many Documents with model.remove()", - "Chain Search Query Helpers to Narrow Search Results" - ], - "Apis and Microservices Projects": [ - "Timestamp Microservice", - "Request Header Parser Microservice", - "URL Shortener Microservice", - "Exercise Tracker", - "File Metadata Microservice" - ] - }, - "Information Security And Quality Assurance Certification (300 hours)": { - "Information Security with HelmetJS": [ - "Install and Require Helmet", - "Hide Potentially Dangerous Information Using helmet.hidePoweredBy()", - "Mitigate the Risk of Clickjacking with helmet.frameguard()", - "Mitigate the Risk of Cross Site Scripting (XSS) Attacks with helmet.xssFilter()", - "Avoid Inferring the Response MIME Type with helmet.noSniff()", - "Prevent IE from Opening Untrusted HTML with helmet.ieNoOpen()", - "Ask Browsers to Access Your Site via HTTPS Only with helmet.hsts()", - "Disable DNS Prefetching with helmet.dnsPrefetchControl()", - "Disable Client-Side Caching with helmet.noCache()", - "Set a Content Security Policy with helmet.contentSecurityPolicy()", - "Configure Helmet Using the ‘parent’ helmet() Middleware", - "Understand BCrypt Hashes", - "Hash and Compare Passwords Asynchronously", - "Hash and Compare Passwords Synchronously" - ], - "Quality Assurance and Testing with Chai": [ - "Learn How JavaScript Assertions Work", - "Test if a Variable or Function is Defined", - "Use Assert.isOK and Assert.isNotOK", - "Test for Truthiness", - "Use the Double Equals to Assert Equality", - "Use the Triple Equals to Assert Strict Equality", - "Assert Deep Equality with .deepEqual and .notDeepEqual", - "Compare the Properties of Two Elements", - "Test if One Value is Below or At Least as Large as Another", - "Test if a Value Falls within a Specific Range", - "Test if a Value is an Array", - "Test if an Array Contains an Item", - "Test if a Value is a String", - "Test if a String Contains a Substring", - "Use Regular Expressions to Test a String", - "Test if an Object has a Property", - "Test if a Value is of a Specific Data Structure Type", - "Test if an Object is an Instance of a Constructor", - "Run Functional Tests on API Endpoints using Chai-HTTP", - "Run Functional Tests on API Endpoints using Chai-HTTP II", - "Run Functional Tests on an API Response using Chai-HTTP III - PUT method", - "Run Functional Tests on an API Response using Chai-HTTP IV - PUT method", - "Run Functional Tests using a Headless Browser", - "Run Functional Tests using a Headless Browser II" - ], - "Advanced Node and Express": [ - "Set up a Template Engine", - "Use a Template Engine's Powers", - "Set up Passport", - "Serialization of a User Object", - "Implement the Serialization of a Passport User", - "Authentication Strategies", - "How to Use Passport Strategies", - "Create New Middleware", - "How to Put a Profile Together", - "Logging a User Out", - "Registration of New Users", - "Hashing Your Passwords", - "Clean Up Your Project with Modules", - "Implementation of Social Authentication", - "Implementation of Social Authentication II", - "Implementation of Social Authentication III", - "Set up the Environment", - "Communicate by Emitting", - "Handle a Disconnect", - "Authentication with Socket.IO", - "Announce New Users", - "Send and Display Chat Messages" - ], - "Information Security and Quality Assurance Projects": [ - "Metric-Imperial Converter", - "Issue Tracker", - "Personal Library", - "Stock Price Checker", - "Anonymous Message Board" - ] - }, - "Coding Interview Prep (Thousands of hours of challenges)": { - "Algorithms": [ - "Find the Symmetric Difference", - "Inventory Update", - "No Repeats Please", - "Pairwise", - "Implement Bubble Sort", - "Implement Selection Sort", - "Implement Insertion Sort", - "Implement Quick Sort", - "Implement Merge Sort" - ], - "Data Structures": [ - "Typed Arrays", - "Learn how a Stack Works", - "Create a Stack Class", - "Create a Queue Class", - "Create a Priority Queue Class", - "Create a Circular Queue", - "Create a Set Class", - "Remove from a Set", - "Size of the Set", - "Perform a Union on Two Sets", - "Perform an Intersection on Two Sets of Data", - "Perform a Difference on Two Sets of Data", - "Perform a Subset Check on Two Sets of Data", - "Create and Add to Sets in ES6", - "Remove items from a set in ES6", - "Use .has and .size on an ES6 Set", - "Use Spread and Notes for ES5 Set() Integration", - "Create a Map Data Structure", - "Create an ES6 JavaScript Map", - "Create a Hash Table", - "Work with Nodes in a Linked List", - "Create a Linked List Class", - "Remove Elements from a Linked List", - "Search within a Linked List", - "Remove Elements from a Linked List by Index", - "Add Elements at a Specific Index in a Linked List", - "Create a Doubly Linked List", - "Reverse a Doubly Linked List", - "Find the Minimum and Maximum Value in a Binary Search Tree", - "Add a New Element to a Binary Search Tree", - "Check if an Element is Present in a Binary Search Tree", - "Find the Minimum and Maximum Height of a Binary Search Tree", - "Use Depth First Search in a Binary Search Tree", - "Use Breadth First Search in a Binary Search Tree", - "Delete a Leaf Node in a Binary Search Tree", - "Delete a Node with One Child in a Binary Search Tree", - "Delete a Node with Two Children in a Binary Search Tree", - "Invert a Binary Tree", - "Create a Trie Search Tree", - "Insert an Element into a Max Heap", - "Remove an Element from a Max Heap", - "Implement Heap Sort with a Min Heap", - "Adjacency List", - "Adjacency Matrix", - "Incidence Matrix", - "Breadth-First Search", - "Depth-First Search" - ], - "Take Home Projects": [ - "Show the Local Weather", - "Build a Wikipedia Viewer", - "Use the Twitch JSON API", - "Build an Image Search Abstraction Layer", - "Build a Tic Tac Toe Game", - "Build a Simon Game", - "Build a Camper Leaderboard", - "Build a Recipe Box", - "Build the Game of Life", - "Build a Roguelike Dungeon Crawler Game", - "P2P Video Chat Application", - "Show National Contiguity with a Force Directed Graph", - "Map Data Across the Globe", - "Manage a Book Trading Club", - "Build a Pinterest Clone", - "Build a Nightlife Coordination App", - "Chart the Stock Market", - "Build a Voting App", - "Build a Pong Game", - "Build a Light-Bright App" - ], - "Rosetta Code": [ - "100 doors", - "24 game", - "9 billion names of God the integer", - "ABC Problem", - "Abundant, deficient and perfect number classifications", - "Accumulator factory", - "Ackermann function", - "Align columns", - "Amicable pairs", - "Averages/Mode", - "Averages/Pythagorean means", - "Averages/Root mean square", - "Babbage problem", - "Balanced brackets", - "Circles of given radius through two points", - "Closest-pair problem", - "Combinations", - "Comma quibbling", - "Compare a list of strings", - "Convert seconds to compound duration", - "Count occurrences of a substring", - "Count the coins", - "Cramer's rule", - "Date format", - "Date manipulation", - "Day of the week", - "Deal cards for FreeCell", - "Deepcopy", - "Define a primitive data type", - "Department Numbers", - "Discordian date", - "Element-wise operations", - "Emirp primes", - "Entropy", - "Equilibrium index", - "Ethiopian multiplication", - "Euler method", - "Evaluate binomial coefficients", - "Execute a Markov algorithm", - "Execute Brain****", - "Extensible prime generator", - "Factorial", - "Factors of a Mersenne number", - "Factors of an integer", - "Farey sequence", - "Fibonacci n-step number sequences", - "Fibonacci sequence", - "Fibonacci word", - "Fractran", - "Gamma function", - "Gaussian elimination", - "General FizzBuzz", - "Generate lower case ASCII alphabet", - "Generator/Exponential", - "Gray code", - "Greatest common divisor", - "Greatest subsequential sum", - "Hailstone sequence", - "Happy numbers", - "Harshad or Niven series", - "Hash from two arrays", - "Hash join", - "Heronian triangles", - "Hofstadter Figure-Figure sequences", - "Hofstadter Q sequence", - "I before E except after C", - "IBAN", - "Identity matrix", - "Iterated digits squaring", - "Jaro distance", - "JortSort", - "Josephus problem", - "Sailors, coconuts and a monkey problem", - "SEDOLs", - "S-Expressions", - "Taxicab numbers", - "Tokenize a string with escaping", - "Topological sort", - "Top rank per group", - "Towers of Hanoi", - "Vector cross product", - "Vector dot product", - "Word wrap", - "Y combinator", - "Zeckendorf number representation", - "Zhang-Suen thinning algorithm", - "Zig-zag matrix" - ], - "Project Euler": [ - "Problem 1: Multiples of 3 and 5", - "Problem 2: Even Fibonacci Numbers", - "Problem 3: Largest prime factor", - "Problem 4: Largest palindrome product", - "Problem 5: Smallest multiple", - "Problem 6: Sum square difference", - "Problem 7: 10001st prime", - "Problem 8: Largest product in a series", - "Problem 9: Special Pythagorean triplet", - "Problem 10: Summation of primes", - "Problem 11: Largest product in a grid", - "Problem 12: Highly divisible triangular number", - "Problem 13: Large sum", - "Problem 14: Longest Collatz sequence", - "Problem 15: Lattice paths", - "Problem 16: Power digit sum", - "Problem 17: Number letter counts", - "Problem 18: Maximum path sum I", - "Problem 19: Counting Sundays", - "Problem 20: Factorial digit sum", - "Problem 21: Amicable numbers", - "Problem 22: Names scores", - "Problem 23: Non-abundant sums", - "Problem 24: Lexicographic permutations", - "Problem 25: 1000-digit Fibonacci number", - "Problem 26: Reciprocal cycles", - "Problem 27: Quadratic primes", - "Problem 28: Number spiral diagonals", - "Problem 29: Distinct powers", - "Problem 30: Digit n powers", - "Problem 31: Coin sums", - "Problem 32: Pandigital products", - "Problem 33: Digit cancelling fractions", - "Problem 34: Digit factorials", - "Problem 35: Circular primes", - "Problem 36: Double-base palindromes", - "Problem 37: Truncatable primes", - "Problem 38: Pandigital multiples", - "Problem 39: Integer right triangles", - "Problem 40: Champernowne's constant", - "Problem 41: Pandigital prime", - "Problem 42: Coded triangle numbers", - "Problem 43: Sub-string divisibility", - "Problem 44: Pentagon numbers", - "Problem 45: Triangular, pentagonal, and hexagonal", - "Problem 46: Goldbach's other conjecture", - "Problem 47: Distinct primes factors", - "Problem 48: Self powers", - "Problem 49: Prime permutations", - "Problem 50: Consecutive prime sum", - "Problem 51: Prime digit replacements", - "Problem 52: Permuted multiples", - "Problem 53: Combinatoric selections", - "Problem 54: Poker hands", - "Problem 55: Lychrel numbers", - "Problem 56: Powerful digit sum", - "Problem 57: Square root convergents", - "Problem 58: Spiral primes", - "Problem 59: XOR decryption", - "Problem 60: Prime pair sets", - "Problem 61: Cyclical figurate numbers", - "Problem 62: Cubic permutations", - "Problem 63: Powerful digit counts", - "Problem 64: Odd period square roots", - "Problem 65: Convergents of e", - "Problem 66: Diophantine equation", - "Problem 67: Maximum path sum II", - "Problem 68: Magic 5-gon ring", - "Problem 69: Totient maximum", - "Problem 70: Totient permutation", - "Problem 71: Ordered fractions", - "Problem 72: Counting fractions", - "Problem 73: Counting fractions in a range", - "Problem 74: Digit factorial chains", - "Problem 75: Singular integer right triangles", - "Problem 76: Counting summations", - "Problem 77: Prime summations", - "Problem 78: Coin partitions", - "Problem 79: Passcode derivation", - "Problem 80: Square root digital expansion", - "Problem 81: Path sum: two ways", - "Problem 82: Path sum: three ways", - "Problem 83: Path sum: four ways", - "Problem 84: Monopoly odds", - "Problem 85: Counting rectangles", - "Problem 86: Cuboid route", - "Problem 87: Prime power triples", - "Problem 88: Product-sum numbers", - "Problem 89: Roman numerals", - "Problem 90: Cube digit pairs", - "Problem 91: Right triangles with integer coordinates", - "Problem 92: Square digit chains", - "Problem 93: Arithmetic expressions", - "Problem 94: Almost equilateral triangles", - "Problem 95: Amicable chains", - "Problem 96: Su Doku", - "Problem 97: Large non-Mersenne prime", - "Problem 98: Anagramic squares", - "Problem 99: Largest exponential", - "Problem 100: Arranged probability", - "Problem 101: Optimum polynomial", - "Problem 102: Triangle containment", - "Problem 103: Special subset sums: optimum", - "Problem 104: Pandigital Fibonacci ends", - "Problem 105: Special subset sums: testing", - "Problem 106: Special subset sums: meta-testing", - "Problem 107: Minimal network", - "Problem 108: Diophantine Reciprocals I", - "Problem 109: Darts", - "Problem 110: Diophantine Reciprocals II", - "Problem 111: Primes with runs", - "Problem 112: Bouncy numbers", - "Problem 113: Non-bouncy numbers", - "Problem 114: Counting block combinations I", - "Problem 115: Counting block combinations II", - "Problem 116: Red, green or blue tiles", - "Problem 117: Red, green, and blue tiles", - "Problem 118: Pandigital prime sets", - "Problem 119: Digit power sum", - "Problem 120: Square remainders", - "Problem 121: Disc game prize fund", - "Problem 122: Efficient exponentiation", - "Problem 123: Prime square remainders", - "Problem 124: Ordered radicals", - "Problem 125: Palindromic sums", - "Problem 126: Cuboid layers", - "Problem 127: abc-hits", - "Problem 128: Hexagonal tile differences", - "Problem 129: Repunit divisibility", - "Problem 130: Composites with prime repunit property", - "Problem 131: Prime cube partnership", - "Problem 132: Large repunit factors", - "Problem 133: Repunit nonfactors", - "Problem 134: Prime pair connection", - "Problem 135: Same differences", - "Problem 136: Singleton difference", - "Problem 137: Fibonacci golden nuggets", - "Problem 138: Special isosceles triangles", - "Problem 139: Pythagorean tiles", - "Problem 140: Modified Fibonacci golden nuggets", - "Problem 141: Investigating progressive numbers, n, which are also square", - "Problem 142: Perfect Square Collection", - "Problem 143: Investigating the Torricelli point of a triangle", - "Problem 144: Investigating multiple reflections of a laser beam", - "Problem 145: How many reversible numbers are there below one-billion?", - "Problem 146: Investigating a Prime Pattern", - "Problem 147: Rectangles in cross-hatched grids", - "Problem 148: Exploring Pascal's triangle", - "Problem 149: Searching for a maximum-sum subsequence", - "Problem 150: Searching a triangular array for a sub-triangle having minimum-sum", - "Problem 151: Paper sheets of standard sizes: an expected-value problem", - "Problem 152: Writing 1/2 as a sum of inverse squares", - "Problem 153: Investigating Gaussian Integers", - "Problem 154: Exploring Pascal's pyramid", - "Problem 155: Counting Capacitor Circuits", - "Problem 156: Counting Digits", - "Problem 157: Solving the diophantine equation 1/a+1/b= p/10n", - "Problem 158: Exploring strings for which only one character comes lexicographically after its neighbour to the left", - "Problem 159: Digital root sums of factorisations", - "Problem 160: Factorial trailing digits", - "Problem 161: Triominoes", - "Problem 162: Hexadecimal numbers", - "Problem 163: Cross-hatched triangles", - "Problem 164: Numbers for which no three consecutive digits have a sum greater than a given value", - "Problem 165: Intersections", - "Problem 166: Criss Cross", - "Problem 167: Investigating Ulam sequences", - "Problem 168: Number Rotations", - "Problem 169: Exploring the number of different ways a number can be expressed as a sum of powers of 2", - "Problem 170: Find the largest 0 to 9 pandigital that can be formed by concatenating products", - "Problem 171: Finding numbers for which the sum of the squares of the digits is a square", - "Problem 172: Investigating numbers with few repeated digits", - "Problem 173: Using up to one million tiles how many different \"hollow\" square laminae can be formed?", - "Problem 174: Counting the number of \"hollow\" square laminae that can form one, two, three, ... distinct arrangements", - "Problem 175: Fractions involving the number of different ways a number can be expressed as a sum of powers of 2", - "Problem 176: Right-angled triangles that share a cathetus", - "Problem 177: Integer angled Quadrilaterals", - "Problem 178: Step Numbers", - "Problem 179: Consecutive positive divisors", - "Problem 180: Rational zeros of a function of three variables", - "Problem 181: Investigating in how many ways objects of two different colours can be grouped", - "Problem 182: RSA encryption", - "Problem 183: Maximum product of parts", - "Problem 184: Triangles containing the origin", - "Problem 185: Number Mind", - "Problem 186: Connectedness of a network", - "Problem 187: Semiprimes", - "Problem 188: The hyperexponentiation of a number", - "Problem 189: Tri-colouring a triangular grid", - "Problem 190: Maximising a weighted product", - "Problem 191: Prize Strings", - "Problem 192: Best Approximations", - "Problem 193: Squarefree Numbers", - "Problem 194: Coloured Configurations", - "Problem 195: Inscribed circles of triangles with one angle of 60 degrees", - "Problem 196: Prime triplets", - "Problem 197: Investigating the behaviour of a recursively defined sequence", - "Problem 198: Ambiguous Numbers", - "Problem 199: Iterative Circle Packing", - "Problem 200: Find the 200th prime-proof sqube containing the contiguous sub-string \"200\"", - "Problem 201: Subsets with a unique sum", - "Problem 202: Laserbeam", - "Problem 203: Squarefree Binomial Coefficients", - "Problem 204: Generalised Hamming Numbers", - "Problem 205: Dice Game", - "Problem 206: Concealed Square", - "Problem 207: Integer partition equations", - "Problem 208: Robot Walks", - "Problem 209: Circular Logic", - "Problem 210: Obtuse Angled Triangles", - "Problem 211: Divisor Square Sum", - "Problem 212: Combined Volume of Cuboids", - "Problem 213: Flea Circus", - "Problem 214: Totient Chains", - "Problem 215: Crack-free Walls", - "Problem 216: Investigating the primality of numbers of the form 2n2-1", - "Problem 217: Balanced Numbers", - "Problem 218: Perfect right-angled triangles", - "Problem 219: Skew-cost coding", - "Problem 220: Heighway Dragon", - "Problem 221: Alexandrian Integers", - "Problem 222: Sphere Packing", - "Problem 223: Almost right-angled triangles I", - "Problem 224: Almost right-angled triangles II", - "Problem 225: Tribonacci non-divisors", - "Problem 226: A Scoop of Blancmange", - "Problem 227: The Chase", - "Problem 228: Minkowski Sums", - "Problem 229: Four Representations using Squares", - "Problem 230: Fibonacci Words", - "Problem 231: The prime factorisation of binomial coefficients", - "Problem 232: The Race", - "Problem 233: Lattice points on a circle", - "Problem 234: Semidivisible numbers", - "Problem 235: An Arithmetic Geometric sequence", - "Problem 236: Luxury Hampers", - "Problem 237: Tours on a 4 x n playing board", - "Problem 238: Infinite string tour", - "Problem 239: Twenty-two Foolish Primes", - "Problem 240: Top Dice", - "Problem 241: Perfection Quotients", - "Problem 242: Odd Triplets", - "Problem 243: Resilience", - "Problem 244: Sliders", - "Problem 245: Coresilience", - "Problem 246: Tangents to an ellipse", - "Problem 247: Squares under a hyperbola", - "Problem 248: Numbers for which Euler’s totient function equals 13!", - "Problem 249: Prime Subset Sums", - "Problem 250: 250250", - "Problem 251: Cardano Triplets", - "Problem 252: Convex Holes", - "Problem 253: Tidying up", - "Problem 254: Sums of Digit Factorials", - "Problem 255: Rounded Square Roots", - "Problem 256: Tatami-Free Rooms", - "Problem 257: Angular Bisectors", - "Problem 258: A lagged Fibonacci sequence", - "Problem 259: Reachable Numbers", - "Problem 260: Stone Game", - "Problem 261: Pivotal Square Sums", - "Problem 262: Mountain Range", - "Problem 263: An engineers' dream come true", - "Problem 264: Triangle Centres", - "Problem 265: Binary Circles", - "Problem 266: Pseudo Square Root", - "Problem 267: Billionaire", - "Problem 268: Counting numbers with at least four distinct prime factors less than 100", - "Problem 269: Polynomials with at least one integer root", - "Problem 270: Cutting Squares", - "Problem 271: Modular Cubes, part 1", - "Problem 272: Modular Cubes, part 2", - "Problem 273: Sum of Squares", - "Problem 274: Divisibility Multipliers", - "Problem 275: Balanced Sculptures", - "Problem 276: Primitive Triangles", - "Problem 277: A Modified Collatz sequence", - "Problem 278: Linear Combinations of Semiprimes", - "Problem 279: Triangles with integral sides and an integral angle", - "Problem 280: Ant and seeds", - "Problem 281: Pizza Toppings", - "Problem 282: The Ackermann function", - "Problem 283: Integer sided triangles for which the area/perimeter ratio is integral", - "Problem 284: Steady Squares", - "Problem 285: Pythagorean odds", - "Problem 286: Scoring probabilities", - "Problem 287: Quadtree encoding (a simple compression algorithm)", - "Problem 288: An enormous factorial", - "Problem 289: Eulerian Cycles", - "Problem 290: Digital Signature", - "Problem 291: Panaitopol Primes", - "Problem 292: Pythagorean Polygons", - "Problem 293: Pseudo-Fortunate Numbers", - "Problem 294: Sum of digits - experience #23", - "Problem 295: Lenticular holes", - "Problem 296: Angular Bisector and Tangent", - "Problem 297: Zeckendorf Representation", - "Problem 298: Selective Amnesia", - "Problem 299: Three similar triangles", - "Problem 300: Protein folding", - "Problem 301: Nim", - "Problem 302: Strong Achilles Numbers", - "Problem 303: Multiples with small digits", - "Problem 304: Primonacci", - "Problem 305: Reflexive Position", - "Problem 306: Paper-strip Game", - "Problem 307: Chip Defects", - "Problem 308: An amazing Prime-generating Automaton", - "Problem 309: Integer Ladders", - "Problem 310: Nim Square", - "Problem 311: Biclinic Integral Quadrilaterals", - "Problem 312: Cyclic paths on Sierpiński graphs", - "Problem 313: Sliding game", - "Problem 314: The Mouse on the Moon", - "Problem 315: Digital root clocks", - "Problem 316: Numbers in decimal expansions", - "Problem 317: Firecracker", - "Problem 318: 2011 nines", - "Problem 319: Bounded Sequences", - "Problem 320: Factorials divisible by a huge integer", - "Problem 321: Swapping Counters", - "Problem 322: Binomial coefficients divisible by 10", - "Problem 323: Bitwise-OR operations on random integers", - "Problem 324: Building a tower", - "Problem 325: Stone Game II", - "Problem 326: Modulo Summations", - "Problem 327: Rooms of Doom", - "Problem 328: Lowest-cost Search", - "Problem 329: Prime Frog", - "Problem 330: Euler's Number", - "Problem 331: Cross flips", - "Problem 332: Spherical triangles", - "Problem 333: Special partitions", - "Problem 334: Spilling the beans", - "Problem 335: Gathering the beans", - "Problem 336: Maximix Arrangements", - "Problem 337: Totient Stairstep Sequences", - "Problem 338: Cutting Rectangular Grid Paper", - "Problem 339: Peredur fab Efrawg", - "Problem 340: Crazy Function", - "Problem 341: Golomb's self-describing sequence", - "Problem 342: The totient of a square is a cube", - "Problem 343: Fractional Sequences", - "Problem 344: Silver dollar game", - "Problem 345: Matrix Sum", - "Problem 346: Strong Repunits", - "Problem 347: Largest integer divisible by two primes", - "Problem 348: Sum of a square and a cube", - "Problem 349: Langton's ant", - "Problem 350: Constraining the least greatest and the greatest least", - "Problem 351: Hexagonal orchards", - "Problem 352: Blood tests", - "Problem 353: Risky moon", - "Problem 354: Distances in a bee's honeycomb", - "Problem 355: Maximal coprime subset", - "Problem 356: Largest roots of cubic polynomials", - "Problem 357: Prime generating integers", - "Problem 358: Cyclic numbers", - "Problem 359: Hilbert's New Hotel", - "Problem 360: Scary Sphere", - "Problem 361: Subsequence of Thue-Morse sequence", - "Problem 362: Squarefree factors", - "Problem 363: Bézier Curves", - "Problem 364: Comfortable distance", - "Problem 365: A huge binomial coefficient", - "Problem 366: Stone Game III", - "Problem 367: Bozo sort", - "Problem 368: A Kempner-like series", - "Problem 369: Badugi", - "Problem 370: Geometric triangles", - "Problem 371: Licence plates", - "Problem 372: Pencils of rays", - "Problem 373: Circumscribed Circles", - "Problem 374: Maximum Integer Partition Product", - "Problem 375: Minimum of subsequences", - "Problem 376: Nontransitive sets of dice", - "Problem 377: Sum of digits, experience 13", - "Problem 378: Triangle Triples", - "Problem 379: Least common multiple count", - "Problem 380: Amazing Mazes!", - "Problem 381: (prime-k) factorial", - "Problem 382: Generating polygons", - "Problem 383: Divisibility comparison between factorials", - "Problem 384: Rudin-Shapiro sequence", - "Problem 385: Ellipses inside triangles", - "Problem 386: Maximum length of an antichain", - "Problem 387: Harshad Numbers", - "Problem 388: Distinct Lines", - "Problem 389: Platonic Dice", - "Problem 390: Triangles with non rational sides and integral area", - "Problem 391: Hopping Game", - "Problem 392: Enmeshed unit circle", - "Problem 393: Migrating ants", - "Problem 394: Eating pie", - "Problem 395: Pythagorean tree", - "Problem 396: Weak Goodstein sequence", - "Problem 397: Triangle on parabola", - "Problem 398: Cutting rope", - "Problem 399: Squarefree Fibonacci Numbers", - "Problem 400: Fibonacci tree game", - "Problem 401: Sum of squares of divisors", - "Problem 402: Integer-valued polynomials", - "Problem 403: Lattice points enclosed by parabola and line", - "Problem 404: Crisscross Ellipses", - "Problem 405: A rectangular tiling", - "Problem 406: Guessing Game", - "Problem 407: Idempotents", - "Problem 408: Admissible paths through a grid", - "Problem 409: Nim Extreme", - "Problem 410: Circle and tangent line", - "Problem 411: Uphill paths", - "Problem 412: Gnomon numbering", - "Problem 413: One-child Numbers", - "Problem 414: Kaprekar constant", - "Problem 415: Titanic sets", - "Problem 416: A frog's trip", - "Problem 417: Reciprocal cycles II", - "Problem 418: Factorisation triples", - "Problem 419: Look and say sequence", - "Problem 420: 2x2 positive integer matrix", - "Problem 421: Prime factors of n15+1", - "Problem 422: Sequence of points on a hyperbola", - "Problem 423: Consecutive die throws", - "Problem 424: Kakuro", - "Problem 425: Prime connection", - "Problem 426: Box-ball system", - "Problem 427: n-sequences", - "Problem 428: Necklace of Circles", - "Problem 429: Sum of squares of unitary divisors", - "Problem 430: Range flips", - "Problem 431: Square Space Silo", - "Problem 432: Totient sum", - "Problem 433: Steps in Euclid's algorithm", - "Problem 434: Rigid graphs", - "Problem 435: Polynomials of Fibonacci numbers", - "Problem 436: Unfair wager", - "Problem 437: Fibonacci primitive roots", - "Problem 438: Integer part of polynomial equation's solutions", - "Problem 439: Sum of sum of divisors", - "Problem 440: GCD and Tiling", - "Problem 441: The inverse summation of coprime couples", - "Problem 442: Eleven-free integers", - "Problem 443: GCD sequence", - "Problem 444: The Roundtable Lottery", - "Problem 445: Retractions A", - "Problem 446: Retractions B", - "Problem 447: Retractions C", - "Problem 448: Average least common multiple", - "Problem 449: Chocolate covered candy", - "Problem 450: Hypocycloid and Lattice points", - "Problem 451: Modular inverses", - "Problem 452: Long Products", - "Problem 453: Lattice Quadrilaterals", - "Problem 454: Diophantine reciprocals III", - "Problem 455: Powers With Trailing Digits", - "Problem 456: Triangles containing the origin II", - "Problem 457: A polynomial modulo the square of a prime", - "Problem 458: Permutations of Project", - "Problem 459: Flipping game", - "Problem 460: An ant on the move", - "Problem 461: Almost Pi", - "Problem 462: Permutation of 3-smooth numbers", - "Problem 463: A weird recurrence relation", - "Problem 464: Möbius function and intervals", - "Problem 465: Polar polygons", - "Problem 466: Distinct terms in a multiplication table", - "Problem 467: Superinteger", - "Problem 468: Smooth divisors of binomial coefficients", - "Problem 469: Empty chairs", - "Problem 470: Super Ramvok", - "Problem 471: Triangle inscribed in ellipse", - "Problem 472: Comfortable Distance II", - "Problem 473: Phigital number base", - "Problem 474: Last digits of divisors", - "Problem 475: Music festival", - "Problem 476: Circle Packing II", - "Problem 477: Number Sequence Game", - "Problem 478: Mixtures", - "Problem 479: Roots on the Rise", - "Problem 480: The Last Question" - ] - } -}; - let challengeMap = lesson_map; + const rawJSON = fs.readFileSync('gvl_codes_path.json'); + let challengeMap = JSON.parse(rawJSON); // Inconsistent capitalization, thus map to lower case completedChallenges = completedChallenges.map(x => x.toLowerCase()); + let progress = ''; + // Loop through curriculum JSON for (let section of Object.keys(challengeMap)) { for (let subsection of Object.keys(challengeMap[section])) { @@ -1565,36 +60,47 @@ let getProgress = (completedChallenges) => { return completedChallenges.indexOf(val) != -1 ? ++acc : acc; }, 0); - challengeMap[section][subsection] = `${Math.round(100 * numCompleted / numChallenges)}%`; + progress += `${Math.round(100 * numCompleted / numChallenges)}%` + ';'; } } - return challengeMap; + return progress; }; -// Writes the JSON object to a file -let writeJSON = (json) => { - const outputFile = 'test.json'; - // Format the json for readability - const jsonString = JSON.stringify(json, null, 2); +// Writes the url and progress strings to a file +let writeProgress = (writeArray, file) => { + const outputString = writeArray.join('\n'); - fs.writeFile(outputFile, jsonString, (err) => { + fs.writeFile(file, outputString, (err) => { // Report success / failure - const successMessage = 'FCC progress was written to ' + outputFile; + const successMessage = 'Greenville Codes progress was written to ' + file; + err ? console.log(err) : console.log(successMessage); }); }; // Runs the program -let run = () => { - // const url = 'https://www.freecodecamp.org/magoun'; +let run = async () => { + const outputFile = 'test.json'; + const urlFile = 'fcc_profiles.txt'; + + // Get urls from urlFile + const urlArray = readURLs(urlFile); + let writeArray = []; - // getHTML(url) - // .then(parseHTML) - // .then(getProgress) - // .then(writeJSON); + // Clear output file + fs.writeFileSync(outputFile, ''); + + // Assemble student progress into array + for (let url of urlArray) { + let progress = await getHTML(url) + .then(parseHTML) + .then(getProgress); + + writeArray[urlArray.indexOf(url)] = url + ';' + progress; + } - readURLs(); + writeProgress(writeArray, outputFile); }; run(); \ No newline at end of file From 7af0e53cf0793af25df3f44d21211d3171be808a Mon Sep 17 00:00:00 2001 From: Creighton Magoun Date: Fri, 19 Oct 2018 03:03:08 +0000 Subject: [PATCH 24/37] Change format to csv and rename for consistency --- bulk-fcc-progress.js | 464 ------------------------------------------- bulk_fcc_progress.js | 118 +++++++++++ 2 files changed, 118 insertions(+), 464 deletions(-) delete mode 100644 bulk-fcc-progress.js create mode 100644 bulk_fcc_progress.js diff --git a/bulk-fcc-progress.js b/bulk-fcc-progress.js deleted file mode 100644 index c2f25a3..0000000 --- a/bulk-fcc-progress.js +++ /dev/null @@ -1,464 +0,0 @@ -// ==UserScript== -// @name FCC Progress -// @namespace http://tampermonkey.net/ -// @version 0.4 -// @description try to take over the world! -// @author David Cohen -// @updateURL https://raw.githubusercontent.com/dacohenii/fcc-progress/master/bulk-fcc-progress.js -// @match https://docs.google.com/spreadsheets/* -// @grant GM_registerMenuCommand -// @grant GM_setClipboard -// @grant GM_notification -// @grant GM_xmlhttpRequest -// @connect freecodecamp.org -// @connect freecodecamp.com -// ==/UserScript== - - -(function() { - function sanitizeText(text) { - return text.split('').map(char => char.toLowerCase()).filter(char => /[a-z]/.test(char)).join(''); - } - - Set.prototype.intersection = function(setB) { - var intersection = new Set(); - for (var elem of setB) { - if (this.has(elem)) { - intersection.add(elem); - } - } - return intersection; - } - - const sections = [ - [ - "HTML5 and CSS", - [ - "Learn How freeCodeCamp Works", - "Say Hello to HTML Elements", - "Headline with the h2 Element", - "Inform with the Paragraph Element", - "Uncomment HTML", - "Comment out HTML", - "Fill in the Blank with Placeholder Text", - "Delete HTML Elements", - "Change the Color of Text", - "Join a freeCodeCamp Study Group in Your City", - "Become a Supporter", - "Use CSS Selectors to Style Elements", - "Use a CSS Class to Style an Element", - "Style Multiple Elements with a CSS Class", - "Change the Font Size of an Element", - "Set the Font Family of an Element", - "Import a Google Font", - "Specify How Fonts Should Degrade", - "Add Images to your Website", - "Size your Images", - "Add Borders Around your Elements", - "Add Rounded Corners with a Border Radius", - "Make Circular Images with a Border Radius", - "Link to External Pages with Anchor Elements", - "Nest an Anchor Element within a Paragraph", - "Make Dead Links using the Hash Symbol", - "Turn an Image into a Link", - "Create a Bulleted Unordered List", - "Create an Ordered List", - "Create a Text Field", - "Add Placeholder Text to a Text Field", - "Create a Form Element", - "Add a Submit Button to a Form", - "Use HTML5 to Require a Field", - "Create a Set of Radio Buttons", - "Create a Set of Checkboxes", - "Check Radio Buttons and Checkboxes by Default", - "Nest Many Elements within a Single Div Element", - "Give a Background Color to a Div Element", - "Set the ID of an Element", - "Use an ID Attribute to Style an Element", - "Adjusting the Padding of an Element", - "Adjust the Margin of an Element", - "Add a Negative Margin to an Element", - "Add Different Padding to Each Side of an Element", - "Add Different Margins to Each Side of an Element", - "Use Clockwise Notation to Specify the Padding of an Element", - "Use Clockwise Notation to Specify the Margin of an Element", - "Style the HTML Body Element", - "Inherit Styles from the Body Element", - "Prioritize One Style Over Another", - "Override Styles in Subsequent CSS", - "Override Class Declarations by Styling ID Attributes", - "Override Class Declarations with Inline Styles", - "Override All Other Styles by using Important", - "Use Hex Code for Specific Colors", - "Use Hex Code to Mix Colors", - "Use Abbreviated Hex Code", - "Use RGB values to Color Elements", - "Use RGB to Mix Colors" - ] - ], - [ - "Responsive Design with Bootstrap", - [ - "Use Responsive Design with Bootstrap Fluid Containers", - "Make Images Mobile Responsive", - "Center Text with Bootstrap", - "Create a Bootstrap Button", - "Create a Block Element Bootstrap Button", - "Taste the Bootstrap Button Color Rainbow", - "Call out Optional Actions with Button Info", - "Warn your Users of a Dangerous Action", - "Use the Bootstrap Grid to Put Elements Side By Side", - "Ditch Custom CSS for Bootstrap", - "Use Spans for Inline Elements", - "Create a Custom Heading", - "Add Font Awesome Icons to our Buttons", - "Add Font Awesome Icons to all of our Buttons", - "Responsively Style Radio Buttons", - "Responsively Style Checkboxes", - "Style Text Inputs as Form Controls", - "Line up Form Elements Responsively with Bootstrap", - "Create a Bootstrap Headline", - "House our page within a Bootstrap Container Fluid Div", - "Create a Bootstrap Row", - "Split your Bootstrap Row", - "Create Bootstrap Wells", - "Add Elements within your Bootstrap Wells", - "Apply the Default Bootstrap Button Style", - "Create a Class to Target with jQuery Selectors", - "Add ID Attributes to Bootstrap Elements", - "Label Bootstrap Wells", - "Give Each Element a Unique ID", - "Label Bootstrap Buttons", - "Use Comments to Clarify Code" - ] - ], - [ - "jQuery", - [ - "Learn how Script Tags and Document Ready Work", - "Target HTML Elements with Selectors Using jQuery", - "Target Elements by Class Using jQuery", - "Target Elements by ID Using jQuery", - "Delete your jQuery Functions", - "Target the same element with multiple jQuery Selectors", - "Remove Classes from an element with jQuery", - "Change the CSS of an Element Using jQuery", - "Disable an Element Using jQuery", - "Change Text Inside an Element Using jQuery", - "Remove an Element Using jQuery", - "Use appendTo to Move Elements with jQuery", - "Clone an Element Using jQuery", - "Target the Parent of an Element Using jQuery", - "Target the Children of an Element Using jQuery", - "Target a Specific Child of an Element Using jQuery", - "Target Even Numbered Elements Using jQuery", - "Use jQuery to Modify the Entire Page" - ] - ], - [ - "Basic Front End Development Projects", - [ - "Get Set for our Front End Development Projects", - "Build a Tribute Page", - "Build a Personal Portfolio Webpage" - ] - ], - [ - "Basic JavaScript", - [ - "Comment your JavaScript Code", - "Declare JavaScript Variables", - "Storing Values with the Assignment Operator", - "Initializing Variables with the Assignment Operator", - "Understanding Uninitialized Variables", - "Understanding Case Sensitivity in Variables", - "Add Two Numbers with JavaScript", - "Subtract One Number from Another with JavaScript", - "Multiply Two Numbers with JavaScript", - "Divide One Number by Another with JavaScript", - "Increment a Number with JavaScript", - "Decrement a Number with JavaScript", - "Create Decimal Numbers with JavaScript", - "Multiply Two Decimals with JavaScript", - "Divide one Decimal by Another with JavaScript", - "Finding a Remainder in JavaScript", - "Compound Assignment With Augmented Addition", - "Compound Assignment With Augmented Subtraction", - "Compound Assignment With Augmented Multiplication", - "Compound Assignment With Augmented Division", - "Convert Celsius to Fahrenheit", - "Declare String Variables", - "Escaping Literal Quotes in Strings", - "Quoting Strings with Single Quotes", - "Escape Sequences in Strings", - "Concatenating Strings with Plus Operator", - "Concatenating Strings with the Plus Equals Operator", - "Constructing Strings with Variables", - "Appending Variables to Strings", - "Find the Length of a String", - "Use Bracket Notation to Find the First Character in a String", - "Understand String Immutability", - "Use Bracket Notation to Find the Nth Character in a String", - "Use Bracket Notation to Find the Last Character in a String", - "Use Bracket Notation to Find the Nth-to-Last Character in a String", - "Word Blanks", - "Store Multiple Values in one Variable using JavaScript Arrays", - "Nest one Array within Another Array", - "Access Array Data with Indexes", - "Modify Array Data With Indexes", - "Access Multi-Dimensional Arrays With Indexes", - "Manipulate Arrays With push()", - "Manipulate Arrays With pop()", - "Manipulate Arrays With shift()", - "Manipulate Arrays With unshift()", - "Shopping List", - "Write Reusable JavaScript with Functions", - "Passing Values to Functions with Arguments", - "Global Scope and Functions", - "Local Scope and Functions", - "Global vs. Local Scope in Functions", - "Return a Value from a Function with Return", - "Assignment with a Returned Value", - "Stand in Line", - "Understanding Boolean Values", - "Use Conditional Logic with If Statements", - "Comparison with the Equality Operator", - "Comparison with the Strict Equality Operator", - "Comparison with the Inequality Operator", - "Comparison with the Strict Inequality Operator", - "Comparison with the Greater Than Operator", - "Comparison with the Greater Than Or Equal To Operator", - "Comparison with the Less Than Operator", - "Comparison with the Less Than Or Equal To Operator", - "Comparisons with the Logical And Operator", - "Comparisons with the Logical Or Operator", - "Introducing Else Statements", - "Introducing Else If Statements", - "Logical Order in If Else Statements", - "Chaining If Else Statements", - "Golf Code", - "Selecting from many options with Switch Statements", - "Adding a default option in Switch statements", - "Multiple Identical Options in Switch Statements", - "Replacing If Else Chains with Switch", - "Returning Boolean Values from Functions", - "Return Early Pattern for Functions", - "Counting Cards", - "Build JavaScript Objects", - "Accessing Objects Properties with the Dot Operator", - "Accessing Objects Properties with Bracket Notation", - "Accessing Objects Properties with Variables", - "Updating Object Properties", - "Add New Properties to a JavaScript Object", - "Delete Properties from a JavaScript Object", - "Using Objects for Lookups", - "Testing Objects for Properties", - "Manipulating Complex Objects", - "Accessing Nested Objects", - "Accessing Nested Arrays", - "Iterate with JavaScript For Loops", - "Iterate Odd Numbers With a For Loop", - "Count Backwards With a For Loop", - "Iterate Through an Array with a For Loop", - "Nesting For Loops", - "Iterate with JavaScript While Loops", - "Profile Lookup", - "Generate Random Fractions with JavaScript", - "Generate Random Whole Numbers with JavaScript", - "Generate Random Whole Numbers within a Range", - "Sift through Text with Regular Expressions", - "Find Numbers with Regular Expressions", - "Find Whitespace with Regular Expressions", - "Invert Regular Expression Matches with JavaScript" - ] - ], - [ - "Object Oriented and Functional Programming", - [ - "Declare JavaScript Objects as Variables", - "Construct JavaScript Objects with Functions", - "Make Instances of Objects with a Constructor Function", - "Make Unique Objects by Passing Parameters to our Constructor", - "Make Object Properties Private", - "Iterate over Arrays with map", - "Condense arrays with reduce", - "Filter Arrays with filter", - "Sort Arrays with sort", - "Reverse Arrays with reverse", - "Concatenate Arrays with concat", - "Split Strings with split", - "Join Strings with join" - ] - ], - [ - "Basic Algorithm Scripting", - [ - "Get Set for our Algorithm Challenges", - "Reverse a String", - "Factorialize a Number", - "Check for Palindromes", - "Find the Longest Word in a String", - "Title Case a Sentence", - "Return Largest Numbers in Arrays", - "Confirm the Ending", - "Repeat a string repeat a string", - "Truncate a string", - "Chunky Monkey", - "Slasher Flick", - "Mutations", - "Falsy Bouncer", - "Seek and Destroy", - "Where do I belong", - "Caesars Cipher" - ] - ], - [ - "JSON APIs and Ajax", - [ - "Trigger Click Events with jQuery", - "Change Text with Click Events", - "Get JSON with the jQuery getJSON Method", - "Convert JSON Data to HTML", - "Render Images from Data Sources", - "Prefilter JSON", - "Get Geo-location Data" - ] - ], - [ - "Intermediate Front End Development Projects", - [ - "Build a Random Quote Machine", - "Show the Local Weather", - "Build a Wikipedia Viewer", - "Use the Twitch.tv JSON API" - ] - ], - [ - "Intermediate Algorithm Scripting", - [ - "Sum All Numbers in a Range", - "Diff Two Arrays", - "Roman Numeral Converter", - "Wherefore art thou", - "Search and Replace", - "Pig Latin", - "DNA Pairing", - "Missing letters", - "Boo who", - "Sorted Union", - "Convert HTML Entities", - "Spinal Tap Case", - "Sum All Odd Fibonacci Numbers", - "Sum All Primes", - "Smallest Common Multiple", - "Finders Keepers", - "Drop it", - "Steamroller", - "Binary Agents", - "Everything Be True", - "Arguments Optional" - ] - ], - [ - "Advanced Algorithm Scripting", - [ - "Validate US Telephone Numbers", - "Record Collection", - "Symmetric Difference", - "Exact Change", - "Inventory Update", - "No repeats please", - "Make a Person", - "Map the Debris", - "Pairwise" - ] - ], - [ - "Advanced Front End Development Projects", - [ - "Build a JavaScript Calculator", - "Build a Pomodoro Clock", - "Build a Tic Tac Toe Game", - "Build a Simon Game" - ] - ] - ]; - - /** - * take a string and turn it into a DOM node - */ - function parseDOM(str){ - const parser = new DOMParser(); - return parser.parseFromString(str, "text/html"); - } - - /** - * takes a parent DOM node (e.g. document) - * and scrapes the HTML to determine completion of all sections. - * - * returns an array of respective completion percentages for each section - */ - function getStudentProgress(node = document){ - - // total complete over all sections - const arrComplete = Array.from(node.querySelectorAll('body div table > tbody > tr > td:nth-child(1)')).map(x => sanitizeText(x.innerText)); - const setComplete = new Set(arrComplete); - - return sections.map(section => { - const assignments = section[1].map(sanitizeText); - // this is the important part... - const sectionProgress = setComplete.intersection(assignments).size; - - // expressed as a percentage: - return `${Math.round(100 * sectionProgress / assignments.length)}%`; - }); - } - - function init(){ - const strUrls = prompt('Paste all URLs here and click OK'); - if(!strUrls){ return false; } - - const urls = strUrls.split(/[ \n]+/); - - // create a result container array - const result = urls.map(url => ""); - - const responsesExpected = urls.filter(u => u.length > 0).length; - - let responsesReceived = 0; - - // asynchronously fill the container - urls.forEach(function(u, i){ - // skip blank lines - if(u.length){ - GM_xmlhttpRequest({ - "method": "GET", - "url": u, - "onerror": function(response){ - responsesReceived++; - result[i] = 'Error - check the console.'; - console.error(`Bad response from ${url}:`, response); - }, - "onload": function(response) { - responsesReceived++; - result[i] = getStudentProgress(parseDOM(response.responseText)).join('\t'); - - // this is how we find out whether we're done. - if(responsesReceived >= responsesExpected){ - GM_setClipboard(result.join('\n'), { type: 'text', mimetype: 'text/plain'}); - - GM_notification({ - title: "Results Copied.", - text: "Select the top-left destination cell and paste." - }); - } - } - }); - } - }); - - } - - GM_registerMenuCommand("Get Student Progress", init); - -})(); diff --git a/bulk_fcc_progress.js b/bulk_fcc_progress.js new file mode 100644 index 0000000..6abe60a --- /dev/null +++ b/bulk_fcc_progress.js @@ -0,0 +1,118 @@ +/** + * Scrapes multiple user profile from fcc_profiles.txt and + * compares completed challenges against the Greenville Codes curriculum. + * + * The Greenville Codes curriculum is found in gvl_codes_path.json. + * + * The results are output to student_progress.csv. + * + * Usage: node bulk_fcc_progress.js + * + */ + +const fs = require('fs'); +const puppeteer = require('puppeteer'); + +// Read list of profile urls +// Returns an array of profile URLs +let readURLs = (file) => { + let profiles = fs.readFileSync(file, 'utf8'); + + // Splitting the return on new line yields an array + return profiles.split('\n'); +}; + +// Fetch html using puppeteer +let getHTML = async (url) => { + const browser = await puppeteer.launch(); + const page = await browser.newPage(); + + // Wait for React components to load + await page.goto(url, { waitUntil: 'networkidle0'}); + + const html = await page.content(); + await browser.close(); + return html; +}; + +// Parse the HTML for completed challenges +// Returns an array of challenge names +let parseHTML = (html) => { + const $ = require('cheerio').load(html); + let challenges = []; + + $('tr', 'tbody').each(function (index, element) { + let challenge = $(this).find('a').text(); + challenges.push(challenge); + }); + + return challenges; +}; + +// Compare progress to overall curriculum +// Returns a comma delimited string +let getProgress = (completedChallenges) => { + const rawJSON = fs.readFileSync('gvl_codes_path.json'); + let challengeMap = JSON.parse(rawJSON); + + // Inconsistent capitalization, thus map to lower case + completedChallenges = completedChallenges.map(x => x.toLowerCase()); + + let progress = ''; + + // Loop through curriculum JSON + for (let section of Object.keys(challengeMap)) { + for (let subsection of Object.keys(challengeMap[section])) { + let numChallenges = challengeMap[section][subsection].length; + + // Inconsistent capitalization, thus map to lower case + let subsectionArray = challengeMap[section][subsection].map(x => x.toLowerCase()); + + let numCompleted = subsectionArray.reduce((acc, val) => { + return completedChallenges.indexOf(val) != -1 ? ++acc : acc; + }, 0); + + progress += `${Math.round(100 * numCompleted / numChallenges)}%` + ','; + } + } + + return progress; +}; + +// Writes the url and progress strings to a file +let writeProgress = (writeArray, file) => { + const outputString = writeArray.join('\n'); + + fs.writeFile(file, outputString, (err) => { + // Report success / failure + const successMessage = 'Greenville Codes progress was written to ' + file; + + err ? console.log(err) : console.log(successMessage); + }); +}; + +// Runs the program +let run = async () => { + const outputFile = 'student_progress.csv'; + const urlFile = 'fcc_profiles.txt'; + + // Get urls from urlFile + const urlArray = readURLs(urlFile); + let writeArray = []; + + // Clear output file + fs.writeFileSync(outputFile, ''); + + // Assemble student progress into array + for (let url of urlArray) { + let progress = await getHTML(url) + .then(parseHTML) + .then(getProgress); + + writeArray[urlArray.indexOf(url)] = url + ',' + progress; + } + + writeProgress(writeArray, outputFile); +}; + +run(); \ No newline at end of file From 9f63750ece658a0851332441c68b5c923fc5c555 Mon Sep 17 00:00:00 2001 From: Creighton Magoun Date: Fri, 19 Oct 2018 03:04:21 +0000 Subject: [PATCH 25/37] Remove line to clear write file, no longer needed --- bulk_fcc_progress.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/bulk_fcc_progress.js b/bulk_fcc_progress.js index 6abe60a..8a08d84 100644 --- a/bulk_fcc_progress.js +++ b/bulk_fcc_progress.js @@ -100,9 +100,6 @@ let run = async () => { const urlArray = readURLs(urlFile); let writeArray = []; - // Clear output file - fs.writeFileSync(outputFile, ''); - // Assemble student progress into array for (let url of urlArray) { let progress = await getHTML(url) From 63ac0502552e0372b4f7ef786de11b47709eb7de Mon Sep 17 00:00:00 2001 From: Creighton Magoun Date: Fri, 19 Oct 2018 03:05:51 +0000 Subject: [PATCH 26/37] No longer needed for testing --- wip.js | 106 --------------------------------------------------------- 1 file changed, 106 deletions(-) delete mode 100644 wip.js diff --git a/wip.js b/wip.js deleted file mode 100644 index e04b1df..0000000 --- a/wip.js +++ /dev/null @@ -1,106 +0,0 @@ -const fs = require('fs'); -const puppeteer = require('puppeteer'); - -// Read list of profile urls -// Returns an array of profile URLs -let readURLs = (file) => { - let profiles = fs.readFileSync(file, 'utf8'); - - // Splitting the return on new line yields an array - return profiles.split('\n'); -}; - -// Fetch html using puppeteer -let getHTML = async (url) => { - const browser = await puppeteer.launch(); - const page = await browser.newPage(); - - // Wait for React components to load - await page.goto(url, { waitUntil: 'networkidle0'}); - - const html = await page.content(); - await browser.close(); - return html; -}; - -// Parse the HTML for completed challenges -// Returns an array of challenge names -let parseHTML = (html) => { - const $ = require('cheerio').load(html); - let challenges = []; - - $('tr', 'tbody').each(function (index, element) { - let challenge = $(this).find('a').text(); - challenges.push(challenge); - }); - - return challenges; -}; - -// Compare progress to overall curriculum -// Returns a semicolon delimited string -let getProgress = (completedChallenges) => { - const rawJSON = fs.readFileSync('gvl_codes_path.json'); - let challengeMap = JSON.parse(rawJSON); - - // Inconsistent capitalization, thus map to lower case - completedChallenges = completedChallenges.map(x => x.toLowerCase()); - - let progress = ''; - - // Loop through curriculum JSON - for (let section of Object.keys(challengeMap)) { - for (let subsection of Object.keys(challengeMap[section])) { - let numChallenges = challengeMap[section][subsection].length; - - // Inconsistent capitalization, thus map to lower case - let subsectionArray = challengeMap[section][subsection].map(x => x.toLowerCase()); - - let numCompleted = subsectionArray.reduce((acc, val) => { - return completedChallenges.indexOf(val) != -1 ? ++acc : acc; - }, 0); - - progress += `${Math.round(100 * numCompleted / numChallenges)}%` + ';'; - } - } - - return progress; -}; - -// Writes the url and progress strings to a file -let writeProgress = (writeArray, file) => { - const outputString = writeArray.join('\n'); - - fs.writeFile(file, outputString, (err) => { - // Report success / failure - const successMessage = 'Greenville Codes progress was written to ' + file; - - err ? console.log(err) : console.log(successMessage); - }); -}; - -// Runs the program -let run = async () => { - const outputFile = 'test.json'; - const urlFile = 'fcc_profiles.txt'; - - // Get urls from urlFile - const urlArray = readURLs(urlFile); - let writeArray = []; - - // Clear output file - fs.writeFileSync(outputFile, ''); - - // Assemble student progress into array - for (let url of urlArray) { - let progress = await getHTML(url) - .then(parseHTML) - .then(getProgress); - - writeArray[urlArray.indexOf(url)] = url + ';' + progress; - } - - writeProgress(writeArray, outputFile); -}; - -run(); \ No newline at end of file From 9f48bec315a2cac1a9fabdc7571dc38de593c49c Mon Sep 17 00:00:00 2001 From: Creighton Magoun Date: Fri, 19 Oct 2018 03:20:26 +0000 Subject: [PATCH 27/37] Move input/output declarations to script head for ease of use --- bulk_fcc_progress.js | 15 +++++++-------- fcc_progress.js | 18 ++++++++---------- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/bulk_fcc_progress.js b/bulk_fcc_progress.js index 8a08d84..9627243 100644 --- a/bulk_fcc_progress.js +++ b/bulk_fcc_progress.js @@ -2,14 +2,16 @@ * Scrapes multiple user profile from fcc_profiles.txt and * compares completed challenges against the Greenville Codes curriculum. * - * The Greenville Codes curriculum is found in gvl_codes_path.json. - * - * The results are output to student_progress.csv. + * Track Greenville Codes progress with gvl_codes_path.json. * * Usage: node bulk_fcc_progress.js * */ - + +const outputFile = 'student_progress.csv', + urlFile = 'fcc_profiles.txt', + trackFile = 'gvl_codes_path.json'; + const fs = require('fs'); const puppeteer = require('puppeteer'); @@ -52,7 +54,7 @@ let parseHTML = (html) => { // Compare progress to overall curriculum // Returns a comma delimited string let getProgress = (completedChallenges) => { - const rawJSON = fs.readFileSync('gvl_codes_path.json'); + const rawJSON = fs.readFileSync(trackFile); let challengeMap = JSON.parse(rawJSON); // Inconsistent capitalization, thus map to lower case @@ -93,9 +95,6 @@ let writeProgress = (writeArray, file) => { // Runs the program let run = async () => { - const outputFile = 'student_progress.csv'; - const urlFile = 'fcc_profiles.txt'; - // Get urls from urlFile const urlArray = readURLs(urlFile); let writeArray = []; diff --git a/fcc_progress.js b/fcc_progress.js index 6cec630..395f3ba 100644 --- a/fcc_progress.js +++ b/fcc_progress.js @@ -1,16 +1,18 @@ /** * Scrapes a user profile from https://www.freecodecamp.org/{username} and * compares completed challenges against the FCC curriculum. The results are - * output in JSON format to fcc_progress.json + * output in JSON format to outputFile. * - * The FCC curriculum is gathered using lesson_map.js. + * Track Greenville Codes progress with gvl_codes_path.json. + * Track overall FreeCodeCamp progress with fcc_path.json. * * Usage: node fcc_progress.js * - * Set output file in writeJSON() - * Set user to scrape in run() - * */ + +const outputFile = 'fcc_progress.json', + url = 'https://www.freecodecamp.org/magoun', + trackFile = 'gvl_codes_path.json'; const fs = require('fs'); const puppeteer = require('puppeteer'); @@ -45,8 +47,7 @@ let parseHTML = (html) => { // Compare progress to overall curriculum // Returns a JSON object let getProgress = (completedChallenges) => { - // Hard coded, but can be pulled dynamically with lesson_map.js - const rawJSON = fs.readFileSync('gvl_codes_path.json'); + const rawJSON = fs.readFileSync(trackFile); let challengeMap = JSON.parse(rawJSON); // Inconsistent capitalization, thus map to lower case @@ -73,7 +74,6 @@ let getProgress = (completedChallenges) => { // Writes the JSON object to a file let writeJSON = (json) => { - const outputFile = 'fcc_progress.json'; // Format the json for readability const jsonString = JSON.stringify(json, null, 2); @@ -86,8 +86,6 @@ let writeJSON = (json) => { // Runs the program let run = () => { - const url = 'https://www.freecodecamp.org/magoun'; - getHTML(url) .then(parseHTML) .then(getProgress) From 48ab862b73c0ebc497f950ba3d1f84f24896abe8 Mon Sep 17 00:00:00 2001 From: Creighton Magoun Date: Fri, 19 Oct 2018 03:20:43 +0000 Subject: [PATCH 28/37] Rename to match similar files --- fcc_curriculum.json => fcc_path.json | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename fcc_curriculum.json => fcc_path.json (100%) diff --git a/fcc_curriculum.json b/fcc_path.json similarity index 100% rename from fcc_curriculum.json rename to fcc_path.json From 9fcdff08bac44a9e05559d680d1ac10382f2ac27 Mon Sep 17 00:00:00 2001 From: Creighton Magoun Date: Fri, 19 Oct 2018 03:26:24 +0000 Subject: [PATCH 29/37] Update with current usage --- README.md | 33 ++++++++------------------------- 1 file changed, 8 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index a08b608..af0558a 100644 --- a/README.md +++ b/README.md @@ -1,37 +1,20 @@ +# Greenville Codes Student Progress Tracker + ## Overview -_Note: To Edit_ -This script takes a newline-delimited list of FreeCodeCamp profile URLs and returns a report on their progress as a newline-delimited list of tab-delimited percentages. +This script takes a newline-delimited list of FreeCodeCamp profile URLs and returns a report on their progress as a newline-delimited list of comma-separated percentages. These can be easily pasted into a Google sheet used for tracking a cohort's progress through the Greenville Codes program. ## Installation + Requires Node v7.6 or higher (testing done with v10.1.0). Clone the repo and cd into it. Install the dependencies with `npm install`. ## Usage -Create the curriculum map with `node lesson_map.js`. -It will create lesson_map.json or overwrite the existing file. - - -#### OLD README BELOW #### - -_Note: This script sends a request for all these URLs essentially at the same time, so and hasn't been tested for more than ~30 at a time. Too many more and their serers might not appreciate it._ -1. Copy a spreadsheet column (or newline-separated list) of URLs to be scraped to the clipboard. - - empty cells / lines are okay and will be preserved on paste. -2. Invoke the script via the Tampermonkey menu. -3. A prompt should come up. Paste the addresses into the prompt and submit it. -4. At this point, it will start retrieving results. -5. A notification should appear to let you know the process is complete. When this happens select the top-left destination cell and paste the result. - -## Misc. Notes - -The main functionality is in `bulk-fcc-progress.js`. - -`fcc-progress.js` scrapes a single profile and must be run directly from that page. - -This was developed and tested using Tampermonkey and Chrome 60. YMMV. +Create the FreeCodeCamp curriculum map with `node lesson_map.js`. +It will create lesson_map.json or overwrite the existing file. -The lessons are currently hard-coded in the files. This can be pulled dynamically in the future, but they don't seem to change too often. +Use `node fcc_progress.js` to get a detailed progress report for a single FCC profile. You can specify to track the overall FCC curriculum or the Greenville Codes specific path in the file head. -Also, it's a web scraper, which is likely to break at some point when they change their website, but that's okay, becuase the next version will probably use an API, +Use `node bulk_fcc_progress.js` to get a csv report of a full list of student profiles. By default, these are pulled from fcc_profiles.txt, but this can be modified in the file head. \ No newline at end of file From b794e25951630b5be71549e59123a89c446cc9af Mon Sep 17 00:00:00 2001 From: Creighton Magoun Date: Fri, 19 Oct 2018 03:29:04 +0000 Subject: [PATCH 30/37] Rename for clarity of use --- fcc_progress.js => get_bulk_fcc_progress.js | 0 bulk_fcc_progress.js => get_bulk_progress.js | 0 lesson_map.js => map_fcc_path.js | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename fcc_progress.js => get_bulk_fcc_progress.js (100%) rename bulk_fcc_progress.js => get_bulk_progress.js (100%) rename lesson_map.js => map_fcc_path.js (100%) diff --git a/fcc_progress.js b/get_bulk_fcc_progress.js similarity index 100% rename from fcc_progress.js rename to get_bulk_fcc_progress.js diff --git a/bulk_fcc_progress.js b/get_bulk_progress.js similarity index 100% rename from bulk_fcc_progress.js rename to get_bulk_progress.js diff --git a/lesson_map.js b/map_fcc_path.js similarity index 100% rename from lesson_map.js rename to map_fcc_path.js From 425494609f8b0bdd447660f0a6dd95009913d112 Mon Sep 17 00:00:00 2001 From: Creighton Magoun Date: Fri, 19 Oct 2018 03:29:24 +0000 Subject: [PATCH 31/37] Update file references --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index af0558a..d3fef87 100644 --- a/README.md +++ b/README.md @@ -12,9 +12,9 @@ Install the dependencies with `npm install`. ## Usage -Create the FreeCodeCamp curriculum map with `node lesson_map.js`. -It will create lesson_map.json or overwrite the existing file. +Create the FreeCodeCamp curriculum map with `node map_fcc_path.js`. +It will create fcc_path.json or overwrite the existing file. -Use `node fcc_progress.js` to get a detailed progress report for a single FCC profile. You can specify to track the overall FCC curriculum or the Greenville Codes specific path in the file head. +Use `node get_fcc_progress.js` to get a detailed progress report for a single FCC profile. You can specify to track the overall FCC curriculum or the Greenville Codes specific path in the file head. -Use `node bulk_fcc_progress.js` to get a csv report of a full list of student profiles. By default, these are pulled from fcc_profiles.txt, but this can be modified in the file head. \ No newline at end of file +Use `node get_bulk_fcc_progress.js` to get a csv report of a full list of student profiles. By default, these are pulled from fcc_profiles.txt, but this can be modified in the file head. \ No newline at end of file From 4c6d81e7ff4f4dd8ed68b9e19eb06c3ad9ff5e93 Mon Sep 17 00:00:00 2001 From: Creighton Magoun Date: Fri, 19 Oct 2018 03:48:15 +0000 Subject: [PATCH 32/37] Correct misnamed bulk/non-bulk files --- get_bulk_fcc_progress.js | 63 ++++++++++++++------- get_bulk_progress.js => get_fcc_progress.js | 63 +++++++-------------- 2 files changed, 63 insertions(+), 63 deletions(-) rename get_bulk_progress.js => get_fcc_progress.js (59%) diff --git a/get_bulk_fcc_progress.js b/get_bulk_fcc_progress.js index 395f3ba..9627243 100644 --- a/get_bulk_fcc_progress.js +++ b/get_bulk_fcc_progress.js @@ -1,22 +1,29 @@ /** - * Scrapes a user profile from https://www.freecodecamp.org/{username} and - * compares completed challenges against the FCC curriculum. The results are - * output in JSON format to outputFile. + * Scrapes multiple user profile from fcc_profiles.txt and + * compares completed challenges against the Greenville Codes curriculum. * * Track Greenville Codes progress with gvl_codes_path.json. - * Track overall FreeCodeCamp progress with fcc_path.json. * - * Usage: node fcc_progress.js + * Usage: node bulk_fcc_progress.js * */ -const outputFile = 'fcc_progress.json', - url = 'https://www.freecodecamp.org/magoun', +const outputFile = 'student_progress.csv', + urlFile = 'fcc_profiles.txt', trackFile = 'gvl_codes_path.json'; - + const fs = require('fs'); const puppeteer = require('puppeteer'); +// Read list of profile urls +// Returns an array of profile URLs +let readURLs = (file) => { + let profiles = fs.readFileSync(file, 'utf8'); + + // Splitting the return on new line yields an array + return profiles.split('\n'); +}; + // Fetch html using puppeteer let getHTML = async (url) => { const browser = await puppeteer.launch(); @@ -45,7 +52,7 @@ let parseHTML = (html) => { }; // Compare progress to overall curriculum -// Returns a JSON object +// Returns a comma delimited string let getProgress = (completedChallenges) => { const rawJSON = fs.readFileSync(trackFile); let challengeMap = JSON.parse(rawJSON); @@ -53,6 +60,8 @@ let getProgress = (completedChallenges) => { // Inconsistent capitalization, thus map to lower case completedChallenges = completedChallenges.map(x => x.toLowerCase()); + let progress = ''; + // Loop through curriculum JSON for (let section of Object.keys(challengeMap)) { for (let subsection of Object.keys(challengeMap[section])) { @@ -65,31 +74,41 @@ let getProgress = (completedChallenges) => { return completedChallenges.indexOf(val) != -1 ? ++acc : acc; }, 0); - challengeMap[section][subsection] = `${Math.round(100 * numCompleted / numChallenges)}%`; + progress += `${Math.round(100 * numCompleted / numChallenges)}%` + ','; } } - return challengeMap; + return progress; }; -// Writes the JSON object to a file -let writeJSON = (json) => { - // Format the json for readability - const jsonString = JSON.stringify(json, null, 2); +// Writes the url and progress strings to a file +let writeProgress = (writeArray, file) => { + const outputString = writeArray.join('\n'); - fs.writeFile(outputFile, jsonString, (err) => { + fs.writeFile(file, outputString, (err) => { // Report success / failure - const successMessage = 'Greenville Codes progress was written to ' + outputFile; + const successMessage = 'Greenville Codes progress was written to ' + file; + err ? console.log(err) : console.log(successMessage); }); }; // Runs the program -let run = () => { - getHTML(url) - .then(parseHTML) - .then(getProgress) - .then(writeJSON); +let run = async () => { + // Get urls from urlFile + const urlArray = readURLs(urlFile); + let writeArray = []; + + // Assemble student progress into array + for (let url of urlArray) { + let progress = await getHTML(url) + .then(parseHTML) + .then(getProgress); + + writeArray[urlArray.indexOf(url)] = url + ',' + progress; + } + + writeProgress(writeArray, outputFile); }; run(); \ No newline at end of file diff --git a/get_bulk_progress.js b/get_fcc_progress.js similarity index 59% rename from get_bulk_progress.js rename to get_fcc_progress.js index 9627243..395f3ba 100644 --- a/get_bulk_progress.js +++ b/get_fcc_progress.js @@ -1,29 +1,22 @@ /** - * Scrapes multiple user profile from fcc_profiles.txt and - * compares completed challenges against the Greenville Codes curriculum. + * Scrapes a user profile from https://www.freecodecamp.org/{username} and + * compares completed challenges against the FCC curriculum. The results are + * output in JSON format to outputFile. * * Track Greenville Codes progress with gvl_codes_path.json. + * Track overall FreeCodeCamp progress with fcc_path.json. * - * Usage: node bulk_fcc_progress.js + * Usage: node fcc_progress.js * */ -const outputFile = 'student_progress.csv', - urlFile = 'fcc_profiles.txt', +const outputFile = 'fcc_progress.json', + url = 'https://www.freecodecamp.org/magoun', trackFile = 'gvl_codes_path.json'; - + const fs = require('fs'); const puppeteer = require('puppeteer'); -// Read list of profile urls -// Returns an array of profile URLs -let readURLs = (file) => { - let profiles = fs.readFileSync(file, 'utf8'); - - // Splitting the return on new line yields an array - return profiles.split('\n'); -}; - // Fetch html using puppeteer let getHTML = async (url) => { const browser = await puppeteer.launch(); @@ -52,7 +45,7 @@ let parseHTML = (html) => { }; // Compare progress to overall curriculum -// Returns a comma delimited string +// Returns a JSON object let getProgress = (completedChallenges) => { const rawJSON = fs.readFileSync(trackFile); let challengeMap = JSON.parse(rawJSON); @@ -60,8 +53,6 @@ let getProgress = (completedChallenges) => { // Inconsistent capitalization, thus map to lower case completedChallenges = completedChallenges.map(x => x.toLowerCase()); - let progress = ''; - // Loop through curriculum JSON for (let section of Object.keys(challengeMap)) { for (let subsection of Object.keys(challengeMap[section])) { @@ -74,41 +65,31 @@ let getProgress = (completedChallenges) => { return completedChallenges.indexOf(val) != -1 ? ++acc : acc; }, 0); - progress += `${Math.round(100 * numCompleted / numChallenges)}%` + ','; + challengeMap[section][subsection] = `${Math.round(100 * numCompleted / numChallenges)}%`; } } - return progress; + return challengeMap; }; -// Writes the url and progress strings to a file -let writeProgress = (writeArray, file) => { - const outputString = writeArray.join('\n'); +// Writes the JSON object to a file +let writeJSON = (json) => { + // Format the json for readability + const jsonString = JSON.stringify(json, null, 2); - fs.writeFile(file, outputString, (err) => { + fs.writeFile(outputFile, jsonString, (err) => { // Report success / failure - const successMessage = 'Greenville Codes progress was written to ' + file; - + const successMessage = 'Greenville Codes progress was written to ' + outputFile; err ? console.log(err) : console.log(successMessage); }); }; // Runs the program -let run = async () => { - // Get urls from urlFile - const urlArray = readURLs(urlFile); - let writeArray = []; - - // Assemble student progress into array - for (let url of urlArray) { - let progress = await getHTML(url) - .then(parseHTML) - .then(getProgress); - - writeArray[urlArray.indexOf(url)] = url + ',' + progress; - } - - writeProgress(writeArray, outputFile); +let run = () => { + getHTML(url) + .then(parseHTML) + .then(getProgress) + .then(writeJSON); }; run(); \ No newline at end of file From 806e9f40c9d5f9163309457c81e2cfaeb3e4d6fa Mon Sep 17 00:00:00 2001 From: Creighton Magoun Date: Sun, 28 Oct 2018 05:37:43 +0000 Subject: [PATCH 33/37] Remove unnessary dependency --- package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/package.json b/package.json index 487e978..52811c7 100644 --- a/package.json +++ b/package.json @@ -5,8 +5,7 @@ "main": "fcc-progress.js", "dependencies": { "cheerio": "^1.0.0-rc.2", - "puppeteer": "^1.9.0", - "request-promise": "^4.2.2" + "puppeteer": "^1.9.0" }, "devDependencies": {}, "scripts": { From 482bf2d095b650e5c4722e2518bb2cf4ad655ca6 Mon Sep 17 00:00:00 2001 From: Creighton Magoun Date: Sun, 28 Oct 2018 05:44:24 +0000 Subject: [PATCH 34/37] Add section on troubleshooting --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d3fef87..f51f658 100644 --- a/README.md +++ b/README.md @@ -17,4 +17,9 @@ It will create fcc_path.json or overwrite the existing file. Use `node get_fcc_progress.js` to get a detailed progress report for a single FCC profile. You can specify to track the overall FCC curriculum or the Greenville Codes specific path in the file head. -Use `node get_bulk_fcc_progress.js` to get a csv report of a full list of student profiles. By default, these are pulled from fcc_profiles.txt, but this can be modified in the file head. \ No newline at end of file +Use `node get_bulk_fcc_progress.js` to get a csv report of a full list of student profiles. By default, these are pulled from fcc_profiles.txt, but this can be modified in the file head. + +## Troubleshooting +I ran into a few problems getting this to work on another computer. My errors were related to dependencies for Chrome. I resolved them by following the advice [here](https://github.com/GoogleChrome/puppeteer/blob/master/docs/troubleshooting.md). + +`npm install` loads the dependencies locally, so `ldd chrome | grep not` won't work in the base directory. You'll have to navigate all the way down to the node_modules directory for puppeteer, through the .local-chromium directory until you find the chrome binary, then run the command. This should give you the missing dependencies that need to be installed. \ No newline at end of file From 9fb655d92c8f58af20fd495df1c18790151cfc12 Mon Sep 17 00:00:00 2001 From: Creighton Magoun Date: Tue, 6 Nov 2018 23:54:45 +0000 Subject: [PATCH 35/37] Add more to troubleshooting section --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index f51f658..8ff1174 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,8 @@ Use `node get_fcc_progress.js` to get a detailed progress report for a single FC Use `node get_bulk_fcc_progress.js` to get a csv report of a full list of student profiles. By default, these are pulled from fcc_profiles.txt, but this can be modified in the file head. ## Troubleshooting +Running `node get_bulk_fcc_progress.js` with an invalid url will return an error. This includes newline characters at the end of the file! I'll work on fixing this. + I ran into a few problems getting this to work on another computer. My errors were related to dependencies for Chrome. I resolved them by following the advice [here](https://github.com/GoogleChrome/puppeteer/blob/master/docs/troubleshooting.md). `npm install` loads the dependencies locally, so `ldd chrome | grep not` won't work in the base directory. You'll have to navigate all the way down to the node_modules directory for puppeteer, through the .local-chromium directory until you find the chrome binary, then run the command. This should give you the missing dependencies that need to be installed. \ No newline at end of file From 1d235ae892814705cbfee70178ff3cf6846d00bf Mon Sep 17 00:00:00 2001 From: Creighton Magoun Date: Tue, 6 Nov 2018 23:58:30 +0000 Subject: [PATCH 36/37] Add debugging information --- get_bulk_fcc_progress.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/get_bulk_fcc_progress.js b/get_bulk_fcc_progress.js index 9627243..b5664be 100644 --- a/get_bulk_fcc_progress.js +++ b/get_bulk_fcc_progress.js @@ -10,7 +10,8 @@ const outputFile = 'student_progress.csv', urlFile = 'fcc_profiles.txt', - trackFile = 'gvl_codes_path.json'; + trackFile = 'gvl_codes_path.json', + debug = true; const fs = require('fs'); const puppeteer = require('puppeteer'); @@ -19,6 +20,9 @@ const puppeteer = require('puppeteer'); // Returns an array of profile URLs let readURLs = (file) => { let profiles = fs.readFileSync(file, 'utf8'); + if (debug) { + console.log('Reading profile urls from ' + urlFile); + } // Splitting the return on new line yields an array return profiles.split('\n'); @@ -26,6 +30,10 @@ let readURLs = (file) => { // Fetch html using puppeteer let getHTML = async (url) => { + if (debug) { + console.log('Getting HTML from ' + url); + } + const browser = await puppeteer.launch(); const page = await browser.newPage(); @@ -34,6 +42,7 @@ let getHTML = async (url) => { const html = await page.content(); await browser.close(); + return html; }; From 582b0ce7ae79dac2a631b31321818c6d56d029be Mon Sep 17 00:00:00 2001 From: Creighton Magoun Date: Wed, 7 Nov 2018 00:36:50 +0000 Subject: [PATCH 37/37] Make debugging text standard and implement URL validation --- get_bulk_fcc_progress.js | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/get_bulk_fcc_progress.js b/get_bulk_fcc_progress.js index b5664be..13b584e 100644 --- a/get_bulk_fcc_progress.js +++ b/get_bulk_fcc_progress.js @@ -10,29 +10,37 @@ const outputFile = 'student_progress.csv', urlFile = 'fcc_profiles.txt', - trackFile = 'gvl_codes_path.json', - debug = true; + trackFile = 'gvl_codes_path.json'; const fs = require('fs'); const puppeteer = require('puppeteer'); +const URL = require('url'); + +// Function for filtering bad inputs from urlFile +let validateURL = (str) => { + const url = URL.parse(str); + + if (url.hostname) { + return true; + } else { + console.log('Skipping ' + str + ' (invalid URL)'); + return false; + } +}; // Read list of profile urls // Returns an array of profile URLs let readURLs = (file) => { let profiles = fs.readFileSync(file, 'utf8'); - if (debug) { - console.log('Reading profile urls from ' + urlFile); - } + console.log('Reading profile urls from ' + urlFile); // Splitting the return on new line yields an array - return profiles.split('\n'); + return profiles.split('\n').filter(validateURL); }; // Fetch html using puppeteer let getHTML = async (url) => { - if (debug) { - console.log('Getting HTML from ' + url); - } + console.log('Getting HTML from ' + url); const browser = await puppeteer.launch(); const page = await browser.newPage(); @@ -111,8 +119,8 @@ let run = async () => { // Assemble student progress into array for (let url of urlArray) { let progress = await getHTML(url) - .then(parseHTML) - .then(getProgress); + .then(parseHTML) + .then(getProgress); writeArray[urlArray.indexOf(url)] = url + ',' + progress; }