{"tracks":{},"units":{"order":["introduction","precourse","precourse-part-2","pair-programming","functions-execution-context","callbacks","closures","recursion","object-oriented-programming","async","build-with-code","chrome-extension","what-now","future-code"],"introduction":{"unitId":"introduction","header":"Overview of CSX","level":"Introductory","tagline":["Welcome to CSX! In this Overview Unit, we’ll cover everything you need to know about CSX, additional learning opportunities and resources, the CSX community, and where to get help. We’re happy to have you here!"],"completeNotification":"Congrats on finishing the Intro! You're killing it - keep it up and share your success","description":[{"list":["The CSX teaching style","Additional free learning resources","The CSX Community","CSX's connection to Codesmith's programs"]}],"subunits":["intro","csx-teaching-style","learning-resources","help-stuck","csx-to-codesmith"]},"precourse":{"unitId":"precourse","header":"Precourse - Part 1","level":"Introductory","tagline":["In the CSX Precourse we’ll cover the JavaScript basics such as variables, strings, data types, arrays, and loops. We designed this unit to give you an introduction to the core JavaScript functionality so you can move on to tackle more advanced challenges. This unit is required precourse work for JavaScript for Beginners. Completion of this unit is required for admission to CS Prep."],"completeNotification":"Congrats on finishing part 1 of the Precourse! You're killing it - keep it up and share your success","description":[{"list":["Variables","Data Types Overview","Strings","Numbers","Booleans"]}],"disclaimers":["<i>Required for JavaScript for Beginners</i>","<i>Required for CS Prep</i>"],"subunits":["precourse-what-is-js","workshop-intro-to-javascript","workshop-js-fundamentals-pt1","challenge-console","precourse-variables","challenge-variable-assignment-var","challenge-variable-assignment-let","challenge-variable-assignment-const","precourse-data-types","challenge-data-types-basics","challenge-strings-intro","challenge-strings-escape-seqs","challenge-string-concatenation","challenge-strings-template-literal","challenge-string-methods","challenge-strings-bracket-notation","challenge-numbers-addition-subtraction","challenge-numbers-multiplication-division","challenge-numbers-exponent-modulus","challenge-numbers-incrementor","challenge-numbers-assignment-operators","challenge-booleans-intro","challenge-booleans-comparison","challenge-type-coercion","challenge-typeof"]},"precourse-part-2":{"unitId":"precourse-part-2","header":"Precourse - Part 2","level":"Introductory","tagline":["In the CSX Precourse we’ll cover the JavaScript basics such as variables, strings, data types, arrays, and loops. The precourse is designed to give an introduction to core JavaScript functionality so you can move on to tackle more advanced challenges. This unit is required precourse work for JavaScript for Beginners. Completion of this unit is required for admission to CS Prep."],"completeNotification":"Congrats on finishing the Precourse! You're killing it - keep it up and share your success","description":[{"list":["Arrays","Objects","Loops","Control Flow"]}],"disclaimers":["<i>Required for JavaScript for Beginners</i>","<i>Required for CS Prep</i>"],"subunits":["challenge-arrays-examining-elements","challenge-arrays-adding-elements","challenge-for-loops-fundamentals","solution-for-loops-fundamentals","challenge-for-loops-arrays","solution-for-loops-arrays","challenge-for-loops-array-indices","challenge-for-loops-calculating-array-elements","challenge-while-loops-fundamentals","challenge-while-loops-conditional-expression","challenge-control-flow-if-statements","challenge-fizzbuzz","precourse-fizzbuzz-solution","challenge-control-flow-iteration","challenge-objects-examining-properties","challenge-objects-iterating-with-for-in","challenge-objects-iterating-with-for-loop","challenge-objects-nested-arrays","challenge-objects-adding-properties","solution-obj-adding-properties","challenge-objects-evaluating-keys"]},"pair-programming":{"unitId":"pair-programming","header":"Pair Programming","level":"Introductory","tagline":["In this unit we’ll describe how pair programming is central to excellent technical communication and problem solving which are essential to software engineering. We’ll also teach how to pair program and how to use CSX to pair. Completion of this unit is strongly recommended as precourse work for JavaScript for Beginners, and is required precourse work for CS Prep."],"description":[{"list":["Learning how to learn","The power of pair programming approach","How to pair program"]}],"disclaimers":["<i>Strongly recommended for JavaScript for Beginners</i>","<i>Required for CS Prep</i>","<i>Assessed on the Technical Interview</i>"],"subunits":["pair-programming-read","pair-programming-read2"]},"functions-execution-context":{"unitId":"functions-execution-context","header":"Functions and Execution Context","level":"Introductory","tagline":["In this unit we’ll build a strong foundation in the principles of programming in JavaScript - code execution, memory (variable environment), execution context and the call stack. We’ll diagram through these foundations to give ourselves a foundation from which to tackle even the most complex feature of JavaScript in later units. This unit is required for admission to CS Prep."],"completeNotification":"Congrats on finishing the Functions and Execution Context Unit! You're killing it - keep it up and share your success","description":[{"list":["Prereqs challenge self assessment","30+ challenges","Workshop (Intro to Web Development)"]}],"disclaimers":["<i>Required for CS Prep </i>","<i>Assessed on the Technical Interview</i>"],"subunits":["intro-functions-execution-context","workshop-functions-and-objects","challenge-add-two","challenge-add-s","challenge-say-hello","challenge-were-awesome","challenge-last-letter","challenge-passing-arguments","challenge-functions-adding-arguments","challenge-invoking-functions","solution-invoking-functions","challenge-make-plans","challenge-functions-display-vs-execution","challenge-is-odd","challenge-control-flow-if-statements-and-remainders","challenge-get-remainder","challenge-control-flow-if-statements-and-multiple-conditions","challenge-grade-calculator","challenge-droids","challenge-functions-using-for-each","challenge-functions-short-circuiting-a-loop","solution-functions-short-circuiting-a-loop","challenge-for-loops-updating-array-elements","challenge-make-plural","challenge-for-loops-summing-array-elements","challenge-multiply-all","solution-multiply-all","challenge-loops-summing-two-arrays","challenge-loops-and-control-flow","challenge-while-loops-counters","challenge-control-flow-if-statements-and-the-math-object","challenge-loops-range","challenge-loops-multiple-conditions","challenge-disemvowel","solution-disemvowel","challenge-add-waldo","challenge-find-waldo","challenge-array-builder","solution-array-builder","challenge-functions-expressions","challenge-functions-es6"]},"callbacks":{"unitId":"callbacks","header":"Callbacks & Higher-order Functions","level":"Intermediate","tagline":["In this unit we explore higher order functions and callbacks. Functions like map, reduce and filter are powerful tools and keep our code DRY but can be complex to navigate. We will learn how to build these functions from scratch so you can easily implement and debug them in your code. Completion of this unit is required to get ready for CS Prep."],"completeNotification":"Congrats on finishing the Callbacks and Higher Order Functions Unit! You're killing it - keep it up and share your success","description":[{"list":["Map, Filter, Reduce","13 challenges & 2.5hrs of video lecture","Workshop (JSHP 1)"]}],"disclaimers":["<i>Required for CS Prep</i>","<i>Assessed on the Technical Interview</i>"],"subunits":["intro-callbacks-video","intro-callbacks-read","workshop-callbacks","challenge-pluralize","challenge-map","solution-map","challenge-for-each","solution-for-each","challenge-filter-array","challenge-either-filter","challenge-either-callback","solution-either-callback","challenge-reduce","solution-reduce","challenge-intersection","solution-intersection","challenge-union","solution-union","challenge-obj-of-matches","solution-obj-of-matches","challenge-array-to-obj","challenge-join-and-map","challenge-multi-map","challenge-majority","challenge-prioritize","challenge-count-by","challenge-group-by","solution-group-by","challenge-good-keys","additional-learning-resources-callbacks"]},"closures":{"unitId":"closures","header":"Closure, Scope & Execution Context","level":"Intermediate","tagline":["In this unit we understand closure – probably the most misunderstood feature of JavaScript yet one of the most powerful. By introducing the execution context and variable environment, we’ll be able to understand classic closure functions like once, memoize and even password-protected functions."],"completeNotification":"Congrats on finishing the Closure, Scope, and Execution Context Unit! You're killing it - keep it up and share your success","description":[{"list":["Closure with lexical scope and the backpack","12 challenges and 2.5hrs of lecture video","Workshop (JSHP 2)"]}],"disclaimers":["<i>Assessed on the Technical Interview</i>"],"subunits":["intro-closures","closures-divein","workshop-closures","challenge-create-function","solution-create-function","challenge-function-with-input","solution-function-with-input","challenge-scoping","intro-closures-pt-2","challenge-add-by-x","challenge-once","solution-once","challenge-after","solution-after","challenge-delay","challenge-save-output","solution-save-output","challenge-cycle-iterator","solution-cycle-iterator","challenge-define-first-arg","challenge-hobbyTracker","challenge-date-stamp","solution-date-stamp","challenge-censor","solution-censor","additional-learning-resources-closures"]},"recursion":{"unitId":"recursion","header":"Recursion","level":"Intermediate","tagline":["In this unit we will develop the intuitions necessary to tackle recursion problems effectively. We cover structural and generative recursion and visualize recursive code execution to help prepare you for many of the most popular recursion interview questions."],"completeNotification":"Congrats on finishing the Recursion Unit! You're killing it - keep it up and share your success","description":[{"list":["Recursion, parameters as storage, and performance","4 challenges, solution videos, and 1.5hrs of lecture video","Workshop (Recursion - A Deep Dive)"]}],"disclaimers":["<i>Assessed on the Technical Interview</i>"],"subunits":["intro-recursion","workshop-recursion","challenge-repeater","solution-repeater","parameters-as-storage","challenge-factorial","solution-factorial","recursion-performance","challenge-get-length","solution-get-length","challenge-pow","challenge-flow","solution-flow","challenge-shuffle-cards","challenge-cascade","additional-learning-resources-recursion"]},"object-oriented-programming":{"unitId":"object-oriented-programming","header":"Object Oriented Programming","level":"Advanced Intermediate","tagline":["In this unit we dive into the many ways that we can create, manipulate, and make blueprints for objects in JavaScript. Well cover using object literals, constructor functions, class syntax, and more."],"description":[{"list":["Creating objects using object literals, Object.create, constructors, and classes"]}],"subunits":["intro-oop","workshop-oop","workshop-jshp-oop-pt1","workshop-jshp-oop-pt2","challenge-make-person","challenge-person-store","challenge-person-from-person-store","solution-person-from-person-store","challenge-introduce","challenge-person-constructor","solution-person-constructor","challenge-person-from-constructor","challenge-introduce-pt-2","challenge-dog-constructor","challenge-inventory","challenge-person-class","challenge-developer-class","challenge-chain-stores","additional-learning-resources-oop"]},"async":{"unitId":"async","header":"Asynchronous JavaScript","level":"Advanced Intermediate","tagline":["In this unit we take a deep dive on asynchronous JavaScript - the backbone of modern web development. To do so we’ll get a clear sense of the call stack, event loop and task queue so you can navigate complex asynchronous problems easily."],"completeNotification":"Congrats on finishing the Async Unit! You're killing it - keep it up and share your success","description":[{"list":["Asynchronous, callbacks, web browser, APIs, the callbacks queue and event loop","Challenges and 2.5hrs of live lecture video","Workshop (JSHP 3)"]}],"subunits":["intro-async","workshop-async","challenge-set-timeout","challenge-for-each-async","solution-for-each-async","challenge-ajax-simulate","solution-ajax-simulate","challenge-limited-interval","challenge-run-in-order","solution-run-in-order","additional-learning-resources-async"]},"build-with-code":{"unitId":"build-with-code","header":"Build with Code","level":"Advanced Intermediate","tagline":["With a deeper understanding of JavaScript fundamentals, engineering best practices, technical communication, and analytical problem-solving, we can begin to think about the opportunities to use code to solve real-world problems."],"completeNotification":"Congrats on finishing the Build with Code Unit! You're killing it - keep it up and share your success","description":[{"list":["Problem-solving approach for engineers","Developing tools with a real-world benefit from scratch","Resources for building with code"]}],"subunits":["build-intro","build-problem-solving-approach","build-identifying-project","build-resources-for-building","build-complete-build"]},"chrome-extension":{"unitId":"chrome-extension","header":"Chrome Extension","level":"Advanced Intermediate","tagline":["In this unit we’ll guide you to build a Chrome Extension that will help you solve a problem you face every day. The extension requires DOM manipulation, jQuery, APIs, and AJAX designed to enhance project building capabilities."],"completeNotification":"Congrats on completing the chrome extension. Email us a link for a chance at a scholarship at csx@codesmith.io! Read about our previous winner","targetLinkNotification":"here","linkNotification":"https://www.facebook.com/codesmithhq/photos/pcb.1684348281604556/1684348234937894/?type=3&theater","description":[{"list":["Building a useful productivity tool from scratch"]}],"subunits":["chrome-extension-1","chrome-extension-2","chrome-extension-3","chrome-extension-4","chrome-extension-5","chrome-extension-6"]},"what-now":{"unitId":"what-now","header":"What Now?","tagline":["Congratulations on making it through CSX! We hope that this unit will help guide you through possible next steps as you continue on your journey to become a Software Engineer."],"completeNotification":"Congrats on finishing the unit! You're killing it - keep it up and share your success","description":[{"read":null},{"list":["What to do once you've completed CSX"]}],"subunits":["what-now-structured-programs","what-now-technical-interview-prep","what-now-additional-information-info-sessions-and-alumni-advisor-calls","what-now-software-engineering-as-a-career"]},"future-code":{"unitId":"future-code","header":"Future Code","hidden":true,"level":"Introductory","tagline":["Here's a take-home technical challenge for you to demonstrate your coding skills!"],"completeNotification":"Congrats on finishing the Future Code take-home!","description":[{"list":["Take-home challenge"]}],"subunits":["future-code-take-home"]}},"subunits":{"additional-learning-resources-async":{"subunitId":"additional-learning-resources-async","heading":"Additional Learning Resources","read":["Congratulations on completing the asynchronous JavaScript unit! We encourage you to refactor your code and even try the challenges again from scratch to be fully prepared for the technical interview. Check out these additional resources to further your knowledge on asynchronous JavaScript!","<a href=\"https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous\" target=\"_blank\">MDN: Asynchronous JavaScript</a>","<a href=\"https://eloquentjavascript.net/11_async.html\" target=\"_blank\">Eloquent Javascript: Asynchronous Programming</a>","<a href=\"https://www.freecodecamp.org/news/synchronous-vs-asynchronous-in-javascript/\" target=\"_blank\">freeCodeCamp: Synchronous vs Asynchronous JavaScript – Call Stack, Promises, and More</a>"]},"additional-learning-resources-callbacks":{"subunitId":"additional-learning-resources-callbacks","heading":"Additional Learning Resources","read":["Congratulations on completing the Callbacks & Higher-Order Functions unit! We encourage you to refactor your code and even try the challenges again from scratch to be fully prepared for the technical interview. Check out these additional resources to further your knowledge on callbacks and higher-order functions!","<a href=\"https://developer.mozilla.org/en-US/docs/Glossary/Callback_function\" target=\"_blank\">MDN: Callback Function</a>","<a href=\"https://eloquentjavascript.net/05_higher_order.html\" target=\"_blank\">Eloquent Javascript: Higher-Order Functions</a>","<a href=\"https://www.youtube.com/watch?v=rRgD1yVwIvE\" target=\"_blank\">Traversy Media: JavaScript Higher Order Functions & Arrays</a>"]},"additional-learning-resources-closures":{"subunitId":"additional-learning-resources-closures","heading":"Additional Learning Resources","read":["Congratulations on completing the Closure, Scope & Execution Context unit! We encourage you to refactor your code and even try the challenges again from scratch to be fully prepared for the technical interview. Check out these additional resources to further your knowledge on closure!","<a href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures\" target=\"_blank\">MDN: Closures</a>","<a href=\"https://www.w3schools.com/js/js_function_closures.asp\" target=\"_blank\">W3 Schools: JavaScript Closures</a>","<a href=\"https://www.freecodecamp.org/news/closures-in-javascript/\" target=\"_blank\">freeCodeCamp: How to Use Closures in JavaScript – A Beginner's Guide </a>"]},"additional-learning-resources-oop":{"subunitId":"additional-learning-resources-oop","heading":"Additional Learning Resources","read":["Congratulations on completing the Object Oriented Programming unit! Check out these additional resources to further your knowledge on object oriented programming  JavaScript!","<a href=\"https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object-oriented_JS\" target=\"_blank\">MDN: Object-oriented JavaScript for beginners</a>","<a href=\"https://www.freecodecamp.org/news/how-javascript-implements-oop/\" target=\"_blank\">freeCodeCamp: Object Oriented Programming in JavaScript – Explained with Examples</a>","<a href=\"https://eloquentjavascript.net/06_object.html\" target=\"_blank\">Eloquent Javascript: The Secret Life of Objects</a>"]},"additional-learning-resources-recursion":{"subunitId":"additional-learning-resources-recursion","heading":"Additional Learning Resources","read":["Congratulations on completing the Recursion unit! We encourage you to refactor your code and even try the challenges again from scratch to be fully prepared for the technical interview. Check out these additional resources to further your knowledge on recursion!","<a href=\"https://developer.mozilla.org/en-US/docs/Glossary/Recursion\" target=\"_blank\">MDN: Recursion</a>","<a href=\"https://www.freecodecamp.org/news/what-is-recursion-in-javascript/\" target=\"_blank\">freeCodeCamp: What is Recursion? A Recursive Function Explained with JavaScript Code Examples</a>","<a href=\"https://www.youtube.com/watch?v=Mv9NEXX1VHc\" target=\"_blank\">Computerphile: What on Earth is Recursion?</a>","<a href=\"https://www.youtube.com/watch?v=NA2Oj9xqaZQ\" target=\"_blank\">Coderbyte: How to Code Combinations Using Recursion</a>"]},"build-complete-build":{"subunitId":"build-complete-build","heading":"Creating & Sharing a Project Demo","watch":[{"description":["Achieving a working product that you’ve built from scratch is a rewarding experience. The next step toward launching your product to the audience you’re serving is to create a demo to explain its purpose and how it works.","Once you have a working product, you will be able to share what you’ve built in the <a href = \"https://codesmithx.slack.com/archives/C05CGEG9TQF\" target=\"_blank\"><u>#build-with-code</u></a> channel in the CSX Slack workspace. Posting a recording of your project demo to the channel allows community members to see how your product works, provide meaningful feedback, and offer ideas for stretch features.","Demos can be created using the recording feature on Zoom, should be no longer than 4 minutes long, and should include your description of the following:",{"list":["The problem or issue you were aiming to solve","The solution you came up with, including a screen-share demo of your product in action","The biggest technical challenge you faced while working on this project"]},"To see an example, watch Engineering Project Advisor Parker’s project demo below."]},"https://www.youtube.com/embed/zu4zYp4sxyU",{"description":["In the next unit, we’ll continue creating tools to solve problems you face every day by building a Chrome Extension."]}]},"build-identifying-project":{"subunitId":"build-identifying-project","heading":"Project Ideation & Planning","read":["These approaches are analogous to those used across software engineering and product teams, but also apply to projects you can build to solve challenges in your own work.","At this point, you may already have several ideas for projects in mind. To help organize your thoughts and begin outlining the bones of your project, make a copy of the <a href=\"https://docs.google.com/document/d/1DhyWCSKTrArPn67k83nfJwZriCMDHwG315AF1L2mi3k/edit\" target=\"_blank\"><u>Build with Code Ideation & Planning Worksheet</u></a>.","The resources outlined in the next section are also designed to support your project ideation and expand your problem-solving toolkit."]},"build-intro":{"subunitId":"build-intro","heading":"Introduction to Building with Code","read":["The ability to create something from nothing is one of the most empowering aspects of software engineering. With code, we are able to create solutions to problems ranging from issues we encounter in our own work through the challenges of entire organizations and communities.","To accomplish this, we require a framework that identifies the problem, defines a solution, and allows us to handle challenges along the way. Engineering is a land of 'edge cases', which are bugs that may not be an issue in the majority of users, but will be for a small percentage. Solving for these edge cases is a vital, and incredibly satisfying, part of building with code. To make the process of handling edge cases manageable, we have to start with the most limited solution that just about works, or a Minimum Viable Product (MVP), which we’ll cover in this unit.","Whether you’ve already built products with millions of users or are earlier in your journey of building with code, approaching the development cycle through this framework is vital.","In this unit, we’ll review:",{"list":["The problem-solving approach we employ as software engineers","Identifying opportunities for building with code","Our range of resources for self-guided project development","Contributing to the CSX <a href=\"https://codesmithx.slack.com/archives/C05CGEG9TQF\" target=\"_blank\">#build-with-code</a> Slack community"]}]},"build-problem-solving-approach":{"subunitId":"build-problem-solving-approach","heading":"The Problem-Solving Approach for Engineers","read":["We can start our cultivation of project ideas by thinking about the framework we use for problem-solving as engineers.","<b>1. Identify the Problem</b>","Real-world problem-solving starts by pinpointing an issue that needs to be resolved. Oftentimes, these challenges are not obviously “technical”, but could be solved using technical problem-solving and code.","<i>Example:</i>",{"list":["A Customer Success Coordinator is responsible for following up on support tickets for the large online community they oversee.","A frequent challenge they face is how time-consuming it can be to follow up on a large volume of support tickets. It can be difficult to see what tickets are a top priority without going through each ticket individually, which can backlog their support requests.","They’d like to find a way to streamline this process so they can prioritize the tickets by both risk and urgency to be able to better support more customers and improve their workflow."]},"<b>2. Define a Solution</b>","Next, let’s think about how we can approach these issues using technical problem-solving and code.","These should be minimal solutions to start, or a Minimum Viable Product (MVP). An MVP is a product with enough features to validate a project idea and get it off the ground, but it doesn’t require you to have every detail fleshed out yet. Essentially, the MVP is a product that works well enough that everyday users can find value in it, so try to think about what is reasonable to attempt first.","<i>Example:</i>",{"list":["Continuing with the previous example, the Customer Success Coordinator could build a tool that automates the ticket review process and monitors for at-risk tickets by using certain keywords and time-frame monitoring. This tool could send them an automated list of high-priority tickets so they can effectively manage their time and ensure that more urgent tickets are handled first."]},"<b>3. Build your ‘MVP’</b>","When building your Minimum Viable Product, keep in mind what tech stack makes the most sense for you at this time. Consider your current knowledge of engineering tools and what new techonologies may be reasonable for you to learn while developing your product.","While you have an understanding of JavaScript fundamentals, your MVP may rely on tech outside of JS. The most important consideration is what actual use cases your product can have. This can be accomplished with technologies you use in your day-to-day work, like VBA, Python, or SQL. You can also use tools like webforms and shell scripting, which our Build with Code workshops will help you gain a deeper understanding of.","<i>Example:</i>",{"list":["To go back to our earlier example, an MVP for this customer service ticketing project could be a tool that pulls data from the ticketing system via simple APIs, manipulates that data, then outputs the new data into a new spreadsheet or database with tags for urgency based on time since they’ve been submitted and specific keywords. This allows the Customer Success Manager to effectively prioritize their workload and ensure high-priority tickets are dealt with on time!"]},"<b>4. Feedback and Revision</b>","It’s always important to seek feedback from those using your product to see where improvements can be made to simplify either the user or developer experience, as well as identify potential additional features of your product.","Remember that there is always more than one solution, so your peers might have other ideas for approaching these issues. This is why feedback is so important - it allows us to see things we might not have caught on our own.","To meet other Codesmith community members working on this unit and get feedback from one another, we encourage you to join and participate in the Build with Code CSX Slack channel (<a href=\"https://codesmithx.slack.com/archives/C05CGEG9TQF\" target=\"_blank\"><u>#build-with-code</u></a>).","<b>5. Add Stretch Features</b>","Stretch features are “nice to have” additional features of your product that can be built out once you have a working tool, but are not necessary to get it up and running.","While it’s a great idea to identify some of these potential features now, keep in mind that they may require a more in-depth understanding of certain technologies that you will gain in the Immersive program and beyond. It is okay to keep these ideas on hold until later and focus on getting your product working for now!","In the next section, we’ll use this model to start brainstorming ideas for projects."]},"build-resources-for-building":{"subunitId":"build-resources-for-building","heading":"Resources for Building with Code","read":["<b>CSX Build with Code Community</b>","The <a href = \"https://codesmithx.slack.com/archives/C05CGEG9TQF\" target=\"_blank\"><u>#build-with-code</u></a> channel in the CSX Slack workspace is a hub for sharing project demos, getting feedback from other engineers, and gathering input on challenges you may encounter while building your product."]},"challenge-add-by-x":{"subunitId":"challenge-add-by-x","heading":"Challenge: addByX","solve":{"code":"// ADD CODE HERE\n\nconst addByTwo = addByX(2);\n\n// Now call addByTwo with an input of 1 and log the output\n\n// Now call addByTwo with an input of 2 and log the output\n","test":"describe('addByX', () => {\n  it('should create and return a function', () => {\n    const addByOne = addByX(1);\n    expect(addByOne).to.be.a('function');\n  });\n});\n\ndescribe('addByTwo(1)', () => {\n  it('should return 3', () => {\n    const addByTwo = addByX(2);\n    expect(addByTwo(1)).to.equal(3);\n  });\n});\n\ndescribe('addByTwo(2)', () => {\n  it('should return 4', () => {\n    const addByTwo = addByX(2);\n    expect(addByTwo(2)).to.equal(4);\n  });\n});\n\ndescribe('addByThree(1)', () => {\n  it('should return 4', () => {\n    const addByThree = addByX(3);\n    expect(addByThree(1)).to.equal(4);\n  });\n});\n\ndescribe('addByFour(10)', () => {\n  it('should return 14', () => {\n    const addByFour = addByX(4);\n    expect(addByFour(10)).to.equal(14);\n  });\n});\n","instructions":[{"instructionContent":["Now we are going to create a function <code>addByX</code> that returns a function that will add an input by x.",{"codeBlock":"const addByTwo = addByX(2);\naddByTwo(1); //should return 3\naddByTwo(2); //should return 4\naddByTwo(3); //should return 5\n\nconst addByThree = addByX(3);\naddByThree(1); //should return 4\naddByThree(2); //should return 5\n\nconst addByFour = addByX(4);\naddByFour(4); //should return 8\naddByFour(10); //should return 14"}]}]}},"challenge-add-s":{"subunitId":"challenge-add-s","heading":"Challenge: addS","solve":{"code":"// ADD CODE HERE\n\n// Uncomment these to check your work!\n// console.log(typeof addS); // should log: 'function'\n// console.log(addS('cat')); // should log: 'cats'\n","test":"describe('addS', () => {\n  it('should be a function', () => {\n    expect(addS).to.be.a('function');\n  });\n});\n\ndescribe('addS(\"cat\")', () => {\n  it('should return \"cats\"', () => {\n    expect(addS('cat')).to.eq('cats');\n  });\n});\n","instructions":[{"instructionContent":["Create a function <code>addS</code> that accepts a string, and returns the string with an \"s\" added to the end."]}]}},"challenge-add-two":{"subunitId":"challenge-add-two","heading":"Challenge: addTwo","solve":{"code":"// ADD CODE HERE\n\n// Uncomment these to check your work!\n// console.log(typeof addTwo); // should log: 'function'\n// console.log(addTwo(10)); // should log: 12","test":"describe('addTwo', () => {\n  it('should be a function', () => {\n    expect(addTwo).to.be.a('function');\n  });\n  it('should take in one argument', () => {\n    expect(addTwo.length).to.eq(1);\n  });\n});\n\ndescribe('addTwo(10)', () => {\n  it('should return 12', () => {\n    expect(addTwo(10)).to.eq(12);\n  });\n});\n\ndescribe('addTwo(12)', () => {\n  it('should return 14', () => {\n    expect(addTwo(12)).to.eq(14);\n  });\n});\n","instructions":[{"instructionContent":["Create a function <code>addTwo</code> that accepts a number, and returns the number plus 2."]}]}},"challenge-add-waldo":{"subunitId":"challenge-add-waldo","heading":"Challenge: addWaldo","solve":{"code":"// ADD CODE HERE \n\n// Uncomment these to check your work!\n// const siliconValley = {'Richard': 'Hendricks', 'Erlich': 'Bachman', 'Bertram': 'Gilfoyle'}\n// console.log(addWaldo(siliconValley)) // should log:{ Richard: 'Hendricks', Erlich: 'Bachman', Bertram: 'Gilfoyle', Waldo: 'unknown' }","test":"describe('addWaldo', () => {\n  it('should be a function', () => {\n    expect(addWaldo).to.be.a('function');\n  });\n});\n\ndescribe(\"addWaldo({'Richard': 'Hendricks', 'Erlich': 'Bachman', 'Bertram': 'Gilfoyle'})\", () => {\n  it(\"should return { Richard: 'Hendricks', Erlich: 'Bachman', Bertram: 'Gilfoyle', Waldo: 'unknown' }\", () => {\n    let names = { Richard: 'Hendricks', Erlich: 'Bachman', Bertram: 'Gilfoyle' };\n    addWaldo(names);\n    expect(names.Waldo).to.eq('unknown', 'Waldo not found. Are you sure you modified the original object?');\n  });\n});\n","instructions":[{"instructionContent":["Create a function <code>addWaldo</code> that accepts an object with keys being first names and values being last names.  For example <code>addWaldo({'Luke': 'Skywalker', 'Harley': 'Quinn', 'Ryan': 'Reynolds'})</code> should add the key <code>'Waldo'</code> with the value <code>'unknown'</code> to the object and return the mutated object."]}]}},"challenge-after":{"subunitId":"challenge-after","heading":"Challenge: after","solve":{"code":"// ADD CODE HERE\n\nconst called = function(string) { return('hello ' + string); };\nconst afterCalled = after(3, called);\n\n// UNCOMMENT THESE LINES TO TEST YOUR WORK\n// console.log(afterCalled('world')); // -> undefined is printed\n// console.log(afterCalled('world')); // -> undefined is printed\n// console.log(afterCalled('world')); // -> 'hello world' is printed","test":"describe('after', () => {\n  const addByOneAfter = after(function (num) {\n    return num + 1;\n  });\n\n  it('should create and return a function', () => {\n    expect(addByOneAfter).to.be.a('function');\n  });\n});\n\ndescribe('The function returned from after', () => {\n  const addByTwoAfter = after(2, function (num) {\n    return num + 2;\n  });\n  const addByThreeAfter = after(3, function (num) {\n    return num + 3;\n  });\n\n  it('should not run the callback before it has been called count times', () => {\n    expect(addByTwoAfter(0)).to.equal(undefined);\n    expect(addByThreeAfter(9)).to.equal(undefined);\n    expect(addByThreeAfter(9)).to.equal(undefined);\n  });\n\n  it('should run the callback (with arguments) after count calls', () => {\n    expect(addByTwoAfter(0)).to.equal(2);\n    expect(addByTwoAfter(1)).to.equal(3);\n    expect(addByThreeAfter(9)).to.equal(12);\n    expect(addByThreeAfter(10)).to.equal(13);\n  });\n});\n","instructions":[{"instructionContent":["Write a function <code>after</code> that takes the number of times the callback needs to be called before being executed as the first parameter and the callback as the second parameter."]}]}},"challenge-ajax-simulate":{"subunitId":"challenge-ajax-simulate","heading":"Challenge: ajaxSimulate","solve":{"code":"let dataReceived;\n\nfunction ajaxSimulate(id, callback) {\n  const database = ['Aaron', 'Barbara', 'Chris'];\n  // Add code here\n}\n\n// Also add code here\n","test":"const { oldConsoleLog, logged } = reDefineConsoleLog((arg) => {\n  logged.push(arg);\n});\n\ndescribe('ajaxSimulate', () => {\n  it('should be a function', () => {\n    expect(ajaxSimulate).to.be.a('function');\n  });\n});\n\ndescribe('storeData', () => {\n  it('should be a function', () => {\n    expect(storeData).to.be.a('function');\n  });\n});\n\ndescribe('storeData', () => {\n  it('should log \"Barbara\" after 0 ms', (done) => {\n    delay(20, logged)\n      .then((resolved) => {\n        expect(resolved[0]).to.eq('Barbara');\n        console.log = oldConsoleLog;\n      })\n      .then(done, done);\n  });\n});\n\n//resolve promise after ms milleseconds\nfunction delay(ms, logged) {\n  return new Promise((resolve) => {\n    setTimeout(() => resolve(logged), ms);\n  });\n}\n\n// logged will contain all arguments passed into console.log\nfunction reDefineConsoleLog(newConsoleLog, logged = []) {\n  const oldConsoleLog = console.log;\n  console.log = newConsoleLog;\n  return { oldConsoleLog, logged };\n}\n","instructions":[{"instructionContent":["In this challenge we are going to simulate an AJAX call to get information from a server. This is not a real AJAX call, but the asynchonicity is similar.","The function <code>ajaxSimulate</code> takes an <code>id</code> and a <code>callback</code> function as input. Modify the function so that after the <code>database</code> array, it will set a timer that will pass the element of <code>database</code> whose index matches <code>id</code> to the <code>callback</code> function after 0 ms.","Create a second function <code>storeData</code> (outside of <code>ajaxSimulate</code>) that takes <code>data</code> as input and assigns it to the <code>dataReceived</code> variable already defined.","Invoke the <code>ajaxSimulate</code> function with an id of 1 and the <code>storeData</code> function as the callback. Immediately after, log to the console the value of <code>dataReceived</code>. What do you expect it to be?","Without changing anything else, copy-paste the <code>console.log</code> statement somewhere where it will log with the info we need."]}]}},"challenge-array-builder":{"subunitId":"challenge-array-builder","heading":"Challenge: arrayBuilder","solve":{"code":"function arrayBuilder(obj) {\n  // ADD CODE HERE\n}\n\n// Uncomment these to check your work!\n// console.log(arrayBuilder({'cats': 2, 'dogs': 1})); // => ['cats', 'cats', 'dogs']\n// console.log(arrayBuilder({})); // => []","test":"describe('arrayBuilder', () => {\n  it('should be a function', () => {\n    expect(arrayBuilder).to.be.a('function');\n  });\n});\n\ndescribe('arrayBuilder({})', () => {\n  it('should equal []', () => {\n    expect(arrayBuilder({})).to.deep.equal([]);\n  });\n});\n\ndescribe('arrayBuilder({\"cats\": 2, \"dogs\": 1})', () => {\n  it('should equal [\"cats\", \"cats\", \"dogs\"]', () => {\n    expect(arrayBuilder({ cats: 2, dogs: 1 })).to.deep.equal(['cats', 'cats', 'dogs']);\n  });\n  it('should group \"cats\" together', () => {\n    let result = arrayBuilder({ cats: 2, dogs: 1 });\n    let firstCatsIndex = result.indexOf('cats');\n    expect(result[firstCatsIndex + 1]).to.eq('cats');\n  });\n});\n","instructions":[{"instructionContent":["Write a function <code>arrayBuilder</code> that takes in a count object and returns an array filled with the appropriate numbers of elements. The order of the elements in the array does not matter, but repeated elements should be grouped."]}]}},"challenge-array-to-obj":{"subunitId":"challenge-array-to-obj","heading":"Challenge: arrToObj","solve":{"code":"function arrToObj(array, callback) {\n  // ADD CODE HERE\n}\n\n// Uncomment these to check your work!\n// const arrOfStrings = ['beer', 'glue'];\n// const capitalize = str => str.toUpperCase();\n// console.log(arrToObj(arrOfStrings, capitalize)); // should log: { beer: 'BEER', glue: 'GLUE' }","test":"describe('arrToObj', () => {\n  it('should be a function', () => {\n    expect(arrToObj).to.be.a('function');\n  });\n});\n\ndescribe('arrToObj(arrOfStrings, capitalize)', () => {\n  it(\"should return { beer: 'BEER', glue: 'GLUE' }\", () => {\n    expect(arrToObj(arrOfStrings, capitalize)).to.deep.equal({ beer: 'BEER', glue: 'GLUE' });\n  });\n});\n","instructions":[{"instructionContent":["Add code to the function <code>arrToObj</code> in the place marked <code>\"ADD CODE HERE\"</code> in order to achieve the desired console logs. <code>arrToObj</code> should return an object that has elements from the passed-in array as keys, and the outputs from the callback (when those elements are passed in) as the corresponding values."]}]}},"challenge-arrays-adding-elements":{"subunitId":"challenge-arrays-adding-elements","heading":"Challenge: Arrays - Adding Elements","solve":{"code":"const  netflixShows = [\"Orange is the New Black\", \"Black Mirror\", \"Chewing Gum\"];\n\n// ADD CODE HERE\n\n\n// Write a console.log statement below to check your work!\n","test":"describe('netflixShows', () => {\n  it('should be an array', () => {\n    expect(netflixShows).to.be.a('array');\n  });\n});\n\ndescribe('netflixShows', () => {\n  it('should have a length of 4', () => {\n    expect(netflixShows.length).to.eq(4);\n  });\n});\n","instructions":[{"instructionHeading":"Challenge","instructionContent":["Use a built-in JavaScript method to add another show to the <code>netflixShows</code> array. Then log your updated array to the console."]}]}},"challenge-arrays-examining-elements":{"subunitId":"challenge-arrays-examining-elements","heading":"Challenge: Arrays - Examining Elements","solve":{"code":"const horror = ['Freddy', 'Jason', 'Michael', 'Ghostface', 'Chucky'];\n\n// ADD CODE HERE\n\n\n// Write a console.log statement below to check your work!\n","test":"describe('fourthItem', () => {\n  it('should be of type string', () => {\n    expect(fourthItem).to.be.a('string');\n  });\n\n  it('should be the string \"Ghostface\"', () => {\n    expect(fourthItem).to.equal('Ghostface');\n  });\n});\n","instructions":[{"instructionHeading":" ","instructionContent":["We know that if we need to hold on to a value, we can create a variable. But what if we need to store multiple values in a single place? One way to store a list of values is in an array.","Arrays are denoted by square brackets <code>[]</code>, with each value inside of the array separated by commas like so:",{"codeBlock":"let fellows = [\"Brandon\", \"Sam\", \"Gordon\"];"},"Notice that the array is a lot like a list. JavaScript uses a <strong>zero-based</strong> indexing system to keep track of values in the array, starting at 0 for the first array element, 1 for the second array element, and so on. This makes arrays very easy to work with, as you'll see in the next section.",{"codeBlock":"let letters = ['a', 'b', 'c']\n// The index of 'a' is 0\n// The index of 'b' is 1\n// The index of 'c' is 2"},"What if we need to grab only a single element from our array? We can use the index of that element in the array to select it:",{"codeBlock":"let friends = ['George', 'Thai', 'Brandon'];\nconsole.log(friends[2]); // should log: 'Brandon'"},"Something that's also very handy is knowing how many elements are in an array at any given time. Arrays come with a built-in <code>length</code> property that tells us how many items are currently in the array.",{"codeBlock":"const myArray = [1, 3, 4, 2];\n\nconsole.log(myArray.length); // should log 4"},"We can also add and remove items from our arrays using some additional built-in methods. To add an element <strong>to the end</strong> of an array, use the <code>push</code> method. To remove items <strong>from the end</strong> of an array, use the <code>pop</code> method.",{"codeBlock":"let numbers = [1, 2, 3, 4];\nnumbers.push(5);\nconsole.log(numbers); // should log: [1, 2, 3, 4, 5]\n\nnumbers.pop();\nconsole.log(numbers); // should log: [1, 2, 3, 4]"}]},{"instructionHeading":"Challenge","instructionContent":["Create a variable called <code>fourthItem</code> and assign it the value of the fourth item in the <code>horror</code> array ('Ghostface'). Then console.log <code>fourthItem</code> to see the output."]}]}},"challenge-booleans-comparison":{"subunitId":"challenge-booleans-comparison","heading":"Challenge: Booleans: Comparison Operators","solve":{"code":"// 1.\nconst small = 2;\nconst large = 5342;\n// ADD CODE BELOW (isSmaller)\n\n\n// 2.\nconst num = 45;\nconst string = \"45\";\n// ADD CODE BELOW (isLooselyEqual and isStrictlyEqual)\n\n\n\n// 3.\nconst isTrue = true;\nconst isFalse = false;\n// ADD CODE BELOW (isTrueNotFalse)\n\n\n// Uncomment these to check your work! \n// console.log('Is 2 < 5342?');\n// console.log(isSmaller);\n// console.log('Is 45 loosely equal to \"45\"?'); \n// console.log(isLooselyEqual);\n// console.log('Is 45 strictly equal to \"45\"?');\n// console.log(isStrictlyEqual);\n// console.log('Is true not equal to false?');\n// console.log(isTrueNotFalse);","test":"describe('isSmaller', () => {\n  it('should be true', () => {\n    expect(isSmaller).to.equal(true);\n  });\n});\n\ndescribe('isLooselyEqual', () => {\n  it('should be true', () => {\n    expect(isLooselyEqual).to.equal(true);\n  });\n});\n\ndescribe('isStrictlyEqual', () => {\n  it('should be false', () => {\n    expect(isStrictlyEqual).to.equal(false);\n  });\n});\n\ndescribe('isTrueNotFalse', () => {\n  it('should be true', () => {\n    expect(isTrueNotFalse).to.equal(true);\n  });\n});\n","instructions":[{"instructionHeading":"Comparison Operators","instructionContent":["In programming, when working with data, we often need to compare different values.  To do this,  we use a series of operators called <strong>comparison operators</strong>.  Check out this list of  the most common comparison operators:",{"list":["<code><</code> - <strong>Less than</strong>","<code>></code> - <strong>Greater than</strong>","<code><=</code> - <strong>Less than or equal to</strong>","<code>>=</code> - <strong>Greater than or equal to</strong>","<code>==</code> - <strong>Is loosely equal to</strong>","<code>===</code> - <strong>Is strictly equal to</strong>","<code>!=</code> - <strong>Is not loosely equal to</strong>","<code>!==</code> - <strong>Is not strictly equal to</strong>"]},"The first four are probably pretty familiar to you from primary school math class, but things  start to get a little tricky when we talk about equality in JavaScript.","First, we already know that a single equals sign (<code>=</code>) is used to assign value to a  variable, so we can't use that to compare to values unfortunately.","So let's start with <strong>loose equality</strong> (<code>==</code>).  This operator is used to  compare if 2 values have the same <em>value</em>, even if they aren't necessarily the same  <em>type</em>.",{"codeBlock":" 1   ==  1        // true\n\"1\"  ==  1        // true\n 1   == '1'       // true\n\ntrue == true      // true\nfalse == false    // true\n"},"In the example above, all of these comparisons are true, because the <em>value</em> is the same  even though they may have a different data <em>type</em>.","For 2 values to be <strong>strictly equal</strong> (<code>===</code>) to each other, they need to  not only have the same <em>value</em>, but also must have the same data <em>type</em>:",{"codeBlock":" 2   ===  2        // true\n\"2\"  ===  2        // false\n 2   === '2'       // false\n\ntrue === true      // true\nfalse === false    // true\n"},"Don't worry if this still seems a little confusing.  We'll come back to it a bit more when we get to  conditional statements in the second half of the precourse."]},{"instructionHeading":"Challenge","instructionContent":["For the following problems, you will be using the comparison operators (<code>==</code>, <code>===</code>, <code><</code>, <code>></code>, <code><=</code>, <code>>=</code>) to compare two variables and see if the comparison yields <code>true</code> or <code>false</code>. You will assign the resulting boolean to a variable. For example:",{"codeBlock":"let first = 7;\nlet second = 8;\n\nlet isFirstBigger = first > second;\nconsole.log(isFirstBigger); // should log: false\n\nfirst = 16;\nisFirstBigger = first > second;\nconsole.log(isFirstBigger); // should log: true\n"},"<strong>1.</strong> Compare <code>small</code> and <code>large</code> using the <code><</code> operator. Assign the result to a variable called <code>isSmaller</code>.","<strong>2.</strong> Compare <code>num</code> and <code>string</code>. First, use the <code>==</code> operator to compare the two variables, and assign the result to a variable called<code>isLooselyEqual</code>. Second, use the <code>===</code> operator to compare the variables; assign the result to a variable called <code>isStrictlyEqual</code>.","<strong>3.</strong> Compare <code>isTrue</code> and <code>isFalse</code> using the <code>!==</code> operator. Assign the result to a variable called <code>isTrueNotFalse</code>.","Continue to experiment with different comparison operators and data types. You can see a full list of comparison operators <a href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators\">here</a>."]}]}},"challenge-booleans-intro":{"subunitId":"challenge-booleans-intro","heading":"Challenge: Booleans","solve":{"code":"let iHaveChanged = false;\n\n// ADD CODE BELOW","test":"describe('iHaveChanged', () => {\n  it('should be true', () => {\n    expect(iHaveChanged).to.equal(true);\n  });\n});\n\ndescribe('iLoveCoding', () => {\n  it('should be true', () => {\n    expect(iLoveCoding).to.equal(true);\n  });\n});\n\ndescribe('codingIsTooHard', () => {\n  it('should be false', () => {\n    expect(codingIsTooHard).to.equal(false);\n  });\n});\n","instructions":[{"instructionHeading":" ","instructionContent":["Boolean (BOO-lee-uhn) is another data type in JavaScript. JavaScript boolean values can be either <code>true</code> or <code>false</code>. They are useful for determining whether or not blocks of code should be executed. They are also the default result for many evaluations.",{"codeBlock":"let likesJavaScript = true;\nlet likesMath = false;\n\nconst numToCheck = 10;\nconsole.log(numToCheck === 10) // => true"},"In the example above, we're using the <code>===</code> operator (<em>we'll  talk about this in more detail in the next challenge</em>) to compare <code>numToCheck</code> with 10 and determine if they are equal. If they are equal, both in value and data type, then JavaScript will log <code>true</code>. Otherwise, it will log <code>false</code>.","Booleans are extremely handy when dealing with conditional statements - you'll learn more about them in a later section."]},{"instructionHeading":"Challenge","instructionContent":["<strong>1.</strong> Below line 3, reassign the value of <code>iHaveChanged</code>  to <code>true</code>.","<strong>2.</strong> Declare a variable <code>iLoveCoding</code> and assign it a boolean  value of <code>true</code>.","<strong>3.</strong> Declare a variable <code>codingIsTooHard</code> and assign it the  boolean value of <code>false</code>."]}]}},"challenge-cascade":{"subunitId":"challenge-cascade","heading":"Challenge: cascade","solve":{"code":"function cascade(number) {\n\t// Your code here!\n}\n\n\n\n// // Uncomment to test your work!\n// cascade(111)\n// // should print\n// /*\n// 111\n// 11\n// 1\n// 11\n// 111\n// */","test":"describe('cascade', () => {\n  it('should be a function', () => {\n    expect(cascade).to.be.a('function');\n  });\n\n  it('should return undefined', () => {\n    expect(cascade()).to.equal(undefined);\n    expect(cascade(12345)).to.equal(undefined);\n  });\n\n  it('should return a cascade of the input', () => {\n    let logged = [];\n    (function () {\n      const realConsoleLog = console.log;\n      console.log = function (input) {\n        logged.push(input);\n      };\n      cascade(11111);\n      console.log = realConsoleLog;\n    })();\n    expect(logged[0]).to.equal(11111);\n    expect(logged[1]).to.equal(1111);\n    expect(logged[2]).to.equal(111);\n    expect(logged[3]).to.equal(11);\n    expect(logged[4]).to.equal(1);\n    expect(logged[5]).to.equal(11);\n    expect(logged[6]).to.equal(111);\n    expect(logged[7]).to.equal(1111);\n    expect(logged[8]).to.equal(11111);\n    logged = [];\n    (function () {\n      const realConsoleLog = console.log;\n      console.log = function (input) {\n        logged.push(input);\n      };\n\n      cascade(101);\n      console.log = realConsoleLog;\n    })();\n    expect(logged[0]).to.equal(101);\n    expect(logged[1]).to.equal(10);\n    expect(logged[2]).to.equal(1);\n    expect(logged[3]).to.equal(10);\n    expect(logged[4]).to.equal(101);\n  });\n});\n","instructions":[{"instructionContent":["Write a function <code>cascade</code> that takes a positive integer and prints a cascade of this integer. Hint - this very challenging problem can be solved with and without string manipulation!",{"codeBlock":"cascade(12345) should print\n\n12345\n1234\n123\n12\n1\n12\n123\n1234\n12345"}]}]}},"challenge-censor":{"subunitId":"challenge-censor","heading":"Challenge: censor","solve":{"code":"// ADD CODE HERE\n\n// Uncomment these to check your work!\n// const changeScene = censor();\n// changeScene('dogs', 'cats');\n// changeScene('quick', 'slow');\n// console.log(changeScene('The quick, brown fox jumps over the lazy dogs.')); // should log: 'The slow, brown fox jumps over the lazy cats.'","test":"const rewrite = censor();\n\ndescribe('censor', () => {\n  it('should create and return a function', () => {\n    expect(rewrite).to.be.a('function');\n  });\n});\n\ndescribe('The function returned from censor', () => {\n  it('should not return anything when two strings are given', () => {\n    expect(rewrite('hello', 'goodbye')).to.equal(undefined);\n    expect(rewrite('want', 'do not want')).to.equal(undefined);\n  });\n\n  it('should return a string when one string is given', () => {\n    expect(rewrite('')).to.be.a('string');\n    expect(rewrite('I want to grade assessments')).to.be.a('string');\n  });\n});\n\ndescribe('The returned string', () => {\n  it('should be the same as the input string, with all instances of a first string in a saved pair replaced with the second string', () => {\n    expect(rewrite('I want to grade assessments')).to.equal('I do not want to grade assessments');\n    expect(rewrite('hello world')).to.equal('goodbye world');\n    expect(rewrite('Say hello if you want to enter the gate')).to.equal(\n      'Say goodbye if you do not want to enter the gate'\n    );\n    expect(rewrite('You say hello, I say goodbye')).to.equal('You say goodbye, I say goodbye');\n  });\n});\n","instructions":[{"instructionContent":["Create a function <code>censor</code> that accepts no arguments. <code>censor</code> will return a function that will accept either two strings, or one string. When two strings are given, the returned function will hold onto the two strings as a pair, for future use. When one string is given, the returned function will return the same string, except all instances of a first string (of a saved pair) will be replaced with the second string (of a saved pair)."]}]}},"challenge-chain-stores":{"subunitId":"challenge-chain-stores","heading":"Challenge: Chain Stores","solve":{"code":"class Chain {\n\t// add code here\n}\n\nclass Franchise {\n    //add code here\n}\n\n\nconst buenoBell = new Chain('Bueno Bell');\n\n// Uncomment these lines to check your work!\n//buenoBell.openStore('Will', 'Phoenix');\n//buenoBell.openStore('Kyle', 'Austin');\n//buenoBell.openStore('Allison', 'Wichita');\n\n//console.log(buenoBell.totalStores); //should log 3\n//console.log(buenoBell.locations[0].owner) //should log 'Will'\n\n//buenoBell.closeStore('Austin'); // Should log 'Bueno Bell closed the store in Austin.'\n//buenoBell.closeStore('Maui'); // Should log 'Bueno Bell doesn't have a store in Maui.'\n","test":"describe('Chain', () => {\n  it('- created object has Chain as constructor', () => {\n    const mcKing = new Chain('McKing');\n    expect(mcKing.constructor).to.equal(Chain);\n  });\n  it('- created object has name property initialized properly', () => {\n    const mcKing = new Chain('McKing');\n    expect(mcKing.name).to.equal('McKing');\n  });\n  it('- created object has totalStores property initialized to 0', () => {\n    const mcKing = new Chain('McKing');\n    expect(mcKing.totalStores).to.equal(0);\n  });\n  it('- has a locations property initially set to an empty array', () => {\n    const mcKing = new Chain('McKing');\n    expect(Array.isArray(mcKing.locations)).to.equal(true);\n    expect(mcKing.locations.length).to.equal(0);\n    expect(mcKing.totalStores).to.equal(0);\n  });\n  it('- created object has an openStore and closeStore method', () => {\n    const mcKing = new Chain('McKing');\n    expect(mcKing.openStore).to.be.a('function');\n    expect(mcKing.closeStore).to.be.a('function');\n    mcKing.openStore('Will', 'Phoenix');\n    expect(mcKing.locations[0].city).to.equal('Phoenix');\n    let log;\n    function testLogs(string) {\n      const oldConsoleLog = console.log;\n      console.log = function (input) {\n        log = input;\n      };\n      mcKing.closeStore(string);\n      console.log = oldConsoleLog;\n    }\n    testLogs('Phoenix');\n    expect(log).to.equal('McKing closed the store in Phoenix!');\n    testLogs('Cleveland');\n    expect(log).to.equal(\"McKing doesn't have a store in Cleveland.\");\n  });\n  it('- created object increments and decrements totalStores property correctly', () => {\n    const mcKing = new Chain('McKing');\n    expect(mcKing.totalStores).to.equal(mcKing.locations.length);\n    mcKing.openStore('Will', 'Phoenix');\n    mcKing.openStore('Kyle', 'Austin');\n    mcKing.openStore('Allison', 'Wichita');\n    expect(mcKing.totalStores).to.equal(mcKing.locations.length);\n  });\n  it('- both methods should be stored on the Chain prototype rather than the object itself', () => {\n    const mcKing = new Chain('McKing');\n    expect(Object.hasOwn(mcKing, 'addStore')).to.equal(false);\n    expect(Object.hasOwn(mcKing, 'closeStore')).to.equal(false);\n  });\n});\n\ndescribe('Franchise', () => {\n  it('- created object has Franchise as constructor', () => {\n    const newLocation = new Franchise('Will', 'Phoenix');\n    expect(newLocation.constructor).to.equal(Franchise);\n  });\n  it('- created object has owner and city properties initialized properly', () => {\n    const newLocation = new Franchise('Will', 'Phoenix');\n    expect(newLocation.owner).to.equal('Will');\n    expect(newLocation.city).to.equal('Phoenix');\n  });\n});\n","instructions":[{"instructionContent":["Declare a class <code>Chain</code> that creates a new instance of a <code>Chain</code> object when invoked with the <code>new</code> keyword. Each <code>Chain</code> object should have a <code>name</code> property, a <code>totalStores</code> property, and a <code>locations</code> property.  The <code>name</code> property will be assigned to a string which is passed in as an argument when calling the <code>Chain</code> function. The <code>totalStores</code> property should be initialized to 0 and the <code>locations</code> property set to an array representing all the existing franchises of that chain store. When a new object is initiated, the <code>locations</code> array should be empty.","Declare another class <code>Franchise</code> that creates a new instance of a <code>Franchise</code> object when invoked with the <code>new</code> keyword.  Each <code>Franchise</code> object should have an <code>owner</code> property and a <code>city</code> property, both of which will be set equal to strings passed in as arguments to the constructor.","All instances of your <code>Chain</code> class must also have access to two methods that are stored on the class's <code>prototype</code>:","The first method, <code>openStore</code>, should take in 2 strings as arguments.  Those strings should be passed into a new instance of a <code>Franchise</code> object as the arguments for the <code>owner</code> and <code>city</code> properties. The new instance of <code>Franchise</code> should be added to the <code>locations</code> array which belongs to the <code>Chain</code> instance the method was called on.  The <code>totalStores</code> property should also be updated accordingly.","The second method, <code>closeStore</code>, should take a single string as an argument. It should check to see if there is an instance of a <code>Franchise</code> with a <code>city</code> property that matches the input string in the <code>locations</code> array on the instance of <code>Chain</code> the method was called on.  If so, it should remove the instance from the <code>locations</code> array, update the <code>totalStores</code> property and display the string '<code>name</code> closed the store in <code>city</code>!' If not, log the string '<code>name</code> doesn't have a store in <code>city</code>.'"]}]}},"challenge-console":{"subunitId":"challenge-console","heading":"Comments and the Console","solve":{"code":"// Try un-commenting the line below\n// console.log(\"Hello World!\")\n\n// ADD CODE BELOW HERE\n\n\n\n","instructions":[{"instructionHeading":"Comments and Console Logs","instructionContent":["Welcome to your first challenge! Don't worry, we'll ease you into it.   We're going to go step by step through the basics throughout this entire  pre-course unit.  Don't stress out too much if it seems a little  daunting at first.","You'll be using the code editor to the right to work through the  challenges provided while viewing the output of your code in the <code> console</code> window just below it.","Unfortunately, much of what the computer does \"under the hood\" is invisible  to us.  This is where the console comes in!  If we want the computer to show  us what's going on, we can print, or log, directly to our console.","Logging things to the console is a really handy way to see how JavaScript is interpreting values. We'll be using it frequently throughout the course, so you'll be a pro at it in no time. To use it, you need only type <code>console.log()</code> - whatever you pass between the parentheses (<code>()</code>) will be logged to the console.","Notice that there are two forward slashes (<code>//</code>) before the <code>console.log</code> statement on line 2. These forward slashes create a <code>comment</code>.  Comments are another really useful tool  because they let us write little notes for ourselves or anyone else who's  reading our code.  Commented lines are ignored when the code runs, so they  won't affect what happens when our code runs.","Go ahead and run the code in the editor to the right by clicking the blue  \"Run Code\" button.  Nothing got printed to the console!  The only thing we see is  the console's note to us that it has finished executing code.  How can we fix this?","Let's give it a try, you got it! Then uncomment the <code>console.log</code> statement  on line 2 by removing the forward slashes (<code>//</code>) at the beginning of the line.  Now let's run the code again by clicking the blue Run Code button again.  Now you should  see \"Hello World!\" down in your console window."]},{"instructionHeading":"Challenge","instructionContent":["Now it's your turn!  Go ahead and give it a try yourself!  Create your own console.log below  line 4.  You can print any word or phrase you like to the console.  Just make sure you put  the word or phrase in between quotes (<code>\"\"</code>) like the example.  We'll go into detail  very soon as to what that means."]}]}},"challenge-control-flow-if-statements":{"subunitId":"challenge-control-flow-if-statements","heading":"Challenge: Control Flow - if statements","solve":{"code":"const num = 40;\nlet final;\n// ADD CODE HERE\n\n\n// Log final to the console below to check your work\n","test":"describe('final', () => {\n  it('should be 80', () => {\n    expect(final).to.eq(80);\n  });\n});\n\ndescribe('final', () => {\n  it('should be of type number', () => {\n    expect(typeof final).to.eq('number');\n  });\n});\n","instructions":[{"instructionHeading":" ","instructionContent":["Sometimes there are certain conditions that need to be met in order for an event to occur. Let's take dating as an example. If going out on a first date is a horrible experience, then there won't be a second date. If the first date is wonderful, then there will probably be a second date. We use this same kind of logic in programming.","Using an <code>if</code> statement, we can execute a block of code if the condition inside the parentheses is met.",{"codeBlock":"if (5 > 2) {\n  console.log(\"Math still works!\"); // 'Math still works!'\n}"},"If we wanted to chain more if statements together, we could use an <code>else if</code> block. In the example below, four is not less than two so we don't run the block of code inside the if statement. Next, we move to the else if statement. That condition is true, so the code runs.",{"codeBlock":"if (4 < 2) {\n  console.log(\"This shouldn't log\");\n} else if (4 > 2) {\n  console.log(\"This should log\"); // 'This should log'\n}"},"You can also use an <code>else</code> statement to catch anything that your <code>if</code>  and <code>else if</code>  conditions don't meet.",{"codeBlock":"let day = \"Christmas\";\nif (day === \"work day\") {\n  console.log(\"Time to go to work!\");\n} else if (day === \"sick day\") {\n  console.log(\"Stay home and rest up!\");\n} else {\n  console.log(\"Enjoy your holiday!\");\n}"},"In the code above we have specific conditions for sick days and work days. However, there are other days that have special conditions. We don't want to write a condition for every holiday; that would take too long. Instead we use an <code>else</code> block to catch those cases."]},{"instructionHeading":"Challenge","instructionContent":["Use an <code>if</code> statement to check if <code>num</code> is greater than 100. If <code>num</code> is greater than 100, reassign the value of <code>final</code> to <code>null</code>. Otherwise, set <code>final</code> to be two times the value of <code>num</code>.","Learn more about null <a href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/null\">here</a>."]}]}},"challenge-control-flow-if-statements-and-multiple-conditions":{"subunitId":"challenge-control-flow-if-statements-and-multiple-conditions","heading":"Challenge: Control Flow - if statements & multiple conditions","solve":{"code":"function greetings(hour) {\n  // ADD CODE HERE\n}\n\n// Uncomment these to check your work!\n// console.log(greetings(8)); // expected log 'Good Morning!'\n// console.log(greetings(12)); // expected log 'Good Afternoon!'\n// console.log(greetings(14)); // expected log 'Good Afternoon!'\n// console.log(greetings(15)); // expected log 'Good Night!'\n// console.log(greetings(18)); // expected log 'Good Night!'\n","test":"describe('greetings', () => {\n  it('should be a function', () => {\n    expect(greetings).to.be.a('function');\n  });\n});\n\ndescribe('greetings(8)', () => {\n  it(\"should return 'Good Morning!'\", () => {\n    expect(greetings(8)).to.eq('Good Morning!');\n  });\n});\n\ndescribe('greetings(12)', () => {\n  it(\"should return 'Good Afternoon!'\", () => {\n    expect(greetings(12)).to.eq('Good Afternoon!');\n  });\n});\n\ndescribe('greetings(14)', () => {\n  it(\"should return 'Good Afternoon!'\", () => {\n    expect(greetings(14)).to.eq('Good Afternoon!');\n  });\n});\n\ndescribe('greetings(15)', () => {\n  it(\"should return 'Good Night!'\", () => {\n    expect(greetings(15)).to.eq('Good Night!');\n  });\n});\n\ndescribe('greetings(18)', () => {\n  it(\"should return 'Good Night!'\", () => {\n    expect(greetings(18)).to.eq('Good Night!');\n  });\n});\n","instructions":[{"instructionContent":["Using an IF/ELSE statement, write a function <code>greetings</code> which returns 'Good Morning!' if the hour is before 12, 'Good Afternoon!' if the hour is before 15, or 'Good Night!' if the hour is 15 or after."]}]}},"challenge-control-flow-if-statements-and-remainders":{"subunitId":"challenge-control-flow-if-statements-and-remainders","heading":"Challenge: Control Flow - if statements & remainders","solve":{"code":"// ADD CODE HERE\n\n// Uncomment these to check your work!\n// console.log(iLoveEvenNumbers(42)); // expected log 'Oh Yeah Evens!'\n// console.log(iLoveEvenNumbers(17)); // expected log 'I am too normal for odd numbers'\n","test":"describe('iLoveEvenNumbers', () => {\n  it('should be a function', () => {\n    expect(iLoveEvenNumbers).to.be.a('function');\n  });\n});\n\ndescribe('iLoveEvenNumbers(60)', () => {\n  it(\"should return 'Oh Yeah Evens!'\", () => {\n    expect(iLoveEvenNumbers(60)).to.eq('Oh Yeah Evens!');\n  });\n});\n\ndescribe('iLoveEvenNumbers(61)', () => {\n  it(\"should return 'I am too normal for odd numbers'\", () => {\n    expect(iLoveEvenNumbers(61)).to.eq('I am too normal for odd numbers');\n  });\n});\n","instructions":[{"instructionContent":["Write a function <code>iLoveEvenNumbers</code> that takes a number argument and returns 'Oh Yeah Evens!' if the argument is even or 'I am too normal for odd numbers' if the argument is odd."]}]}},"challenge-control-flow-if-statements-and-the-math-object":{"subunitId":"challenge-control-flow-if-statements-and-the-math-object","heading":"Challenge: Control Flow - if statements and the Math object","solve":{"code":"function closestToTheMark(player1, player2){\n  const theMark = Math.floor(Math.random() * 100)\n  console.log(`If theMark is ${theMark}...`);\n  // ADD CODE HERE\n}\n\n// Uncomment the line below to check your work!\n// console.log(closestToTheMark(25, 75));\n","test":"describe('closestToTheMark', () => {\n  it('should be a function', () => {\n    expect(closestToTheMark).to.be.a('function');\n  });\n});\n\ndescribe('closestToTheMark(25, 75)', () => {\n  it('should return a string', () => {\n    expect(typeof closestToTheMark(25, 75)).to.eq('string');\n  });\n});\n","instructions":[{"instructionContent":["Using an IF/ELSE statement, write a function <code>closestToTheMark</code> that takes two player inputs as number arguments. The function will return 'Player 1 is closest' or 'Player 2 is closest' depending on which player input is closest to the randomly generated number.","Note: Due to the output being based off of a random factor, the tests provided below cannot determine if you have solved the prompt exactly. The test cases for this challenge check for the correct data types only."]}]}},"challenge-control-flow-iteration":{"subunitId":"challenge-control-flow-iteration","heading":"Challenge: Control Flow and Iteration","solve":{"code":"const timesTenIfOverFive = [23, 9, 11, 2, 10, 6];\n// ADD CODE HERE\n\n\n// Uncomment the line below to check your work!\n// console.log(timesTenIfOverFive); // -> should print [230, 90, 110, 2, 100, 60]","test":"describe('timesTenIfOverFive', () => {\n  it('should be of type array', () => {\n    expect(Array.isArray(timesTenIfOverFive)).to.eq(true);\n  });\n});\n\ndescribe('timesTenIfOverFive', () => {\n  it('should timesTenIfOverFive to equal', () => {\n    expect(timesTenIfOverFive).to.eql([230, 90, 110, 2, 100, 60]);\n  });\n});\n","instructions":[{"instructionHeading":" ","instructionContent":["Iterate through the array and multiply a number by 10 if it is greater than or equal to 5."]}]}},"challenge-count-by":{"subunitId":"challenge-count-by","heading":"Challenge: countBy","solve":{"code":"// ADD CODE HERE\n\n// Uncomment these to check your work!\n// function evenOdd(n) {\n//   if (n % 2 === 0) return 'even';\n//   else return 'odd';\n// }\n// const nums = [1, 2, 3, 4, 5];\n// console.log(countBy(nums, evenOdd)); // should log: { odd: 3, even: 2 }","test":"describe('countBy', () => {\n  const evenOdd = (n) => (n % 2 === 0 ? 'even' : 'odd');\n  it('should be a function', () => {\n    expect(countBy).to.be.a('function');\n  });\n  it('should return an object', () => {\n    expect(countBy([], () => {})).to.eql({});\n  });\n  it('should apply callback results as keys in the returned object', () => {\n    const answer = countBy([1, 2, 3, 4, 5], evenOdd);\n    expect(answer).to.have.own.property('even');\n    expect(answer).to.have.own.property('odd');\n  });\n  it('should count how many times the callback returns identical values', () => {\n    const answer = countBy([1, 2, 3, 4, 5], evenOdd);\n    expect(answer).to.eql({ odd: 3, even: 2 });\n  });\n});\n","instructions":[{"instructionContent":["Create a function <code>countBy</code> that accepts an array and a callback, and returns an object. <code>countBy</code> will iterate through the array and perform the callback on each element. Each return value from the callback will be saved as a key on the object. The value associated with each key will be the number of times that particular return value was returned."]}]}},"challenge-create-function":{"subunitId":"challenge-create-function","heading":"Challenge: createFunction","solve":{"code":"// ADD CODE HERE\n\n// Uncomment these to check your work!\n// const myFunction = createFunction();\n// console.log(myFunction()); //should log: 'hello world'","test":"describe('myFunction', () => {\n  it('should create and return a function', () => {\n    const myFunction = createFunction();\n    expect(myFunction).to.be.a('function');\n  });\n\n  it(\"should return 'hello world'\", () => {\n    expect(myFunction()).to.equal('hello world');\n  });\n});\n","instructions":[{"instructionContent":["Create a function <code>createFunction</code> that creates and returns a function. When that newly created function is called, it should return the string 'hello world'.",{"codeBlock":"const myFunction = createFunction();\n // Let's call the function we created and log its return value\nconsole.log(myFunction()); //should log: 'hello world'"},"When you think you completed <code>createFunction</code>, un-comment out those lines in the code and run it to see if it works."]}]}},"challenge-cycle-iterator":{"subunitId":"challenge-cycle-iterator","heading":"Challenge: cycleIterator","solve":{"code":"// ADD CODE HERE\n\n// Uncomment these to check your work!\n// const threeDayWeekend = ['Fri', 'Sat', 'Sun'];\n// const getDay = cycleIterator(threeDayWeekend);\n// console.log(getDay()); // should log: 'Fri'\n// console.log(getDay()); // should log: 'Sat'\n// console.log(getDay()); // should log: 'Sun'\n// console.log(getDay()); // should log: 'Fri'","test":"describe('cycleIterator', () => {\n  it('should create and return a function', () => {\n    const cycleFunc = cycleIterator([0, 1, 2]);\n    expect(cycleFunc).to.be.a('function');\n  });\n});\n\ndescribe('The function returned from cycleIterator', () => {\n  const cycleFruit = cycleIterator(['jackfruit', 'mango', 'pineapple']);\n\n  it('should return the first element of the array the first time it is called', () => {\n    expect(cycleFruit()).to.equal('jackfruit');\n  });\n\n  it('should return the second element of the array the second time it is called', () => {\n    expect(cycleFruit()).to.equal('mango');\n  });\n\n  it('should return the third element of the array the third time it is called', () => {\n    expect(cycleFruit()).to.equal('pineapple');\n  });\n\n  it('should cycle back to the first element after returning the last element of the array', () => {\n    expect(cycleFruit()).to.equal('jackfruit');\n  });\n});\n","instructions":[{"instructionContent":["Create a function <code>cycleIterator</code> that accepts an array, and returns a function. The returned function will accept zero arguments. When first invoked, the returned function will return the first element of the array. When invoked a second time, the returned function will return the second element of the array, and so forth. After returning the last element of the array, the next invocation will return the first element of the array again, and continue on with the second after that, and so forth."]}]}},"challenge-data-types-basics":{"subunitId":"challenge-data-types-basics","heading":"Challenge: Primitive Data Types","solve":{"code":"// ADD CODE HERE\n\n\n\n// Uncomment these to check your work!\n// console.log('My name is ' + name);\n// console.log('I am ' + age + ' years old');\n// console.log('It\\'s ' + loveJavaScript + ', I love JavaScript');\n// console.log('The list of things I hate about JavaScript is ' + listOfComplaints);\n","test":"describe('name', () => {\n  function changeConst() {\n    return (name = 'Arya Stark');\n  }\n\n  it('should not be undefined or null', () => {\n    expect(name).to.not.equal(undefined);\n    expect(name).to.not.equal(null);\n  });\n  it('should be a constant', () => {\n    expect(changeConst).to.throw();\n  });\n  it('should be a string', () => {\n    expect(name).to.be.a('string');\n  });\n});\n\ndescribe('age', () => {\n  it('should not be undefined or null', () => {\n    expect(age).to.not.equal(undefined);\n    expect(age).to.not.equal(null);\n  });\n  it('should be a number', () => {\n    expect(age).to.be.a('number');\n  });\n});\n\ndescribe('loveJavaScript', () => {\n  function changeConst() {\n    return (loveJavaScript = false);\n  }\n\n  it('should not be undefined or null', () => {\n    expect(loveJavaScript).to.not.equal(undefined);\n    expect(loveJavaScript).to.not.equal(null);\n  });\n  it('should be a constant', () => {\n    expect(changeConst).to.throw();\n  });\n  it('should be a boolean', () => {\n    expect(loveJavaScript).to.be.a('boolean');\n  });\n  it('should be true', () => {\n    expect(loveJavaScript).to.be.true;\n  });\n});\n\ndescribe('listOfComplaints', () => {\n  it('should not be undefined', () => {\n    expect(listOfComplaints).to.not.equal(undefined);\n  });\n  it('should be null', () => {\n    expect(listOfComplaints).to.be.null;\n  });\n});\n","instructions":[{"instructionContent":["Now that you have been introduced to some of JavaScript's data types, take a stab at  declaring some variables below with different data types.  Make sure to read the challenge  carefully so you know if you should be using <code>let</code> or <code>const</code>!","<strong>Challenge 1:</strong> Declare a constant <code>name</code> that is a <code>string</code>, and set it equal to your name.","<strong>Challenge 2:</strong> Declare a variable <code>age</code> that is a <code>number</code>, and set it equal to your age.","<strong>Challenge 3:</strong> Declare a constant <code>loveJavaScript</code> that is a <code>boolean</code>, and set it equal to <code>true</code>.","<strong>Challenge 4:</strong> Declare a variable <code>listOfComplaints</code> and set it's value to <code>null</code>"]}]}},"challenge-date-stamp":{"subunitId":"challenge-date-stamp","heading":"Challenge: dateStamp","solve":{"code":"// ADD CODE HERE\n\n// Uncomment these to check your work!\n// const stampedMultBy2 = dateStamp(n => n * 2);\n// console.log(stampedMultBy2(4)); // should log: { date: (today's date), output: 8 }\n// console.log(stampedMultBy2(6)); // should log: { date: (today's date), output: 12 }","test":"describe('dateStamp', () => {\n  it('should create and return a function', () => {\n    const dateFunc = dateStamp((n) => n);\n    expect(dateFunc).to.be.a('function');\n  });\n});\n\ndescribe('The function returned from dateStamp', () => {\n  it('should return an object', () => {\n    const stampedAddTwo = dateStamp((n) => n + 2);\n    const stampedFour = stampedAddTwo(2);\n    const stampedMax = dateStamp((...args) => Math.max(...args));\n    const stampedSix = stampedMax(-5, -7, 0, 3, 6);\n    expect(stampedFour).to.be.an('object');\n    expect(stampedSix).to.be.an('object');\n  });\n});\n\ndescribe('The returned object', () => {\n  it('should have a date key and an output key', () => {\n    const stampedAddTwo = dateStamp((n) => n + 2);\n    const stampedFour = stampedAddTwo(2);\n    const stampedMax = dateStamp((...args) => Math.max(...args));\n    const stampedSix = stampedMax(-5, -7, 0, 3, 6);\n    expect(stampedFour).to.have.all.keys('date', 'output');\n    expect(stampedSix).to.have.all.keys('date', 'output');\n  });\n});\n\ndescribe('The date key on the returned object', () => {\n  it(\"should have today's date as its value\", () => {\n    const stampedAddTwo = dateStamp((n) => n + 2);\n    const stampedFour = stampedAddTwo(2);\n    const stampedMax = dateStamp((...args) => Math.max(...args));\n    const stampedSix = stampedMax(-5, -7, 0, 3, 6);\n    expect(stampedFour.date).to.equal(new Date().toDateString());\n    expect(stampedSix.date).to.equal(new Date().toDateString());\n  });\n});\n\ndescribe('The output key on the returned object', () => {\n  it('should contain the result from invoking the passed-in function', () => {\n    const stampedAddTwo = dateStamp((n) => n + 2);\n    const stampedFour = stampedAddTwo(2);\n    const stampedMax = dateStamp((...args) => Math.max(...args));\n    const stampedSix = stampedMax(-5, -7, 0, 3, 6);\n    expect(stampedFour.output).to.equal(4);\n    expect(stampedSix.output).to.equal(6);\n  });\n});\n","instructions":[{"instructionContent":["Create a function <code>dateStamp</code> that accepts a function and returns a function. The returned function will accept whatever arguments the passed-in function accepts and return an object with a <code>date</code> key whose value is today's date (not including the time) represented as a human-readable string (see <a target=\"_blank\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date\">the Date object</a> for conversion methods), and an <code>output</code> key that contains the result from invoking the passed-in function."]}]}},"challenge-define-first-arg":{"subunitId":"challenge-define-first-arg","heading":"Challenge: defineFirstArg","solve":{"code":"// ADD CODE HERE\n\n// Uncomment these to check your work!\n// const subtract = function(big, small) { return big - small; };\n// const subFrom20 = defineFirstArg(subtract, 20);\n// console.log(subFrom20(5)); // should log: 15","test":"describe('defineFirstArg', () => {\n  it('should create and return a function', () => {\n    const addTwoNums = (first, second) => first + second;\n    const add15 = defineFirstArg(addTwoNums, 15);\n    expect(add15).to.be.a('function');\n  });\n});\n\ndescribe('The function returned from defineFirstArg', () => {\n  const repeatString = (string) => `${string} ${string}`;\n  const repeatRabbit = defineFirstArg(repeatString, 'rabbit');\n  const repeatHa = defineFirstArg(repeatString, 'ha ha');\n  const multiplyThreeNums = (x, y, z) => x * y * z;\n  const multiplyTwoNumsAnd5 = defineFirstArg(multiplyThreeNums, 5);\n\n  it('should invoke the passed-in function with the passed-in argument as its first argument', () => {\n    expect(repeatRabbit()).to.equal('rabbit rabbit');\n    expect(repeatHa()).to.equal('ha ha ha ha');\n  });\n\n  it('should accept additional arguments and invoke the passed-in function with them', () => {\n    expect(multiplyTwoNumsAnd5(2, 3)).to.equal(30);\n    expect(multiplyTwoNumsAnd5(-1, 2)).to.equal(-10);\n  });\n});\n","instructions":[{"instructionContent":["Create a function <code>defineFirstArg</code> that accepts a function and an argument. Also, the function being passed in will accept at least one argument. <code>defineFirstArg</code> will return a new function that invokes the passed-in function with the passed-in argument as the passed-in function's first argument. Additional arguments needed by the passed-in function will need to be passed into the returned function."]}]}},"challenge-delay":{"subunitId":"challenge-delay","heading":"Challenge: delay","solve":{"code":"// ADD CODE HERE\n\n// UNCOMMENT THE CODE BELOW TO TEST DELAY\n// let count = 0;\n// const delayedFunc = delay(() => count++, 1000);\n// delayedFunc();\n// console.log(count); \t\t\t\t\t\t\t\t\t\t\t\t // should print '0'\n// setTimeout(() => console.log(count), 1000); // should print '1' after 1 second","test":"describe('delay', () => {\n  it('should create and return a function', () => {\n    const delayedFunc = delay(() => count++, 50);\n    expect(delayedFunc).to.be.a('function');\n  });\n});\n\ndescribe('The function returned from delay', () => {\n  it('should only execute the callback after the specified wait time', (done) => {\n    let count = 0;\n    const delayedFunc = delay(() => count++, 50);\n    delayedFunc();\n    setTimeout(() => expect(count).to.eql(0), 49);\n    setTimeout(() => {\n      expect(count).to.eql(1);\n      done();\n    }, 51);\n  });\n});\n","instructions":[{"instructionContent":["Write a function <code>delay</code> that accepts two arguments, a callback and the wait time in milliseconds. Delay should return a function that, when invoked waits for the specified amount of time before executing. HINT -  research setTimeout();"]}]}},"challenge-developer-class":{"subunitId":"challenge-developer-class","heading":"Challenge: DeveloperClass","solve":{"code":"class PersonClass {\n\tconstructor(name) {\n    this.name = name;\n\t}\n\n\tgreet() {\n    console.log('hello');\n  }\n}\n\n// add code here\n\nconst thai = new DeveloperClass('Thai', 32);\n\n// Uncomment these lines to check your work!\n// console.log(thai.name); // -> Logs 'Thai'\n// thai.introduce(); // -> Logs 'Hello World, my name is Thai'","test":"describe('PersonClass', () => {\n  it('- DeveloperClass should extend PersonClass', () => {\n    expect(DeveloperClass.prototype instanceof PersonClass).to.equal(true);\n  });\n  it('- DeveloperClass creates objects with an introduce method', () => {\n    const thai = new DeveloperClass('Thai', 32);\n    expect(thai.introduce).to.be.a('function');\n    let log;\n    (function () {\n      const oldConsoleLog = console.log;\n      console.log = function (input) {\n        log = input;\n      };\n      thai.introduce();\n      console.log = oldConsoleLog;\n    })();\n    expect(log).to.equal('Hello World, my name is Thai');\n  });\n});\n","instructions":[{"instructionContent":["Create a class <code>DeveloperClass</code> that creates objects by extending the <code>PersonClass</code> class. In addition to having a <code>name</code> property and <code>greet</code> method, <code>DeveloperClass</code> should have an <code>introduce</code> method. When called, <code>introduce</code> should log the string \"Hello World, my name is [name]\"."]}]}},"challenge-disemvowel":{"subunitId":"challenge-disemvowel","heading":"Challenge: disemvowel","solve":{"code":"function disemvowel(string) {\n  // ADD CODE HERE\n}\n\n// Uncomment these to check your work!\n// console.log(disemvowel('CodeSmith')); // => 'CdSmth'\n// console.log(disemvowel('BANANA')); // => 'BNN'\n// console.log(disemvowel('hello world')); // => 'hll wrld'","test":"describe('disemvowel', () => {\n  it('should be a function', () => {\n    expect(disemvowel).to.be.a('function');\n  });\n});\n\ndescribe('disemvowel(\"CodeSmith\")', () => {\n  it('should return \"CdSmth\"', () => {\n    expect(disemvowel('CodeSmith')).to.eq('CdSmth');\n  });\n});\n\ndescribe('disemvowel(\"BANANA\")', () => {\n  it('should return \"BNN\"', () => {\n    expect(disemvowel('BANANA')).to.eq('BNN');\n  });\n});\n\ndescribe('disemvowel(\"hello world\")', () => {\n  it('should return \"hll wrld\"', () => {\n    expect(disemvowel('hello world')).to.eq('hll wrld');\n  });\n});\n","instructions":[{"instructionContent":["Write a function <code>disemvowel</code> that takes in a string and returns a new string with all vowels removed."]}]}},"challenge-dog-constructor":{"subunitId":"challenge-dog-constructor","heading":"Challenge: Dog Constructor","solve":{"code":"function Dog(name, breed) {\n\t// add code here\n\n}\n\nconst fido = new Dog('Fido', 'poodle');\n\n// Uncomment these lines to check your work!\n// fido.learnTrick('fetch');\n// fido.performTrick('fetch'); // should log 'Fido performed fetch!'\n// fido.performTrick('sit'); // should log 'Fido doesn't know that trick.'","test":"describe('Dog', () => {\n  it('- created object has Dog as constructor', () => {\n    const fido = new Dog('Fido', 'beagle');\n    expect(fido.constructor).to.equal(Dog);\n  });\n  it('- created object has a name and breed property', () => {\n    const fido = new Dog('Fido', 'beagle');\n    expect(fido.name).to.equal('Fido');\n    expect(fido.breed).to.equal('beagle');\n  });\n  it('- has a tricks property initially set to an empty array', () => {\n    const fido = new Dog('Fido', 'beagle');\n    expect(fido.tricks).to.be.an('array');\n    expect(fido.tricks.length).to.equal(0);\n  });\n  it('- created object has a learnTrick and performTrick method', () => {\n    const fido = new Dog('Fido', 'beagle');\n    expect(fido.learnTrick).to.be.a('function');\n    expect(fido.performTrick).to.be.a('function');\n    fido.learnTrick('fetch');\n    expect(fido.tricks[0]).to.equal('fetch');\n    let log;\n    function testLogs(string) {\n      const oldConsoleLog = console.log;\n      console.log = function (input) {\n        log = input;\n      };\n      fido.performTrick(string);\n      console.log = oldConsoleLog;\n    }\n    testLogs('fetch');\n    expect(log).to.equal('Fido performed fetch!');\n    testLogs('sit');\n    expect(log).to.equal(\"Fido doesn't know that trick.\");\n  });\n  it('- both methods should be stored on the Dog prototype rather than the object itself', () => {\n    const fido = new Dog('Fido', 'beagle');\n    expect(Object.hasOwn(fido, 'learnTrick')).to.equal(false);\n    expect(Object.hasOwn(fido, 'performtrick')).to.equal(false);\n  });\n});\n","instructions":[{"instructionContent":["Declare a function <code>Dog</code> that creates a new instance of a <code>Dog</code> object when invoked with the <code>new</code> keyword. Each <code>Dog</code> object should have a <code>name</code> property and a <code>breed</code> property, both strings which are passed in as arguments when calling the <code>Dog</code> function. It should also have a property called <code>tricks</code>, set to an array representing all the tricks that dog knows. When a new object is initiated, <code>tricks</code> should be empty.","All of your <code>Dog</code> objects must also have access to two methods that are stored on the constructor's <code>prototype</code>:","The first method, <code>learnTrick</code>, should take in a string as an argument and add that string to the <code>tricks</code> array of the particular <code>Dog</code> object it was called on.","The second method, <code>performTrick</code>, should also take a string as an argument. It should check to see if that string is in the <code>tricks</code> array belonging to the <code>Dog</code> instance it was called on; if so, it should log the string '<code>name</code> performed </code>trick</code>!' If not, log the string '<code>name</code> doesn't know that trick."]}]}},"challenge-droids":{"subunitId":"challenge-droids","heading":"Challenge: droids","solve":{"code":"function droids(arr) {\n  let result = '';\n  // ADD CODE HERE\n  return result;\n}\n\n// Uncomment these to check your work! \n// const starWars = [\"Luke\", \"Finn\", \"Rey\", \"Kylo\", \"Droids\"] \n// const thrones = [\"Jon\", \"Danny\", \"Tyrion\", \"The Mountain\", \"Cersei\"] \n// console.log(droids(starWars)) // should log: \"Found Droids!\"\n// console.log(droids(thrones)) // should log: \"These are not the droids you're looking for.\"","test":"describe('droids', () => {\n  it('should be a function', () => {\n    expect(droids).to.be.a('function');\n  });\n});\n\ndescribe('droids([\"Luke\", \"Finn\", \"Rey\", \"Kylo\", \"Droids\"])', () => {\n  it(\"should return 'Found Droids!'\", () => {\n    expect(droids(['Luke', 'Finn', 'Rey', 'Kylo', 'Droids'])).to.eq('Found Droids!');\n  });\n});\n\ndescribe('droids([\"Jon\", \"Danny\", \"Tyrion\", \"The Mountain\", \"Cersei\"])', () => {\n  it(\"should return 'These are not the droids you're looking for.'\", () => {\n    expect(droids(['Jon', 'Danny', 'Tyrion', 'The Mountain', 'Cersei'])).to.eq(\n      \"These are not the droids you're looking for.\"\n    );\n  });\n});\n","instructions":[{"instructionContent":["Complete the function <code>droids</code> that accepts an array of strings and iterates through the array using a FOR loop. Update the variable result to <code>\"Found Droids!\"</code> if the array contains the string <code>\"Droids\"</code>. Otherwise update the variable result to <code>\"These are not the droids you're looking for.\"</code> Return your updated result."]}]}},"challenge-either-callback":{"subunitId":"challenge-either-callback","heading":"Challenge: eitherCallback","solve":{"code":"function eitherCallback(callback1, callback2) {\n  // ADD CODE HERE\n}\n\n// Uncomment these to check your work!\n// function filterArray(array, callback) {\n//   const newArray = [];\n//   for (let i = 0; i < array.length; i += 1) {\n//     if (callback(array[i], i, array)) newArray.push(array[i]);\n//   }\n//   return newArray;\n// }\n// const arrOfNums = [10, 35, 105, 9];\n// const integerSquareRoot = n => Math.sqrt(n) % 1 === 0;\n// const over100 = n => n > 100;\n// const intSqRtOrOver100 = eitherCallback(integerSquareRoot, over100);\n// console.log(filterArray(arrOfNums, intSqRtOrOver100)); // should log: [105, 9]","test":"describe('eitherCallback', () => {\n  it('should be a function', () => {\n    expect(eitherCallback).to.be.a('function');\n  });\n});\n\ndescribe('eitherCallback', () => {\n  it('should return a function', () => {\n    expect(eitherCallback(integerSquareRoot, over100)).to.be.a('function');\n  });\n});\n\ndescribe('filterArray(arrOfNums, intSqRtOrOver100)', () => {\n  it('should return [105, 9]', () => {\n    expect(filterArray(arrOfNums, intSqRtOrOver100)).to.deep.equal([105, 9]);\n  });\n});\n","instructions":[{"instructionContent":["Add code to the function <code>eitherCallback</code> in the place marked <code>\"ADD CODE HERE\"</code> in order to achieve the desired console logs. Notice that the lines of code testing your work are using functions and an array from previous challenges. The result of using <code>eitherCallback</code> to combine two callbacks into one callback and then passing that one callback into <code>filterArray</code> should match the results of simply passing the two callbacks into <code>eitherFilter</code> in the previous challenge."]}]}},"challenge-either-filter":{"subunitId":"challenge-either-filter","heading":"Challenge: eitherFilter","solve":{"code":"function eitherFilter(array, callback1, callback2) {\n  // ADD CODE HERE\n}\n\n// Uncomment these to check your work!\n// const arrOfNums = [10, 35, 105, 9];\n// const integerSquareRoot = n => Math.sqrt(n) % 1 === 0;\n// const over100 = n => n > 100;\n// console.log(eitherFilter(arrOfNums, integerSquareRoot, over100)); // should log: [105, 9]","test":"describe('eitherFilter', () => {\n  it('should be a function', () => {\n    expect(eitherFilter).to.be.a('function');\n  });\n});\n\ndescribe('eitherFilter(arrOfNums, integerSquareRoot, over100)', () => {\n  it('should return [105, 9]', () => {\n    expect(eitherFilter(arrOfNums, integerSquareRoot, over100)).to.deep.equal([105, 9]);\n  });\n});\n","instructions":[{"instructionContent":["Add code to the function <code>eitherFilter</code> in the place marked <code>\"ADD CODE HERE\"</code> in order to achieve the desired console logs. The array returned from <code>eitherFilter</code> should contain all elements in the passed-in array that yield a truthy return value when passed into EITHER of the two callbacks passed into <code>eitherFilter</code>."]}]}},"challenge-factorial":{"subunitId":"challenge-factorial","heading":"Challenge: Factorial","solve":{"code":"function factorial(num) {\r\n\r\n}\r\n\r\n// To check if you've completed the challenge, uncomment these console.logs!\r\n// console.log(factorial(4)); // -> 24\r\n// console.log(factorial(6)); // -> 720\r\n","test":"describe('factorial', () => {\n  it('should be a function', () => {\n    expect(factorial).to.be.a('function');\n  });\n});\n\ndescribe('factorial(4)', () => {\n  it('should return 24', () => {\n    expect(factorial(4)).to.eq(24);\n  });\n});\n\ndescribe('factorial(6)', () => {\n  it('should return 720', () => {\n    expect(factorial(6)).to.eq(720);\n  });\n});\n","instructions":[{"instructionContent":["Write a function that returns the factorial of a number.","EXAMPLE4! = 4 * 3 * 2 * 1 = 24, so calling factorial(4) should return 24.",{"codeBlock":"Input: {Number} num - number whose factorial is sought\nOutput: {Number}"}]}]}},"challenge-filter-array":{"subunitId":"challenge-filter-array","heading":"Challenge: filterArray","solve":{"code":"function filterArray(array, callback) {\n  const newArray = [];\n  for (let i = 0; i < array.length; i += 1) {\n    if (callback(array[i])) newArray.push(array[i]);\n  }\n  return newArray;\n}\nconst arrOfNums = [1, 2, 3, 4, 5];\nfunction func1(num) {\n  // ADD CODE HERE\n}\nfunction func2(num) {\n  // ADD CODE HERE\n}\n\n// Uncomment these to check your work!\n// console.log(filterArray(arrOfNums, func1)); // should log: [2, 4]\n// console.log(filterArray(arrOfNums, func2)); // should log: [1, 3, 5]","test":"describe('filterArray', () => {\n  it('should be a function', () => {\n    expect(filterArray).to.be.a('function');\n  });\n});\n\ndescribe('filterArray(arrOfNums, func1)', () => {\n  it('should return [2, 4]', () => {\n    expect(filterArray(arrOfNums, func1)).to.deep.equal([2, 4]);\n  });\n});\n\ndescribe('filterArray(arrOfNums, func2)', () => {\n  it('should return [1, 3, 5]', () => {\n    expect(filterArray(arrOfNums, func2)).to.deep.equal([1, 3, 5]);\n  });\n});\n","instructions":[{"instructionContent":["Add code to the functions <code>func1</code> and <code>func2</code> in the places marked <code>\"ADD CODE HERE\"</code> in order to achieve the desired console logs."]}]}},"challenge-find-waldo":{"subunitId":"challenge-find-waldo","heading":"Challenge: findWaldo","solve":{"code":"// ADD CODE HERE\n\n// Uncomment these to check your work!\n// const DC = {'Bruce': 'Wayne', 'Harley': 'Quinn'}\n// const supernatural = {'Sam': 'Winchester', 'Dean': 'Winchester', 'Waldo': 'unknown'}\n// console.log(findWaldo(DC)) // should log: 'Where's Waldo?'\n// console.log(findWaldo(supernatural)) // should log: 'unknown'","test":"describe('findWaldo', () => {\n  it('should be a function', () => {\n    expect(findWaldo).to.be.a('function');\n  });\n});\n\ndescribe(\"findWaldo({'Bruce': 'Wayne', 'Harley': 'Quinn'})\", () => {\n  it(\"should return 'Where's Waldo?'\", () => {\n    expect(findWaldo({ Bruce: 'Wayne', Harley: 'Quinn' })).to.eq(\"Where's Waldo?\");\n  });\n});\n\ndescribe(\"findWaldo({'Sam': 'Winchester', 'Dean': 'Winchester', 'Waldo': 'unknown'})\", () => {\n  it(\"should return 'unknown'\", () => {\n    expect(findWaldo({ Sam: 'Winchester', Dean: 'Winchester', Waldo: 'unknown' })).to.eq('unknown');\n  });\n});\n","instructions":[{"instructionContent":["Create a function <code>findWaldo</code> that accepts an object and returns the value associated with the key <code>'Waldo'</code>. If the key <code>'Waldo'</code> is not found, the function should return <code>'Where's Waldo?'</code>"]}]}},"challenge-fizzbuzz":{"subunitId":"challenge-fizzbuzz","heading":"Challenge: fizzbuzz","solve":{"code":"const fb = [];\n// ADD CODE HERE\n\n\n\n// should log: [1, 2, 'fizz', 4, 'buzz', 'fizz', 7, 8, 'fizz', 'buzz', 11, 'fizz', 13, 14, 'fizzbuzz', 16]","test":"describe('fb', () => {\n  it('should be an array', () => {\n    expect(Array.isArray(fb)).to.eq(true);\n  });\n\n  it('should have a length of 16', () => {\n    expect(fb.length).to.eq(16);\n  });\n  it(\"should equal [1, 2, 'fizz', 4, 'buzz', 'fizz', 7, 8, 'fizz', 'buzz', 11, 'fizz', 13, 14, 'fizzbuzz', 16]\", () => {\n    expect(fb).eql([1, 2, 'fizz', 4, 'buzz', 'fizz', 7, 8, 'fizz', 'buzz', 11, 'fizz', 13, 14, 'fizzbuzz', 16], fb);\n  });\n});\n","instructions":[{"instructionHeading":" ","instructionContent":["Use a loop to iterate through the numbers 1 through 16. Push each number into <code>fb</code>, but push the string \"fizz\" in place of numbers divisible by 3, \"buzz\" in place of numbers divisible by 5, and \"fizzbuzz\" in place of numbers divisible by both 3 and 5.","Log <code>fb</code> to the console to see the output.","<strong>Hint</strong>: Check out the remainder/modulo operator: <code>%</code>."]}]}},"challenge-flow":{"subunitId":"challenge-flow","heading":"Challenge: flow","solve":{"code":"function flow(input, funcArray) {\r\n\r\n}\r\n\r\n// To check if you've completed the challenge, uncomment this code!\r\n// function multiplyBy2(num) { return num * 2; }\r\n// function add7(num) { return num + 7; }\r\n// function modulo4(num) { return num % 4; }\r\n// function subtract10(num) { return num - 10; }\r\n// const arrayOfFunctions = [multiplyBy2, add7, modulo4, subtract10];\r\n// console.log(flow(2, arrayOfFunctions)); // -> -7","test":"describe('flow', () => {\n  it('should be a function', () => {\n    expect(flow).to.be.a('function');\n  });\n});\n\ndescribe('flow(2, arrayOfFunctions)', () => {\n  const multiplyBy2 = (num) => num * 2;\n  const add7 = (num) => num + 7;\n  const modulo4 = (num) => num % 4;\n  const subtract10 = (num) => num - 10;\n  const arrayOfFunctions = [multiplyBy2, add7, modulo4, subtract10];\n  it('should return -7', () => {\n    expect(flow(2, arrayOfFunctions)).to.eq(-7);\n  });\n});\n","instructions":[{"instructionContent":["Write a function that takes an array of functions and a number that will be piped through all those functions. The input number passes through the first function, whose output is passed as input to the second function, whose output is passed as input to the third function, and so on. Use recursion to return the final output of the last function in the array.",{"codeBlock":"Input 1: {Number} input - number flowing through all functions\nInput 2: {Array} funcArray - array of functions to pass input through\nOutput: {Number} - final output of final function"}]}]}},"challenge-for-each":{"subunitId":"challenge-for-each","heading":"Challenge: forEach","solve":{"code":"// ADD CODE HERE\n\n// Uncomment these to check your work!\n// console.log(typeof forEach); // should log: 'function'\n// forEach(['a','b','c'], i => console.log(i)); // should log: 'a', 'b', 'c'\n// console.log(typeof map); // should log: 'function'\n// console.log(map([3,4,5], n => n - 2)); // should log: [1, 2, 3]","test":"describe('forEach', () => {\n  it('should be a function', () => {\n    expect(forEach).to.be.a('function');\n  });\n  it('should execute a callback function on each item', () => {\n    const testOutput = [];\n    forEach([1, 2, 3], (item) => testOutput.push(item * 2));\n    expect(testOutput).to.eql([2, 4, 6]);\n  });\n});\n\ndescribe('map', () => {\n  it('should be a function', () => {\n    expect(map).to.be.a('function');\n  });\n  it('should not contain a for loop', () => {\n    const loop = /for\\s\\(/.test(String(map)) || /for\\(/.test(String(map)) ? 'for ()' : null;\n    expect(loop).to.not.exist;\n  });\n  it('should return an array', () => {\n    expect(map([], () => null)).to.be.an('array');\n  });\n  it('should execute a callback function on each element', () => {\n    expect(map([3, 4, 5], (n) => n - 2)).to.eql([1, 2, 3]);\n  });\n});\n","instructions":[{"instructionHeading":"Part 1","instructionContent":["Create a function <code>forEach</code> which takes an array and a callback, and runs the callback on each element of the array. <code>forEach</code> does not return anything. Please do not use the native <code>forEach</code> or map method.",{"codeBlock":"let alphabet = '';\nconst letters = ['a', 'b', 'c', 'd'];\nforEach(letters, function(char) {\n  alphabet += char;\n});\nconsole.log(alphabet); //prints 'abcd'"}]},{"instructionHeading":"Part 2","instructionContent":["Now let's rebuild <code>map</code> from the previous challenge. This time instead of using a <code>for</code> loop, you're going to use the <code>forEach</code> we just created."]}]}},"challenge-for-each-async":{"subunitId":"challenge-for-each-async","heading":"Challenge: forEach","solve":{"code":"// Add code here","test":"const { oldConsoleLog, logged } = reDefineConsoleLog((arg) => {\n  logged.push(arg);\n});\n\ndescribe('forEach', () => {\n  it('should be a function', () => {\n    expect(forEach).to.be.a('function');\n  });\n});\n\ndescribe('delayLog', () => {\n  it('should be a function', () => {\n    expect(delayLog).to.be.a('function');\n  });\n});\n\ndescribe('', () => {\n  it('should log in correct order', (done) => {\n    delay(600, logged)\n      .then((resolved) => {\n        expect(resolved.toString()).to.eq(\n          'printing element 2,printing element 0,printing element 3,printing element 1'\n        );\n        console.log = oldConsoleLog;\n      })\n      .then(done, done);\n  });\n});\n\n//resolve promise after ms milleseconds\nfunction delay(ms, logged) {\n  return new Promise((resolve) => {\n    setTimeout(() => resolve(logged), ms);\n  });\n}\n\n// logged will contain all arguments passed into console.log\nfunction reDefineConsoleLog(newConsoleLog, logged = []) {\n  const oldConsoleLog = console.log;\n  console.log = newConsoleLog;\n  return { oldConsoleLog, logged };\n}\n","instructions":[{"instructionContent":["Recreate the built in array method, <code>forEach</code> - Write a function that takes as parameters an array, <code>arr</code>, and a callback function, <code>cb</code>. The <code>forEach</code> function will iterate through <code>arr</code> passing each element and its index as arguments to <code>cb</code>.","Create a variable named <code>delays</code> and assign to it an array with the numbers 200, 500, 0, and 350 (in that order).","Write a function, <code>delayLog</code>, that takes as input a <code>delayTime</code> and an index, <code>i</code>. When invoked, the function should wait <code>delayTime</code> milliseconds before logging to the console, \"printing element i\" (with \"i\" replaced with the actual index passed in).","Putting it all together, run the <code>delayLog</code> function on each item of the <code>delays</code> array using the <code>forEach</code> function you created."]}]}},"challenge-for-loops-array-indices":{"subunitId":"challenge-for-loops-array-indices","heading":"Challenge: For Loops and Array Indices","solve":{"code":"const firstNames = [\"Jon\", \"Arya\", \"Jamie\"];\nconst lastNames = [\"Snow\", \"Stark\", \"Lannister\"];\nconst places = [\"The Wall\", \"Winterfell\", \"Kings Landing\"];\n\n\nconst bios = [];\n\n// Loop through your arrays and store the following strings in the bios array:\n// 'My name is Jon Snow and I am from The Wall'\n// 'My name is Arya Stark and I am from Winterfell'\n// 'My name is Jamie Lannister and I am from Kings Landing'\n\n// ADD CODE HERE\n\n","test":"describe('bios', () => {\n  it(\"should contain Jon Snow's bio at index 0\", () => {\n    expect(bios[0]).to.eq('My name is Jon Snow and I am from The Wall');\n  });\n  it(\"hould contain Arya Stark's bio at index 1\", () => {\n    expect(bios[1]).to.eq('My name is Arya Stark and I am from Winterfell');\n  });\n  it(\"should contain Jamie Lannister's bio at index 2\", () => {\n    expect(bios[2]).to.eq('My name is Jamie Lannister and I am from Kings Landing');\n  });\n});\n\ndescribe('bios', () => {\n  it('should be of length 3', () => {\n    expect(bios.length).to.eq(3);\n  });\n});\n","instructions":[{"instructionHeading":" ","instructionContent":["You are given 3 different arrays, one of first names, last names and places. Imagine that each array element at a certain index corresponds to one user.","For example, my friends are Mary Snow, Kris Bowles, and Janelle Wong. I have two arrays, one of first names and one of last names. In order to get the full name of my friend, I need to access both arrays",{"codeBlock":"const firstNames = [\"Mary\", \"Kris\", \"Janelle\"];\nconst lastNames = [\"Snow\", \"Bowles\", \"Wong\"];\n\nconsole.log(firstNames[1]) // returns Kris\nconsole.log(lastNames[1]) // returns Bowles"},"For this challenge, loop through the arrays and push a string with the format \"My name is <em>[firstName]</em> <em>[lastName]</em> and I am from <em>[place]</em>\" into the array holding the respective bios."]}]}},"challenge-for-loops-arrays":{"subunitId":"challenge-for-loops-arrays","heading":"Challenge: For Loops and Arrays","solve":{"code":"const synonyms = ['fantastic', 'wonderful', 'great'];\nconst greetings = [];\n\n// 1.\n// Loop through the synonyms array. Each time, push a string into the greetings array. \n// The string should have the format 'Have a [synonym] day!'\n// ADD CODE HERE\n\n\n// 2. \n// Loop through the greetings array, logging each greeting to the console:\n// 'Have a fantastic day!'\n// 'Have a wonderful day!'\n// 'Have a great day!'\n// ADD CODE HERE\n\n","test":"describe('greetings', () => {\n  it('should include three different strings', () => {\n    expect(greetings).to.include('Have a fantastic day!');\n    expect(greetings).to.include('Have a wonderful day!');\n    expect(greetings).to.include('Have a great day!');\n  });\n});\n\ndescribe('greetings', () => {\n  it('should be of length 3', () => {\n    expect(greetings.length).to.eq(3);\n  });\n});\n","instructions":[{"instructionHeading":" ","instructionContent":["1. Iterate through the <code>synonyms</code> array using a for loop, pushing a greeting string with the format \"Have a <em>[synonym]</em> day!\" into the greetings array.","2. Use a second for loop to iterate through the <code>greetings</code> and console.log() each greetings."]}]}},"challenge-for-loops-calculating-array-elements":{"subunitId":"challenge-for-loops-calculating-array-elements","heading":"Challenge: For Loops - Calculating Array Elements","solve":{"code":"const increaseByTwo = [1, 2, 3, 4, 5];\n// ADD CODE HERE\n\n\n// Uncomment the line below to check your work!\n// console.log(increaseByTwo); // -> should print [3, 4, 5, 6, 7];","test":"describe('increaseByTwo', () => {\n  it('should be an array', () => {\n    expect(Array.isArray(increaseByTwo)).to.equal(true);\n  });\n  it('increaseByTwo should equal [3, 4, 5, 6, 7] ', () => {\n    expect(increaseByTwo).to.deep.equal([3, 4, 5, 6, 7]);\n  });\n});\n","instructions":[{"instructionHeading":" ","instructionContent":["You are given an array of five numbers called <code>increaseByTwo</code>. Use a for loop to iterate through the array and increase each number by two."]}]}},"challenge-for-loops-fundamentals":{"subunitId":"challenge-for-loops-fundamentals","heading":"Challenge: For Loops - Fundamentals","solve":{"code":"let countDown = 10;\n// ADD CODE HERE\n\n\n// Uncomment the below line to check your work\n// console.log(countDown) // -> should print 0;","test":"describe('countDown', () => {\n  it('should equal 0', () => {\n    expect(countDown).to.eq(0);\n  });\n});\n","instructions":[{"instructionHeading":" ","instructionContent":["Often times you'll find yourself needing to repeat the same operation over and over. While it's tempting to simply write out the logic by hand, there is a better way! Let's talk about iteration statements or loops. Loops will allow you to write a block of code once, and repeat the execution of the code for a given number of times. There are a few different kinds of iteration statements in Javascript - but for now we'll cover only the most basic one: a <code>for</code> loop.",{"codeBlock":"for (let i = 0; i < 10; i++) {\n  // code to be repeated goes here\n}"},"There are a few things going on here so let’s break this down. First off, we’re using the <code>for</code> keyword to tell JavaScript that we want to run a loop. Immediately after the <code>for</code> keyword, we’ll enclose a few conditions for the loop inside of a set of parentheses, separated by semicolons. <code>for</code> loops accept three conditions:","1. Initial Expression — this is simply a place for you to initialize any JavaScript expression (an expression is a bit of JavaScript code that evaluates to a single value). Most often, it’s used to declare a variable, in this case <code>i</code>, that will be used as a counter for how many times the loop iterates. You should definitely follow this pattern until you’re comfortable enough to try a more complex expression.","2. Conditional Expression — this should be a JavaScript expression that will evaluate to a <code>true</code> or <code>false</code>. In the example above, since <code>i</code> , which is currently set to 0 is indeed less than 10 , this will evaluate to <code>true</code> and execute the block of code inside of the curly braces <code>{}</code>. This condition is checked every time the loop runs, just before the code is executed. If this condition ever evaluates to <code>false</code>, the loop will stop and JavaScript will move on with executing code below it.","3. Increment Expression — this should be an expression that increments your loop counter as the loop runs. It will be executed after the code inside of the loop block is run. In the example above, <code>i++</code> is shorthand for increasing the value of <code>i</code> by 1.","Finally, once you’ve declared your loop conditions, you can insert the code that you want to be repeated inside of the curly braces <code>{}</code>. Again this code will be executed until your condition (#2 above) evaluates to <code>false</code>."]},{"instructionHeading":"Looping through Arrays","instructionContent":["Now that we know how to write a loop, let's talk about how to loop through an array.","Remember, a value in an array can be accessed using the index of its position in the array: <code>myArray[0]</code>. With this in mind, we can utilize our loop counter, <code>i</code> to access each successive element in an array as the loop runs. Let's take a look at an example:",{"codeBlock":"const myArray = ['string1', 'string2', 'string3'];\n\nfor (let i = 0; i < myArray.length; i++) {\n  console.log( myArray[i] );\n}"},"Let's break this down a bit. We've declared a variable <code>myArray</code> and have assigned it a value of an array containing a few strings.","Next, we've declared a <code>for</code> loop that will run as long as <code>i</code> is less than the length of the array (remember, we're incrementing <code>i</code> by 1 each time the loop runs). Now, since both the array's indexes and <code>i</code> start at 0 and increment by 1, we can effectively use <code>i</code> to lookup the elements in the array in order, where <code>i</code> will correspond to an index in the array.","Now that the idea of using <code>i</code> as an index has been established, inside of our loops code block we can reference the current element of an array like so: <code>myArray[i]</code>."]},{"instructionHeading":"Challenge","instructionContent":["Using a <code>for</code> loop, decrement <code>countDown</code> by one each time the loop runs until it equals 0, making use of looping functionality instead of logging each number separately."]}]}},"challenge-for-loops-summing-array-elements":{"subunitId":"challenge-for-loops-summing-array-elements","heading":"Challenge: For Loops - Summing Array Elements","solve":{"code":"function getTheSum(arr){\n  // ADD CODE HERE\n}\n\n// Uncomment these to check your work!\n//console.log(getTheSum([3, 6, 9])); // expected log 18\n//console.log(getTheSum([10, 11, 12])); // expected log 33","test":"describe('getTheSum', () => {\n  it('should be a function', () => {\n    expect(getTheSum).to.be.a('function');\n  });\n});\n\ndescribe('getTheSum([3, 6, 9])', () => {\n  it('should return 18', () => {\n    expect(getTheSum([3, 6, 9])).to.eq(18);\n  });\n});\n\ndescribe('getTheSum([10, 11, 12])', () => {\n  it('should return 33', () => {\n    expect(getTheSum([10, 11, 12])).to.eq(33);\n  });\n});\n","instructions":[{"instructionContent":["Using a FOR loop, write a function <code>getTheSum</code> which adds each element in <code>arr</code> to find the array total."]}]}},"challenge-for-loops-updating-array-elements":{"subunitId":"challenge-for-loops-updating-array-elements","heading":"Challenge: For Loops - Updating Array Elements","solve":{"code":"function addN(arr, n){\n  // ADD CODE HERE\n} \n\n// Uncomment these to check your work!\n// console.log(addN([1, 2, 3], 3)); // expected log [4, 5, 6]\n// console.log(addN([3, 4, 5], 2)); // expected log [5, 6, 7]","test":"describe('addN', () => {\n  it('should be a function', () => {\n    expect(addN).to.be.a('function');\n  });\n});\n\ndescribe('addN([1, 2, 3], 3)', () => {\n  it('should return [4, 5, 6]', () => {\n    expect(addN([1, 2, 3], 3)).to.deep.equal([4, 5, 6]);\n  });\n});\n\ndescribe('addN([3, 4, 5], 2)', () => {\n  it('should return [5, 6, 7]', () => {\n    expect(addN([3, 4, 5], 2)).to.deep.equal([5, 6, 7]);\n  });\n});\n","instructions":[{"instructionContent":["Using a FOR loop, write a function <code>addN</code> which adds the argument <code>n</code> to each number in the array <code>arr</code> and returns the updated <code>arr</code>."]}]}},"challenge-function-with-input":{"subunitId":"challenge-function-with-input","heading":"Challenge: createFunctionWithInput","solve":{"code":"// ADD CODE HERE\n\n// UNCOMMENT THESE TO TEST YOUR WORK!\n// const sampleFunc = createFunctionWithInput('sample');\n// console.log(sampleFunc()); // should log: 'sample'\n// const helloFunc = createFunctionWithInput('hello');\n// console.log(helloFunc()); // should log: 'hello'","test":"describe('createFunctionWithInput', () => {\n  it('should create and return a function', () => {\n    const hiFunc = createFunctionWithInput('hi');\n    expect(hiFunc).to.be.a('function');\n  });\n});\n\ndescribe('The created function', () => {\n  it('should return the input value passed to createFunctionWithInput when it was created', () => {\n    const sampleFunc = createFunctionWithInput('sample');\n    const helloFunc = createFunctionWithInput('hello');\n    expect(sampleFunc()).to.equal('sample');\n    expect(helloFunc()).to.equal('hello');\n  });\n});\n","instructions":[{"instructionContent":["Create a function <code>createFunctionWithInput</code> that accepts one input and returns a function. When that created function is called, it should return the input that was passed to <code>createFunctionWithInput</code> when it was created.",{"codeBlock":"const sampleFunc = createFunctionWithInput('sample');\nconst helloFunc = createFunctionWithInput('hello');\n\n// Now we'll call the functions we created and log the result\nconsole.log(sampleFunc()); \n// should log 'sample' to the console\nconsole.log(helloFunc());\n// should log 'hello' to the console"}]}]}},"challenge-functions-adding-arguments":{"subunitId":"challenge-functions-adding-arguments","heading":"Challenge: Functions - Adding Arguments","solve":{"code":"const x = 23\n\nfunction isX(num) {\n  const x = 44;\n  return num === x;\n}\n\nfunction isY(num) {\n  return num ===x;\n}\n\nconst one = isX(/* ADD CODE HERE */);\nconst two = isY(/* ADD CODE HERE */);\n\n// Uncomment these to check your work!\n// console.log(one); // should log: true\n// console.log(two); // should log: true","instructions":[{"instructionContent":["Examine the code given to you. Determine what arguments must be passed into <code>isX</code> and <code>isY</code> respectively to obtain an output of true for both, and pass in the arguments accordingly."]}]}},"challenge-functions-display-vs-execution":{"subunitId":"challenge-functions-display-vs-execution","heading":"Challenge: Functions - Display vs. Execution","solve":{"code":"function add20 (num){\n  return num + 20\n}\n\n// CREATE YOUR CONSOLE.LOG BELOW \n","instructions":[{"instructionContent":["Create a console log that displays the contents of the function rather than executing it.  For example, your result should be <code>function add20 (num){ return num + 20 }</code>."]}]}},"challenge-functions-es6":{"subunitId":"challenge-functions-es6","heading":"Challenge: Functions - ES6","solve":{"code":"function myJob (name, profession) {\n  return `Hi, my name is ${name} and I'm a ${profession}.`\n}\n\n// console.log(myJob(\"Jon\", \"Knights Watchman\"));","test":"describe('myJob', () => {\n  it('should be a function', () => {\n    expect(myJob).to.be.a('function');\n  });\n\n  it('should be an arrow function', () => {\n    expect(myJob.toString()).to.include('=>', 'Arrow syntax is missing from function');\n  });\n});\n\ndescribe('myJob(\"Jon\", \"Knights Watchman\")', () => {\n  it(\"should return 'Hi, my name is Jon and I'm a Knights Watchman.'\", () => {\n    expect(myJob('Jon', 'Knights Watchman')).to.eq(\"Hi, my name is Jon and I'm a Knights Watchman.\");\n  });\n});\n","instructions":[{"instructionContent":["For this challenge, convert the function <code>myJob</code> from ES5 syntax to arrow function syntax."]}]}},"challenge-functions-expressions":{"subunitId":"challenge-functions-expressions","heading":"Challenge: Functions - Function Expression","solve":{"code":"// MODIFY THE CODE BELOW \nfunction functionDeclaration() {\n  return \"Hi there!\";\n}\n\n// console.log(myFunc()) //should log: \"Hi there!\"","test":"describe('myFunc', () => {\n  it('should be a function', () => {\n    expect(myFunc).to.be.a('function');\n  });\n});\n\ndescribe('myFunc()', () => {\n  it(\"should return 'Hi there!'\", () => {\n    expect(myFunc()).to.eq('Hi there!');\n  });\n});\n","instructions":[{"instructionContent":["Convert the function named <code>functionDeclaration</code> to an anonymous function expression and assign it to a variable called <code>myFunc</code>."]}]}},"challenge-functions-short-circuiting-a-loop":{"subunitId":"challenge-functions-short-circuiting-a-loop","heading":"Challenge: Short-Circuiting a Loop","solve":{"code":"function holidays(arr) {\n  // Do not use a variable to store your result \n  // ADD CODE HERE\n}\n\n// Uncomment these to check your work!\n// const months = [\"April\", \"May\", \"June\", \"October\"];\n// const animals = [\"Cats\", \"Dogs\", \"Pigs\"];\n// console.log(holidays(months)); // should return: \"Happy Halloween\"\n// console.log(holidays(animals)); // should return: \"Have a great day!\"","test":"describe('holidays', () => {\n  it('should be a function', () => {\n    expect(holidays).to.be.a('function');\n  });\n});\n\ndescribe('holidays([\"April\", \"May\", \"June\", \"October\"])', () => {\n  it(\"should return 'Happy Halloween'\", () => {\n    expect(holidays(['April', 'May', 'June', 'October'])).to.eq('Happy Halloween');\n  });\n});\n\ndescribe('holidays([\"Cats\", \"Dogs\", \"Pigs\"])', () => {\n  it(\"should return 'Have a great day!'\", () => {\n    expect(holidays(['Cats', 'Dogs', 'Pigs'])).to.eq('Have a great day!');\n  });\n});\n","instructions":[{"instructionContent":["Complete the function <code>holidays</code> that accepts an array of strings and iterates through the array. If the array contains the string <code>\"October\"</code>, return <code>\"Happy Halloween\"</code>. Otherwise, return the string <code>\"Have a great day!\"</code>.  Do not use a variable to store the result that you are returning."]}]}},"challenge-functions-using-for-each":{"subunitId":"challenge-functions-using-for-each","heading":"Challenge: Using forEach","solve":{"code":"function droids(arr) {\n  let result = '';\n  // ADD CODE HERE\n  return result;\n}\n\n// Uncomment these to check your work! \n// const starWars = [\"Luke\", \"Finn\", \"Rey\", \"Kylo\", \"Droids\"] \n// const thrones = [\"Jon\", \"Danny\", \"Tyrion\", \"The Mountain\", \"Cersei\"] \n// console.log(droids(starWars)) // should log: \"Found Droids!\"\n// console.log(droids(thrones)) //should log: \"These are not the droids you're looking for.\"","test":"describe('droids', () => {\n  it('should be a function', () => {\n    expect(droids).to.be.a('function');\n  });\n});\n\ndescribe('droids([\"Luke\", \"Finn\", \"Rey\", \"Kylo\", \"Droids\"])', () => {\n  it(\"should return 'Found Droids!'\", () => {\n    expect(droids(['Luke', 'Finn', 'Rey', 'Kylo', 'Droids'])).to.eq('Found Droids!');\n  });\n});\n\ndescribe('droids([\"Jon\", \"Danny\", \"Tyrion\", \"The Mountain\", \"Cersei\"])', () => {\n  it(\"should return 'These are not the droids you're looking for.'\", () => {\n    expect(droids(['Jon', 'Danny', 'Tyrion', 'The Mountain', 'Cersei'])).to.eq(\n      \"These are not the droids you're looking for.\"\n    );\n  });\n});\n","instructions":[{"instructionContent":["Recreate the function <code>droids</code> from the previous challenge, but instead of using a FOR loop, use the built-in <code>forEach</code> method."]}]}},"challenge-get-length":{"subunitId":"challenge-get-length","heading":"Challenge: getLength","solve":{"code":"function getLength(array) {\r\n\r\n}\r\n\r\n// To check if you've completed the challenge, uncomment these console.logs!\r\n// console.log(getLength([1])); // -> 1\r\n// console.log(getLength([1, 2])); // -> 2\r\n// console.log(getLength([1, 2, 3, 4, 5])); // -> 5\r\n// console.log(getLength([])); // -> 0\r\n","test":"describe('getLength', () => {\n  it('should be a function', () => {\n    expect(getLength).to.be.a('function');\n  });\n});\n\ndescribe('getLength([1])', () => {\n  it('should return 1', () => {\n    expect(getLength([1])).to.eq(1);\n  });\n});\n\ndescribe('getLength([1,2])', () => {\n  it('should return 2', () => {\n    expect(getLength([1, 2])).to.eq(2);\n  });\n});\n\ndescribe('getLength([1])', () => {\n  it('should return 1', () => {\n    expect(getLength([1])).to.eq(1);\n  });\n});\n\ndescribe('getLength([])', () => {\n  it('should return 0', () => {\n    expect(getLength([])).to.eq(0);\n  });\n});\n","instructions":[{"instructionContent":["Get the length of an array using recursion without accessing its length property.",{"codeBlock":"Input: {Array} array - array whose length is sought\nOutput: {Number}"}]}]}},"challenge-get-remainder":{"subunitId":"challenge-get-remainder","heading":"Challenge: getRemainder","solve":{"code":"function getRemainder(num1, num2) {\n  // INSERT CODE HERE\n}\n\n// Uncomment the lines below to test your code\n// console.log(getRemainder(17, 5)); // => 2\n// console.log(getRemainder(20, 5)); // => 0\n// console.log(getRemainder(8, 22)); // => 6\n// console.log(getRemainder(7, 42)); // => 0","test":"describe('getRemainder', () => {\n  it('should be a function', () => {\n    expect(getRemainder).to.be.a('function');\n  });\n});\n\ndescribe('getRemainder(17, 5)', () => {\n  it('should return 2', () => {\n    expect(getRemainder(17, 5)).to.eq(2);\n  });\n});\n\ndescribe('getRemainder(20, 5)', () => {\n  it('should return 0', () => {\n    expect(getRemainder(20, 5)).to.eq(0);\n  });\n});\n\ndescribe('getRemainder(8, 22)', () => {\n  it('should return 6', () => {\n    expect(getRemainder(8, 22)).to.eq(6);\n  });\n});\n\ndescribe('getRemainder(7, 42)', () => {\n  it('should return 0', () => {\n    expect(getRemainder(7, 42)).to.eq(0);\n  });\n});\n","instructions":[{"instructionContent":["Create a function <code>getRemainder</code> that takes two numbers and returns the remainder (value left over from division) of dividing the larger number by the smaller one.","Hint- You have no guarantee which number will be the bigger number, how can you determine which is which?"]}]}},"challenge-good-keys":{"subunitId":"challenge-good-keys","heading":"Challenge: goodKeys","solve":{"code":"// ADD CODE HERE\n\n// Uncomment these to check your work!\n// const sunny = { mac: 'priest', dennis: 'calculator', charlie: 'birdlaw', dee: 'bird', frank: 'warthog' };\n// function startsWithBird(str) { return str.slice(0, 4).toLowerCase() === 'bird'; };\n// console.log(goodKeys(sunny, startsWithBird)); // should log: ['charlie', 'dee']","test":"describe('goodKeys', () => {\n  const approve = () => true;\n  const isEven = (n) => n % 2 === 0;\n  const obj = { a: 1, b: 2, c: 3, d: 4 };\n\n  it('should be a function', () => {\n    expect(goodKeys).to.be.a('function');\n  });\n  it('should return an array', () => {\n    expect(goodKeys({}, () => {})).to.be.an('array');\n  });\n  it(\"should iterate through the object and populate the returned array with the object's keys\", () => {\n    const answer = goodKeys(obj, approve);\n    expect(answer.length).to.equal(4);\n  });\n  it(\"should filter keys who's values don't evaluate to true when passed to the callback\", () => {\n    const answer = goodKeys(obj, isEven);\n    expect(answer).to.eql(['b', 'd']);\n  });\n});\n","instructions":[{"instructionContent":["Create a function <code>goodKeys</code> that accepts an object and a callback. The callback will return either <code>true</code> or <code>false</code>. <code>goodKeys</code> will iterate through the object and perform the callback on each value. <code>goodKeys</code> will then return an array consisting only the keys whose associated values yielded a <code>true</code> return value from the callback."]}]}},"challenge-grade-calculator":{"subunitId":"challenge-grade-calculator","heading":"Challenge: gradeCalculator","solve":{"code":"function gradeCalculator(grade) {\n  // ADD CODE HERE\n}\n\n// Uncomment the lines below to test your code\n// console.log(gradeCalculator(92)); // => \"A\"\n// console.log(gradeCalculator(84)); // => \"B\"\n// console.log(gradeCalculator(70)); // => \"C\"\n// console.log(gradeCalculator(61)); // => \"D\"\n// console.log(gradeCalculator(43)); // => \"F\"","test":"describe('gradeCalculator', () => {\n  it('should be a function', () => {\n    expect(gradeCalculator).to.be.a('function');\n  });\n});\n\ndescribe('gradeCalculator(92)', () => {\n  it('should return \"A\"', () => {\n    expect(gradeCalculator(92)).to.eq('A');\n  });\n});\n\ndescribe('gradeCalculator(85)', () => {\n  it('should return \"B\"', () => {\n    expect(gradeCalculator(85)).to.eq('B');\n  });\n});\n\ndescribe('gradeCalculator(70)', () => {\n  it('should return \"C', () => {\n    expect(gradeCalculator(70)).to.eq('C');\n  });\n});\n\ndescribe('gradeCalculator(61)', () => {\n  it('should return \"D\"', () => {\n    expect(gradeCalculator(61)).to.eq('D');\n  });\n});\n\ndescribe('gradeCalculator(43)', () => {\n  it('should return \"F\"', () => {\n    expect(gradeCalculator(43)).to.eq('F');\n  });\n});\n","instructions":[{"instructionContent":["Create a function <code>gradeCalculator</code> which takes a grade (number) and returns its letter grade.","grades 90 and above should return \"A\"","grades 80 to 89 should return \"B\"","grades 70 to 79 should return \"C\"","grades 60 to 69 should return \"D\"","59 and below should return \"F\""]}]}},"challenge-group-by":{"subunitId":"challenge-group-by","heading":"Challenge: groupBy","solve":{"code":"// ADD CODE HERE\n\n// Uncomment these to check your work!\n// const decimals = [1.3, 2.1, 2.4];\n// const floored = function(num) { return Math.floor(num); };\n// console.log(groupBy(decimals, floored)); // should log: { 1: [1.3], 2: [2.1, 2.4] }\n","test":"describe('groupBy', () => {\n  const evenOdd = (n) => (n % 2 === 0 ? 'even' : 'odd');\n  const floored = (n) => {\n    return Math.floor(n);\n  };\n\n  let evenOddArray;\n  let flooredArray;\n\n  if (typeof groupBy === 'function') {\n    evenOddArray = groupBy([1, 2, 3, 4, 5], evenOdd);\n    flooredArray = groupBy([1.3, 2.1, 2.4], floored);\n  }\n\n  it('should be a function', () => {\n    expect(groupBy).to.be.a('function');\n  });\n  it('should return an object', () => {\n    expect(groupBy([], () => {})).to.eql({});\n  });\n  it('should apply callback results as keys in the returned object', () => {\n    expect(evenOddArray).to.have.own.property('even');\n    expect(evenOddArray).to.have.own.property('odd');\n    expect(flooredArray).to.have.own.property('1');\n    expect(flooredArray).to.have.own.property('2');\n  });\n  it('should create arrays as values of the returned object', () => {\n    expect(evenOddArray['odd']).to.be.an('array');\n    expect(evenOddArray['even']).to.be.an('array');\n    expect(flooredArray['1']).to.be.an('array');\n    expect(flooredArray['2']).to.be.an('array');\n  });\n  it('should group array items together if the callback returns the same value when they are passed in', () => {\n    expect(evenOddArray).to.eql({ odd: [1, 3, 5], even: [2, 4] });\n    expect(flooredArray).to.eql({ 1: [1.3], 2: [2.1, 2.4] });\n  });\n});\n","instructions":[{"instructionContent":["Create a function <code>groupBy</code> that accepts an array and a callback, and returns an object. <code>groupBy</code> will iterate through the array and perform the callback on each element. Each return value from the callback will be saved as a key on the object. The value associated with each key will be an array consisting of all the elements that resulted in that return value when passed into the callback."]}]}},"challenge-hobbyTracker":{"subunitId":"challenge-hobbyTracker","heading":"Challenge: hobbyTracker","solve":{"code":"function hobbyTracker(hobbies) {\n  \n  \n}\n\n\n\n\n// Uncomment the code below to check your code:\n// const updateHobbies = hobbyTracker(['yoga', 'baking', 'piano']);\n// updateHobbies('yoga', 2);\n// updateHobbies('baking', 4);\n// updateHobbies('yoga', 1);\n// console.log(updateHobbies('piano', 2)); // --> { yoga: 3, baking: 4, piano: 2 }\n// console.log(updateHobbies()); // --> 'tracker has been reset!'\n// console.log(updateHobbies('baking', 1)); // --> { yoga: 0, baking: 1, piano: 0}","test":"describe('hobbyTracker', () => {\n  let updateHobbies;\n\n  before(() => {\n    updateHobbies = hobbyTracker(['yoga', 'baking', 'piano']);\n  });\n\n  describe('hobbyTracker', () => {\n    it('should create and return a function', () => {\n      expect(updateHobbies).to.be.a('function');\n    });\n  });\n\n  describe(\"updateHobbies('piano', 2)\", () => {\n    it('should return an object: { yoga: 3, baking: 4, piano: 2 }', () => {\n      expect(updateHobbies('yoga', 2)).to.deep.equal({ yoga: 2, baking: 0, piano: 0 });\n      expect(updateHobbies('baking', 4)).to.deep.equal({ yoga: 2, baking: 4, piano: 0 });\n      expect(updateHobbies('yoga', 1)).to.deep.equal({ yoga: 3, baking: 4, piano: 0 });\n      expect(updateHobbies('piano', 2)).to.deep.equal({ yoga: 3, baking: 4, piano: 2 });\n    });\n  });\n\n  describe('updateHobbies()', () => {\n    it(\"should return string: 'tracker has been reset'\", () => {\n      expect(updateHobbies()).to.equal('tracker has been reset!');\n    });\n  });\n\n  describe(\"updateHobbies('baking', 1)\", () => {\n    it('should return an object: { yoga: 0, baking: 1, piano: 0 }', () => {\n      expect(updateHobbies('baking', 1)).to.deep.equal({ yoga: 0, baking: 1, piano: 0 });\n    });\n  });\n});\n","instructions":[{"instructionContent":["Create a function <code>hobbyTracker</code> that takes an array of hobbies as a parameter and creates a cache object with each hobby as a key. <code>hobbyTracker</code> should return a function that takes a string representing the hobby and an integer representing how many hours practiced as parameters.","When the returned function is invoked, it should update the cache object adding the value of the passed in integer to the cache at the key corresponding with the passed in 'hobby' then should return the updated cache object. If the returned function is invoked with no arguments, it should reset all values in the cache object to zero and return the string 'tracker has been reset!'",{"codeBlock":"const updateHobbies = hobbyTracker(['yoga', 'baking', 'piano']);\n\nupdateHobbies('yoga', 2); \n// { yoga: 2, baking: 0, piano: 0  }\n\nupdateHobbies('baking', 3);\n// { yoga: 2, baking: 3, piano: 0  }\n\nupdateHobbies(); \n// 'tracker has been reset!'"}]}]}},"challenge-intersection":{"subunitId":"challenge-intersection","heading":"Challenge: intersection","solve":{"code":"// ADD CODE HERE\n\n// Uncomment these to check your work!\n// const arr1 = [5, 10, 15, 20];\n// const arr2 = [15, 88, 1, 5, 7];\n// const arr3 = [1, 10, 15, 5, 20];\n// console.log(intersection([arr1, arr2, arr3])); // should log: [5, 15]","test":"describe('intersection', () => {\n  it('should be a function', () => {\n    expect(intersection).to.be.a('function');\n  });\n  it('should return an array', () => {\n    const answer = intersection([[], []]);\n    expect(answer).to.eql([]);\n  });\n  it('should find common elements in two arrays', () => {\n    const answer = intersection([\n      [1, 2, 3],\n      [2, 3],\n    ]);\n    expect(answer).to.eql([2, 3]);\n  });\n  it('should find common elements in many arrays', () => {\n    const arr1 = [1, 2, 3, 4, 5];\n    const arr2 = [1, 2, 3, 4, 7, 8, 9];\n    const arr3 = [2, 3, 7, 8, 9];\n    const arr4 = [1, 7, 8, 9, 2, 3];\n    const answer = intersection([arr1, arr2, arr3, arr4]);\n    expect(answer).to.eql([2, 3]);\n  });\n});\n","instructions":[{"instructionContent":["Construct a function <code>intersection</code> that compares input arrays and returns a new array with elements found in all of the inputs. BONUS - Use reduce!"]}]}},"challenge-introduce":{"subunitId":"challenge-introduce","heading":"Challenge: introduce","solve":{"code":"const personStore = {\n  greet: function() {\n    console.log('hello');\n  }\n}\n\nfunction personFromPersonStore(name, age) {\n\tconst person = Object.create(personStore);\n  person.name = name;\n  person.age = age;\n  return person;\n}\n\nconst sandra = personFromPersonStore('Sandra', 26);\n\n// add code here\n\n\n// Uncomment this line to check your work!\n// sandra.introduce(); // -> Logs 'Hi, my name is Sandra'","test":"describe('personStore', () => {\n  it('- returned object should have an introduce method', () => {\n    expect(sandra.introduce).to.be.a('function');\n    let log;\n    (function () {\n      const oldConsoleLog = console.log;\n      console.log = function (input) {\n        log = input;\n      };\n      sandra.introduce();\n      console.log = oldConsoleLog;\n    })();\n    expect(log).to.equal('Hi, my name is Sandra');\n  });\n  it('should have an introduce method', () => {\n    expect(personStore.introduce).to.be.a('function');\n  });\n});\n","instructions":[{"instructionContent":["Without editing the code you've already written, add an <code>introduce</code> method to the <code>personStore</code> object that logs \"Hi, my name is [name]\"."]}]}},"challenge-introduce-pt-2":{"subunitId":"challenge-introduce-pt-2","heading":"Challenge: introduce (cont.)","solve":{"code":"function PersonConstructor() {\n  this.greet = function() {\n    console.log('hello');\n  }\n}\n\nfunction personFromConstructor(name, age) {\n  const person = new PersonConstructor();\n  person.name = name;\n  person.age = age;\n  return person;\n}\n\nconst mike = personFromConstructor('Mike', 30);\n\n// add code here\n\n\n// Uncomment this line to check your work!\n// mike.introduce(); // -> Logs 'Hi, my name is Mike'","test":"describe('PersonConstructor', () => {\n  it('should have an introduce method', () => {\n    const mike = personFromConstructor('Mike', 30);\n    expect(PersonConstructor.prototype.isPrototypeOf(mike)).to.equal(true);\n  });\n  it('- returned object should have introduce method', () => {\n    const mike = personFromConstructor('Mike', 30);\n    expect(mike.introduce).to.be.a('function');\n    let log;\n    (function () {\n      const oldConsoleLog = console.log;\n      console.log = function (input) {\n        log = input;\n      };\n      mike.introduce();\n      console.log = oldConsoleLog;\n    })();\n    expect(log).to.equal('Hi, my name is Mike');\n  });\n});\n","instructions":[{"instructionContent":["Without editing the code you've already written, add an <code>introduce</code> method to the <code>PersonConstructor</code> function that logs \"Hi, my name is [name]\"."]}]}},"challenge-inventory":{"subunitId":"challenge-inventory","heading":"Challenge: Inventory","solve":{"code":"function Inventory(item, price) {\n  // add code here\n  \n}\n\nconst myInventory = new Inventory('cucumber', 2);\n\n// Uncomment these lines to check your work!\n// myInventory.addItem('carrot', 1);\n// console.log(myInventory.checkItem('cucumber')); // Logs: { price: 2, quantity: 1 }\n// myInventory.addItem('cucumber', 3); \n// console.log(myInventory.deleteItem('carrot')); // Logs: 'Deleted'\n// console.log(myInventory.deleteItem('carrot')); // Logs: 'Nothing to delete'\n// console.log(myInventory); // Logs: { cucumber: { price: 3, quantity: 2 }, carrot: { price: 1, quantity: 0 } }\n// console.log(myInventory.checkItem('radish')); // Logs: 'Item is not in inventory'","test":"describe('Inventory', () => {\n  it('- created object has Inventory as constructor', () => {\n    const myInventory = new Inventory('banana', 2);\n    expect(myInventory.constructor).to.equal(Inventory);\n  });\n  it('- addItem method adds an item to created object and updates price and quantity', () => {\n    const myInventory = new Inventory('banana', 2);\n    expect(myInventory.banana.price).to.equal(2);\n    expect(myInventory.banana.quantity).to.equal(1);\n    myInventory.addItem('banana', 3);\n    expect(myInventory.banana.price).to.equal(3);\n    expect(myInventory.banana.quantity).to.equal(2);\n  });\n  it('- deleteItem method subtracts from the quantity of an item', () => {\n    const myInventory = new Inventory('banana', 2);\n    myInventory.addItem('banana', 2);\n    expect(myInventory.deleteItem('banana')).to.equal('Deleted');\n    expect(myInventory.banana.quantity).to.equal(1);\n    myInventory.deleteItem('banana');\n    myInventory.deleteItem('banana');\n    expect(myInventory.deleteItem('banana')).to.equal('Nothing to delete');\n    expect(myInventory.banana.quantity).to.equal(0);\n  });\n  it('- checkItem method checks for an item and returns it if it exists', () => {\n    const myInventory = new Inventory('banana', 2);\n    expect(myInventory.checkItem('banana')).to.equal(myInventory.banana);\n    expect(myInventory.checkItem('apple')).to.equal('Item is not in inventory');\n  });\n  it('- all methods should be stored on the Inventory prototype rather than the object itself', () => {\n    const myInventory = new Inventory('banana', 2);\n    expect(Object.hasOwn(myInventory, 'addItem')).to.equal(false);\n    expect(Object.hasOwn(myInventory, 'deleteItem')).to.equal(false);\n    expect(Object.hasOwn(myInventory, 'checkItem')).to.equal(false);\n  });\n});\n","instructions":[{"instructionContent":["Declare a function <code>Inventory</code> that, when invoked with the <code>new</code> keyword, returns objects that keep track of an inventory. Your <code>Inventory</code> function should accept two arguments: <code>item</code>, a string, and <code>price</code>, a number. The object returned should contain a property whose key matches the passed-in <code>item</code> argument, and is set to another object with two properties: <code>price</code> (which will be set to the <code>price</code> argument the method was called with) and <code>quantity</code>, which should be initially set to 1.","Each object returned from this <code>Inventory</code> constructor should, via the prototype chain, have access to three methods:","The method <code>addItem</code> will add additional items to the object returned from the constructor. It should also accept an <code>item</code> and <code>price</code> argument, and when invoked, should check to see if the <code>Inventory</code> object it is called upon has a property that matches the passed-in item name. If it does not, add one, and set it to another item object, following the same format as above. If the <code>Inventory</code> object does have a property with that name,  increment that item's <code>quantity</code> property by one, and replace the <code>price</code> with whatever number was just passed in.","The method <code>deleteItem</code> should accept a string as an argument. If a matching property exists on the <code>Inventory</code> object, decrement its <code>quantity</code> by 1 and return the string 'Deleted'. If the quantity is already 0, return the string 'Nothing to delete'.","The method <code>checkItem</code> should take a string as an argument and check to see whether that string exists as a property on the <code>Inventory</code> object. If so, return the object for that item. If not, return the string 'Item is not in inventory'."]}]}},"challenge-invoking-functions":{"subunitId":"challenge-invoking-functions","heading":"Challenge: Invoking Functions","solve":{"code":"let calls = \"\";\n\nfunction jerry(str) {\n\n}\n\nfunction george(str) {\n\n}\n\nfunction elaine(str) {\n\n}\n\nfunction kramer(str) {\n\n}\n\n\n// Uncomment these to check your work!\n// calls = jerry(calls);\n// console.log(calls); // should log: 'JerryKramerGeorgeElaine'","test":"describe('Calling jerry()', () => {\n  it('should modify the value of \"calls\" to \"JerryKramerGeorgeElaine\"', () => {\n    jerry('');\n    expect(calls).to.eq('JerryKramerGeorgeElaine');\n  });\n});\n","instructions":[{"instructionContent":["Examine the code given to you. Try to make the calls variable equal to 'JerryKramerGeorgeElaine' with only a single invocation to the function <code>jerry</code>."]}]}},"challenge-is-odd":{"subunitId":"challenge-is-odd","heading":"Challenge: isOdd","solve":{"code":"// ADD CODE HERE\n\n// Uncomment these to check your work!\n// console.log(isOdd(5)); // should log: true\n// console.log(isOdd(2008)); // should log: false","test":"describe('isOdd', () => {\n  it('should be a function', () => {\n    expect(isOdd).to.be.a('function');\n  });\n});\n\ndescribe('isOdd(5)', () => {\n  it('should return true', () => {\n    expect(isOdd(5)).to.eq(true);\n  });\n});\n\ndescribe('isOdd(2008)', () => {\n  it('should return false', () => {\n    expect(isOdd(2008)).to.eq(false);\n  });\n});\n","instructions":[{"instructionContent":["Create a function <code>isOdd</code> that accepts a number argument. <code>isOdd</code> will return true if the number is odd and false if the number is even."]}]}},"challenge-jedi":{"subunitId":"challenge-jedi","heading":"Challenge: jedi","solve":{"code":"let calls = '';\n\nfunction jedi(){\n// ADD CODE HERE?\n}\n\nfunction may() {\n  calls += 'May';\n  // ADD CODE HERE?\n}\n\nfunction you() {\n  calls += 'You';\n  // ADD CODE HERE?\n}\n\nfunction force() {\n  calls += 'TheForce';\n  // ADD CODE HERE?\n}\n\nfunction beWith() {\n  calls += 'BeWith'\n  // ADD CODE HERE?\n}\n\n// Uncomment these to check your work!\n// jedi();\n// console.log(calls); // should log: 'MayTheForceBeWithYou'","instructions":[{"instructionContent":["Examine the code given to you. Try to make the calls variable equal to 'MayTheForceBeWithYou' with only a single invocation to the function <code>jedi</code>, as done in the commented out lines below the code given to you. You may add code to the places marked <code>ADD CODE HERE?</code>, though it might not be necessary to add code to all places."]}]}},"challenge-join-and-map":{"subunitId":"challenge-join-and-map","heading":"Challenge: joinAndMap","solve":{"code":"// ADD CODE HERE\n\n// Uncomment these to check your work!\n// const arrRed = ['strawberry', 'cherry', 'wine'];\n// const arrBlue = ['blueberry', 'sky', 'ocean'];\n// const capitalize = str => str.toUpperCase();\n// console.log(joinAndMap(arrRed, arrBlue, capitalize)); // should log: ['STRAWBERRY', 'CHERRY', 'WINE', 'BLUEBERRY', 'SKY', 'OCEAN']","test":"describe('joinAndMap', () => {\n  const capitalize = (str) => str.toUpperCase();\n\n  it('should be a function', () => {\n    expect(joinAndMap).to.be.a('function');\n  });\n\n  it('should return an empty array when called with two empty arrays', () => {\n    let nothing = [];\n    expect(joinAndMap(nothing, nothing, capitalize)).to.eql([]);\n  });\n\n  it('should not mutate either input array', () => {\n    let animalsIn = ['dog', 'cat', 'tree frog'];\n    let fruitIn = ['apple', 'pear', 'banana'];\n    joinAndMap(animalsIn, fruitIn, capitalize);\n    expect(animalsIn).to.eql(['dog', 'cat', 'tree frog']);\n    expect(fruitIn).to.eql(['apple', 'pear', 'banana']);\n  });\n\n  it('should join and map the items in the input array', () => {\n    let moreAnimals = ['sparrow', 'cheetah', 'penguin'];\n    let evenMoreAnimals = ['ant', 'sea lion'];\n    expect(joinAndMap(moreAnimals, evenMoreAnimals, capitalize)).to.eql([\n      'SPARROW',\n      'CHEETAH',\n      'PENGUIN',\n      'ANT',\n      'SEA LION',\n    ]);\n  });\n});\n","instructions":[{"instructionContent":["Construct a function <code>joinAndMap</code> with three parameters: array1, array2, and a callback function. The function should combine the two arrays then invoke the callback function on each element, returning the resulting array. This function should not mutate the passed-in arrays."]}]}},"challenge-last-letter":{"subunitId":"challenge-last-letter","heading":"Challenge: lastLetter","solve":{"code":"function lastLetter(word) {\n  // INSERT CODE HERE\n}\n\n// Uncomment the lines below to test your code\n// console.log(lastLetter(\"hello\")); //=> \"o\"\n// console.log(lastLetter(\"goodbye!\")); //=> \"!\"\n// console.log(lastLetter(\"ZeltoiD\")); //=> \"D\"\n// console.log(lastLetter(\"I love Javascript\")); //=> \"t\"","test":"describe('lastLetter', () => {\n  it('should be a function', () => {\n    expect(lastLetter).to.be.a('function');\n  });\n});\n\ndescribe('lastLetter(\"hello\")', () => {\n  it('should return \"o\"', () => {\n    expect(lastLetter('hello')).to.eq('o');\n  });\n});\n\ndescribe('lastLetter(\"goodbye!\")', () => {\n  it('should return \"!', () => {\n    expect(lastLetter('goodbye!')).to.eq('!');\n  });\n});\n\ndescribe('lastLetter(\"ZeltoiD\")', () => {\n  it('should return \"D\"', () => {\n    expect(lastLetter('ZeltoiD')).to.eq('D');\n  });\n});\n\ndescribe('lastLetter(\"I love Javascript\")', () => {\n  it('should return \"t\"', () => {\n    expect(lastLetter('I love Javascript')).to.eq('t');\n  });\n});\n","instructions":[{"instructionContent":["Create a function <code>lastLetter</code> that takes a word (string) and returns the last character/letter of that string.","Hint- Remember that each character/letter in a string has an index position that you can access with brackets- '[]'"]}]}},"challenge-limited-interval":{"subunitId":"challenge-limited-interval","heading":"Challenge: limitedInterval","solve":{"code":"// Add code here\n\n// /* Uncomment the following line and click 'run' to test your work */\n// limitedInterval(() => console.log('repeating'), 100, 550); // should log 'repeating' once per 100 ms, five times.\n","test":"const { oldConsoleLog, logged } = reDefineConsoleLog((arg) => {\n  logged.push(arg);\n});\n\ndescribe('limitedInterval', () => {\n  it('should log \"repeating\" five times', (done) => {\n    delay(900, logged)\n      .then((resolved) => {\n        expect(resolved.length).to.eq(5);\n        console.log = oldConsoleLog;\n      })\n      .then(done, done);\n  });\n});\n\n//resolve promise after ms milleseconds\nfunction delay(ms, logged) {\n  return new Promise((resolve) => {\n    setTimeout(() => resolve(logged), ms);\n  });\n}\n\n// logged will contain all arguments passed into console.log\nfunction reDefineConsoleLog(newConsoleLog, logged = []) {\n  const oldConsoleLog = console.log;\n  console.log = newConsoleLog;\n  return { oldConsoleLog, logged };\n}\n","instructions":[{"instructionContent":["Write a function called limitedInterval that accepts as arguments in this order -",{"list":["<code>callback</code> function","<code>wait</code> time in milliseconds","<code>limit</code> time in milliseconds."]},"<code>limitedInterval</code> should run the callback once every <code>wait</code> milliseconds, up to <code>limit</code> milliseconds, and then stop."]}]}},"challenge-loops-and-control-flow":{"subunitId":"challenge-loops-and-control-flow","heading":"Challenge: Loops & Control Flow","solve":{"code":"function mergingTripletsAndQuints(array1, array2) {\n // ADD CODE HERE\n}\n\n// Uncomment these to check your work!\n// console.log(mergingTripletsAndQuints([1, 2, 3, 4, 5, 15], [1, 3, 6, 7, 8, 9])); // expected log [1, 2, 9, 4, 13, 24]\n// console.log(mergingTripletsAndQuints([1, 1, 3, 9, 5, 15], [1, 2, 3, 4, 5, 6])); // expected log [1, 1, 6, 13, 10, 21]","test":"describe('mergingTripletsAndQuints', () => {\n  it('should be a function', () => {\n    expect(mergingTripletsAndQuints).to.be.a('function');\n  });\n});\n\ndescribe('mergingTripletsAndQuints([1, 2, 3, 4, 5, 15], [1, 3, 6, 7, 8, 9])', () => {\n  it('should return [1, 2, 9, 4, 13, 24]', () => {\n    expect(mergingTripletsAndQuints([1, 2, 3, 4, 5, 15], [1, 3, 6, 7, 8, 9])).to.deep.equal([1, 2, 9, 4, 13, 24]);\n  });\n});\n\ndescribe('mergingTripletsAndQuints([1, 1, 3, 9, 5, 15], [1, 2, 3, 4, 5, 6])', () => {\n  it('should return [1, 1, 6, 13, 10, 21]', () => {\n    expect(mergingTripletsAndQuints([1, 1, 3, 9, 5, 15], [1, 2, 3, 4, 5, 6])).to.deep.equal([1, 1, 6, 13, 10, 21]);\n  });\n});\n","instructions":[{"instructionContent":["Write a function <code>mergingTripletsAndQuints</code> which takes in two arrays as arguments. This function will return a new array replacing the elements in <code>array1</code> if they are divisible by 3 or 5. The number should be replaced with the sum of itself added to the element at the corresponding index in <code>array2</code>."]}]}},"challenge-loops-multiple-conditions":{"subunitId":"challenge-loops-multiple-conditions","heading":"Challenge: Loops - Multiple Conditions","solve":{"code":"function addingAllTheWeirdStuff(array1, array2){\n  // ADD CODE HERE\n}\n\n// Uncomment these to check your work!\n// console.log(addingAllTheWeirdStuff([1, 3, 5, 17, 15], [1, 2, 3, 4, 5])); // expected log [10, 12, 14, 23, 21]\n// console.log(addingAllTheWeirdStuff([1, 3, 5, 17, 15, 1], [1, 2, 3, 4, 5, 22])); // expected log [11, 13, 15, 46, 44, 11]\n","test":"describe('addingAllTheWeirdStuff', () => {\n  it('should be a function', () => {\n    expect(addingAllTheWeirdStuff).to.be.a('function');\n  });\n});\n\ndescribe('addingAllTheWeirdStuff([1, 3, 5, 17, 15], [1, 2, 3, 4, 5])', () => {\n  it('should return [10, 12, 14, 23, 21]', () => {\n    expect(addingAllTheWeirdStuff([1, 3, 5, 17, 15], [1, 2, 3, 4, 5])).to.deep.equal([10, 12, 14, 23, 21]);\n  });\n});\n\ndescribe('BONUS: addingAllTheWeirdStuff([1, 3, 5, 17, 15, 1], [1, 2, 3, 4, 5, 22])', () => {\n  it('should return [11, 13, 15, 46, 44, 11]', () => {\n    expect(addingAllTheWeirdStuff([1, 3, 5, 17, 15, 1], [1, 2, 3, 4, 5, 22])).to.deep.equal([11, 13, 15, 46, 44, 11]);\n  });\n});\n\ndescribe('BONUS: addingAllTheWeirdStuff([1, 3, 5, 17, 15, 1], [1, 29, 3, 4, 5, 22])', () => {\n  it('should return [40, 42, 44, 44, 42, 40]', () => {\n    expect(addingAllTheWeirdStuff([1, 3, 5, 17, 15, 1], [1, 29, 3, 4, 5, 22])).to.deep.equal([40, 42, 44, 44, 42, 40]);\n  });\n});\n","instructions":[{"instructionContent":["Write a function <code>addingAllTheWeirdStuff</code> which adds the sum of all the odd numbers in <code>array2</code> to each element under 10 in <code>array1</code>. Similarly, <code>addingAllTheWeirdStuff</code> should also add the sum of all the even numbers in <code>array2</code> to those elements over 10 in <code>array1</code>.","BONUS: If any element in <code>array2</code> is greater than 20, add 1 to every element in <code>array1</code>."]}]}},"challenge-loops-range":{"subunitId":"challenge-loops-range","heading":"Challenge: Loops - Range","solve":{"code":"function getTheRange(arr){\n  // ADD CODE HERE\n}\n\n// Uncomment these to check your work!\n// console.log(getTheRange([3, 2, 5, 4, 7, 9, 10])); // expect log [2, 10, 8]","test":"describe('getTheRange', () => {\n  it('should be a function', () => {\n    expect(getTheRange).to.be.a('function');\n  });\n});\n\ndescribe('getTheRange([3, 2, 5, 4, 7, 9, 10])', () => {\n  it('should return [2, 10, 8]', () => {\n    expect(getTheRange([3, 2, 5, 4, 7, 9, 10])).to.deep.equal([2, 10, 8]);\n  });\n});\n","instructions":[{"instructionContent":["Using a loop, write a function <code>getTheRange</code> which finds the range (difference between high and low) of <code>arr</code>. The value returned should be an array with the low, high, and range."]}]}},"challenge-loops-summing-two-arrays":{"subunitId":"challenge-loops-summing-two-arrays","heading":"Challenge: Loops - Summing Two Arrays","solve":{"code":"function mergingElements(array1, array2){\n  // ADD CODE HERE\n}\n\n// Uncomment these to check your work!\n// console.log(mergingElements([1, 2, 3, 4], [5, 6, 7, 8])); // expected log [6, 8, 10, 12]\n// console.log(mergingElements([7, 3, 6, 0], [3, 9, 17, 81])); // expected log [10, 12, 23, 81]","test":"describe('mergingElements', () => {\n  it('should be a function', () => {\n    expect(mergingElements).to.be.a('function');\n  });\n});\n\ndescribe('mergingElements([1,2,3,4], [5,6,7,8])', () => {\n  it('should return [6, 8, 10, 12]', () => {\n    expect(mergingElements([1, 2, 3, 4], [5, 6, 7, 8])).to.deep.equal([6, 8, 10, 12]);\n  });\n});\n\ndescribe('mergingElements([7,3,6,0], [3,9,17,81])', () => {\n  it('should return [10, 12, 23, 81]', () => {\n    expect(mergingElements([7, 3, 6, 0], [3, 9, 17, 81])).to.deep.equal([10, 12, 23, 81]);\n  });\n});\n","instructions":[{"instructionContent":["Write a function <code>mergingElements</code> which adds each element in <code>array1</code> to the corresponding element of <code>array2</code> and returns the new array."]}]}},"challenge-majority":{"subunitId":"challenge-majority","heading":"Challenge: majority","solve":{"code":"// ADD CODE HERE\n\n// Uncomment these to check your work!\n// const isOdd = function(num) { return num % 2 === 1; };\n// console.log(majority([1, 2, 3, 4, 5], isOdd)); // should log: true\n// console.log(majority([2, 3, 4, 5], isOdd)); // should log: false","test":"describe('majority', () => {\n  const isALongWord = (str) => str.length > 6;\n  it('should be a function', () => {\n    expect(majority).to.be.a('function');\n  });\n  it('should return a boolean value', () => {\n    expect(majority([], () => {})).to.be.a('boolean');\n  });\n  it('should return true if a majority of items in the array pass the test specified in the callback', () => {\n    const answer = majority(['salamander', 'dog', 'meerkat', 'cat', 'elephant'], isALongWord);\n    expect(answer).to.eql(true);\n  });\n  it('should return false if the number of passes and fails are equal', () => {\n    const answer = majority(['dog', 'meerkat', 'cat', 'elephant'], isALongWord);\n    expect(answer).to.eql(false);\n  });\n});\n","instructions":[{"instructionContent":["Create a function <code>majority</code> that accepts an array and a callback. The callback will return either <code>true</code> or <code>false</code>. <code>majority</code> will iterate through the array and perform the callback on each element until it can be determined if the <code>majority</code> of the return values from the callback are <code>true</code>. If the number of <code>true</code> returns is equal to the number of <code>false</code> returns, majority should return <code>false</code>."]}]}},"challenge-make-person":{"subunitId":"challenge-make-person","heading":"Challenge: makePerson","solve":{"code":"function makePerson(name, age) {\n\t// add code here\n\n\n}\n\nconst vicky = makePerson('Vicky', 24);\n\n\n// Uncomment these lines to check your work!\n// console.log(vicky.name); // -> Logs 'Vicky'\n// console.log(vicky.age); // -> Logs 24","test":"describe('makePerson', () => {\n  it('should return an object', () => {\n    expect(makePerson('Vicky', 24)).to.be.an('object');\n  });\n  it('- returned object should have a name property', () => {\n    expect(makePerson('Vicky', 24)).to.have.own.property('name', 'Vicky');\n  });\n  it('- returned object should have an age property', () => {\n    expect(makePerson('Vicky', 24)).to.have.own.property('age', 24);\n  });\n});\n","instructions":[{"instructionContent":["Create a function that accepts two inputs (name and age) and returns an object. Let's call this function <code>makePerson</code>. This function will:<ol><li>Create an empty object</li><li>Add a <code>name</code> property to the newly created object with its value being the <code>name</code> argument passed into the function</li><li>Add an <code>age</code> property to the newly created object with its value being the \"age\" argument passed into the function</li><li>Return the object</li></ol>"]}]}},"challenge-make-plans":{"subunitId":"challenge-make-plans","heading":"Challenge: makePlans","solve":{"code":"let friendsAvailable = true;\n\nfunction makePlans(name) {\n  // INSERT CODE HERE\n}\n\nfunction callFriend(bool, name) {\n  // INSERT CODE HERE\n}\n\n// Uncomment these to check your work!\n// console.log(makePlans(\"Mary\")) // should return: \"Plans made with Mary this weekend'\n// friendsAvailable = false;\n// console.log(makePlans(\"James\")) //should return: \"Everyone is busy this weekend.\"\n","test":"describe('makePlans', () => {\n  it('should be a function', () => {\n    expect(makePlans).to.be.a('function');\n  });\n});\n\ndescribe('callFriend', () => {\n  it('should be a function', () => {\n    expect(callFriend).to.be.a('function');\n  });\n});\n\ndescribe('makePlans(\"Mary\")', () => {\n  it(\"should return 'Plans made with Mary this weekend'\", () => {\n    friendsAvailable = true;\n    expect(makePlans('Mary')).to.eq('Plans made with Mary this weekend');\n  });\n});\n\ndescribe('makePlans(\"James\")', () => {\n  it(\"should return 'Everyone is busy this weekend'\", () => {\n    friendsAvailable = false;\n    expect(makePlans('James')).to.eq('Everyone is busy this weekend');\n  });\n});\n","instructions":[{"instructionContent":["Create a function <code>makePlans</code> that accepts a string. This string should be a name. The function <code>makePlans</code> should call the function <code>callFriend</code> and return the result. <code>callFriend</code> accepts a boolean value and a string. Pass in the <code>friendsAvailable</code> variable and name to <code>callFriend</code>.","Create a function <code>callFriend</code> that accepts a boolean value and a string. If the boolean value is true, <code>callFriend</code> should return the string <code>'Plans made with NAME this weekend'</code>.  Otherwise it should return <code>'Everyone is busy this weekend'</code>."]}]}},"challenge-make-plural":{"subunitId":"challenge-make-plural","heading":"Challenge: makePlural","solve":{"code":"function makePlural(arr){\n  // ADD CODE HERE\n} \n\n\nconst arr1 = ['lion', 'tiger', 'bear']\nconst arr2 = ['computer', 'video game', 'system']\n\n// Uncomment these to check your work!\n// console.log(makePlural(arr1)); // should log: ['lions', 'tigers', 'bears']\n// console.log(makePlural(arr2)); // should log: ['computers', 'video games', 'systems']","test":"describe('makePlural', () => {\n  it('should be a function', () => {\n    expect(makePlural).to.be.a('function');\n  });\n});\n\ndescribe('makePlural([\"lion\", \"tiger\", \"bear\"])', () => {\n  it('should return [\"lions\", \"tigers\", \"bears\"]', () => {\n    expect(makePlural(['lion', 'tiger', 'bear'])).to.deep.equal(['lions', 'tigers', 'bears']);\n  });\n});\n\ndescribe('makePlural([\"computer\", \"video game\", \"system\"])', () => {\n  it('should return [\"computers\", \"video games\", \"systems\"]', () => {\n    expect(makePlural(['computer', 'video game', 'system'])).to.deep.equal(['computers', 'video games', 'systems']);\n  });\n});\n","instructions":[{"instructionContent":["Create a function <code>makePlural</code> that accepts an array argument. <code>makePlural</code> will iterate through the array, add an 's' to the end of each array element, and return the mutated array."]}]}},"challenge-map":{"subunitId":"challenge-map","heading":"Challenge: map","solve":{"code":"// ADD CODE HERE\n\n// Uncomment these to check your work!\n// console.log(typeof subtractTwo); // should log: 'function'\n// console.log(typeof map); // should log: 'function'\n// console.log(map([3,4,5], subtractTwo)); // should log: [ 1, 2, 3 ]","test":"describe('subtractTwo', () => {\n  it('should be a function', () => {\n    expect(subtractTwo).to.be.a('function');\n  });\n});\n\ndescribe('map', () => {\n  it('should be a function', () => {\n    expect(map).to.be.a('function');\n  });\n  it('should return an array', () => {\n    expect(map([], subtractTwo)).to.be.an('array');\n  });\n  it('should execute a callback function on each element', () => {\n    expect(map([3, 4, 5], subtractTwo)).to.eql([1, 2, 3]);\n  });\n});\n","instructions":[{"instructionContent":["Create a function <code>subtractTwo</code> that accepts a number and returns that number minus 2.","Then create a function <code>map</code> that takes two inputs -",{"orderedList":["an array of numbers (a list of numbers)","a 'callback' function - this function is applied to each element of the array (inside of the function 'map')"]},"Have your <code>map</code> function return a new array filled with numbers that are the result of using the 'callback' function on each element of the input array. Please do not use the native <code>map</code> or <code>forEach</code> method.",{"codeBlock":"map([3,4,5], subtractTwo); //-> [1,2,3]\nsubtractTwo(10); //-> 8\nsubtractTwo(12); //-> 10\n"}]}]}},"challenge-multi-map":{"subunitId":"challenge-multi-map","heading":"Challenge: multiMap","solve":{"code":"// ADD CODE HERE\n\n// Uncomment these to check your work!\n// function uppercaser(str) { return str.toUpperCase(); }\n// function capitalize(str) { return str[0].toUpperCase() + str.slice(1).toLowerCase(); }\n// function repeater(str) { return str + str; }\n// const items = ['catfood', 'glue', 'beer'];\n// const functions = [uppercaser, capitalize, repeater];\n// console.log(multiMap(items, functions)); // should log: { catfood: ['CATFOOD', 'Catfood', 'catfoodcatfood'], glue: ['GLUE', 'Glue', 'glueglue'], beer: ['BEER', 'Beer', 'beerbeer'] }","test":"describe('multiMap', () => {\n  const addTwo = (n) => n + 2;\n  const addTen = (n) => n + 10;\n  const double = (n) => n * 2;\n  const arr1 = [1, 2, 3];\n  const arr2 = [addTwo, addTen, double];\n  var obj;\n  if (typeof multiMap === 'function') obj = multiMap(arr1, arr2);\n\n  it('should be a function', () => {\n    expect(multiMap).to.be.a('function');\n  });\n  it('should return an object', () => {\n    expect(multiMap([], [])).to.eql({});\n  });\n  it('should use items from the first array as keys in the returned object', () => {\n    expect(obj['1']).to.exist;\n    expect(obj['2']).to.exist;\n    expect(obj['3']).to.exist;\n  });\n  it('should store arrays as the values for each key in the returned object', () => {\n    expect(obj['1']).to.be.an('array');\n    expect(obj['2']).to.be.an('array');\n    expect(obj['3']).to.be.an('array');\n  });\n  it('should populate the arrays in the returned object with results from calling each function in the second argument', () => {\n    expect(obj['1'][0]).to.eql(3);\n    expect(obj['1'][1]).to.eql(11);\n    expect(obj['1'][2]).to.eql(2);\n    expect(obj['2'][0]).to.eql(4);\n    expect(obj['2'][1]).to.eql(12);\n    expect(obj['2'][2]).to.eql(4);\n    expect(obj['3'][0]).to.eql(5);\n    expect(obj['3'][1]).to.eql(13);\n    expect(obj['3'][2]).to.eql(6);\n  });\n});\n","instructions":[{"instructionContent":["Construct a function <code>multiMap</code> that will accept two arrays - an array of values and an array of callbacks. <code>multiMap</code> will return an object whose keys match the elements in the array of values. The corresponding values that are assigned to the keys will be arrays consisting of outputs from the array of callbacks, where the input to each callback is the key."]}]}},"challenge-multiply-all":{"subunitId":"challenge-multiply-all","heading":"Challenge: multiplyAll","solve":{"code":"// ADD CODE HERE \n\n// Uncomment these to check your work!\n// console.log(multiplyAll(9, 4, 5, 6, 7, 2, 1, 8, 3)) // should log: 362880\n// console.log(multiplyAll(5, 5, 5, 3)) // should log: 375","test":"describe('multiplyAll', () => {\n  it('should be a function', () => {\n    expect(multiplyAll).to.be.a('function');\n  });\n});\n\ndescribe('multiplyAll(9, 4, 5, 6, 7, 2, 1, 8, 3)', () => {\n  it('should return 362880', () => {\n    expect(multiplyAll(9, 4, 5, 6, 7, 2, 1, 8, 3)).to.eq(362880);\n  });\n});\n\ndescribe('multiplyAll(5, 5, 5, 3)', () => {\n  it('should return 375', () => {\n    expect(multiplyAll(5, 5, 5, 3)).to.eq(375);\n  });\n});\n","instructions":[{"instructionContent":["Create a function <code>multiplyAll</code> that takes an unknown number of integer arguments, multiplies them all together, and returns the result."]}]}},"challenge-numbers-addition-subtraction":{"subunitId":"challenge-numbers-addition-subtraction","heading":"Challenge: Numbers - Addition/Subtraction","solve":{"code":"// ADD CODE BELOW\n\n\n// Uncomment these to check your work!\n// console.log(birthYear);\n// console.log(age);\n// console.log(in10Yrs);","test":"describe('birthYear', () => {\n  it('should be a number', () => {\n    expect(birthYear).to.be.a('number');\n  });\n});\n\ndescribe('age', () => {\n  it('should be a number', () => {\n    expect(age).to.be.a('number');\n  });\n  it('should be in appropriate range relative to birth year', () => {\n    const currentYear = new Date().getFullYear();\n    expect(age).to.be.within(currentYear - birthYear - 1, currentYear - birthYear);\n  });\n});\n\ndescribe('in10Yrs', () => {\n  it('should be a number', () => {\n    expect(in10Yrs).to.be.a('number');\n  });\n  it('should be age plus ten years', () => {\n    expect(in10Yrs).to.equal(age + 10);\n  });\n});\n","instructions":[{"instructionHeading":" ","instructionContent":["Another type of value that can be stored in a variable is a number. Pay close attention to the fact that the number is not wrapped in quotes. Keep in mind that if a value is wrapped in quotes, it becomes a string.",{"codeBlock":"let age = 26;  // age is a number\nlet ageText = \"26\";  // ageText is a string"},"Numbers can be added or subtracted using the addition (<code>+</code>) and subtraction (<code>-</code>) operators.",{"codeBlock":"let sum = 2 + 2; \nconsole.log(sum); // should log: 4\n\nlet age = 30;\nlet tenYrsAgo = age - 10;\nconsole.log(tenYrsAgo); // should log: 20"}]},{"instructionHeading":"Challenge","instructionContent":["Create a variable <code>birthYear</code> and set it equal to the year of your birth.","Next, create a variable named <code>age</code> and set the value to your current age.","Finally, create a variable named <code>in10Yrs</code> and set the value to equal your age plus 10."]}]}},"challenge-numbers-assignment-operators":{"subunitId":"challenge-numbers-assignment-operators","heading":"Challenge: Numbers - Assignment Operators","solve":{"code":"let num1 = 32;\nlet num2 = 25;\nlet num3 = 92;\nlet num4 = 64;\n\n// ADD CODE BELOW HERE","test":"describe('num1', () => {\n  it('should be a number', () => {\n    expect(num1).to.be.a('number');\n  });\n  it('should equal 49', () => {\n    expect(num1).to.equal(49);\n  });\n});\n\ndescribe('num2', () => {\n  it('should be a number', () => {\n    expect(num2).to.be.a('number');\n  });\n  it('should equal 11', () => {\n    expect(num2).to.equal(11);\n  });\n});\n\ndescribe('num3', () => {\n  it('should be a number', () => {\n    expect(num3).to.be.a('number');\n  });\n  it('should equal 1012', () => {\n    expect(num3).to.equal(1012);\n  });\n});\n\ndescribe('num4', () => {\n  it('should be a number', () => {\n    expect(num4).to.be.a('number');\n  });\n  it('should equal 8', () => {\n    expect(num4).to.equal(8);\n  });\n});\n","instructions":[{"instructionHeading":"Assignment Operator","instructionContent":["What if we wanted to increase our value by more than 1 though?  Luckily, there's an operator  for that as well!  We call this an <strong>assignment operator</strong>.",{"codeBlock":"let num = 5;\n\nnum += 10\nconsole.log(num) // => 15"},"Here, we have the syntax of <code>num += 10</code>.  This is the same thing as typing <code> num = num + 10</code>.  By using the addition assignment operator (<code>+=</code>) we are able  to add 10 to <code>num</code> similarly to how we did above with the incrementor/decrementor.","The best part, is we aren't just limited to addition with the assignment operator.  Each  arithmetic operator has its own assignment operator:",{"list":["<code>+=</code> - addition","<code>-=</code> - subtraction","<code>*=</code> - multiplication","<code>/=</code> - division"]}]},{"instructionHeading":"Challenge","instructionContent":["<strong>1.</strong> Using the appropriate assignment operator, reassign the value of  <code>num1</code> to the current value <em>plus</em> 17.","<strong>2.</strong> Using the appropriate assignment operator, reassign the value of  <code>num2</code> to the current value <em>minus</em> 14.","<strong>3.</strong> Using the appropriate assignment operator, reassign the value of  <code>num3</code> to the current value <em>times</em> 11.","<strong>4.</strong> Using the appropriate assignment operator, reassign the value of  <code>num4</code> to the current value <em>divided by</em> 8.","Utilize the <code>console</code> to test your code before you submit it!"]}]}},"challenge-numbers-exponent-modulus":{"subunitId":"challenge-numbers-exponent-modulus","heading":"Challenge: Numbers - Exponents & Remainders","solve":{"code":"// ADD CODE BELOW\n\n\n\n\n\n\n// ADD CONSOLE LOGS BELOW\n","test":"describe('fiveSquared', () => {\n  it('should be of type integer', () => {\n    expect(fiveSquared).to.be.a('number');\n  });\n  it('should be 25', () => {\n    expect(fiveSquared).to.equal(25);\n  });\n});\n\ndescribe('eightCubed', () => {\n  it('should be of type integer', () => {\n    expect(eightCubed).to.be.a('number');\n  });\n  it('should be 512', () => {\n    expect(eightCubed).to.equal(512);\n  });\n});\n\ndescribe('sevenToTheSixth', () => {\n  it('should be of type integer', () => {\n    expect(sevenToTheSixth).to.be.a('number');\n  });\n  it('should be 117649', () => {\n    expect(sevenToTheSixth).to.equal(117649);\n  });\n});\n\ndescribe('eightyThreeModSix', () => {\n  it('should be of type integer', () => {\n    expect(eightyThreeModSix).to.be.a('number');\n  });\n  it('should be 5', () => {\n    expect(eightyThreeModSix).to.equal(5);\n  });\n});\n\ndescribe('sixtyModNine', () => {\n  it('should be of type integer', () => {\n    expect(sixtyModNine).to.be.a('number');\n  });\n  it('should be 6', () => {\n    expect(sixtyModNine).to.equal(6);\n  });\n});\n","instructions":[{"instructionHeading":" ","instructionContent":["Two other really useful arithmetic operators we have access to in Javascript  are the <strong>exponentiation operator</strong> (<code>**</code>) and the  <strong>modulus (remainder) operator</strong> (<code>%</code>).","The <strong>exponentiation operator</strong> (<code>**</code>) raises the first number to  the power of the second number.",{"codeBlock":"2 ** 2 = 4\n2 ** 3 = 8\n2 ** 4 = 16\n4 ** 4 = 256"},"The <strong>modulus (remainder) operator</strong> (<code>%</code>) returns the remainder of  dividing the first number by the second number.",{"codeBlock":"4 % 2 = 0\n4 % 3 = 1\n\n4 % 5 = 4"},"In the first example, we get 0 because 2 divides evenly into 4, so there isn't  a remainder.  In the second, we have a result of 1 since 3 goes into 4 one time and  then leaves us with a remainer of 1.  The last example may seem a little tricky, but  think of of it like this:  5 is larger than 4, so technically it can't go into 4 at  all, so the remainder would be 4.","Maybe you're asking yourself why would you need to use this?  Well one common use is  determining whether a number is even or odd.  Since we know that even numbers are divisible  by 2, then we can then say that if the remainder of dividing any number by 2 = 0, then it is  an even number.  Likewise, if the remainder is 1, then it is odd.",{"codeBlock":"45 % 2 = 1 (45 is odd)\n36 % 2 = 0 (36 is even)"}]},{"instructionHeading":"Challenge","instructionContent":["Now we're gonna take the training wheels off a bit now. This time you're going to have to write  your own tests!  Utilize the space below line 8 to write any <code>console.log</code> statements  that you'd like to use to test your answers.","<strong>1.</strong> Declare a constant <code>fiveSquared</code> and assign it the value  of 5 to the power of 2 using the exponentiation operator.","<strong>2.</strong> Declare a constant <code>eightCubed</code> and assign it the value  of 8 to the power of 3 using the exponentiation operator.","<strong>3.</strong> Declare a constant <code>sevenToTheSixth</code> and assign it the value  of 7 to the power of 6 using the exponentiation operator.","<strong>4.</strong> Declare a constant <code>eightyThreeModSix</code> and assign it remainder  of dividing 83 by 6.","<strong>5.</strong> Declare a constant <code>sixtyModNine</code> and assign it the remainder  of dividing 60 by 9."]}]}},"challenge-numbers-incrementor":{"subunitId":"challenge-numbers-incrementor","heading":"Challenge: Numbers - Incrementor & Decrementor","solve":{"code":"let num1 = 32;\nlet num2 = 44;\n\n// ADD CODE BELOW HERE","test":"describe('num1', () => {\n  it('should be a number', () => {\n    expect(num1).to.be.a('number');\n  });\n  it('should equal 33', () => {\n    expect(num1).to.equal(33);\n  });\n});\n\ndescribe('num2', () => {\n  it('should be a number', () => {\n    expect(num2).to.be.a('number');\n  });\n  it('should equal 43', () => {\n    expect(num2).to.equal(43);\n  });\n});\n","instructions":[{"instructionHeading":"Incrementor / Decrementor","instructionContent":["As programmers, we are constantly updating data. By now you're probably getting  pretty familiar with how to reassign the value of a variable, but here's an example  to refresh your memory.",{"codeBlock":"let num = 7;\n\nnum = num + 1;\nconsole.log(num); // => 8"},"Notice how we use the syntax <code>num = num + 1</code> to change the value of num.  Wouldn't  it be nice if we didn't have to type our variable name in twice?  Luckily, in JavaScript,  we have some really useful built-in operators to help us handle this redundancy.  The first 2  we are going to cover are the <strong>incrementor</strong> (<code>++</code>) and the  <strong>decrementor</strong> (<code>--</code>). Take a look at the example below:",{"codeBlock":"let num = 10;\n\nnum++\nconsole.log(num) // => 11"},"In the above example, just by using <code>num++</code> we were able to increment the value  of <code>num</code> by 1.  Likewise, if we wanted to decrement the value by one, we could use  <code>num--</code>.  These operators are extremely useful, and you'll be using them quite a  lot in Precourse - Part 2 when we dive into loops."]},{"instructionHeading":"Challenge","instructionContent":["<strong>1.</strong> Using the <code>incrementor</code> operator, increase the value of  <code>num1</code> by 1.","<strong>2.</strong> Using the <code>decrementor</code> operator, decrease the value of  <code>num2</code> by 1."]}]}},"challenge-numbers-multiplication-division":{"subunitId":"challenge-numbers-multiplication-division","heading":"Challenge: Numbers - Multiplication/Division","solve":{"code":"// ADD CODE BELOW\n\n\n// Uncomment these to check your work!\n// console.log(twentyTimesFour);\n// console.log(nineOverThree);\n// console.log(twoHundredTimesThree);","test":"describe('twentyTimesFour', () => {\n  it('should be of type integer', () => {\n    expect(twentyTimesFour).to.be.a('number');\n  });\n  it('should be 80', () => {\n    expect(twentyTimesFour).to.equal(80);\n  });\n});\n\ndescribe('nineOverThree', () => {\n  it('should be of type integer', () => {\n    expect(nineOverThree).to.be.a('number');\n  });\n  it('should be 3', () => {\n    expect(nineOverThree).to.equal(3);\n  });\n});\n\ndescribe('twoHundredTimesThree', () => {\n  it('should be 600.9000000000001', () => {\n    expect(twoHundredTimesThree).to.equal(600.9000000000001);\n  });\n});\n","instructions":[{"instructionHeading":" ","instructionContent":["Numbers can also be multiplied and divided using the multiplication (<code>*</code>) and division (<code>/</code>) operators.",{"codeBlock":"console.log(6 * 5); // => 30\nconsole.log(45 / 5); // => 9"}]},{"instructionHeading":"Challenge","instructionContent":["Perform the following multiplication/division operations in the code editor:","1. Multiply 20 by 4 and save the result to a variable called <code>twentyTimesFour</code>","2. Divide 9 by 3 and save the result to a variable called <code>nineOverThree</code>","3. Multiply 200.3 * 3 and save the result to a variable called <code>twoHundredTimesThree</code>"]},{"instructionHeading":"Floats","instructionContent":["Any number with the decimal point is a <code>float</code>. Notice that in the last exercise you multiplied 200.3 by 3 and the output from that was 600.9000000000001. What happened here? Why didn't we get 600.9?","The way floats are handled in JavaScript can cause these rounding errors. Some decimal numbers cannot be represented accurately. The reason has to do with how numbers are encoded in JavaScript. It's something to be aware of when working with decimal numbers in JavaScript.","If you'd like to read more into the intricacies of <code>float</code>,  click <a href=\"https://en.wikipedia.org/wiki/Floating-point_arithmetic#Accuracy_problems\" target=\"_blank\"> here</a>."]}]}},"challenge-obj-of-matches":{"subunitId":"challenge-obj-of-matches","heading":"Challenge: objOfMatches","solve":{"code":"// ADD CODE HERE\n\n// Uncomment these to check your work!\n// const arr1 = ['hi', 'howdy', 'bye', 'later', 'hello'];\n// const arr2 = ['HI', 'Howdy', 'BYE', 'later', 'HELLO'];\n// function uppercaser(str) { return str.toUpperCase(); }\n// console.log(objOfMatches(arr1, arr2, uppercaser)); // should log: { hi: 'HI', bye: 'BYE', hello: 'HELLO' }\n","test":"describe('objOfMatches', () => {\n  const uppercaser = (str) => str.toUpperCase();\n  it('should be a function', () => {\n    expect(objOfMatches).to.be.a('function');\n  });\n  it('should return an object', () => {\n    const answer = objOfMatches([], [], uppercaser);\n    expect(answer).to.eql({});\n  });\n  it('should set keys of the returned object to array 1 items that match array 2 items when run through the callback function', () => {\n    const answer = objOfMatches(['puppy', 'cat', 'pony'], ['DOG', 'CAT', 'pony'], uppercaser);\n    expect(answer).to.eql({ cat: 'CAT' });\n  });\n});\n","instructions":[{"instructionContent":["Construct a function <code>objOfMatches</code> that accepts two arrays and a callback. <code>objOfMatches</code> will build an object and return it. To build the object, <code>objOfMatches</code> will test each element of the first array using the callback to see if the output matches the corresponding element (by index) of the second array. If there is a match, the element from the first array becomes a key in an object, and the element from the second array becomes the corresponding value."]}]}},"challenge-objects-adding-properties":{"subunitId":"challenge-objects-adding-properties","heading":"Challenge: Objects - Adding Properties","solve":{"code":"const possibleIterable = [4, 3, 9, 6, 23];\nconst divByThree = {};\n// ADD CODE HERE\n","test":"describe('divByThree', () => {\n  it('should contain keys from possibleIterable', () => {\n    expect(divByThree).to.include.keys('3', '6', '9');\n  });\n\n  it('should exclude keys that are not divisible by three', () => {\n    expect(divByThree).to.not.have.any.keys('4', '23');\n  });\n\n  it('should deep equal { 3: 1, 6: 3, 9: 2 }', () => {\n    expect(divByThree).to.eql({ 3: 1, 6: 3, 9: 2 });\n  });\n});\n","instructions":[{"instructionHeading":" ","instructionContent":["You are provided with an array, <code>possibleIterable</code>. Using a for loop, build out the object <code>divByThree</code> so that each key is an element of <code>possibleIterable</code> that is divisible by three. The value of each key should be the array index at which that key can be found in <code>possibleIterable</code>."]}]}},"challenge-objects-evaluating-keys":{"subunitId":"challenge-objects-evaluating-keys","heading":"Challenge: Objects - Evaluating Keys","solve":{"code":"const sumMe = {\n  hello: 'there',\n  you: 8,\n  are: 7,\n  almost: '10',\n  done: '!'\n};\nlet total = 0;\n// ADD CODE HERE\n","test":"describe('total', () => {\n  it('should be a number', () => {\n    expect(typeof total).to.equal('number');\n  });\n});\n\ndescribe('total', () => {\n  it('should equal 15', () => {\n    expect(total).to.eql(15);\n  });\n});\n","instructions":[{"instructionHeading":" ","instructionContent":["You are given an object called <code>sumMe</code> containing several key/value pairs and a variable called <code>total</code> whose initial value is 0. Using a <code>for... in loop</code>, iterate through the keys of <code>sumMe</code>; if the value corresponding to a key is a number, add it to <code>total</code>."]}]}},"challenge-objects-examining-properties":{"subunitId":"challenge-objects-examining-properties","heading":"Challenge: Objects - Examining Properties","solve":{"code":"const checkObj = {\n  oddNum: 1,\n  evenNum: 2,\n  foundNum: 5,\n  randomNum: 18\n};\n\nlet found = 0;\n// ADD CODE HERE","test":"describe('found', () => {\n  it('should be 1', () => {\n    expect(found).to.eq(1);\n  });\n});\n\ndescribe('found', () => {\n  it('should be a number', () => {\n    expect(typeof found).to.eq('number');\n  });\n});\n","instructions":[{"instructionHeading":" ","instructionContent":["Objects are data structures used to store related data represented with <code>keys</code> and associated <code>values</code>.  Keys are also referred to as <code>properties</code>.  Keys give us an easy way to reference the values, so they are almost always descriptive strings.   Values can be any valid data type: a number, string, array, even other objects that contain even more objects!","We can iterate through an object's properties in much the same way we iterate through the elements of an array, though the implementation is a bit different.  Research <code>for... in</code> and <code>Object.keys</code> before continuing with these challenges."]},{"instructionHeading":"Challenge","instructionContent":["You are provided with an object called <code>checkObj</code>. Using a <code>for... in</code> loop, determine if the object contains the property <code>foundNum</code>. If it exists, reassign the value of <code>found</code> to 1."]}]}},"challenge-objects-iterating-with-for-in":{"subunitId":"challenge-objects-iterating-with-for-in","heading":"Challenge: Objects - Iterating with for... in","solve":{"code":"const checkObj = {\n  oddNum: 1,\n  evenNum: 2,\n  foundNum: 5,\n  randomNum: 18\n};\n\nconst objToArray = [];\n// ADD CODE HERE","test":"describe('objToArray', () => {\n  it('should contain three elements', () => {\n    expect(objToArray.length).to.equal(3);\n  });\n});\n\ndescribe('objToArray', () => {\n  it('should equal [2, 5, 18]', () => {\n    expect(objToArray).to.eql([2, 5, 18]);\n  });\n});\n\ndescribe('checkObj', () => {\n  it('should not be modified', () => {\n    expect(checkObj).to.eql({\n      oddNum: 1,\n      evenNum: 2,\n      foundNum: 5,\n      randomNum: 18,\n    });\n  });\n});\n","instructions":[{"instructionHeading":" ","instructionContent":["You are provided with an empty array called <code>objToArray</code>. Using a <code>for... in</code> loop, fill the array with all of the numbers from the <code>checkObj</code> object if they are greater than or equal to 2."]}]}},"challenge-objects-iterating-with-for-loop":{"subunitId":"challenge-objects-iterating-with-for-loop","heading":"Challenge: Objects - Iterating with a for loop","solve":{"code":"const checkObj = {\n  oddNum: 1,\n  evenNum: 2,\n  foundNum: 5,\n  randomNum: 18\n};\n\nlet divBy6 = false;\n// ADD CODE HERE\n","test":"describe('objToArray', () => {\n  it('should equal [1, 2, 5, 18]', () => {\n    expect(objToArray).to.deep.equal([1, 2, 5, 18]);\n  });\n});\n\ndescribe('divBy6', () => {\n  it('should be true', () => {\n    expect(divBy6).to.eq(true);\n  });\n});\n","instructions":[{"instructionHeading":" ","instructionContent":["This time, use the <a href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/values\">Object.values()</a> method to return an array of <code>checkObj</code>'s values, and assign this array to a constant called <code>objToArray</code>. Next, use a for loop to iterate through <code>objToArray</code> and determine if any of the numbers are divisible by 6. If so, reassign the value of <code>divBy6</code> to true."]}]}},"challenge-objects-nested-arrays":{"subunitId":"challenge-objects-nested-arrays","heading":"Challenge: Objects - Nested Arrays","solve":{"code":"const nestedArr = [];\n// ADD CODE HERE\n","test":"describe('nestedArr', () => {\n  it('should be an array', () => {\n    expect(Array.isArray(nestedArr)).equal(true);\n  });\n\n  it('should contain five elements', () => {\n    expect(nestedArr.length).to.equal(5);\n  });\n\n  it('should contain the specified nested subarrays', () => {\n    expect(nestedArr).to.deep.include(['loop0', 0]);\n    expect(nestedArr).to.deep.include(['loop1', 1]);\n    expect(nestedArr).to.deep.include(['loop2', 2]);\n    expect(nestedArr).to.deep.include(['loop3', 3]);\n    expect(nestedArr).to.deep.include(['loop4', 4]);\n  });\n});\n","instructions":[{"instructionHeading":" ","instructionContent":["You are provided with an empty array called <code>nestedArr</code>. Using a for loop starting at index 0, add 5 subarrays to <code>nestedArr</code>, with each nested array containing the string 'loop' concatenated with the corresponding index in <code>nestedArr</code> as its first element, and the index as its second element.","Example of a subarray: <code>['loop3', 3]</code>."]}]}},"challenge-once":{"subunitId":"challenge-once","heading":"Challenge: once","solve":{"code":"// ADD CODE HERE\n\nconst addByTwoOnce = once(function(num) {\n  return num + 2;\n});\n\n// UNCOMMENT THESE TO TEST YOUR WORK!\n// console.log(addByTwoOnce(5));  //should log 7\n// console.log(addByTwoOnce(10));  //should log 7\n// console.log(addByTwoOnce(9001));  //should log 7","test":"describe('once', () => {\n  it('should create and return a function', () => {\n    const addByOne = once(function (num) {\n      return num + 1;\n    });\n    expect(addByOne).to.be.a('function');\n  });\n});\n\ndescribe('A function returned from once', () => {\n  const addByTwoOnce = once(function (num) {\n    return num + 2;\n  });\n  const addByThreeOnce = once(function (num) {\n    return num + 3;\n  });\n\n  it(' should run the callback the first time it is called', () => {\n    expect(addByTwoOnce(0)).to.equal(2);\n    expect(addByThreeOnce(9)).to.equal(12);\n  });\n  it('should return the output of the first call on subsequent calls', () => {\n    expect(addByTwoOnce(1)).to.equal(2);\n    expect(addByTwoOnce(2)).to.equal(2);\n    expect(addByThreeOnce(10)).to.equal(12);\n  });\n});\n","instructions":[{"instructionContent":["Write a function <code>once</code> that accepts a callback as input and returns a function. When the returned function is called the first time, it should call the callback and return that output. If it is called any additional times, instead of calling the callback again it will simply return the output value from the first time it was called."]}]}},"challenge-passing-arguments":{"subunitId":"challenge-passing-arguments","heading":"Challenge: Passing Arguments","solve":{"code":"const x = 3;\n\nfunction isX1(num) {\n    const x = 5;\n    return num === x;\n}\n\nfunction isX2(num) {\n    return num === x;\n}\n\nconst one = isX1(/* ADD CODE HERE */);\nconst two = isX2(/* ADD CODE HERE */);\n\n// Uncomment these to check your work!\n// console.log(one); // should log: true\n// console.log(two); // should log: true\n","test":"describe('one', () => {\n  it('should have the value true', () => {\n    expect(one).to.be.true;\n  });\n});\n\ndescribe('two', () => {\n  it('should have the value true', () => {\n    expect(two).to.be.true;\n  });\n});\n","instructions":[{"instructionContent":["Examine the code given to you. Determine what arguments must be passed into <code>isX1</code> and <code>isX2</code> respectively to obtain an output of true for both, and pass in the arguments accordingly."]}]}},"challenge-person-class":{"subunitId":"challenge-person-class","heading":"Challenge: PersonClass","solve":{"code":"class PersonClass {\n\tconstructor() {\n    // add code here\n\n\n\t}\n\n\t// add code here\n\n}\n\nconst george = new PersonClass('George');\n\n// Uncomment this line to check your work!\n// george.greet(); // -> Logs 'hello'\n","test":"describe('PersonClass', () => {\n  it('should have a constructor that accepts a name argument', () => {\n    expect(PersonClass.constructor).to.be.a('function');\n    expect(PersonClass.constructor.length).to.equal(1);\n  });\n  it('- returned object should have a name property', () => {\n    const george = new PersonClass('George');\n    expect(george).to.have.own.property('name', 'George');\n  });\n  it('- returned object should have a greet method that logs \"hello\"', () => {\n    const george = new PersonClass('George');\n    expect(george.greet).to.be.a('function');\n    let log;\n    (function () {\n      const oldConsoleLog = console.log;\n      console.log = function (input) {\n        log = input;\n      };\n      george.greet();\n      console.log = oldConsoleLog;\n    })();\n    expect(log).to.equal('hello');\n  });\n});\n","instructions":[{"instructionContent":["Create a class <code>PersonClass</code>. <code>PersonClass</code> should have a constructor that is passed an input of <code>name</code> and saves it to a property by the same name. <code>PersonClass</code> should also have a method called <code>greet</code> that logs the string \"hello\"."]}]}},"challenge-person-constructor":{"subunitId":"challenge-person-constructor","heading":"Challenge: PersonConstructor","solve":{"code":"function PersonConstructor() {\n\t// add code here\n\n\n}\n\nconst simon = new PersonConstructor();\n\n// Uncomment this line to check your work!\n// simon.greet(); // -> Logs 'hello'","test":"describe('PersonConstructor', () => {\n  it('- created object has PersonConstructor as constructor', () => {\n    const simon = new PersonConstructor();\n    expect(simon.constructor).to.equal(PersonConstructor);\n  });\n  it('- created object has a greet method', () => {\n    const simon = new PersonConstructor();\n    expect(simon.greet).to.be.a('function');\n    let log;\n    (function () {\n      const oldConsoleLog = console.log;\n      console.log = function (input) {\n        log = input;\n      };\n      simon.greet();\n      console.log = oldConsoleLog;\n    })();\n    expect(log).to.equal('hello');\n  });\n});\n","instructions":[{"instructionContent":["Create a function <code>PersonConstructor</code> that uses the <code>this</code> keyword to save a single property onto its scope called <code>greet</code>. <code>greet</code> should be a function that logs the string \"hello\"."]}]}},"challenge-person-from-constructor":{"subunitId":"challenge-person-from-constructor","heading":"Challenge: personFromConstructor","solve":{"code":"function PersonConstructor() {\n  this.greet = function() {\n    console.log('hello');\n  }\n}\n\nfunction personFromConstructor(name, age) {\n\t// add code here\n\n\n}\n\nconst mike = personFromConstructor('Mike', 30);\n\n// Uncomment these lines to check your work!\n// console.log(mike.name); // -> Logs 'Mike'\n// console.log(mike.age); // -> Logs 30\n// mike.greet(); // -> Logs 'hello'","test":"describe('PersonConstructor', () => {\n  it('- personFromConstructor should invoke PersonConstructor', () => {\n    let calledFlag = false;\n    (function () {\n      const oldPersonConstructor = PersonConstructor;\n      PersonConstructor = function () {\n        calledFlag = true;\n        return new oldPersonConstructor();\n      };\n      personFromConstructor('Mike', 30);\n      PersonConstructor = oldPersonConstructor;\n    })();\n    expect(calledFlag).to.equal(true);\n  });\n  const mike = personFromConstructor('Mike', 30);\n  it('- created object has name and age properties', () => {\n    expect(mike).to.have.own.property('age', 30);\n    expect(mike).to.have.own.property('name', 'Mike');\n  });\n  it('- created object has greet method', () => {\n    expect(mike).to.have.own.property('greet');\n    expect(mike.greet).to.be.a('function');\n  });\n});\n","instructions":[{"instructionContent":["Create a function <code>personFromConstructor</code> that takes as input a <code>name</code> and an <code>age</code>. When called, the function will create person objects using the <code>new</code> keyword instead of the <code>Object.create</code> method."]}]}},"challenge-person-from-person-store":{"subunitId":"challenge-person-from-person-store","heading":"Challenge: personFromPersonStore","solve":{"code":"const personStore = {\n  greet: function() {\n    console.log('hello');\n  }\n}\n\nfunction personFromPersonStore(name, age) {\n\t// add code here\n\n\n}\n\nconst sandra = personFromPersonStore('Sandra', 26);\n\n// Uncomment these lines to check your work!\n// console.log(sandra.name); // -> Logs 'Sandra'\n// console.log(sandra.age); // -> Logs 26\n// sandra.greet(); // -> Logs 'hello'","test":"describe('personStore -', () => {\n  it('returned object should have a name property', () => {\n    expect(personFromPersonStore('Sandra', 26)).to.have.own.property('name', 'Sandra');\n  });\n  it('returned object should have an age property', () => {\n    expect(personFromPersonStore('Sandra', 26)).to.have.own.property('age', 26);\n  });\n  it('should use Object.create', () => {\n    let calledFlag = false;\n    (function () {\n      const oldObjectCreate = Object.create;\n      Object.create = function (proto, propsObj) {\n        calledFlag = true;\n        return oldObjectCreate(proto, propsObj);\n      };\n      personFromPersonStore('Sandra', 26);\n      Object.create = oldObjectCreate;\n    })();\n    expect(calledFlag).to.equal(true);\n  });\n});\n","instructions":[{"instructionContent":["Create a function <code>personFromPersonStore</code> that takes as input a <code>name</code> and an <code>age</code>. When called, the function will create person objects using the <code>Object.create</code> method on the <code>personStore</code> object."]}]}},"challenge-person-store":{"subunitId":"challenge-person-store","heading":"Challenge: personStore","solve":{"code":"const personStore = {\n\t// add code here\n\n\n};\n\n// Uncomment this line to check your work!\n// personStore.greet(); // -> Logs 'hello'","test":"describe('personStore', () => {\n  it('- personStore.greet should be a function', () => {\n    expect(personStore.greet).to.be.a('function');\n  });\n  it('- personStore.greet should log \"hello\"', () => {\n    let log;\n    (function () {\n      const oldConsoleLog = console.log;\n      console.log = function (input) {\n        log = input;\n      };\n      personStore.greet();\n      console.log = oldConsoleLog;\n    })();\n    expect(log).to.equal('hello');\n  });\n});\n","instructions":[{"instructionContent":["Inside <code>personStore</code> object, create a property <code>greet</code> where the value is a function that logs \"hello\"."]}]}},"challenge-pluralize":{"subunitId":"challenge-pluralize","heading":"Challenge: pluralize","solve":{"code":"// ADD CODE HERE\n\n// Uncomment these to check your work!\n// const animals = [\"dog\", \"cat\", \"tree frog\"];\n// console.log(pluralize(animals)); // should log: [\"dogs\", \"cats\", \"tree frogs\"]","test":"describe('pluralize', () => {\n  it('should be a function', () => {\n    expect(pluralize).to.be.a('function');\n  });\n\n  it('should return an empty array when called with an empty array', () => {\n    let nothing = [];\n    expect(pluralize(nothing)).to.eql([]);\n  });\n\n  it('should not mutate the input array', () => {\n    let animalsIn = ['dog', 'cat', 'tree frog'];\n    pluralize(animalsIn);\n    expect(animalsIn).to.eql(['dog', 'cat', 'tree frog']);\n  });\n\n  it('should pluralize the strings in the input array', () => {\n    let moreAnimals = ['sparrow', 'cheetah', 'penguin'];\n    let evenMoreAnimals = ['ant', 'sea lion'];\n    expect(pluralize(moreAnimals)).to.eql(['sparrows', 'cheetahs', 'penguins']);\n    expect(pluralize(evenMoreAnimals)).to.eql(['ants', 'sea lions']);\n  });\n});\n","instructions":[{"instructionContent":["Create a function <code>pluralize</code> that takes an array of strings as input and returns a new array with an \"s\" added to the end of each string in the input array. For example, if the string \"carrot\" is in the input array, it should become the string \"carrots\" in the output array.","The body of the <code>pluralize</code> function should employ a single for loop that pluralizes each string in the input array."]}]}},"challenge-pow":{"subunitId":"challenge-pow","heading":"Challenge: POW","solve":{"code":"function pow(base, exponent) {\r\n\r\n}\r\n\r\n// To check if you've completed the challenge, uncomment these console.logs!\r\n// console.log(pow(2, 4)); // -> 16\r\n// console.log(pow(3, 5)); // -> 243","test":"describe('pow', () => {\n  it('should be a function', () => {\n    expect(pow).to.be.a('function');\n  });\n});\n\ndescribe('pow(2, 4)', () => {\n  it('should return 16', () => {\n    expect(pow(2, 4)).to.eq(16);\n  });\n});\n\ndescribe('pow(3, 5)', () => {\n  it('should return 243', () => {\n    expect(pow(3, 5)).to.eq(243);\n  });\n});\n","instructions":[{"instructionContent":["Write a function that takes two inputs, a base and an exponent, and returns the expected value of base ^ exponent. For instance, if our base is 2 and our exponent is 3, then return 8 because 2^3 = 2*2*2 = 8.",{"codeBlock":"Input 1: {Number} base - base number raised to the exponent\nInput 2: {Number} exponent - exponent the base is raised to\nOutput: {Number} - expected value of base raised to exponent\n"}]}]}},"challenge-prioritize":{"subunitId":"challenge-prioritize","heading":"Challenge: prioritize","solve":{"code":"// ADD CODE HERE\n\n// Uncomment these to check your work!\n// function startsWithS(str) { return str[0].toLowerCase() === 's'; }\n// const tvShows = ['curb', 'rickandmorty', 'seinfeld', 'sunny', 'friends']\n// console.log(prioritize(tvShows, startsWithS)); // should log: ['seinfeld', 'sunny', 'curb', 'rickandmorty', 'friends']","test":"describe('prioritize', () => {\n  const isEven = (n) => n % 2 === 0;\n  var nums = [1, 2, 3, 4, 5, 6];\n  if (typeof prioritize === 'function') var answer = prioritize(nums, isEven);\n\n  it('should be a function', () => {\n    expect(prioritize).to.be.a('function');\n  });\n  it('should return an array', () => {\n    expect(prioritize([], () => {})).to.be.an('array');\n  });\n  it('should not mutate the original array', () => {\n    expect(nums).to.eql([1, 2, 3, 4, 5, 6]);\n  });\n  it('should return an array that is reordered based on results of calling the callback function with each item', () => {\n    expect(answer).to.eql([2, 4, 6, 1, 3, 5]);\n  });\n});\n","instructions":[{"instructionContent":["Create a function <code>prioritize</code> that accepts an array and a callback. The callback will return either <code>true</code> or <code>false</code>. <code>prioritize</code> will iterate through the array and perform the callback on each element, and return a new array, where all the elements that yielded a return value of <code>true</code>  come first in the array, and the rest of the elements come second."]}]}},"challenge-reduce":{"subunitId":"challenge-reduce","heading":"Challenge: reduce","solve":{"code":"// ADD CODE HERE\n\n// Uncomment these to check your work!\n// const nums = [4, 1, 3];\n// const add = function(a, b) { return a + b; }\n// console.log(reduce(nums, add, 0)); // should log 8","test":"describe('reduce', () => {\n  const add = (a, b) => a + b;\n  const getTotals = (a, b) => {\n    a[b] ? a[b]++ : (a[b] = 1);\n    return a;\n  };\n  it('should be a function', () => {\n    expect(reduce).to.be.a('function');\n  });\n  it('should not mutate the input array', () => {\n    let nums = [1, 2, 3];\n    reduce(nums, add, 0);\n    expect(nums).to.eql([1, 2, 3]);\n  });\n  it('should sum up an array', () => {\n    const answer = reduce([1, 2, 3], add, 0);\n    expect(answer).to.eql(6);\n  });\n  it('should create a \"totals\" object from an array', () => {\n    const answer = reduce(['a', 'b', 'c', 'a', 'b'], getTotals, {});\n    expect(answer).to.eql({ a: 2, b: 2, c: 1 });\n  });\n});\n","instructions":[{"instructionContent":["The function <code>reduce</code> takes an array and reduces the elements to a single value.","The <code>reduce</code> function loops through the array and applies <em>any operation</em> that you can put into a function to each element in the array while keeping track of the outcome of each loop.  In this way, we could use <code>reduce</code> to do things like sum all the numbers in an array or multiply them all together.",{"codeBlock":"const nums = [4, 1, 3];\nconst add = function(a, b) { return a + b; }\nreduce(nums, add, 0); //-> 8"},"Here's how it works:",{"orderedList":["The function has an \"accumulator value\".  Its job is to keep track of the accumulated output of each loop.  It starts out equal to the initialValue.","The array is iterated over, passing the <strong>accumulator</strong> and the <strong>next array element</strong> as arguments to the callback, and in that order.","The callback's return value becomes the new accumulator value.","The next loop executes with this new accumulator value."]},"In the example above, the accumulator begins at 0. <code>add(0,4)</code> is called. The accumulator's value is now 4. Then <code>add(4, 1)</code> makes it 5. Finally <code>add(5, 3)</code> brings it to 8, which is returned.","Construct your own reduce function that accepts an array, a callback, and an initial value and returns a single value."]}]}},"challenge-repeater":{"subunitId":"challenge-repeater","heading":"Challenge: Repeater","solve":{"code":"console.log('Hello, world!');\r\n\r\nfunction repeater(char) {\r\n\r\n}\r\n\r\n// To check if you've completed the challenge, uncomment these console.logs!\r\n// console.log(repeater('g'));\r\n// console.log(repeater('j'));\r\n\r\n","test":"describe('repeater', () => {\n  it('should be a function', () => {\n    expect(repeater).to.be.a('function');\n  });\n});\n\ndescribe('repeater(g)', () => {\n  it('should return ggggg', () => {\n    expect(repeater('g')).to.eq('ggggg');\n  });\n});\n\ndescribe('repeater(j)', () => {\n  it('should return jjjjj', () => {\n    expect(repeater('j')).to.eq('jjjjj');\n  });\n});\n","instructions":[{"instructionContent":["Write a function that takes an input character and returns that character repeated 5 times using recursion. For example, if the input is 'g', then the output should be 'ggggg'.",{"codeBlock":"Input: {String} char\nOutput: {String}"}]}]}},"challenge-run-in-order":{"subunitId":"challenge-run-in-order","heading":"Challenge: runInOrder","solve":{"code":"// Add code here\n\n// /* Uncomment the following lines and click 'run' to test your work */\n\n// function sayHi() {\n//   console.log('hi');\n// }\n// function sayBye() {\n//   console.log('bye');\n// }\n// function sayHowdy() {\n//   console.log('howdy');\n// }\n\n// runInOrder([sayHi, sayBye, sayHowdy], [200, 100, 300]);\n\n/*\nshould log:\n'hi' (after 200 ms)\n'bye' (100 ms after 'hi')\n'howdy' (300 ms after 'bye')\n*/\n","test":"const { oldConsoleLog, logged } = reDefineConsoleLog((arg) => {\n  logged.push(arg);\n});\n\ndescribe('runInOrder', () => {\n  it('should be a function', () => {\n    expect(runInOrder).to.be.a('function');\n  });\n});\n\ndescribe('runInOrder', () => {\n  it('should log in correct order', (done) => {\n    delay(800, logged)\n      .then((resolved) => {\n        expect(resolved).to.eql(['hi', 'bye', 'howdy']);\n        console.log = oldConsoleLog;\n      })\n      .then(done, done);\n  });\n});\n\n//resolve promise after ms milleseconds\nfunction delay(ms, logged) {\n  return new Promise((resolve) => {\n    setTimeout(() => resolve(logged), ms);\n  });\n}\n\n// logged will contain all arguments passed into console.log\nfunction reDefineConsoleLog(newConsoleLog, logged = []) {\n  const oldConsoleLog = console.log;\n  console.log = newConsoleLog;\n  return { oldConsoleLog, logged };\n}\n","instructions":[{"instructionContent":["Write a function called <code>runInOrder</code> that accepts as arguments in this order -",{"list":["an array of functions","an array of numbers representing times in milliseconds"]},"<code>runInOrder</code> should execute the functions in order, with the corresponding numbers in milliseconds being the time to wait from the previous invocation. For example -",{"codeBlock":"function sayHi() {\n  console.log('hi');\n}\nfunction sayBye() {\n  console.log('bye');\n}\nfunction sayHowdy() {\n  console.log('howdy');\n}\n\nrunInOrder([sayHi, sayBye, sayHowdy], [300, 600, 200]);\n/*\nshould log:\n'hi' (after 300 ms)\n'bye' (600 ms after 'hi')\n'howdy' (200 ms after 'bye')\n*/"}]}]}},"challenge-save-output":{"subunitId":"challenge-save-output","heading":"Challenge: saveOutput","solve":{"code":"// ADD CODE HERE\n\n// Uncomment these to check your work!\n// const multiplyBy2 = function(num) { return num * 2; };\n// const multBy2AndLog = saveOutput(multiplyBy2, 'boo');\n// console.log(multBy2AndLog(2)); // should log: 4\n// console.log(multBy2AndLog(9)); // should log: 18\n// console.log(multBy2AndLog('boo')); // should log: { 2: 4, 9: 18 }","test":"describe('saveOutput', () => {\n  it('should create and return a function', () => {\n    const saveOutputFunc = saveOutput((input) => input, 'magic word');\n    expect(saveOutputFunc).to.be.a('function');\n  });\n});\n\ndescribe('The function returned from saveOutput', () => {\n  const multiplyBy2 = (num) => num * 2;\n  const multBy2AndLog = saveOutput(multiplyBy2, 'magical');\n\n  it('should behave exactly like the passed-in function when not called with the password string', () => {\n    expect(multBy2AndLog(2)).to.equal(4);\n    expect(multBy2AndLog(9)).to.equal(18);\n  });\n\n  it('should return an object with all previously passed-in arguments and outputs when called with the password string', () => {\n    expect(multBy2AndLog('magical')).to.deep.equal({ 2: 4, 9: 18 });\n  });\n});\n","instructions":[{"instructionContent":["Create a function <code>saveOutput</code> that accepts a function (that will accept one argument), and a string (that will act as a password). <code>saveOutput</code> will then return a function that behaves exactly like the passed-in function, except for when the password string is passed in as an argument. When this happens, the returned function will return an object with all previously passed-in arguments as keys, and the corresponding outputs as values"]}]}},"challenge-say-hello":{"subunitId":"challenge-say-hello","heading":"Challenge: sayHello","solve":{"code":"// ADD CODE HERE\n\n// Uncomment these to check your work!\n// console.log(sayHello('Mary')); // should log: 'Hi, Mary'\n// console.log(sayHello('Haley')); // should log: 'Hi, Haley'","test":"describe('sayHello', () => {\n  it('should be a function', () => {\n    expect(sayHello).to.be.a('function');\n  });\n});\n\ndescribe(\"sayHello('Mary')\", () => {\n  it(\"should return 'Hi, Mary'\", () => {\n    expect(sayHello('Mary')).to.eq('Hi, Mary');\n  });\n});\n\ndescribe(\"sayHello('Haley')\", () => {\n  it(\"should return 'Hi, Haley'\", () => {\n    expect(sayHello('Haley')).to.eq('Hi, Haley');\n  });\n});\n","instructions":[{"instructionContent":["Create a function <code>sayHello</code> that accepts a string argument and returns the string 'Hi, ' with the passed-in string added to the end."]}]}},"challenge-scoping":{"subunitId":"challenge-scoping","heading":"Challenge: Scoping","solve":{"code":"function outer() {\n  let counter = 0; // this variable is outside incrementCounter's scope\n  function incrementCounter() {\n    counter++;\n    console.log('counter', counter);\n  }\n  return incrementCounter;\n}\n\nconst willCounter = outer();\nconst jasCounter = outer();\n\n// Uncomment each of these lines one by one.\n// Before your do, guess what will be logged from each function call.\n\n// willCounter();\n// willCounter();\n// willCounter();\n\n// jasCounter();\n// willCounter();","instructions":[{"instructionContent":["Examine the code for the outer function. Notice that we are returning a function and that function is using variables that are outside of its scope. Uncomment those lines of code. Try to deduce the output before executing."]}]}},"challenge-set-timeout":{"subunitId":"challenge-set-timeout","heading":"Challenge: setTimeout","solve":{"code":"// Add code here","test":"const { oldConsoleLog, logged } = reDefineConsoleLog((arg) => {\n  logged.push(arg);\n});\n\ndescribe('setTimeout', () => {\n  it('should log \"I am in the setTimeout callback function\"', (done) => {\n    delay(700, logged)\n      .then((resolved) => {\n        expect(resolved[0]).to.eq('I am in the setTimeout callback function');\n        console.log = oldConsoleLog;\n      })\n      .then(done, done);\n  });\n});\n\n//resolve promise after ms milleseconds\nfunction delay(ms, logged) {\n  return new Promise((resolve) => {\n    setTimeout(() => resolve(logged), ms);\n  });\n}\n\n// logged will contain all arguments passed into console.log\nfunction reDefineConsoleLog(newConsoleLog, logged = []) {\n  const oldConsoleLog = console.log;\n  console.log = newConsoleLog;\n  return { oldConsoleLog, logged };\n}\n","instructions":[{"instructionContent":["Write code that will log to the console, 'I am at the beginning of the code'.","Beneath that console log, set a timer (see <code>setTimeout</code>) that will log to the console 'I am in the <code>setTimeout</code> callback function' after 600 ms.","Next, add code to the end of the challenge to log 'I am at the end of the code'. Now re-run the code.","Make sure the 'console' and 'output' panes are showing (click the tabs above if not) and then run your code with the 'run' button.","Clear the console. Change the delay time in the time from 600 ms to 0. Think hard about how the order should change and then run the code again."]}]}},"challenge-shuffle-cards":{"subunitId":"challenge-shuffle-cards","heading":"Challenge: shuffleCards","solve":{"code":"function shuffleCards(topHalf, bottomHalf) {\n  // YOUR CODE HERE\n}\n\n\n\n// UNCOMMENT TO TEST YOUR WORK\n// const topHalf = ['Queen of Diamonds', 'Five of Hearts', 'Ace of Spades', 'Eight of Clubs'];\n// const bottomHalf = ['Jack of Hearts', 'Ten of Spades'];\n// console.log(shuffleCards(topHalf, bottomHalf));\n//   /*-> ['Queen of Diamonds',\n//         'Jack of Hearts',\n//         'Five of Hearts',\n//         'Ten of Spades',\n//         'Ace of Spades',\n//         'Eight of Clubs',\n//       ]\n//   */","test":"describe('shuffleCards', () => {\n  const topHalfShort = ['Queen of Diamonds', 'Five of Hearts'];\n  const bottomHalfShort = ['Jack of Hearts', 'Ten of Spades'];\n\n  const topHalfLong = ['Queen of Diamonds', 'Five of Hearts', 'Ace of Spades', 'Eight of Clubs'];\n  const bottomHalfLong = ['Jack of Hearts', 'Ten of Spades', 'Four of Diamonds', 'Four of Hearts'];\n\n  it('should return an array', () => {\n    const deck = shuffleCards(topHalfShort, bottomHalfShort);\n    expect(Array.isArray(deck)).to.eq(true);\n  });\n\n  it('should interleave elements in the correct order', () => {\n    expect(shuffleCards(topHalfShort, bottomHalfShort)).to.eql([\n      'Queen of Diamonds',\n      'Jack of Hearts',\n      'Five of Hearts',\n      'Ten of Spades',\n    ]);\n  });\n\n  it('should append remaining elements to end of the array', () => {\n    expect(shuffleCards(topHalfLong, bottomHalfShort)).to.eql([\n      'Queen of Diamonds',\n      'Jack of Hearts',\n      'Five of Hearts',\n      'Ten of Spades',\n      'Ace of Spades',\n      'Eight of Clubs',\n    ]);\n    expect(shuffleCards(topHalfShort, bottomHalfLong)).to.eql([\n      'Queen of Diamonds',\n      'Jack of Hearts',\n      'Five of Hearts',\n      'Ten of Spades',\n      'Four of Diamonds',\n      'Four of Hearts',\n    ]);\n  });\n});\n","instructions":[{"instructionContent":["You are creating a card game application with your friend.","She already wrote a function that divides the deck of cards into top and bottom halves, but needs help writing a function that shuffles the two halves together again."]},{"instructionHeading":"Challenge","instructionContent":["Write a function that takes two arrays as inputs, representing the top and bottom halves of a deck of cards, and shuffles them together. The function will return a single array containing the elements from both input arrays interleaved, like so:","the first element should be the first element of the first input array,","the second element should be the first element of the second input array,","the third element should be the second element of the first input array,","the fourth element should be the second element of the second array,","and so on.","The arrays may be of different lengths. After interleaving the elements of the input arrays, any remaining elements should be appended to the end of the array.","This problem can be solved in many ways, but try to solve it with recursion!",{"codeBlock":"Input1: {Array} topHalf - cards in the top half of the deck\nInput2: {Array} bottomHalf - cards in the bottom half of the deck\nOutput: {Array} - the top and bottom halves of the deck interleaved together, with any remaining cards appended to the end."}]}]}},"challenge-string-concatenation":{"subunitId":"challenge-string-concatenation","heading":"Challenge: String Concatenation","solve":{"code":"const first = \"Welcome\";\nconst second = \"to the\";\nconst third = \"jungle!\";\n\n// ADD CODE BELOW\n\n\n// Uncomment the line below to check your work!\n// console.log(welcomeStatement);","test":"describe('welcomeStatement', () => {\n  it('should equal \"Welcome to the jungle!\"', () => {\n    expect(welcomeStatement).to.equal('Welcome to the jungle!');\n  });\n});\n","instructions":[{"instructionHeading":" ","instructionContent":["In this exercise we will explore string concatenation. String concatenation is joining strings together. You've already seen an example in a previous exercise, which uses the <code>+</code> operator to concatenate strings.",{"codeBlock":"console.log(\"Hi, \" + firstName);"}]},{"instructionHeading":"Challenge","instructionContent":["Use string concatenation to join the three provided strings (<code>first</code>, <code>second</code>, and <code>third</code>) and assign the resulting string to a variable called <code>welcomeStatement</code>. The value of <code>welcomeStatement</code> should be 'Welcome to the jungle!'"]}]}},"challenge-string-methods":{"subunitId":"challenge-string-methods","heading":"Challenge: String Properties & Methods","solve":{"code":"let hometown = \"New York City\";\nlet favAlbum = \"The Rise and Fall of Ziggy Stardust and the Spiders From Mars\"\n\n// ADD CODE BELOW\n\n\n// Uncomment the line below to check your work!\n// console.log(count);\n// console.log(upper);\n// console.log(lower);","test":"describe('count', () => {\n  it('should not be undefined or null', () => {\n    expect(count).to.not.equal(undefined);\n    expect(count).to.not.equal(null);\n  });\n  it('should have a value of type number', () => {\n    expect(count).to.be.a('number');\n  });\n  it('should equal 13', () => {\n    expect(count).to.equal(13);\n  });\n});\n\ndescribe('upper', () => {\n  it('should not be undefined or null', () => {\n    expect(upper).to.not.equal(undefined);\n    expect(upper).to.not.equal(null);\n  });\n  it('should have a value of type string', () => {\n    expect(upper).to.be.a('string');\n  });\n  it('should equal favAlbum in all caps', () => {\n    expect(upper).to.equal('THE RISE AND FALL OF ZIGGY STARDUST AND THE SPIDERS FROM MARS');\n  });\n});\n\ndescribe('lower', () => {\n  it('should not be undefined or null', () => {\n    expect(lower).to.not.equal(undefined);\n    expect(lower).to.not.equal(null);\n  });\n  it('should have a value of type string', () => {\n    expect(lower).to.be.a('string');\n  });\n  it('should equal favAlbum in all lower case', () => {\n    expect(lower).to.equal('the rise and fall of ziggy stardust and the spiders from mars');\n  });\n});\n","instructions":[{"instructionHeading":"Find the Length of a String","instructionContent":["All data types in JavaScript come with some built in properties and  methods which we can use to extract information or manipulate the  data stored inside the variable.  We'll dive into this concept more with  each new data type we cover, but let's start with some of the more simple  things we can do with strings.","What if we wanted to find the length of a string?  Wouldn't it be nice if  we didn't have to sit and count each character ourselves?  Luckily, strings  in JavaScript have a built in length property that we can access by adding  <code>.length</code> to the end of any string.  Take a look at this example:",{"codeBlock":"const myString = \"Howdy\"\nconsole.log(myString.length) // => 5\n\nconsole.log(\"I love JavaScript\".length) // => 17"}]},{"instructionHeading":"String Methods","instructionContent":["JavaScript methods are actions that can be performed on objects. We already  know that all data types in JavaScript are inherently objects, but that also means  that each data type comes with its own set of built in methods.  A method is essentially  a property containing a function definition.","Two common string methods are <code>toUpperCase</code> and <code>toLowerCase</code>.  We call these methods similarly to our length property, but in the case of methods, we  need to add <code>()</code> to the end of the method name.  Here is an example:",{"codeBlock":"const favArtist = \"David Bowie\"\n\nconsole.log(favArtist.toUpperCase()) // => \"DAVID BOWIE\"\nconsole.log(favArtist.toLowerCase()) // => \"david bowie\""},"For a list of all the string properties & methods in JavaScript, click  <a href=\"https://www.w3schools.com/jsref/jsref_obj_string.asp\" target=\"_blank\">here</a>."]},{"instructionHeading":"Challenge","instructionContent":["<strong>1.</strong> Declare a variable <code>count</code> and set its value equal  to the length property of the string variable <code>hometown</code>.","<strong>2.</strong> Declare a variable <code>upper</code> and set its value equal  to the string <code>favAlbum</code> converted to uppercase letters.","<strong>3.</strong> Declare a variable <code>lower</code> and set its value equal  to the string <code>favAlbum</code> converted to lowercase letters."]}]}},"challenge-strings-bracket-notation":{"subunitId":"challenge-strings-bracket-notation","heading":"Challenge: Bracket Notation for Strings","solve":{"code":"const songTitle = \"Space Oddity\"\nconst lyrics = \"This is Ground Control to Major Tom / You’ve really made the grade\"\n\n// ADD CODE BELOW\n\n\n// Uncomment the line below to check your work!\n// console.log(firstLetter);\n// console.log(seventhCharacter);\n// console.log(lastLetter);","test":"describe('firstLetter', () => {\n  it('should not be undefined or null', () => {\n    expect(firstLetter).to.not.equal(undefined);\n    expect(firstLetter).to.not.equal(null);\n  });\n  it('should have a value of type string', () => {\n    expect(firstLetter).to.be.a('string');\n  });\n  it('should be \"S\"', () => {\n    expect(firstLetter).to.equal('S');\n  });\n});\n\ndescribe('seventhCharacter', () => {\n  it('should not be undefined or null', () => {\n    expect(seventhCharacter).to.not.equal(undefined);\n    expect(seventhCharacter).to.not.equal(null);\n  });\n  it('should have a value of type string', () => {\n    expect(seventhCharacter).to.be.a('string');\n  });\n  it('should be \"O\"', () => {\n    expect(seventhCharacter).to.equal('O');\n  });\n});\n\ndescribe('lastLetter', () => {\n  it('should not be undefined or null', () => {\n    expect(lastLetter).to.not.equal(undefined);\n    expect(lastLetter).to.not.equal(null);\n  });\n  it('should have a value of type string', () => {\n    expect(lastLetter).to.be.a('string');\n  });\n  it('should be \"e\"', () => {\n    expect(lastLetter).to.equal('e');\n  });\n});\n","instructions":[{"instructionHeading":" ","instructionContent":["Bracket notation is a way to access a specific character in a string.  We can do so  by simply adding brackets (<code>[]</code>) to the end of our string and placing the  <code>index</code> of the character we want to access inbetween those brackets.","What's an <code>index</code> though?  The <code>index</code> is the position within the  string of the character we want to access.  The catch though is that JavaScript, like most  modern programming languages, uses a <em>zero-based</em> system for indexing.  This means that  we start our count at <code>0</code> instead of <code>1</code>.  So to access the first character  of a string, we would use the index of 0. Take a look at this example:",{"codeBlock":"let favFood = \"tacos\"\nconsole.log(favFood[0]) // => \"t\"\nconsole.log(favFood[2]) // => \"c\""},"One thing to keep in mind though is that even though we can access a specific character of a  string using the bracket notation, it doesn't mean we can change it.  Remember that strings are a  primitive data type in JavaScript.  One key thing to know about primitive data types is that they  are immutable which means they can't be altered. For instance:",{"codeBlock":"let word = \"brand\";\n\nconsole.log(word[3]) // => \"n\";\nword[3] = \"i\";\n\nconsole.log(word[3]) // => \"n\";\nconsole.log(word) // => \"brand\""},"Did you think <code>word</code> would change from \"brand\" to \"braid\"?  Because strings are immutable,  if we want to make that change, we would have to reassign the entire value like this:",{"codeBlock":"let word = \"brand\";\n\nword = \"braid\"\nconsole.log(word) // => \"braid\""}]},{"instructionHeading":"Challenge","instructionContent":["<strong>1. </strong>Declare a variable <code>firstLetter</code> and assign it a value of the first letter  of <code>songTitle</code> using bracket notation.","<strong>2. </strong>Declare a variable <code>seventhCharacter</code> and assign it a value of the seventh character  of <code>songTitle</code> using bracket notation.","<strong>3. </strong>Declare a variable <code>lastLetter</code> and assign it a value of the last letter  of <code>lyrics</code> using bracket notation and the <code>.length</code> property we learned in the last  challenge.","<em>Hint: Don't forget about that zero-based indexing.</em>"]}]}},"challenge-strings-escape-seqs":{"subunitId":"challenge-strings-escape-seqs","heading":"Challenge: Strings - Escape Sequences","solve":{"code":"// const path = \"C:\\Users\\Win\\Files\\javascript.js\";\n// console.log(path);\n\n// const heSaid = \"He said, \"Hey Foo!\"\";\n// console.log(heSaid);\n\n// const sheSaid = 'My name ain't Foo!';\n// console.log(sheSaid);","test":"describe('path', () => {\n  it('should not be undefined or null', () => {\n    expect(path).to.not.equal(undefined);\n    expect(path).to.not.equal(null);\n  });\n  it('should have a value of type string', () => {\n    expect(path).to.be.a('string');\n  });\n  it('should have the proper escaped characters', () => {\n    expect(path).to.equal('C:\\\\Users\\\\Win\\\\Files\\\\javascript.js');\n  });\n});\n\ndescribe('heSaid', () => {\n  it('should not be undefined or null', () => {\n    expect(heSaid).to.not.equal(undefined);\n    expect(heSaid).to.not.equal(null);\n  });\n  it('should have a value of type string', () => {\n    expect(heSaid).to.be.a('string');\n  });\n  it('should have the proper escaped characters', () => {\n    expect(heSaid).to.equal('He said, \"Hey Foo!\"');\n  });\n});\n\ndescribe('sheSaid', () => {\n  it('should not be undefined or null', () => {\n    expect(sheSaid).to.not.equal(undefined);\n    expect(sheSaid).to.not.equal(null);\n  });\n  it('should have a value of type string', () => {\n    expect(sheSaid).to.be.a('string');\n  });\n  it('should have the proper escaped characters', () => {\n    expect(sheSaid).to.equal(\"My name ain't Foo!\");\n  });\n});\n\n// removing for now since it doesn't print properly in our console\n// describe('stairs', () => {\n//   it('should not be undefined or null', () => {\n//     expect(stairs).to.not.equal(undefined);\n//     expect(stairs).to.not.equal(null);\n//   });\n//   it('should have a value of type string', () => {\n//     expect(stairs).to.be.a('string');\n//   });\n//   it('should have the proper escaped characters', () => {\n//     expect(stairs).to.equal('Top Step\\n\\tMiddle Step\\n\\t\\tBottom Step');\n//   });\n// });\n","instructions":[{"instructionHeading":" ","instructionContent":["What if you wanted to put a contraction inside of a string?  For example, take a look at the  folowing code block.",{"codeBlock":"const myString = 'Why doesn't this work';\n// => SyntaxError: Unexpected identifier"},"Looks like the string is getting closed out by our (<code>'</code>) in doesn't.  Hmmmmm...what to  do, what to do! Luckily JavaScript has this figured out for us! Take a look at this example:",{"codeBlock":"const myString = 'Why doesn\\'t this work';\nconsole.log(myString) // => 'Why doesn't this work?'"},"Notice how when we put the (<code>\\</code>) in front of the (<code>'</code>) it didn't end our  string?  This is called <em>escaping</em> the character.  Anytime JavaScript sees a (<code>\\</code>)  inside of a string, it knows that the following character has a special meaning.  Here is a list of  some of the most common escape sequences:",{"list":["<code>\\'</code>  =>  single quote","<code>\\\"</code>  =>  double quote","<code>\\\\</code>  =>  backslash","<code>\\n</code>  =>  newline","<code>\\r</code>  =>  carriage return","<code>\\t</code>  =>  tab","<code>\\b</code>  =>  backspace","<code>\\f</code>  =>  form feed"]},"Notice that even a backslash itself has to be escaped in order to display inside a string as well. Now let's see what you can do!"]},{"instructionHeading":"Challenge","instructionContent":["<strong>1. </strong>Uncomment out lines 1 & 2.  Hit the Run Code button.  Notice how we are missing all those backslashes?  Add the appropriate <code>\\</code>'s so that the <code>path</code> prints to the  console with the proper <code>\\</code>'s where they belong.","<strong>2. </strong>Uncomment out lines 4 & 5.  Hit the Run Code button.  Uh Oh!  We've got an error!  Fix the <code>heSaid</code> string so that it doesn't throw and error and prints to the console  properly.","<strong>3. </strong>Uncomment out lines 7 & 8.  Hit the Run Code button.  Uh Oh!  Another error!  Fix the <code>sheSaid</code> string so that it doesn't throw and error and prints to the console  properly."]}]}},"challenge-strings-intro":{"subunitId":"challenge-strings-intro","heading":"Challenge: Strings","solve":{"code":"// Uncomment the lines below to see examples of strings\n// console.log('A string can be written inside of single quotes.');\n// console.log(\"It can also be written inside of double quotes.\");\n// console.log(`Backticks work, too.`);\n\n// ADD CODE BELOW\n\n\n\n\n// Uncomment the line below to check your work!\n// console.log(mySingleString);\n// console.log(myDoubleString);\n// console.log(myBackString);","test":"describe('mySingleString', () => {\n  it('should not be undefined or null', () => {\n    expect(mySingleString).to.not.equal(undefined);\n    expect(mySingleString).to.not.equal(null);\n  });\n  it('should have a value of type string', () => {\n    expect(mySingleString).to.be.a('string');\n  });\n});\n\ndescribe('myDoubleString', () => {\n  it('should not be undefined or null', () => {\n    expect(myDoubleString).to.not.equal(undefined);\n    expect(myDoubleString).to.not.equal(null);\n  });\n  it('should have a value of type string', () => {\n    expect(myDoubleString).to.be.a('string');\n  });\n});\n\ndescribe('myBackString', () => {\n  it('should not be undefined or null', () => {\n    expect(myBackString).to.not.equal(undefined);\n    expect(myBackString).to.not.equal(null);\n  });\n  it('should have a value of type string', () => {\n    expect(myBackString).to.be.a('string');\n  });\n});\n","instructions":[{"instructionHeading":" ","instructionContent":["Strings are a data type in JavaScript. In short, they are bits of text written inside of quotation marks. You can use either single quotes (<code>'</code>), double quotes (<code>\"</code>), or backticks (<code>`</code>) as quotation marks to wrap a string, as long as the opening and closing symbols match. They are particularly useful for any data or value that can be represented as plain text.","Uncomment the text on lines 2 through 4 to see examples of strings."]},{"instructionHeading":"Challenge","instructionContent":["<strong>1.</strong> On line 7, declare a variable <code>mySingleString</code>  with single quotes (<code>'</code>), and set it's value to any string you like.","<strong>2.</strong> On line 8, declare a variable <code>myDoubleString</code>  with double quotes (<code>\"</code>'), and set it's value to any string you like.","<strong>3.</strong> On line 9, declare a variable <code>myBackString</code> with backticks  (<code>`</code>), and set it's value to any string you like.","<em>Hint: For now, only use plain text without any special characters or contractions.   We'll go into why these may cause you trouble in next challenge.</em>","You can uncomment lines 12-14 to test your code in the console."]}]}},"challenge-strings-template-literal":{"subunitId":"challenge-strings-template-literal","heading":"Challenge: Template Literal","solve":{"code":"// Declare 2 variables x & y that are Numbers\n// Declare a string 'solution' that when printed to the console reads like:\n// \"The sum of <x> and <y> is <x + y>\"\n// ADD CODE BELOW\n\n\n","test":"describe('x', () => {\n  it('should not be undefined or null', () => {\n    expect(x).to.not.equal(undefined);\n    expect(x).to.not.equal(null);\n  });\n\n  it('should have a value of type number', () => {\n    expect(x).to.be.a('number');\n  });\n});\n\ndescribe('y', () => {\n  it('should not be undefined or null', () => {\n    expect(y).to.not.equal(undefined);\n    expect(y).to.not.equal(null);\n  });\n\n  it('should have a value of type number', () => {\n    expect(y).to.be.a('number');\n  });\n});\n\ndescribe('solution', () => {\n  it('should not be undefined or null', () => {\n    expect(solution).to.not.equal(undefined);\n    expect(solution).to.not.equal(null);\n  });\n\n  it('should be a constant', () => {\n    function changeConst() {\n      return (solution = `${solution}`);\n    }\n\n    expect(changeConst).to.throw();\n  });\n\n  it('should have a value of type string', () => {\n    expect(solution).to.be.a('string');\n  });\n\n  it('should print to the console properly', () => {\n    expect(solution).to.equal(`The sum of ${x} and ${y} is ${x + y}`);\n  });\n});\n","instructions":[{"instructionHeading":"ES6 & Template Literal","instructionContent":["ECMAScript is a standardized version of JavaScript meant to unify the language's specifications  and features. As all major browsers and JavaScript-runtimes follow this specification, the terms  JavaScript and ECMAScript are interchangeable.  ECMAScript 6 (ES6), released in 2015, brought  about many new features to JavaScript which we will be exploring throughout this course.  In this  lesson we will focus on the <em>template literal.</em>","Template literals are a special type of string that make creating complex strings so much easier.  Template literals are created by surrounding text between opening and closing backticks (<code>``</code>).  Inside a template literal, you're able to refer to variables or execute code by using <code>${}</code>. Take a look at the following example:",{"codeBlock":"console.log(`10 + 25 = ${10 + 25}`) // => \"10 + 25 = 35\""},"By wrapping the calculation <code>10 + 25</code> in the <code>${}</code>, we are able to calculate the total  right there inside of the string.  We can also refer to specific variables in a template literal as well:",{"codeBlock":"const firstName = 'Kyle';\nconst greeting = `Hi, ${firstName}!`;\nconsole.log(greeting); // => \"Hi, Kyle!\""},"Template literals also remove the need for escaped characters and string concatenation in many case as well.  If you hit return, tab, etc inside of a template it will format the string in that form for you!  You can  also inject multiple variables into the same string.",{"codeBlock":"const firstName = 'David';\nconst lastName = 'Bowie';\nconsole.log(`My favorite artist is ${firstName} ${lastName}`) \n// => \"My favorite artist is David Bowie\""}]},{"instructionHeading":"Challenge","instructionContent":["Declare 2 variables <code>x</code> & <code>y</code>, and set their values to any number you like.  Next  declare a constant <code>solution</code> which is a string that prints to the console like the example below:",{"codeBlock":"let x = 2;\nlet y = 5;\nconst solution = <insert your code here>;\nconsole.log(solution) // => \"The sum of 2 and 5 is 7\""},"Hint: Don't forget the backticks (<code>``</code>)!"]}]}},"challenge-type-coercion":{"subunitId":"challenge-type-coercion","heading":"Challenge: Type Coercion","solve":{"code":"// Uncomment the code below to test\n// console.log(10 + 5);\n// console.log(\"10\" + 5);\n// console.log(5 + \"10\");","instructions":[{"instructionHeading":" ","instructionContent":["Look at the console.log statements for this challenge. What do you think will be logged to the console? When you have an idea, uncomment and run the code.","What happened?",{"codeBlock":"console.log(10 + 5); // 15\nconsole.log(\"10\" + 5); // 105"},"The first statement adds the numbers as expected. But in the second statement, '105' is logged to the console. Notice the quotation marks wrapped around the number 10 in the console.log statement; this means that the value is a string. There are no quotation marks around the number 5.","What happened is type coercion, an important concept in JavaScript. We can't add a string value and a number value together; instead, JavaScript \"coerces\" (changes) the number into a string and treats the <code>+</code> operator as an instruction to concatenate strings.",{"codeBlock":"console.log(\"10\" + \"5\"); // 105\nconsole.log(\"10\" + 5); // 105"}]},{"instructionHeading":"Challenge","instructionContent":["Uncomment the code and see what happens. Then, try it out yourself and make sure you really understand the concept."]}]}},"challenge-typeof":{"subunitId":"challenge-typeof","heading":"Challenge: typeof Operator","solve":{"code":"const favMovie = \"Star Wars: Episod IV\";\nconst timesSeen = 732;\nconst goingToWatchItAgain = true; \n\n// ADD CODE BELOW HERE","test":"describe('favMovieType', () => {\n  it('should be a string', () => {\n    expect(favMovieType).to.be.a('string');\n  });\n  it('should be \"string\"', () => {\n    expect(favMovieType).to.equal('string');\n  });\n});\n\ndescribe('timesSeenType', () => {\n  it('should be a string', () => {\n    expect(timesSeenType).to.be.a('string');\n  });\n  it('should be \"number\"', () => {\n    expect(timesSeenType).to.equal('number');\n  });\n});\n\ndescribe('seeAgainType', () => {\n  it('should be a string', () => {\n    expect(seeAgainType).to.be.a('string');\n  });\n  it('should be \"boolean\"', () => {\n    expect(seeAgainType).to.equal('boolean');\n  });\n});\n","instructions":[{"instructionHeading":" ","instructionContent":["Quite often in programming, we need to be able to look up what the specific data type of a given  operand is. In JavaScript, the <code>typeof</code> operator returns the data type of its operand in the  form of a string. Operand can be any object, function or variable.",{"codeBlock":"typeof(\"testing\")   // => \"string\"\ntypeof(22)         // => \"number\"\ntypeof(false)      // => \"boolean\""},"Keep in mind that the <code>typeof</code> an array is an object."]},{"instructionHeading":"Challenge","instructionContent":["<strong>1.</strong> Declare a variable <code>favMovieType</code>.  Then, using the typeof  operator, assign it the value of favMovie's data type.","<strong>2.</strong> Declare a variable <code>timesSeenType</code>.  Then, using the typeof  operator, assign it the value of timesSeen's data type.","<strong>3.</strong> Declare a variable <code>seeAgainType</code>.  Then, using the typeof  operator, assign it the value of goingToWatchItAgain's data type."]}]}},"challenge-union":{"subunitId":"challenge-union","heading":"Challenge: union","solve":{"code":"// ADD CODE HERE\n\n// Uncomment these to check your work!\n// const arr1 = [5, 10, 15];\n// const arr2 = [15, 88, 1, 5, 7];\n// const arr3 = [100, 15, 10, 1, 5];\n// console.log(union([arr1, arr2, arr3])); // should log: [5, 10, 15, 88, 1, 7, 100]","test":"describe('union', () => {\n  it('should be a function', () => {\n    expect(union).to.be.a('function');\n  });\n  it('should return an array', () => {\n    const answer = union([[], []]);\n    expect(answer).to.eql([]);\n  });\n  it('should flatten two distinct arrays', () => {\n    const arr1 = [1, 2];\n    const arr2 = [3, 4];\n    const answer = union([arr1, arr2]);\n    expect(answer).to.eql([1, 2, 3, 4]);\n  });\n  it('should flatten many arrays with repeated values', () => {\n    const arr1 = [1, 2];\n    const arr2 = [3, 4];\n    const arr3 = [3, 4, 5];\n    const arr4 = [0, 1, 2, 3, 4, 5];\n    const answer = union([arr1, arr2, arr3, arr4]);\n    expect(answer).to.eql([1, 2, 3, 4, 5, 0]);\n  });\n});\n","instructions":[{"instructionContent":["Construct a function <code>union</code> that takes an input array of arrays, compares each array, and returns a new flat array that contains all elements. If there are duplicate elements, only add it once to the new array. Preserve the order of the elements starting from the first element of the first input array. BONUS - Use reduce!"]}]}},"challenge-variable-assignment":{"subunitId":"challenge-variable-assignment","heading":"Challenge: Variable Assignment","solve":{"code":"const firstName = \"Jenny\";\n\n// Try un-commenting the line below\n// console.log(\"Hi, \" + firstName)\n\n// ADD CODE HERE\n\n\n// Uncomment the line below to check your work!\n// console.log(\"Hi, \" + firstName + \" \" + lastName);\n","test":"describe('firstName', () => {\n  it('should not be undefined or null', () => {\n    expect(firstName).to.not.equal(undefined);\n    expect(firstName).to.not.equal(null);\n  });\n\n  it('should have a value of type string', () => {\n    expect(firstName).to.be.a('string');\n  });\n});\n\ndescribe('lastName', () => {\n  it('should not be undefined or null', () => {\n    expect(lastName).to.not.equal(undefined);\n    expect(lastName).to.not.equal(null);\n  });\n  it('should have a value of type string', () => {\n    expect(lastName).to.be.a('string');\n  });\n});\n","instructions":[{"instructionHeading":"Challenge","instructionContent":["Now that we know what variables are, let's create one of our own. Below line 6, declare a constant named <code>lastName</code> and assign it the value of your last name. Make sure you wrap your name in quotation marks, e.g. <code>\"Smith\"</code>.","Now, go back to line 1 and modify the value of <code>firstName</code> to be your first name.  Uncomment the console.log statement on line 10 and run your code; you should see Jenny replaced by your first name—unless your first name is Jenny, of course."]}]}},"challenge-variable-assignment-const":{"subunitId":"challenge-variable-assignment-const","heading":"Challenge: Constant Assignment - (const)","solve":{"code":"// Declare a constant myCodingConfidence and assign it a value of \"unwavering\"\n// ADD CODE HERE\n\n\n// Try un-commenting the line below to test your answer\n// console.log(\"My confidence in my coding ability is \" + myCodingConfidence);\n\n// ADD CODE HERE\n\n\n\n","test":"function changeConst() {\n  return (myCodingConfidence = 'i can change');\n}\n\ndescribe('myCodingConfidence', () => {\n  it('should not be undefined or null', () => {\n    expect(myCodingConfidence).to.not.equal(undefined);\n    expect(myCodingConfidence).to.not.equal(null);\n  });\n\n  it('should be a constant', () => {\n    expect(changeConst).to.throw();\n  });\n\n  it('should have a value of type string', () => {\n    expect(myCodingConfidence).to.be.a('string');\n  });\n\n  it('should be assinged a value of \"unwavering\"', () => {\n    expect(myCodingConfidence).to.equal('unwavering');\n  });\n});\n","instructions":[{"instructionHeading":"Challenge","instructionContent":["Ok, so now that you have a hang of <code>var</code> and <code>let</code>,  let's practice declaring a constant.  As we metioned in the previous lesson,  sometimes we want a variable who's value never changes.  In this case we use  the <code>const</code> keyword.  For instance, take a look at the example below. My favorite TV show is Game of Thrones, and obviously that's never going to change, so I've declared a constant <code>myFavoriteShow</code> and assigned it a value of  \"Game of Thrones\".",{"codeBlock":"const myFavoriteShow = \"Game of Thrones\";\nconsole.log(myFavoriteShow) // => \"Game of Thrones\""},"Maybe your favorite tv show changes quite often though, so here's a few more concrete  examples of variables that won't ever change:",{"codeBlock":"const threeTimesFive = 15;\nconst christmasDay = \"December 25th\"\nconst myDateOfBirth = \"02/23/1978\""},"Now it's your turn.  You're on a roll, and you're feeling good about it, so on line 3,  declare a constant <code>myCodingConfidence</code> and assign it a value of \"unwavering\". Next, uncomment out line 6 to test your code!","Now below line 8, let's try and reassign the value of <code>myCodingConfidence</code> to something else.  After you've reassigned it, hit the Run Code button again and you'll  know you did it right if you get the following error in the console:",{"codeBlock":"Type Error: Assignment to constant variable."},"Did you get the error message?  Congratulations, you have successfully declared a constant!","Now in order to pass the tests, you'll need to get rid of that error, so comment out line 9  where you attempted to reassign the variable and click the Check My Answer button below to  run the tests!"]}]}},"challenge-variable-assignment-let":{"subunitId":"challenge-variable-assignment-let","heading":"Challenge: Variable Assignment - (let)","solve":{"code":"// Declare a variable favFood and assign it a value of \"tacos\"\n// ADD CODE HERE\n\n\n// Try un-commenting the line below to test your answer\n// console.log(\"My favorite food is \" + favFood);\n\n// ADD CODE HERE\n\n\n// Uncomment the line below to check your work!\n// console.log(\"No, but really, my favorite food is \" + favFood);","test":"describe('favFood', () => {\n  it('should not be undefined or null', () => {\n    expect(favFood).to.not.equal(undefined);\n    expect(favFood).to.not.equal(null);\n  });\n\n  it('should have a value of type string', () => {\n    expect(favFood).to.be.a('string');\n  });\n\n  it('should be not be \"tacos\"', () => {\n    expect(favFood).to.not.equal('tacos');\n  });\n});\n","instructions":[{"instructionHeading":"Challenge","instructionContent":["Now let's try declaring a variable with the <code>let</code> keyword.  On line 3, declare a variable <code>favFood</code> using <code>let</code> and  then assign it a value of the string \"tacos\". Now you can uncomment out line 6  to test your code.  You should see \"My favorite food is tacos\" in your console.","But wait!  Maybe tacos aren't YOUR favorite food.  Luckily, since we  declared our variable, favFood, using the <code>let</code> keyword, we can reassign  it's value to something different!","The best part is we don't have to declare the variable again.  All we need to do is  reassign it's value.  Check out the example below:",{"codeBlock":"let lastName = \"Snow\";\nconsole.log(lastName); // => Snow\nlastName = \"Targaryen\";\nconsole.log(lastName); // => Targaryen"},"On line 9, let's change the value of <code>favFood</code> to whatever your favorite  food is.  Next, uncomment the console.log on line 12 to check your code.   You should see \"No, but really, my favorite food is <insert your fav food here>\" in  the console below.","CONGRATULATIONS!  You just made your first variable reassignment!"]}]}},"challenge-variable-assignment-var":{"subunitId":"challenge-variable-assignment-var","heading":"Challenge: Variable Assignment - (var)","solve":{"code":"var firstName = \"Jenny\";\n\n// Try un-commenting the line below\n// console.log(\"Hi, \" + firstName)\n\n// ADD CODE HERE\n\n\n// Uncomment the line below to check your work!\n// console.log(\"Hi, \" + firstName + \" \" + lastName);\n","test":"describe('firstName', () => {\n  it('should not be undefined or null', () => {\n    expect(firstName).to.not.equal(undefined);\n    expect(firstName).to.not.equal(null);\n  });\n\n  it('should have a value of type string', () => {\n    expect(firstName).to.be.a('string');\n  });\n});\n\ndescribe('lastName', () => {\n  it('should not be undefined or null', () => {\n    expect(lastName).to.not.equal(undefined);\n    expect(lastName).to.not.equal(null);\n  });\n  it('should have a value of type string', () => {\n    expect(lastName).to.be.a('string');\n  });\n});\n","instructions":[{"instructionHeading":"Challenge","instructionContent":["Now that we know what variables are, let's create one of our own. Below line 6, declare a variable named <code>lastName</code> and assign it the value of your last name. Make sure you wrap your name in quotation marks, e.g. <code>\"Smith\"</code>.  Here's another example in case:",{"codeBlock":"var myName = \"Kyle\";\nconsole.log(myName) // => \"Kyle\""},"Now, go back to line 1 and modify the value of <code>firstName</code> to be your first name.  Uncomment the console.log statement on line 10 and run your code; you should see Jenny replaced by your first name—unless your first name is Jenny, of course."]}]}},"challenge-variable-reassignment":{"subunitId":"challenge-variable-reassignment","heading":"Challenge: Variable Reassignment","solve":{"code":"let firstName = \"Jenny\";\n\n// ADD CODE BELOW\n\n\n// Uncomment the line below to check your work!\n// console.log(\"Hi, \" + firstName);","test":"describe('firstName', () => {\n  it('should no longer have the value \"Jenny\"', () => {\n    expect(firstName).to.not.equal('Jenny');\n    expect(firstName).to.not.equal(null);\n    expect(firstName).to.not.equal(undefined);\n  });\n  it('should not be undefined or null', () => {\n    expect(firstName).to.not.equal(undefined);\n    expect(firstName).to.not.equal(null);\n  });\n\n  it('should have a value of type string', () => {\n    expect(firstName).to.be.a('string');\n  });\n});\n","instructions":[{"instructionHeading":" ","instructionContent":["You can update variables that you declare with <code>let</code> and <code>var</code>. (What happens if you try to reassign the value of a <code>const</code>?)","Look at the example below and notice how the value assigned to the variable <code>lastName</code> changes.",{"codeBlock":"let lastName = \"Snow\";\nconsole.log(lastName); // should log: Snow\nlastName = \"Fowlkes\";\nconsole.log(lastName); // should log: Fowlkes"}]},{"instructionHeading":"Challenge","instructionContent":["In the code editor, reassign the variable <code>firstName</code> to a new name on line 4."]}]}},"challenge-were-awesome":{"subunitId":"challenge-were-awesome","heading":"Challenge: wereAwesome","solve":{"code":"function wereAwesome(you, yourBuddy) {\n  // ADD CODE HERE\n}\n\n\n// Uncomment the lines below to test your function:\n// console.log(wereAwesome(\"Dave\", \"Will\")); // => \"Will and Dave are awesome!\"\n// console.log(wereAwesome(\"Victoria\", \"Jenny\")); // => \"Jenny and Victoria are awesome!\"\n// console.log(wereAwesome(\"Chris\", \"Jac\")); // => \"Jac and Chris are awesome!\"\n// console.log(wereAwesome(\"Phillip\", \"Skyler\")); // => \"Skyler and Phillip are awesome!\"","test":"describe('wereAwesome', () => {\n  it('should be a function', () => {\n    expect(wereAwesome).to.be.a('function');\n  });\n});\n\ndescribe('wereAwesome(\"Dave\", \"Will\")', () => {\n  it('should return \"Will and Dave are awesome!\"', () => {\n    expect(wereAwesome('Dave', 'Will')).to.eq('Will and Dave are awesome!');\n  });\n});\n\ndescribe('wereAwesome(\"Jenny\", \"Victoria\")', () => {\n  it('should return \"Jenny and Victoria are awesome!\"', () => {\n    expect(wereAwesome('Victoria', 'Jenny')).to.eq('Jenny and Victoria are awesome!');\n  });\n});\n\ndescribe('wereAwesome(\"Chris\", \"Jac\")', () => {\n  it('should return \"Chris and Jac are awesome!\"', () => {\n    expect(wereAwesome('Jac', 'Chris')).to.eq('Chris and Jac are awesome!');\n  });\n});\n\ndescribe('wereAwesome(\"Phillip\", \"Skyler\")', () => {\n  it('should return \"Skyler and Phillip are awesome!\"', () => {\n    expect(wereAwesome('Phillip', 'Skyler')).to.eq('Skyler and Phillip are awesome!');\n  });\n});\n","instructions":[{"instructionContent":["Write a function <code>wereAwesome</code> that takes you and your pair programming partner's name and returns the string \"[your buddy's name] and [you] are awesome!\"","If you are coding on your own, get creative! Instead of a pair programming partner, it could be the name of your friend, your pet, or even your rubber ducky!"]}]}},"challenge-while-loops-conditional-expression":{"subunitId":"challenge-while-loops-conditional-expression","heading":"Challenge: While Loops - Conditional Expression","solve":{"code":"// ADD CODE HERE\n\n\n// Uncomment the line below to check your work!\n// console.log(sum);","test":"describe('addThis', () => {\n  it('should equal 10', () => {\n    expect(addThis).equal(10);\n  });\n});\n\ndescribe('sum', () => {\n  it('should equal 45', () => {\n    expect(sum).to.equal(45);\n  });\n});\n","instructions":[{"instructionHeading":" ","instructionContent":["Initialize a variable <code>addThis</code> to 0 and a variable <code>sum</code> to 0. Use a while loop to repeat a code block as long as <code>addThis</code> is less than 10. In the code block, add the value of <code>addThis</code> to <code>sum</code>, then increment <code>addThis</code> by 1. After the while loop runs, the value of <code>sum</code> should be the sum of the numbers 0 through 9. It's crucial to note that if there's more than one statement in the loop block, the entire block needs to be enclosed in curly braces <code>{}</code>. This ensures that all statements within the block are executed  together in each iteration of the loop."]}]}},"challenge-while-loops-counters":{"subunitId":"challenge-while-loops-counters","heading":"Challenge: While Loops - Counters","solve":{"code":"function imAboutToExplodeWithExcitement(n){\n  // ADD CODE HERE\n}\n\n// Uncomment the line below to check your work!\n// imAboutToExplodeWithExcitement(10); // expected log 10, 9, 8, 7, 6, 'Oh wow, I can't handle the anticipation!', 4, I'm about to explode with excitement!', 2, 1, 'That was kind of a let down'","test":"describe('imAboutToExplodeWithExcitement', () => {\n  it('should be a function', () => {\n    expect(imAboutToExplodeWithExcitement).to.be.a('function');\n  });\n});\n","instructions":[{"instructionContent":["Using a WHILE loop, write a function <code>imAboutToExplodeWithExcitement</code> which prints a countdown from <code>n</code>. When the countdown gets to <code>5</code>, print <code>'Oh wow, I can't handle the anticipation!'</code> When it's at <code>3</code>, print <code>'I'm about to explode with excitement!'</code> When the counter is finished, print <code>'That was kind of a let down'</code>."]}]}},"challenge-while-loops-fundamentals":{"subunitId":"challenge-while-loops-fundamentals","heading":"Challenge: While Loops - Fundamentals","solve":{"code":"let count = 2;\n// ADD CODE HERE\n\n\n// Uncomment these to check your work!\n// console.log(count); ","test":"describe('count', () => {\n  it('should equal 8', () => {\n    expect(count).equal(8);\n  });\n});\n","instructions":[{"instructionHeading":" ","instructionContent":["A while loop is an alternative iteration statement. JavaScript's thread of execution will repeatedly process the code block until the while loop's conditional expression evaluates to false. **Be careful to avoid an infinite loop!**"]},{"instructionHeading":"Challenge","instructionContent":["Use a while loop to increment <code>count</code> by 2 on each repetition of the block of code. Run the code block of your while loop until count is 8."]}]}},"chrome-extension-1":{"subunitId":"chrome-extension-1","heading":"Project Part 1 - Introduction to Chrome Extension Project","read":["You have heard many times in CSX that the best way to learn to code is not to ‘learn to code’. Instead, you should write code to <i>solve problems</i>. Here we’re going to solve a real world problem with JavaScript, HTML and CSS. If you have gone through the JavaScript for Beginners or CS Prep programs, we highly encourage you to complete this project. This experience will introduce you to concepts that will help you prepare for the Codesmith immersive programs. This is a great project to do as part of a hackathon!","We're going to do this by building a Chrome Extension that solves a problem you face every day. Why is this so effective?",{"orderedList":["Minimal lines of 'setup code' means less copying and pasting from tutorials (not effective).","When the going gets tough, you have a clear goal to help push you through blocks.","Focuses you on problem-solving (it's what we look for in Codesmith candidates)."]},"Our <b>Chrome extension is a powerful productivity tool</b>. It keeps a user focused by allowing them to load their favorite distracting site - say Twitch. But rather than showing videos, they see an inspiring image with the text <i>\"Get back to achieving your coding dreams.\"</i>","<img class=\"img-responsive\" src=/assets/chrome-ext/twitch1.png>","This extension is powerful. You don’t need to switch off the extension if you want to watch a specific individual video. There’s less psychological cost than finding a site fully blocked. Instead you see the site load, but the distracting content is replaced with a motivating message.","We'll have 5 parts to building our extension that will introduce us to 5 core concepts of web development.","<b><i>Part 1: Introduction and overview</i></b>","<b><i>Part 2: DOM manipulation and Chrome developer tools</i></b>",{"list":["Introduction to the DOM","Manipulating the DOM manually with Chrome dev tools","Using JavaScript in the Chrome dev tools console to select the main container element on Twitch","Using JavaScript to remove the element"]},"<b><i>Part 3: JSON and configuration </i></b>",{"list":["Creating a manifest file","Adding the key pieces to the manifest (with JSON)","Creating the main JavaScript file","Inserting our DOM manipulation code in the JavaScript file","Running the unpackaged extension in Chrome"]},"<b><i>Part 4: Libraries and jQuery</i></b>",{"list":["Introducing jQuery to gain experience working with 3rd party libraries","Dependencies: Adding jQuery into manifest","Using jQuery to append an image to the DOM and add our custom text: \"Get back to achieving your coding dreams\"","Adding a CSS class to the element (using a CSS style file)"]},"<b><i>Part 5: Asynchronous callbacks and the JavaScript engine</i></b>",{"list":["Introducing the JavaScript engine and how it fits in the browser setup","Asynchronous callbacks - web APIs, event queue"]},"<b><i>Part 6: APIs and Ajax</i></b>",{"list":["Using Lorem Picsum API to return a random image each time we load twitch.tv"]},"All while building a tool that is powerful enough to improve your productivity every day.","We'll start by developing a thorough understanding of the DOM and Chrome developer tools in order to remove the distracting content."]},"chrome-extension-2":{"subunitId":"chrome-extension-2","heading":"Project Part 2 - DOM manipulation and Chrome developer tools","read":["Twitch's webpage, like any, is a collection of ‘content in content’ - video thumbnails, titles, subtitles, text areas, icons, etc.","That’s all HTML is - words that describe:",{"orderedList":["What should be on the page and","In what order"]},{"codeBlock":"<h1>Welcome to Twitch</h1>\n<img src=\"twitch-logo.jpg\">"},"The code above tells the web browser (e.g., Chrome) to place a header with the words 'Welcome to Twitch', then right afterwards place an image - the Twitch logo  (which is in the JPG image format).","Behind the scenes, the browser analyzes each of these instructions and uses them to form a behind-the-scenes diagram/model of the page.","<img class=\"img-responsive\" src=/assets/chrome-ext/dom.png>","This is crucial. It allows us to write JavaScript code that can go and interact with the page by navigating (known as <a href=\"https://zellwk.com/blog/dom-traversals/\" target=\"_blank\">'traversing'</a>) this diagram/model (<a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Introduction\" target=\"_blank\">DOM</a>). We can then use JavaScript to add elements to the page or <u>delete bits</u> without writing any further HTML. We want to use JavaScript to add/remove content because we don’t have to reload the page to do it - it can be done live, or ‘dynamically’, while the page is already loaded.","We can see this behind-the-scenes structure by selecting one of the elements on the page and viewing it in the source code in <a href=\"https://developer.chrome.com/docs/devtools/\" target=\"_blank\">Chrome's developer tools</a>.","<img class=\"img-responsive\" src=/assets/chrome-ext/twitch-inspect.gif>","We need to delete our main element here - we can just go ahead and do it by right clicking on the right section of the source code and deleting!","But of course we need to do it automatically - so we'll need to write code.","We can run JavaScript straight in the webpage from the ‘Console’ (later we'll put the code in a file that will be part of the Chrome extension so we can run it automatically in the background) but for now we can test out the right code to write here. To go to the Console, open it with <b>Command + Option + J</b> (Mac) or <b>Control + Shift + J</b> (Windows).","Each element (in code that is helpfully written) has a label we can use to grab it - called a selector. We can find it by clicking on the element...and there it is:","<img class=\"img-responsive\" src=/assets/chrome-ext/twitch2.png>","The element’s label (its ‘id’) is 'root' (there are different types of labels - ‘id’, ‘class’).","So now we need to use some JavaScript to grab/select that element so we can then apply the delete command (function) to it.","This is where the problem-solving research begins. Before you get the answer from me, take a look at <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Document\" target=\"_blank\">MDN</a>. MDN is a great resource for finding the methods/functions that you will need to interact with the DOM. You can find a method for selecting an element <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Document#instance_methods\" target=\"_blank\">here</a> under \"instance methods\".","","OK, hopefully you went and found that the method we need is:","<i>const contents = document.getElementById('root');</i>","<b>document</b> is an object with lots of built in methods stored on it (functions stored on an object are called methods) and the one we're using takes an 'id' and finds the element with that particular 'id'.","So we now store that element in a variable ready for deletion - we store it in a variable 'contents'. Let’s check if it’s there stored in 'contents':","<img class=\"img-responsive\" src=/assets/chrome-ext/twitchfeed.png>","...and there it is!","Now we need to find the delete method (again, you can go look it up <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Node/removeChild\" target=\"_blank\">here on MDN</a>.","So we need to run the delete function on the element - Our docs say we need to run:","<i>el.parentNode.removeChild(el);</i>","We have to replace ‘el’ with our actual element that we stored in a variable so we’ll be running:","<i>contents.parentNode.removeChild(contents);</i>","Success! We've removed the distracting content from our page using JavaScript, our understanding of the DOM, and the Chrome developer tools.","<b> It’s important to note that, today, it’s more common to use: </b>","<a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector\" target=\"_blank\">document.querySelector('#root')</a> instead of document.getElementById('root') <br>\n → document.querySelector() can select elements using any CSS selector, not just IDs. <br>\n <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Element/remove\" target=\"_blank\">contents.remove()</a>  instead of contents.parentNode.removeChild(contents) <br>\n → element.remove() is a newer, simpler method that removes an element directly from the parent without needing a reference.","For our purposes, we’re keeping it old school because it’s more explicit and a little easier to follow when you’re first learning how the DOM works.","Next we'll move this functionality into an 'extension' so we don't need to type it out in our code each time - instead we can save our code in a file and run it in the background as an extension. We'll do this in Part 3.","<b>Further Challenges:</b>",{"list":["Remove more specific elements - perhaps the History button or other buttons on the page","Try adding (hint: <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Element/append\" target=\"_blank\">appending</a>) content to the page from the console","If your most addictive site isn't Twitch, but for example Instagram, try to emulate this same process with Instagram’s page."]}]},"chrome-extension-3":{"subunitId":"chrome-extension-3","heading":"Project Part 3 - JSON and configuration","read":["In the last lesson, we learned how we could manipulate real website content just by typing a few lines of code directly in our browser. This is really cool, but we wouldn’t want to do this manually every time we visited Twitch.","Luckily for us, we can build a Chrome extension to automate this - and it’s really simple!","To start, open your favorite text editor. If you want to try a tool specifically for coding,  check out <a href=\"https://code.visualstudio.com/\" target=\"_blank\">VSCode</a>! From the file menu, let’s create a new folder to hold our project.  It’s in this folder that we will put all of our files.","Since the code is fresh in our minds, let’s start with the file that will contain that functionality. In our new project folder, let’s add a new file and call it “main.js\".  (The ‘.js’ extension tells us that the contents of this file are in JavaScript.)","In this file, let’s add the two lines of code we previously typed directly into the browser console:","<img class=\"img-responsive\" src=/assets/chrome-ext/main.png>","Later on we’ll add the code to replace our lost videos with an image, but for the moment this is all we need here. Make sure to save the file!","Now how on earth does this code that lives in this main.js file on our computer know that it should run as a Chrome extension? So far, it really has no idea!","We need to create one other file to tell Google the settings for this code - that this code is a Chrome extension and that it should apply only when we visit Twitch.","<img class=\"img-responsive\" src=/assets/chrome-ext/files.png>","Before we create this second file, it is important to understand JavaScript Object Notation - or <a href=\"https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/JSON\" target=\"_blank\">JSON</a> for short.  JSON is a way to format data so it is easily interpreted by computers. Here is an example of how we might format data about a person in JSON:",{"codeBlock":"{\n  \"name\": \"Joe Chrome\",\n  \"age\": 27,\n  \"hometown\": {\n    \"city\": \"Playa Vista\",\n    \"state\": \"CA\"\n  },\n  \"siblings\": [\"Polly\",\"Edgar\"]\n}"},"Notice that the information is wrapped in curly braces, making it one object. Within the braces are several “key-value” pairs. The keys are to the left of the colon, and the values are on the right.","All of the keys are strings (words wrapped in double quotes), but the values can be strings, numbers, arrays of values (wrapped in square brackets), or other objects with their own key-value pairs.","We will follow this same format for our extension settings.","Let’s create our second file and call it “manifest.json”. There are three things Chrome requires this file to contain:",{"orderedList":["The “manifest_version” tells Chrome about the format of the manifest. We'll be using version 3.","The “name” is what we call our extension and how it will be listed with Google.  We’ll call our extension “Focus“.","The “version” field helps Google keep track of updates we make after our extension is published to the world. This needs to be a string, so we’ll call ours “1.0”."]},"With these items, our file should look like this:",{"codeBlock":"{\n  \"manifest_version\": 3,\n  \"name\": \"Focus\",\n  \"version\": \"1.0\"\n}"},"While these are the only required fields for our manifest.json, they don’t make for an exciting Chrome extension! There are <a href=\"https://developer.chrome.com/docs/extensions/reference/manifest?hl=en\" target=\"_blank\">dozens of other fields</a> we can add, but we only need a couple more to make our extension work as we expect.","Let’s tell others what our extension does by adding a “description” field.  You can come up with this one on your own. Just be sure to wrap it in quotes!","Finally - and perhaps, most importantly - we need to link the code in our “main.js” file with Twitch.","Chrome gives us a few ways to do this. We will use a “content_scripts” field in our JSON file since our code needs to run in the context of a certain webpage.","Since more complex extensions often need to define multiple JavaScript files to run in different contexts, the “content_scripts” field is typically an array of objects.  In our case, we will have only one object in our array.",{"codeBlock":"\"content_scripts\": [\n  {\n    \"matches\": [\"https://www.twitch.tv/*\"],\n    \"js\": [\"./main.js\"]\n  }\n]"},"You’ve probably guessed that the “matches” field within our “content_scripts” object tells Chrome that the “js” (JavaScript) code in “main.js” applies only when we are on Twitch’s website. Again, these fields are arrays in case we had multiple matches or JavaScript files to link together.","By now, our “manifest.json” file should look something like this:","<img class=\"img-responsive\" src=/assets/chrome-ext/manifest.png>","We have some more behavior we want to accomplish with our code, but we are all set to test what we have as a Chrome extension!","In Google Chrome, navigate to “chrome://extensions”. Check the box “Developer mode” in the top right corner, and then click the “Load unpacked extension…” button to the left. Find the folder you created earlier and open it.","<img class=\"img-responsive\" src=/assets/chrome-ext/extensions.png>","You should now see your new extension listed below with the name, version, and description you gave it. Make sure to click the 'Enable' slider in the bottom right of the extension card (should be blue!), then head over to Twitch.tv","<img class=\"img-responsive\" src=/assets/chrome-ext/youtube3.png>","What happened to our video feed?","Congratulations! You just created a first draft of a real Chrome extension! But we still want to replace the content we lost with something else. We’ll work on that next time.","<b>Further Challenges:</b>",{"list":["Did you notice our extension is listed with a default puzzle piece icon when we visit  “chrome://extensions”? Try replacing that with something custom. (Check <a href=\"https://developer.chrome.com/docs/extensions/reference/api/action\" target=\"_blank\">this</a> out if you get stuck.)","Try to do the same thing we did to Twitch on another website (like Facebook). Keep in mind that the new item to hide might not be called 'contents'. Can you do this by modifying our existing Chrome extension?","Create a simple popup page for when users click on your extension’s icon in the top right of their browser. What do you need to do this? (Maybe a file to describe the <a href=\"https://developer.chrome.com/docs/extensions/reference/api/action/#popup\" target=\"_blank\">popup page</a> and an addition to our settings.)"]}]},"chrome-extension-4":{"subunitId":"chrome-extension-4","heading":"Project Part 4 - Libraries and jQuery","read":["JavaScript, by itself, is a powerful tool that lets us interact with and modify elements on a web page. As projects grow, however, developers often rely on third-party libraries—collections of pre-written code that make common tasks easier or faster to implement. One of the earliest and most influential of these libraries is jQuery, which became popular for simplifying DOM manipulation, event handling, and animations. In this section, we’ll use jQuery to explore how third-party libraries can extend JavaScript’s capabilities and make our code more efficient.","Check out <a href=\"http://api.jquery.com/\" target=\"_blank\">jQuery's documentation</a> to achieve what we did above in JavaScript, in jQuery. It’s important to note though, jQuery is still written in JavaScript, it just allows us to do more with less code.","For example:","<i>const contents = $('#someID');</i>","<i>const contents = $('.someClass');</i>","Now, our code is a lot cleaner, and more importantly, readable.","Apart from making JavaScript code easier to read, jQuery is well-known for making web page interactions like animations or element changes easier.","However, if we were to edit our webpage right now, using jQuery, we’d get an error. That’s because we haven’t added the code that makes up jQuery into our Chrome extension yet. To do this, we need to add jQuery, a ‘dependency’, to our manifest.json somehow. A dependency is just a bunch of additional code we can add on top of our own to gain additional functionality.","First, we need to download the code behind jQuery.","Download jQuery by clicking this <a href=\"https://code.jquery.com/jquery-3.7.1.min.js\" target=\"_blank\">link</a> and then right-click and choose ‘Save as...’. Save the jQuery file as “jquery.min.js”, and place it in your Chrome extension folder.","Next, add it to your manifest.json (remember that just makes it available to our Chrome extension).",{"codeBlock":"\"content_scripts\": [\n  {\n    \"matches\": [\"https://twitch.tv/*\"],\n    \"js\": [\"jquery.min.js\", \"./main.js\"]\n  }\n]"},"Now, we can use jQuery!","With that in place, let’s go back to building our extension.","So, we’ve just removed <i>contents</i> from the list of elements that make up the Twitch web page. But, what if, we instead just replace the contents of <i>contents</i> with something else - like an image? Let’s do that now.","Remember how we removed <i>contents</i>?","<b>JavaScript</b>","<i>const contents = document.getElementById('root');</i>","<i>contents.parentNode.removeChild(contents);</i>","<b>jQuery</b>","<i>const contents = $('#root');</i>","<i>contents.remove();</i>","We did it by going up to its parent element and telling JavaScript to remove <i>contents</i> as one of its children. However, if we want to replace <i>contents</i> with an image, then we’ll need to keep a reference to where <i>contents</i>’ parent is on the page.","One solution, store the parent element in a variable.","<i>const contentsParent = contents.parent();</i>","However, if you remove <i>contents</i> first before storing a reference to its parent… what do you think would happen? You’d get an error, right? Why?","Well, because we’re trying to access <i>contents</i>’ parent, but <i>contents</i> doesn’t exist anymore. So, we need to change the order of our code then to have a reference to <i>contents</i>’ parent before we delete <i>contents</i>.","Alright, so at this point I’m assuming you’ve successfully deleted <i>contents</i>, but still have access to its parent.","As a challenge, figure out how to add (hint: <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Element/prepend\" target=\"_blank\">prepend</a>) an image as contentsParent’s first child.","<img class=\"img-responsive\" src=/assets/chrome-ext/twitch4.gif>","We’ve just done a remarkable thing! Not only have we removed elements from Twitch, but we’ve also replaced them with a proactive image, wooh!!","Now let’s truly make it our own by adding some text above the image.","In order to achieve this we want to add (or <i>prepend</i>) another child to contentsParent. This time, before the image, because remember, the web page will render elements from top to bottom, so the text will show above the image.","You can make it a div, span, or whatever you like as long as it says something truly inspirational… like “Get back to achieving your coding dreams”. Yeah, that will work.","<img class=\"img-responsive\" src=/assets/chrome-ext/twitch5.png>","So things are going well, but isn’t our text just downright ugly? You’re probably thinking websites are usually these beautiful things, but right now, that text just isn’t cutting it. To mess with styling, we need to be dealing with <a href=\"https://developer.mozilla.org/en-US/docs/Web/CSS\" target=\"_blank\">CSS</a>, or <b>C</b>ascading <b>S</b>tyle <b>S</b>heets.","CSS is just a mechanism to add style to a web page. Go ahead and make an index.css file where all your files for the Chrome extension are.","OK great. Now, in order to style something on a web page we first need to identify the element that we want to change.","We’ve accessed an element before by using its ID, but this time we want to do it through its class.","So, go ahead and <a href=\"https://api.jquery.com/addclass/\" target=\"_blank\">add a class</a>, called <i>beautText</i>, to the text above the image.","According to jQuery’s docs we can add a class as follows:","<i>$message.addClass('beautText');</i>","What, that did nothing? Is what you should be saying at this point. We never defined beautText in our CSS file nor have we added it as a dependency like we did for jQuery. Do this now.",{"codeBlock":".beautText {\n  color: green;\n}\n"},"That covers our CSS file.","In our manifest.json we can also add css files as dependencies. Add the following below our list of JavaScript dependencies:","<i>\"css\": [\"index.css\"]</i>","And now something beautiful happens. The color of the text we wrote above the image changes. That was only possible by first adding our index.css file as a dependency.","But, how does this all really work? How does the browser render HTML, and what does it look like under-the-hood? Jump to the next section for more info!","<b>Further Challenges:</b>",{"orderedList":["Animate the text across the page using jQuery","Cycle through multiple images instead of just one","Have the text change colors"]}]},"chrome-extension-5":{"subunitId":"chrome-extension-5","heading":"Project Part 5 - Asynchronous Callbacks and the JavaScript Engine","read":["Great! It looks like everything is working as planned. Now whenever we visit Twitch, we’ll see a message and an inspirational image…","The same inspirational image...every...time...","After a while, this image would become less and less motivating. Wouldn’t it be great if we could show a random image each time we visited the page?","Lucky for us, there are services called <a href=\"https://www.freecodecamp.org/news/what-is-an-api-in-english-please-b880a3214a82/\" target=\"_blank\">APIs</a> that we can reach out to and request things like random images. This will be a great addition to our Chrome extension, but first we need to understand what is happening behind the scenes when we make such a request.","Because the images we want exist elsewhere on the internet (outside of what is already on Twitch’s page or in our code), we have to request them similar to how we request certain web pages by typing in their URL. Specifically, this is called an HTTP request.","As you know from visiting your favorite website, web pages always take some (usually small) amount of time to respond with content. This is also the case if we make requests to an API in our code.","Why is this important? Well, we haven’t mentioned it explicitly, but JavaScript runs synchronously. This basically means that one line of code executes completely before the next line begins, so we can only do one thing at a time.","This makes a lot of sense for what we have coded so far. We need to assign the element with the ID of <i>root</i> to a variable before we can use that variable to grab its parent. If those lines did not run synchronously, we might expect an error if the second line were to run before the first.","But in the case of requesting a random image, if we were to wait for the image to be returned, we would slow down, or <i>block</i> any code below the request from running until that time. If that code has nothing to do with the image, blocking it from running could be very annoying for the user - even if for just a split second.","Thankfully, web browsers allow us to run code <i>asynchronously</i>. Asynchronously essentially means multiple things can happen at the same time.","In our case, we can request content from an API in one bit of code, continue about the rest of our code as that request is being processed, then do something with the returned content when the response comes in.","How is this possible if JavaScript is synchronous in nature? We’ve talked about JavaScript running in the browser, but we haven’t mentioned the full context our code is running in.","Within the web browser, there is a component called the JavaScript engine. This is where our code runs, and it can only run things synchronously. But there are other browser components besides the JavaScript engine.","<img class=\"img-responsive\" src=/assets/chrome-ext/dataflow.png>","The rendering engine is the part responsible for displaying the HTML and CSS of a website, and it goes about its business separate from the JavaScript engine.","The great thing is that our code running in the JavaScript engine can communicate with the rendering engine to do things like manipulate the HTML and CSS. This is what we’ve done already - both with and without jQuery.","Besides these two components, there are also tools in the browser that deal exclusively with HTTP requests. It is an HTTP request that gets Twitch’s HTML, CSS, and JavaScript files for the other components to process in the first place.","Just like the rendering engine, HTTP requests have little concern for what’s happening in the JavaScript engine. This all means that if we make a request to an API for a random image, we can do so without worry that the rest of our code will be blocked!","However, there comes a bit of a downside with asynchronous code. We lose the predictable nature of our code.","Line by line, our code may translate into:",{"orderedList":["Ask an API for a random image and assign the image to a variable ‘myImg’.","Add ‘myImg’ to the page along with motivational message."]},"But given the request is asynchronous, what actually happens might be:",{"orderedList":["Ask an API for a random image... (request for image is sent)","Add ‘myImg’ to the page along with motivational message.","(response with image is received) ...assign the image to a variable ‘myImg’."]},"We have a problem here! In Step 2, we do something with ‘myImg’, but we don’t receive the actual image until later. So in Step 2, ‘myImg’ is actually <i>undefined</i>.","What if the request takes virtually no time to come back? There has to be a chance we will have the image in time, right?","Wrong! In fact, even if a response is received immediately, we will not have access to it until all of our other code finishes running.","To understand why this is, let’s look more closely at our JavaScript engine.","<img class=\"img-responsive\" src=/assets/chrome-ext/jsengine.png>","Within the JavaScript engine is something called the call stack (or execution stack). The call stack keeps track of our <i>execution context</i> - basically, where we are in our code.","If our code makes a call to JavaScript in another execution context - such as calling a function - that new execution context is pushed to the top of the call stack. Whatever is on top of the stack is the current execution context the JavaScript engine is processing. We go back down the stack only when the execution context on the top finishes and is popped off of the stack.","But remember, the HTTP request for our image doesn’t get handled by the JavaScript engine, so it doesn’t affect the call stack. How then does our code know when the response comes back?","Well in addition to the call stack, the JavaScript engine has something called the event queue. The event queue receives items whenever certain events happen - like a user clicks their mouse, or an HTTP response is received.","The JavaScript engine has a feature called the event loop that periodically checks the event queue for items to be processed - but only <i>after</i> the call stack is emptied. In the case of our code, this means the image we receive back will not be available until all of the synchronous code in our file completes. (Check out <a href=\"https://www.youtube.com/watch?v=8aGhZQkoFbQ\" target=\"_blank\">this video</a> for an in-depth (but digestible!) explanation of the event loop.)","How then can we do something with the image only when we have access to it? That is where callbacks come in.","Callbacks are functions that run their code only when certain events occur. In our JavaScript, we can, for example, tell the browser we want to be alerted when the user clicks on any div.",{"codeBlock":"$('div').click(function() {\n  alert('A div was clicked!');\n});"},"Try adding this code to your extension’s main.js file. Be sure to reload the extension in Chrome settings, and then visit Twitch and click around.","Pretty cool, huh? With our callback we were able to specify code that only runs when a certain event happens.","We can do the same thing when we request our random image, but in that case our callback will detail what to do with the image. If you want to play around more with these concepts, <a href=\"http://latentflip.com/loupe/?code=JC5vbignYnV0dG9uJywgJ2NsaWNrJywgZnVuY3Rpb24gb25DbGljaygpIHsKICAgIHNldFRpbWVvdXQoZnVuY3Rpb24gdGltZXIoKSB7CiAgICAgICAgY29uc29sZS5sb2coJ1lvdSBjbGlja2VkIHRoZSBidXR0b24hJyk7ICAgIAogICAgfSwgMjAwMCk7Cn0pOwoKY29uc29sZS5sb2coIkhpISIpOwoKc2V0VGltZW91dChmdW5jdGlvbiB0aW1lb3V0KCkgewogICAgY29uc29sZS5sb2coIkNsaWNrIHRoZSBidXR0b24hIik7Cn0sIDUwMDApOwoKY29uc29sZS5sb2coIldlbGNvbWUgdG8gbG91cGUuIik7!!!PGJ1dHRvbj5DbGljayBtZSE8L2J1dHRvbj4%3D\" target=\"_blank\">this visualizer</a> is a great tool for understanding Javascript's call stack/event loop/callback queue.","We’ll get into that and how to make AJAX calls to APIs next time!","<b>Further Challenges:</b>",{"list":["Practice working with asynchronous code and callbacks. You can experiment in Chrome’s console with the built-in function ‘<a href=\"https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout\" target=\"_blank\">setTimeout</a>’. Try this to start: <i>setTimeout(function() { alert(“I am delayed”) }, 3000);</i>","In your Chrome extension, change the click handler to make elements disappear when they're clicked","Experiment with other <a href=\"https://api.jquery.com/category/events/\" target=\"_blank\">event listeners</a> and callbacks"]}]},"chrome-extension-6":{"subunitId":"chrome-extension-6","heading":"Project Part 6 - APIs and AJAX","read":["Ready to dynamically render photos to the DOM?! *nerd high five* Hold your horses there. Before we go any further remember that an API is something we can request data from in the form of HTTP requests, and that’s exactly what we’re going to do.","With jQuery we can make HTTP requests using <a href=\"https://developer.mozilla.org/en-US/docs/Web/Guide/AJAX\" target=\"_blank\">AJAX</a>, or Asynchronous JavaScript and XML. Which means you can make requests using JavaScript, and that the process is asynchronous. That’s it. A bunch of fancy mumbo jumbo if you ask me.","Another important note is that most APIs return data in the form of JSON, which we discussed earlier, and Lorem Picsum is no different.","The URL we’ll be requesting images from is <a href=\"https://picsum.photos/list\" target=\"_blank\">picsum.photos</a>. You can visit this page before we even make the AJAX request. I recommend downloading a JSON viewer extension. I use <a href=\"https://chrome.google.com/webstore/detail/json-formatter/bcjindcccaagfpapjjmafapmmgkkhgoa\" target=\"_blank\">JSON Formatter</a> for Chrome, and it just makes the data easier to read, so give it a try if you’d like.","You may be asking what does an AJAX call look like? Well that’s for you to find out. Check out this <a href=\"http://api.jquery.com/jquery.ajax/\" target=\"_blank\">link</a> for more info.","Simple, right? A GET request looks something like this:",{"codeBlock":"$.ajax({\n  method: 'GET',\n  url: 'http://demo.com',\n  success: function(result) {\n   // result is whatever the URL sends back from the request\n  },\n  error: function(err) {\n   // if any errors occur during the process you can check out the\n   // the error by logging the 'err' argument\n  }\n});"},"Or you can specify the type of HTTP request from the get-go. Like so:",{"codeBlock":"$.get('http://demo.com', function(result) {\n  // result is whatever the URL sends back from the request\n});"},"Either one works. But do notice for the first example that we have these <i>success</i> and <i>error</i> callbacks that are exposed to us. Remember how we talked about asynchronicity before? Well, let’s talk about it again.","One way AJAX handles asynchronicity is through these two functions. And these type of functions have to always exist, otherwise we can’t handle the logic after the HTTP request is made. Remember that the JS Engine keeps executing code while this HTTP request is still in the works, and the request event is ultimately dequeued from the Event Loop once resolved.","If we were to try to access the response from outside the success block we would get an error. That’s because we only have access to the response inside the AJAX call, because that’s where it becomes defined!","Basically, we’ll want to move all of our logic inside of the <i>success</i> function, because otherwise elements will render out of order. We want our image to render first, and then append text above it, and this order is only possible once we know when the image is defined.","Anyways, let’s get back to the fun.","As a challenge go ahead and use the first AJAX example to make a GET request to the URL provided above to receive JSON data back, and then log it to the console. I got something like this:","<img class=\"img-responsive\" src=/assets/chrome-ext/json.png>","To me this is an extremely beautiful part of programming. All we did is make a request to a server at a particular URL and it responded with JSON data. Now, we can do whatever we want with it.","And what we’re going to do is cycle through a different photo each time we load Twitch, so our inspiration never withers! We can do so by randomly generating a different index to fetch an image object from this massive array on-load. How would we do this in JavaScript? Check out some of the methods on the <a href=\"http://www.w3schools.com/js/js_math.asp\" target=\"_blank\">Math class</a>, and see if any of them look useful. Did <i>Math.random</i> catch your eye? It caught mine. Let’s use it.","Here’s an example I found on MDN:",{"codeBlock":"// Returns a random number between min (inclusive) and max (exclusive)\nfunction getRandomArbitrary(min, max) {\n  return Math.random() * (max - min) + min;\n}"},"A few things to note about this. One, Math.random returns a floating-point number, or a number with decimals in it, so we have to floor that result to an actual integer, because we can only access elements in an array by an integer based index. And two, our max for the example above would be the length of the image array we got back from the URL.","Alright, just a few more steps and we’ll be there. Okay, so by now you can randomly access a different image object each time the page renders, but we still haven’t added the actual image to the DOM yet.","We’ll format our image element’s <i>src</i> property as follows:","<i>https://picsum.photos/id/&lt;image.id&gt;/1200/800</i><br /> e.g. <br /> <i>&lt;img src=\"https://picsum.photos/id/127/1200/800\" /&gt;</i>","The image ID is a key on the image object we access each time YouTube loads.","<img class=\"img-responsive\" src=/assets/chrome-ext/imageid.png>","And boom! Isn’t that just beautiful? And the true magic is happening under the hood. Every time we load the page it makes an AJAX GET request to the Lorem Picsum URL, and it responds with an array of objects that each represent data about an image. We fetch one randomly by its image ID, and populate it to the DOM… and everything is done dynamically! Wooh! You did it!","<b>Further Challenges:</b>",{"list":["Make the images cycle just by clicking on it, instead of having to reload the page each time to see a new image","Register with the Lorem Picsum API and fetch images once properly authenticated via <a href=\"https://frontend.turing.edu/lessons/module-4/oauth/index.html?ads_cmpid=6451354298&ads_adid=76255849919&ads_matchtype=&ads_network=g&ads_creative=665961240900&utm_term=&ads_targetid=dsa-19959388920&utm_campaign=&utm_source=adwords&utm_medium=ppc&ttv=2&gclid=Cj0KCQjw2qKmBhCfARIsAFy8buIixGzwmOhOA_GEOOTj5WqU6wIgHGDqqVMr8zqaxEwUOnJ0ZnxaBC4aAsLaEALw_wcB\" target=\"_blank\">OAuth</a>","Have the image fade in and fade out by using jQuery animations"]}]},"closures-divein":{"subunitId":"closures-divein","heading":"Dive into Closures","read":[{"subheading":"What We'll Cover","subcontent":[{"orderedList":["Execution Context","Scope","What is a closure?","What are closures used for?"]}]},{"subheading":"Execution Context","subcontent":["The execution context is the environment in which a JavaScript function is being executed. Each execution context has its own variable scope.","Whenever a function is invoked, a new execution context is pushed onto the call stack, and a new variable environment is created along with it. The function’s code runs in the new execution context and has access to the variable environment in the execution context directly below that new execution context (the one in which the function was invoked).","Upon exit of the function, the execution context is popped off of the call stack. Code in one execution context is stopped until the code in the execution context above it finishes running."]},{"subheading":"Scope","subcontent":["Variable environments are commonly referred to as “scope.” While each execution context is stacked on top of the execution context preceding it, each scope is created inside of the previous scope. Code being executed inside a scope not only has access to the variables in that scope, but also the variables in all the scopes that encase it. Therefore, code that runs in a given execution context has access to all the variables created in the execution contexts below it."]},{"subheading":"What is a closure?","subcontent":["A closure is a variable environment that has outlived its execution context and remains attached to a function that also has outlived the same execution context.","If multiple functions are created in the same execution context and all of them outlive that execution context, those functions each have their own closure, and each of these closures will access the same variables in memory. Therefore, mutation of those variables by one of those functions will affect the other functions in the manner that they will be accessing the same (mutated) variables."]},{"subheading":"What are closures used for?","subcontent":["Closures give us the ability to gain some benefits normally associated with object-oriented programming, namely data privacy and data encapsulation (thus name “closure”). When the structure of the encapsulated data and the methods used to access/manipulate the data is too simple to justify using actual object-oriented programming, closures provide a convenient solution.","Closures can aid in maintaining secure and private access to variables, by creating functions that serve as the only objects with access to these variables. The functionality of the functions themselves serves as a method of whitelisting the ways that those variables can be mutated. Because only the created functions have access to the variables, the procedural steps outlined in the created functions are the only procedures that can operate on the variables in the closure.","Closures are used especially often when functionality is being imported into a file from another file. The code in the imported file is executed, creating a closure for any function(s) exported from the file. This is a common method for JavaScript libraries to be made available for use to a developer’s application and helps developers maintain modularity of their code."]}]},"csx-prereqs":{"subunitId":"csx-prereqs","heading":"Prerequisites for CSX","read":["You’re going to hear a lot in CSX and in your journey to Codesmith about the importance of problem-solving and communication of your code - and that it’s more important than your ‘knowledge’ of JavaScript.","However you still have to understand these building blocks to be able to actually wield this knowledge to solve problems and communicate your code. You should just not fall into the trap of thinking coding is about ‘knowledge’ alone.","The journey to coding begins with an understanding of the fundamental building blocks of code: variables, functions, loops, if/else - the pieces that are almost universal to every programming language.",{"subheading":"Recommended prerequisites for CSX","subcontent":["You need to be comfortable with these basic building blocks - and part of that is just repetition and familiarity. There are numerous online resources for these initial foundations and each person finds the one that fits them best. The key is to not stop during these foundations.",{"list":["The CSX Precourse Unit - Part 1 and 2","Codecademy - Text-only teaching and simple challenges - free. You should complete the <a href=\"https://www.codecademy.com/learn/introduction-to-javascript\" target=\"_blank\"> Introduction to JavaScript</a> units 1-8","Team treehouse - Video-based - great introductory tutorials - but monthly subscription. You should complete parts 1-3 of their <a href=\"https://teamtreehouse.com/tracks/full-stack-javascript\" target=\"_blank\">Learn JavaScript track</a> before CSX","Freecodecamp - All the foundations you need in JavaScript, HTML and CSS. Also has an incredible community. You should complete <a href=\"https://www.freecodecamp.org/learn/javascript-algorithms-and-data-structures/basic-javascript/\" target=\"_blank\">Basic JavaScript</a> (10 hours) before CSX"]},"Once you have completed <i>one</i> of these prerequisites, you may want to complete others or start doing the resources’ more advanced parts.","However, at some point you will begin to feel this sense of plateauing - how do I move from following along tutorials to beginning to have the autonomy to tackle new challenges without the tutorial structure. What is the path? The answer is moving to harder open-ended challenges and a deeper understanding of JavaScript.","So what’s stopping everyone from doing this?","Becoming an autonomous problem solver with code is really hard. One of the reasons most of us rely on guided tutorials is that the next level involves hitting lots of intellectual, learning and even emotional blocks - it’s a struggle.","At the same time though, this is where you grow as a software engineer and move beyond following tutorials.","So how can we hope to push through these blocks?","By being part of a learning and building community - and above all - by <b>pair-programming</b>."]}]},"csx-teaching-style":{"subunitId":"csx-teaching-style","heading":"What is the CSX teaching style?","read":["Learning to code is hard, there is no beating around the bush on that. But hard learning is what sticks, and hard things can be accomplished, especially with the right resources and support. We designed CSX to be ‘hard learning’ but we also created it with additional learning opportunities to help you overcome obstacles and grasp the concepts on a fundamental level.","Tutorial style learning feels amazing, but we often find ourselves asking - did we actually learn anything there? Did we retain this information and can we apply it in a new situation that isn’t an exact copy of how we learned it? Very rarely have we found ourselves answering ‘yes’ to those questions without feeling the ‘struggle’ to grasp a concept or connect the dots.","CSX is not tutorial-style learning! The challenges are meant to push you and help you become an autonomous problem solver. You will grapple with applying concepts in different situations, rebuild functions you’ve used without deeper thought, and write efficient clean solutions. But that is the good stuff - struggling is awesome, it leads to that deep understanding!","In order to assist with this struggle, we’ve also built help into CSX in the way of:",{"list":["Testing your code - there’s no better way to understand more about your solution’s viability than by testing your code. You can do so on each challenge by using the ‘check my answer’ functionality as well as by uncommenting the console logs in the boilerplate code.","Solution videos - many of our challenges have video walk-throughs of a solution in the subunit following that challenge. These walkthrough videos are created by our CSX Mentor team and are designed to show you a possible solution to the challenge (remember there are many ways to solve every challenge). We recommend attempting the challenge on your own before using the solution video as a resource!     - The csx-challenge-solution channel on the <a href=\"https://share.codesmith.io/csxslack\" target=\"_blank\">CSX Slack</a> - we’ll talk more about this slack channel later in the overview unit, but this channel is a great place to ask questions about challenges to the CSX community and receive helpful tips and tricks."]},"Additionally, we always recommend the use of:",{"list":["<a href=\"https://developer.mozilla.org/en-US/\" target=\"_blank\">MDN Web Docs</a> - a great place to find general information about JavaScript syntax and how things function","<a href=\"https://www.w3schools.com/\" target=\"_blank\">W3schools</a> - another education website for learning to code with great references on language functionality"]}]},"csx-to-codesmith":{"subunitId":"csx-to-codesmith","heading":"What are the Codesmith programs and how is CSX related to them?","read":["Codesmith offers a variety of programs for all levels of JavaScript learners and for those with varying goals of learning to code. Each of our programs can be prepared for by working through related CSX Units! CSX was designed to help prepare you for Codesmith programs by teaching you JavaScript syntax and functionality, computer science fundamentals, and technical communication through a focus on pair programming.","<a href=\"https://codesmith.io/javascript-for-beginners\">JavaScript for Beginners -</a>","JavaScript for Beginners (JSB) is a part-time, remote program consisting of two consecutive Saturday sessions. The program is designed for those with no previous coding experience and will teach JavaScript fundamentals, as well as provide a broader context to how coding works. The program offers students a launching point to continue their JavaScript studies, prepare for CS Prep, and build a future in software engineering.","Because no coding experience is required for JSB, there’s no need to complete any of our CSX Units. We recommend getting started with our Precourse - Part 1 Unit to familiarize yourself with JavaScript syntax so you can hit the ground running on day 1.","<a href=\"https://www.codesmith.io/cs-prep\">CS Prep -</a>","CS Prep is a 2-week program covering JavaScript concepts, engineering best practices, and technical communication. The program includes live-online instruction, daily problem-solving workshops, and a passionate coding community to help you prepare for top coding boot camps, such as our selective Software Engineering Immersive programs, and solve real-world problems","We do not require any coding experience to apply to CS Prep, but we strongly encourage completing up through Precourse Part 2 and taking a look at the Functions and Execution Context Units before starting the program. CS Prep moves quickly, as there is a lot of ground to cover taking you from beginner to intermediate JS, so the more familiarity you have with these concepts the better! Don’t worry though, in the program we’ll discuss JavaScript fundamentals like functions and data types, closures, callbacks, recursion, and algorithms at length.","<a href=\"https://www.codesmith.io/software-engineering-ai-immersive\">Software Engineering Immersive Program -</a>","Our flagship program is our Software Engineering Immersive taught full-time online, in Los Angeles, and New York City as well as part-time online. The program teaches full-stack JavaScript and computer science to prepare you for mid and senior-level software engineering roles. The expertly designed curriculum and supportive community immerses you in modern web technologies, such as React and Node.js, and encourages you to tackle unique and unfamiliar problems to prepare you for the ever-changing tech landscape. Codesmith offers an extensive hiring support program that guides students through the hiring process, including interview strategies, portfolio development, and post-graduation check-ins. By the end of the 12 weeks, you will be an autonomous engineer, ready to make an impact at innovative tech companies worldwide.","In order to prepare for the Immersive Program you will need to have a firm grasp on all concepts covered in CSX up through Recursion. On the CSX Homepage on each Unit’s overview card you can see which concepts are ‘always’, ‘sometimes’, or ‘never’ tested on the Codesmith Technical Interview. To learn more about the Immersive session we recommend attending an Information Session or scheduling an academic advisor call.","Enjoy CSX and happy coding!"]},"curriculum":{"subunitId":"curriculum","heading":"Curriculum Overview of the Units to Come","read":[{"subheading":"JavaScript Units","subcontent":["CSX Precourse - Part 1",{"list":["[In-person or online workshop] Intro to JavaScript - Variables and Looping","The console","Variables and variable reassignment","Data types overview","Strings - concatenation, properties, and methods","Numbers - addition, subtraction, etc.","Booleans"]},"CSX Precourse - Part 2",{"list":["[In-person or online workshop] Intro to JavaScript - Variable and Looping","Arrays - examining and adding elements","Loops - for loops and while loops","Control flow","Objects - iterating through and adding properties"]},"Unit 1: Functions and Execution Context",{"list":["[In-person or online workshop] Intro to JavaScript - Functions and Objects","How the return keyword works","Function definition vs invocation","Arguments vs parameters","Execution contexts","Memory and thread of execution","Call stack"]},"Unit 2: Callbacks and higher order functions",{"list":["[In-person or online workshop] JavaScript the Hard Parts: Callbacks and Higher Order Functions","Principle of function abstraction","Applying function abstraction to functionality"]},"Unit 3: Closures, Scope, and Execution Context",{"list":["[In-person or online workshop] JavaScript the Hard Parts: Closures","What if our functions could remember their prior invocation?","Returning a function","Lexical scoping","Variable environment and the backpack"]},"Unit 4: Recursion",{"list":["[In-person or online workshop] JavaScript the Hard Parts: Async","Async callbacks, web browser","The Callbacks queue and event loop"]},"Unit 5: OOP",{"list":["[In-person or online workshop] Recursion: A Deep Dive","Parameters as storage","Performance"]},"Unit 6: Async",{"list":["[In-person or online workshop] JavaScript the Hard Parts: OOP","Prototype, __proto__ and the prototype chain","Factories, constructors and classes"]}," Project: Chrome Extension",{"list":["Chrome extension that makes you more productive and a better coder"]},{"button":"<a class=\"btn btn-primary pull-right\" href=\"/learn/csx-tools\">Next Unit</a>"}]}]},"expectations":{"subunitId":"expectations","heading":"Our expectations of you in CSX","read":["In CSX we expect you:",{"orderedList":["To commit a certain number of hours per week minimum to working through CSX material. We recommend 10 per week if possible. Developing a routine that lets you get flow on the material is essential to growing your coding skills.","Attend at least 2 free coding workshops hosted by Codesmith to pair-program either online or in person","Support and contribute to the community and discussion as part of the <a href=\"https://share.codesmith.io/csxslack\" target=\"_blank\">CSX Slack channel</a>","Develop in all 5 capacities that make an excellent software engineer that we described above"]},"You can expect of us:",{"orderedList":["Push you to develop your problem-solving, communication and depth of JavaScript knowledge that will help prepare you for a bootcamp or (with additional work) for Codesmith’s admissions process","Support a workshop and pair-programming environment that is engaging and supportive","Develop and create new CSX challenges and update/fix where there are bugs (email at <a href=\"mailto:csx@codesmith.io\" target=\"_blank\">csx@codesmith.io</a> with bugs)"]}]},"future-code-take-home":{"subunitId":"future-code-take-home","heading":"Future Code Take-Home","solve":{"code":"// Write your code here\n","instructions":[{"instructionContent":["Write out pseudocode (a description of the steps you'd take) for solving this challenge. Then try to solve it in code!","Declare a variable <code>name</code> and initialize it to a string (your name!).","Create an array <code>vowels</code> that contains all of the vowels (a, e, i, o, u).","Using <code>for</code> loops, iterate through all the letters in your name to create a new string variable with the vowels capitalized.","Make sure you come up with ways to test your code!"]}]}},"help-stuck":{"subunitId":"help-stuck","heading":"Where can I get help if I am stuck?","read":["As previously mentioned, CSX is focused on helping you become an autonomous problem-solver equipped with the tools to solve challenges based on learned strategies and approaches, not memorized helper functions. This style of learning is only possible with the addition of the CSX Community!","The CSX Community was created to support and uplift those learning to code. It’s full of spaces to find others learning to code to work together, and a place to share successes and challenges.","<a href=\"https://share.codesmith.io/csxslack\" target=\"_blank\">Join the CSX Slack</a>","The <a href=\"https://share.codesmith.io/csxslack\" target=\"_blank\">CSX Slack</a> is the optimal way to engage with the CSX community. It’s the best place to ask questions, meet other community members, and find out about upcoming events and workshops. Key Channels",{"list":["General - the best place to introduce yourself, hear about CSX news, and learn about upcoming events, workshops and additional learning opportunities","Csx-challenge-help - the place to ask questions about CSX challenges and concepts","Pair-programming - the channel to find potential pair programming partners and interact with others learning to code","Coding-resources - the hub of shared resources for learning to code"]},"<a href=\"mailto:csx@codesmith.io\">CSX Email</a>","If you’re working through a challenge and need some help, feel free to shoot us an email at <a href=\"mailto:csx@codesmith.io\">csx@codesmith.io</a>. We’re happy to check out your code and help recommend a path to a solution or other learning resources! We also love receiving feedback on the platform, so feel free to pass that along as well.","<a href=\"https://calendly.com/codesmith-program/alumni-advisor-call\" target=\"_blank\">Schedule an Alumni Advisor Call</a>","If you’re looking to chat with someone about your particular learning to code path, interest in becoming a software engineer, or ask a question about a Codesmith Program - <a href=\"https://calendly.com/codesmith-program/alumni-advisor-call\" target=\"_blank\">schedule a call with an Alumni Advisor</a>. They can help you determine which concepts to focus on, what may be your next step, and give advice from their own personal experience of becoming a software engineer.","<a href=\"https://www.facebook.com/groups/460331961030253/\" target=\"_blank\">Join the CSX Facebook Group</a>","Though far less active than our Slack Channel, the <a href=\"https://www.facebook.com/groups/460331961030253/\" target=\"_blank\">CSX Facebook</a> is another place for folks to chat. Feel free to post questions, engage with community members, and chat all things code."]},"intro":{"subunitId":"intro","heading":"What is CSX?","read":["Welcome to CSX, we’re so happy to have you here! CSX is both an online free platform to learn JavaScript and an international community of folks committed to learning to code. Our videos and challenges are designed to teach you, beginner, to intermediate JavaScript and computer science fundamentals, and our community will help you overcome blocks and achieve your coding goals.","CSX is maintained by <a href=\"https://codesmith.io/\" target=\"_blank\">Codesmith</a>, the <a href=\"https://codesmith.io/graduate-outcomes\" target=\"_blank\">top-ranked online coding school</a>. We originally built CSX as a tool for our potential students to use to prepare for our Full-time Immersive Program’s technical interview, but it’s grown to be so much more than that! We saw the need for a platform to learn JavaScript that combined difficult challenges with a supportive community so ‘hard learning’ could take place!","As our program offerings and free workshops have expanded, so have the content and community that makes up CSX:",{"orderedList":["All of our CSX Units can be supplemented with <a href=\"https://codesmith.io/coding-events\" target=\"_blank\">free weekly workshops</a> taught by Codesmith on some of the same topics and concepts","CSX has beginner content designed to give folks their first taste of coding alongside our program <a href=\"https://www.udemy.com/course/javascript-for-beginners-the-complete-intro-course-2022/\" target=\"_blank\">JavaScript for Beginners</a> (Precourse Part 1 Unit)","More intermediate level content for folks to deeply understand core JavaScript functionality so they can succeed in our mid-level prep program <a href=\"https://www.codesmith.io/cs-prep\" target=\"_blank\">CS Prep</a> (Precourse Part 2 Unit and Functions & Execution Context Unit)","Intermediate to advanced concepts for students to prepare for our Full-time and Part-time <a href=\"https://www.codesmith.io/software-engineering-ai-immersive\" target=\"_blank\">Software Engineering Immersive Programs</a> (Callbacks & Higher-order Functions Unit, Closure, Scope & Execution Context Unit, Asynchronous JavaScript Unit, and Object-Oriented Programming Unit)"]},{"read":null},"Keep in mind that CSX is not meant to be a standalone resource! As you are working through the challenges, we recommend using additional resources like <a href=\"https://developer.mozilla.org/en-US/\" target=\"_blank\">MDN</a> and <a href=\"https://www.w3schools.com/\" target=\"_blank\">W3Schools</a> to supplement your learning.","Steps to getting started:",{"list":["We recommend filling out our <a href=\"https://share.codesmith.io/unit-quiz\" target=\"_blank\">CSX Track Quiz</a> which will direct you to a unit based on your experience level and goals.","Join the <a href=\"https://share.codesmith.io/csxslack\" target=\"_blank\">CSX Slack Channel</a> to start meeting other community members and asking questions"]},{"read":["Happy Coding!"]}]},"intro-async":{"subunitId":"intro-async","heading":"Introduction to Async","watch":["https://www.youtube.com/embed/xTjx3q2Nm1w",{"description":["Asynchronous JavaScript allows code to continue being executed while we wait for the result of an initiated action, such as starting a timer, reading a file, or requesting data from a server. While the timer is running, the file is being read, or the server is calculating its response, the thread of execution continues. This is called \"non-blocking\" behavior, and it results in better performance than what would come from waiting for things to resolve before continuing to the next line of code (which is called \"blocking\" behavior).","We recommend starting your learning by watching Codesmith CEO, Will Sentance take a deep dive into these concepts.","You can follow along the video with the slides <a target=\"_blank\" href=\"https://drive.google.com/file/d/1NVOGU8gI2qEJ-2cl_-ZUg1U-GGiGsQvk/view?usp=sharing\">here</a>."]}]},"intro-callbacks-read":{"subunitId":"intro-callbacks-read","heading":"Introduction to Callbacks and Higher Order Functions Continued","read":[{"subheading":"Now let's dive in and learn a little more about Callbacks","subcontent":["Object-oriented programming was the most prominent programming paradigm for 25-30 years, but functional programming has taken the lead over the last 5-7 years. As Zoolander's Mugatu would say, \"It's so hot right now.\"","The reason for its rise is clear -- as applications grow in complexity, functional programming gives developers the ability to deliver intuitive, stateless, side-effect free code, greatly streamlining their development process and improving their applications.","Callbacks and higher-order functions are at the heart of functional programming, and they're an essential part of a JavaScript developer's toolbox. Let's explore these concepts together from the ground up."]},{"subheading":"Definitions","subcontent":["If you type “callback” into Google search, you'll see the first definition as “an invitation to return for a second audition or interview.” That’s definitely not the kind of callback we’re discussing here!","In JavaScript, a <b>callback</b> is a function that is passed as an argument to another function. If that doesn’t make sense yet, don’t worry -- we’ll break it down soon.","And what about <b>higher-order functions</b>? A Google search reveals an accurate description - “a function that takes at least one function as input and/or returns a function as output.”","Hmm...Let’s see a code example to clarify -",{"codeBlock":"const array = [1, 2, 3];\n\nfunction update(callback) {\n  const output = [];\n  for (let i = 0; i < array.length; i++) {\n    const updated = callback(array[i]);\n    output.push(updated);\n  }\n\n  return output;\n}\n\n// Callback functions\nfunction add10(num) {\n  return num + 10;\n}\n\nfunction multiplyBy20(num) {\n  return num * 20;\n}\n\nfunction stringify(num) {\n  return num.toString();\n}\n\n// Call update with each callback function\nupdate(add10) // returns [11, 12, 13]\nupdate(multiplyBy20) // returns [20, 40, 60]\nupdate(stringify) // returns [‘1’, ‘2’, ‘3’]"},"So we have two function definitions, and we're executing update with add10 as input. One of these functions is the callback, and one of them is the higher-order function. Can you guess which one is which?","Spoiler alert - the callback is add10, and the higher-order function is update!","Why is add10 the callback? It satisfies these two conditions -",{"list":["It is used as input in another function call.","It is called inside of the other function."]},"Why is 'update' the higher-order function? It satisfies these two conditions -",{"list":["It takes a function as an argument.","It calls its input function when it is called. Hence, the term \"callback\" as one function call leads to another."]},"So basically, higher-order functions have callbacks as inputs and call those callbacks somewhere in their definition.","To clarify, although we may call a function a “callback” or a “higher-order function”, they are both just normal JavaScript functions. Nothing special about them except the terminology we use to describe them."]},{"subheading":"When Do You Use This Stuff","subcontent":["As fundamental building blocks in JavaScript, callbacks and higher-order functions are used in almost every web application. They solve a general set of code duplication problems.","Let’s start thinking about those problems. We’ll build up our understanding through a series of questions that highlight how we can write cleaner, more powerful code with callbacks and higher-order functions."]},{"subheading":"The Questions Begin","subcontent":["Let's say you are tasked with manipulating an array of numbers, such as stock prices. You begin by testing your skills on a small array to see if you can simply add 10 to each integer.","You might write some code that looks like this -",{"codeBlock":"const array = [1, 2, 3];\nconst output = [];\n\nfor (let i = 0; i < array.length; i++) {\n  const updated = array[i] + 10;\n  output.push(updated);\n}\n\nconsole.log(output); // prints [11, 12, 13]"},"If that were the only addition operation you needed to perform in your application, then this code is absolutely fine. However, you realize you need to add other values, too. How would you write new code to add other values, like 20, to each number?","Welp… looks like we’ll have to copy/paste the entire code block just to make one change -",{"codeBlock":"const array = [1, 2, 3];\nconst output = [];\n\nfor (let i = 0; i < array.length; i++) {\n  const updated = array[i] + 20;\n  output.push(updated);\n}\n\nconsole.log(output); // prints [21, 22, 23]"},"It feels dirty to repeat so much code for such a small change. And it’s inefficient because we have to store all this duplicated code in memory.","You may have heard of the DRY principle (Don’t Repeat Yourself). This code breaks that principle. In colloquial terms, it’s not DRY code."]},{"subheading":"For Every Problem, There Is A Solution","subcontent":["How can we solve this repetition problem? In other words, how do we abstract away the code that doesn’t change? Think about this deeply, then keep reading.","-- Stop here if you are just starting to think deeply --","-- If you haven’t thought deeply, you shouldn’t be reading this. Think deeply then come back!--","-- Start here when you’re done thinking deeply --","Time for the answer -- Any time we notice we are writing code that repeats except for one small part, we turn it into a function! The function body will contain the repetitive code block, and its parameter will replace the one thing we want to change. For example, if we want to change the number we’re adding, just replace all instances of that number with the parameter num.",{"codeBlock":"const array = [1, 2, 3];\n\nfunction addNum(num) {\n  const output = [];\n  for (let i = 0; i < array.length; i++) {\n    const updated = array[i] + num;\n    output.push(updated);\n  }\n\n  return output;\n}\n\nconsole.log(addNum(10)); // prints [11, 12, 13]\nconsole.log(addNum(20)); // prints [21, 22, 23]"},"How great is that! Instead of having to copy/paste the same code block over and over and over every time we want to change the number added, we just write one function. Now we can call that function with any number as input and get the appropriate output.","In other words, when we create our functions with parameters like this, we have no idea which number will be added in the future. Think about how cool that is... we are delivering a function that will calculate <i>any</i> possible addition you could throw at it… and all we did was abstract away one number!","This is incredibly useful if you need to frequently transform array elements using addition in your applications."]},{"subheading":"One Step Further","subcontent":["Thinking about our stock prices example, if all we needed to do was add values to the prices, then we could clap our hands and go home -- we would have all the functionality we need. Hooray!","But what if we wanted to perform other operations, like subtraction or more complex manipulation? Functions cannot take operators (like + and -) as parameters, so that's one limiting factor. But more importantly, we can't deliver custom functionality through simple value substitution.","If only we could use other functions as parameters to deliver custom functionality inside our function... oh wait, we can!"]},{"subheading":"First-Class Citizens To The Rescue","subcontent":["In JavaScript, functions are first-class citizens. This means that functions can be passed as input to other functions (as well as returned from other functions, modified, and assigned to variables). This gives developers the ability to use functions as parameters, which we refer to as <b>callbacks</b>.","So how could we perform more complex calculations in our stock prices example? Well, if a number parameter allows us to use <i>any</i> number (like 10 or 20), then a <b>function</b> parameter allows us to use <i>any</i> functionality (like adding, subtracting, or more complex manipulation)!","That’s hard to visualize without a concrete example. So, here’s a concrete example. Notice how the <b>updated</b> variable has changed and we can apply three different functions to the array quite easily -",{"codeBlock":"const array = [1, 2, 3];\n\nfunction update(callback) {\n  const output = [];\n  for (let i = 0; i < array.length; i++) {\n    const updated = callback(array[i]);\n    output.push(updated);\n  }\n\n  return output;\n}\n\n// Callback functions\nfunction add10(num) {\n  return num + 10;\n}\n\nfunction multiplyBy20(num) {\n  return num * 20;\n}\n\nfunction stringify(num) {\n  return num.toString();\n}\n\n// Call update with each callback function\nupdate(add10) // returns [11, 12, 13]\nupdate(multiplyBy20) // returns [20, 40, 60]\nupdate(stringify) // returns [‘1’, ‘2’, ‘3’]"},"Compared to our previous example, we still changed the same variable, updated. Instead of using the ‘+’ operator and a number parameter, we replaced that code with a function call to the array element. This small change now allows us to use <i>any</i> function, referred to as a <b>callback</b>, when we run the update function!","This makes <b>update</b> a higher-order function because it now takes a callback as input. In fact, I’ve been hiding a secret from you this whole time… this update function is essentially the built-in <b>map</b> function in JavaScript!","Given a callback, <b>map</b> will output a new array where each element is the output of a call to the callback. It provides us a powerful tool to transform arrays, and we control the transformation through callbacks."]},{"subheading":"Wrapping Up","subcontent":["Let’s summarize what we’ve discussed in this article.",{"list":["Callbacks are functions that are passed as input to other functions.","Higher-order functions take at least one function as input (and/or return a function, although we haven’t dug into that aspect of them in this article. You can learn more about that in our post on Closures!)","Functions give us the power to use the same code without copy/pasting it. We insert parameters where we’d like control over changing values.","Higher-order functions provide an additional layer of abstraction, using callbacks as parameters to control functionality instead of simple values. The built-in map function is one example of an incredibly useful higher-order function that transforms arrays with callbacks."]}]}]},"intro-callbacks-video":{"subunitId":"intro-callbacks-video","heading":"Introduction to Callbacks and Higher Order Functions","watch":["https://www.youtube.com/embed/viQz4nUUnpw",{"description":["We recommend stating your learning by watching Codesmith CEO, Will Sentance take a deep dive into these concepts.","You can follow along the video with the slides <a target=\"_blank\" href=\"https://drive.google.com/file/d/18e2nJUf2QC3JZ_3N07vRSy8G8xvvjA1X/view?usp=sharing\">here</a>."]}]},"intro-closures":{"subunitId":"intro-closures","heading":"Introduction to Closure, Scope and Execution Context","watch":["https://www.youtube.com/embed/ZVXrJ4dnUxM",{"description":["We recommend beginning by watching this recording of Codesmith CEO, Will Sentance, taking a deep dive into these concepts. You do not need to finish this recording in entirety before moving on to the challenges!","You can follow along the video with the slides <a target=\"_blank\" href=\"https://docs.google.com/presentation/d/10TJv4ENS5YpjdMSSalYS33Eik1eclqCWiKq9N_pAQEc/edit#slide=id.g4b3bf7bf6e_1_0\">here</a>."]}]},"intro-closures-pt-2":{"subunitId":"intro-closures-pt-2","heading":"Introduction to Closure, Scope and Execution Context (continued)","watch":["https://www.youtube.com/embed/ZVXrJ4dnUxM",{"description":["We recommend continuing to reinforce these concepts by watching the remainder of this lecture on closures if you haven't already.","You can continue to follow along the video with the slides <a target=\"_blank\" href=\"https://docs.google.com/presentation/d/10TJv4ENS5YpjdMSSalYS33Eik1eclqCWiKq9N_pAQEc/edit#slide=id.g4b3bf7bf6e_1_0\">here</a>."]}]},"intro-functions-execution-context":{"subunitId":"intro-functions-execution-context","heading":"Introduction to Functions and Execution Context","watch":["https://www.youtube.com/embed/exrc_rLj5iw",{"description":["To gain insight on these topics we recommend beginning with the following recording of Codesmith CEO, Will Sentance diving into these topics.","You can follow along the video with the first part of the slides <a target=\"_blank\" href=\"https://drive.google.com/file/d/18e2nJUf2QC3JZ_3N07vRSy8G8xvvjA1X/view?usp=sharing\">here</a>."]}]},"intro-oop":{"subunitId":"intro-oop","heading":"Introduction to Object-Oriented Programming in JavaScript","read":[{"subheading":"What Is Object-Oriented Programming?","subcontent":["Object-oriented programming (OOP) is a programming paradigm that uses objects to model real world data. OOP in JavaScript allows us to create objects that serve as models, and then create new instances of those models. This is a process called instantiation.","How is object instantiation useful? Imagine that we have an application with many users, and we want to store data about all of those users. For each user we want to track their name, age, number of visits to the our website, and number of comments. We also want each user to have a method <code>introduce</code> that logs out its name. We could do so by creating a new object from scratch every time a user signs up, like so:",{"codeBlock":"function createUser(name, age) {\n  return {\n    name: name,\n    age: age,\n    visits: 0,\n    comments: 0,\n    introduce: function() {\n      console.log('My name is ' + this.name);\n    }\n  };\n}"},"On the other hand, creating a new user object from scratch every single time might not be the most DRY approach. Each user object has the same fields, and all user objects will start with <code>visits</code> and <code>comments</code> set to <code>0</code>. There are several ways in JavaScript that we can create a model, also known as a <b>class</b>, to serve as a template for creating future objects."]},{"subheading":"Create Objects Using a Function","subcontent":["Perhaps the most obvious way to create an object based on a template is to create a function that returns objects with a defined structure. For example, we could create a function <code>createUser</code> that accepts <code>name</code> and <code>age</code> parameters and returns a new object:",{"codeBlock":"function createUser(name, age) {\n  return {\n    name: name,\n    age: age,\n    visits: 0,\n    comments: 0,\n    introduce: function() {\n      console.log('My name is ' + this.name);\n    }\n  };\n}"},"This works, but it still doesn't feel like the most elegant solution. Every object that we create has a new copy of the <code>introduce</code> method, but all of those <code>introduce</code> methods do the exact same thing. If only there were some way we could create new objects with access to the same methods, so that we don't have to keep copying those same methods over and over again (and thus using more and more memory!)."]},{"subheading":"The Prototype Chain","subcontent":["We're in luck! JavaScript does allow us to create new objects with access to the same properties and methods (<b>without</b> creating new copies of those properties and methods each time) through something called the <b>prototype chain</b>. The prototype chain connects objects that we create with another object that serves as a (you guessed it) prototype. Objects inherit properties and methods from objects that are in their prototype chain. You can create an object that inherits from another object, which inherits from another object, which inherits from another object, which...you get the idea! The last object in your chain will inherit properties and methods from every previous object in the prototype chain.","To make the prototype chain more concrete, follow the steps below. Keep in mind that arrays in JavaScript are actually just special object implementations. We'll see exactly how arrays are implemented here!",{"list":["Open your browser's dev tools (in Chrome or Firefox, right-click and then choose \"Inspect\").","Open the console.","Type <code>const tinyArray = ['a', 'b', 'c']</code> and press enter.","Type <code>tinyArray</code> and press enter."]},"We now see our array with a little arrow next to it. Click the arrow, which will show you all of <code>tinyArray</code>'s properties. You can see that it has a length property and a property for each index: <code>0:'a', 1:'b', 2:'c'</code>. But it also has a mysterious <code>__proto__</code> property. What is this? Click it to find out!","You will see a big list of properties and methods sprout from <code>tinyArray</code>. You will assuredly recognize some of them: these are JavaScript's native array methods! If you try calling any of those array methods on <code>tinyArray</code> in the console, you will find that they all work. In fact, all arrays in JavaScript have access to these array methods. And it's all thanks to the prototype chain. That <code>__proto__</code> property of <code>tinyArray</code> is actually a link to the next prototype in the prototype chain. So all arrays in JavaScript are linked to the Array prototype, which is where all array methods and properties are actually stored. In other words, all arrays created in JavaScript inherit from the Array class.","Scroll down to the bottom of the Array properties and methods, and you will see another <code>__proto__</code> property -- a link to the next step up in the prototype chain. Click it, and you'll see that the next step up is the Object prototype. So under the hood, the Array class is an extension of the Object class! Our <code>tinyArray</code> should have access to all of the Object properties and methods you see. Test this out by calling <code>tinyArray.hasOwnProperty(0)</code> in the console.","One last thing on the prototype chain: it only works in one direction. So although all arrays have access to methods of the Object prototype, objects do not have access to methods of the Array prototype."]},{"subheading":"Using the Prototype Chain","subcontent":["Now that you know what the prototype chain is, let's figure out how to use it! The challenge of this unit will lie in researching different methods of creating objects that inherit properties and/or methods from other objects using the prototype chain. As you proceed through the subunits, you should refer to the MDN documentation for <a href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create\" target=\"_blank\"><code>Object.create()</code></a>, using <a href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects#Using_a_constructor_function\" target=\"_blank\">constructor functions</a>, and using <a href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes\" target=\"_blank\" >ES6 <code>class</code> syntax</a>. Also check out <a href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain\" target=\"_blank\" >this article</a> if you want more information on the prototype chain. All right, let's dive in!"]}]},"intro-recursion":{"subunitId":"intro-recursion","heading":"Introduction to Recursion - Repeater","watch":["https://www.youtube.com/embed/21-MlQ_irLo",{"description":["To begin, watch this recording of Codesmith Lead Technical Mentor, George, diving deep into how recursion works -"]}]},"jshp-recordings":{"subunitId":"jshp-recordings","heading":"JSHP Recordings","read":["As mentioned, we live stream our weekly JavaScript the Hard Parts workshops and students interact virtually with the lecture content as well as pair program remotely with other viewers. Check out instructional videos on our <a href=\"https://www.youtube.com/channel/UCAU_6P-M2VHKePIpu5736ag\" target=\"_blank\">youtube channel</a>.","We would recommend starting with these -",{"list":["<a href=\"https://www.youtube.com/watch?v=viQz4nUUnpw&index=5&list=PLWrQZnG8l0E5xUUZQ6d6fWQ0hRECcsy-H\" target=\"_blank\">How to Understand Callbacks and Higher Order Functions</a>","<a href=\"https://www.youtube.com/watch?v=exrc_rLj5iw&list=PLWrQZnG8l0E4kd1T_nyuVoxQUaYEWFgcD&index=5&t=0s\" target=\"_blank\">An Introduction to Functions, Execution Context, and the Call Stack</a>"]},"Though viewing past lectures + videos on youtube is a great way to review content we <b>highly recommend</b> attending our workshops in person if possible, or attending remotely when it is live streamed. There is no equivalent to being fully engaged and immersed in the concepts during lecture that is occurring in real time. Online learning is amazing, but the in person experience with a combination of the pairing, community, and networking/drinks after the workshop cannot be beat.]"]},"learning-resources":{"subunitId":"learning-resources","heading":"What are other learning resources available?","read":["In addition to the challenges, written explanations, and instructional videos that make up CSX - we have many additional learning opportunities and resources to drive forward your learning!","<a href=\"https://www.codesmith.io/free-resources#Events\" target=\"_blank\">Weekly Coding Workshops & Events</a>","The most impactful addition to your CSX learning is our weekly <a href=\"https://www.codesmith.io/free-resources#Events\" target=\"_blank\">free coding workshops</a>. All of our workshops are taught live by our world-class instructors and feature opportunities to ask questions, interact with other attendees, and learn more about Codesmith Programs.","Each of our CSX Units has an associated workshop that’s mentioned in-depth in each individual Unit! We recommend RSVPing on our website because spots in these workshops do fill up.","In addition to workshops covering core JavaScript, we also host larger speaker meetups featuring prominent speakers in the developer community talking about modern technologies, event series focused on Women in Software Engineering, and events focused on sharing information about our programs.","<a href=\"https://www.youtube.com/channel/UCAU_6P-M2VHKePIpu5736ag\" target=\"_blank\">Codesmith’s YouTube Channel</a>","If you aren’t able to make the timing of our free weekly workshops, a great way to experience our instruction and additional in-depth explanations of CSX concepts is on our YouTube Channel. Be sure to check out our <a href=\"https://www.youtube.com/c/Codesmith-School/playlists\" target=\"_blank\">saved playlists</a> if you’re looking for content on a particular concept.","<a href=\"https://www.codesmith.io/free-resources#Events\" target=\"_blank\">Pair Programming Workshops</a>","In addition to our speaker and instructional live workshops, we also host <a href=\"https://www.codesmith.io/free-resources#Events\" target=\"_blank\">pair programming events</a>. Pair programming is central to becoming a better problem solver, technical communicator, and excellent software engineer.","In pair programming workshops, you’re paired up with a partner of your similar experience level and given challenges to work through together. The way we conduct pair programming involves two programmers working together on one shared challenge set where one person is the driver, writing the code, and one person is the navigator, talking through the logic. We also have mentors available for help!"]},"online-in-person-community":{"subunitId":"online-in-person-community","heading":"Online and In-Person CSX-Community","read":["A key component of CSX is the community. Though the units can be completed individually, the best way to grow yourself as a developer involves interacting with other learners and journeying together. A key aspect of the developer community at large involves shared resources, open source contributions, and an ideology that communal knowledge is for the greater good - an excellent example is <a href=\"https://stackoverflow.com\" target=\"_blank\">Stack Overflow</a>!","The in-person CSX Community is vital for CSX growth. The best way to understand the concepts covered is to attend a <a href=\"https://codesmith.io/events\" target=\"_blank\">free in person workshop</a> at Codesmith HQ in Los Angeles or New York City. If you aren't able to attend in person, many of the workshops are also streamed online. There are 6 total workshops in CSX, and key parts of the units are associated with workshops. You can do them before, after, or during the unit - but whatever you do, do them, it will make a big difference in your understanding of the material. The workshops are combined with the units as followed:","<b>Precourse Workshop:</b> JavaScript the Easier Parts - Variables, Control Flow, and Looping","<b>Unit 1 Workshop:</b> JavaScript the Easier Parts - Functions & Objects","<b>Unit 2 Workshop:</b> JavaScript The Hard Parts - Callbacks and Higher Order Functions","<b>Unit 3 Workshop:</b> JavaScript The Hard Parts - Closures, Scope, and Execution Context","<b>Unit 4 Workshop:</b> Recursion - A Deep Dive","<b>Unit 5 Workshop:</b> JavaScript The Hard Parts - Asynchronous JavaScript","<b>Unit 6 Workshop:</b> JavaScript The Hard Parts - Object Oriented Programming","During every workshop there is dedicated time to discuss problem solving methodology, resources for continued practice, and pair programming - the best way to cement knowledge and practice technical communication. In person events are a great way to connect with CSX mentors and form study groups outside of the usual workshop schedule.","In addition to the in person CSX Community, there is the <a href=\"https://codesmith.io/coding-events\" target=\"_blank\">CSX online community</a>. Every JavaScript - The Hard Parts lecture is live streamed and allows viewers to pair up remotely to work through challenges no matter where they are in the world."]},"pair-programming-read":{"subunitId":"pair-programming-read","heading":"Bonus Unit: Pair Programming","read":["When we do ‘hard learning’ it’s very tempting to avoid the struggle - yet this is where the growth is at. There are many ways people avoid the feeling of challenge but the 3 major ones are:",{"orderedList":["By giving up","By focusing on researching and understanding every last detail of the topic but not actually coding","By making it work using code snippets from Stack overflow with no idea <i>how</i> the snippets work"]},"Clearly 1 (giving) up is not a good strategy","However, 2 (researching) and 3 (making it work) are actually vital parts of being an engineer. When these approaches become avoidance is when you get stuck in doing only one of them and don’t balance them both.","Ideally we want to balance ‘research’ with ‘making it work’. How can we do so? With pair programming.","Pair programming is a phenomenal approach that when done right should land us with the ideal balance of ‘researching and understanding’ with ‘making it work’.","<img class=\"img-responsive\" src=/assets/csx-overview/easyhard.png>","<b>You should expect to attend all CSX workshops at least once (many CSX students attend multiple times) to work through the challenges in a pair programming setting.</b>","Here’s the essence of a pair programmed approach to learning. If I have an approach (even if it’s just console logging a variable but all the way up to a sophisticated strategy to tackle the challenge) I will not type it myself but rather explain to my pair programming partner this approach. My partner must then interpret my explanation and implement it in actual typed code.","Following this model of navigator (the explainer) and driver (the implementer) requires you to rationalize (at least a little) why you’re following your approach while still jumping into the code without spending your time only researching.","Simultaneously it requires you to explain your strategy to your partner with clarity and precision - improving your technical communication (one of our 5 key capacities of a software engineer) and underlying problem-solving approach.","Some caveats:",{"list":["If your partner is explaining an approach that you believe is incorrect, let it continue. Half of the time you’ll find they have introduced you to a new approach. If they are in fact incorrect, run the code and see the error - now you have the opportunity to debug together","If your partner consistently has ideas on how to approach the problem. Have that partner explain it to you then you can navigate them back while they type","Try to switch driver/navigator role at least every 15 mins"]}]},"pair-programming-read2":{"subunitId":"pair-programming-read2","heading":"Pair Programming Workshops","read":["Codesmith believes Pair Programming is the key to a complete software engineering education. Apart from connecting with community members through the CSX Slack to schedule pair programming sessions and pair programming during live workshops, Codesmith also has <a href=\"https://www.codesmith.io/free-resources\" target=\"_blank\">weekly Pair Programming Sessions</a> on Thursdays at 6:00 pm EDT.","This is an additional opportunity to pair program and create a community and network of other CSX users, while also improving your understanding of core Javascript principles. You’ll work through blocks faster as a team and improve your technical communication as you learn how to best communicate your ideas with others.","The ability to work well with others and effectively communicate is as important as understanding the technical aspects of software engineering. As you continue on your journey, we hope that you continue to make time for Pair Programming!"]},"parameters-as-storage":{"subunitId":"parameters-as-storage","heading":"Parameters as Storage","watch":["https://www.youtube.com/embed/m8A1D9IBD50",{"description":["To gain a deeper understanding of recursion, watch George explain parameters as storage."]}]},"precourse-data-types":{"subunitId":"precourse-data-types","heading":"Data Types","read":[{"subheading":" ","subcontent":["Now that you know how to declare variables, it would probably be useful to learn what kinds of data you can store within your variables, no?","JavaScript includes data types similar to other programming languages like Java or C#. Data type indicates characteristics of data. It tells the compiler whether the data value is numeric, alphabetic, etc., so that it can perform the appropriate operation.","JavaScript includes primitive and composite data types."]},{"subheading":"Primitive Data Types","subcontent":[{"orderedList":["<strong>String:</strong> a series of characters (letters, numbers, spaces, symbols, etc.) wrapped in quotes","<strong>Number:</strong> integers, floats, etc","<strong>Boolean:</strong> true or false","<strong>Null:</strong> intentionaly having no value","<strong>Undefined:</strong> a declared variable that hasn't been assigned a value yet","<strong>Symbol:</strong> a unique value that's not equal to any other value.  Note, this is an ES6 feature that never really took off, so don't worry about it for now."]}]},{"subheading":"Composite Data Types","subcontent":[{"orderedList":["<strong>Object:</strong> Objects in JavaScript, just as in many other programming languages, can be compared to objects in real life. Objects are standalone entities, with properties stored in key/value pairs. Compare it with a person, for example. A person is an object, with properties. A person has a race, a date of birth, a weight, a height, an eye color, etc. The same way, JavaScript objects can have properties, which define their characteristics.","<strong>Array:</strong> Used to store multiple values in a single variable.  Similar to a list.  <em>Technically</em>, arrays are objects in JavaScript, but we'll dive into that more in second half of the pre-course."]},"Here are some examples of all the above pertinent data types:",{"codeBlock":"// String\nconst name = \"Kyle\"; // <= quotes tell us this is a string\n\n// Number\nconst favNum = 17;\n\n// Boolean\nconst iLoveCoding = true; // <= no quotes\nconst iLoveBeets = false;\n\n// Null\nconst blackHole = null;\n\n// Undefined\nlet address; // here we declared the variable, \n             // but never gave it a value, so \n             // it is Undefined\n\n// Object\nconst person = {\n  name: \"Bart Simpson\",\n  dob: \"02/23/88\", \n  weight: 65,\n  hairColor: \"blonde\" \n}\n\n// Array\nconst fruits = [\"apples\", \"oranges\", \"pears\", \"bananas\"];\nconst myArray = [21, \"pear\", [3, 7, 22], { objectsToo: true }];"},"Take note of the fact that Arrays & Objects can contain an assortment of different data types all stored inside one variable!  This is what makes them <em>Composite</em> data types by definition."]},{"subheading":"Conclusion","subcontent":["We'll dive deeper into each of these data types individually over the course of the pre-course, so don't worry if this is all a bit confusing at this point.  For now, just take note of each's existence and general syntax."]}]},"precourse-fizzbuzz-solution":{"subunitId":"precourse-fizzbuzz-solution","heading":"Solution: fizzbuzz","watch":["https://www.youtube.com/embed/J7n9O8j4rUY",{"description":["After you've completed the challenge, watch our CSX Mentor, Xavyr, explain his solution for fizzbuzz.","Please note that this solution video describes one way to solve this challenge, not the only way. There are many ways to solve every challenge!"]}]},"precourse-variables":{"subunitId":"precourse-variables","heading":"Variables & Constants","read":[{"subheading":"What is a variable?","subcontent":["Defining and manipulating data is the basis of programming. Without data, programming has no purpose. Data in JavaScript is stored in variables to be reused when needed. We do this by using special JS reserved keywords.  For variables that can be changed later, we use <code>var</code> or <code>let</code>, and for constant variables, we use <code>const</code>. <code>let</code> and <code>const</code> declarations come with additional restrictions on how the variable can be used."]},{"subheading":"Var","subcontent":["JavaScript has many different data types. Some of these types are numbers, strings, and booleans. Variables are used in order to store these values. In the code below, the variable is named favoriteShow and the value that is being stored under the name favoriteShow is currently \"Shameless\".",{"codeBlock":"var favoriteShow = \"Shameless\";"},"As we mentioned above, the word <code>var</code> is a keyword in JavaScript which signifies that we are going to create a variable. This is followed by the variable name, then the assignment operator (<code>=</code>) assigns whatever is to the right of the equals sign to the variable name.","Once you create a variable with the <code>var</code> keyword, you can also update that variable's value. First, we create a variable called tvShow and assign it the value \"Black Mirror\". Then, without using the <code>var</code> keyword we reassign tvShow to equal \"Parks and Recreation\".",{"codeBlock":"var tvShow = \"Black Mirror\";\nconsole.log(tvShow) // => \"Black Mirror\"\ntvShow = \"Parks and Recreation\";\nconsole.log(tvShow) // => \"Parks and Recreation\""},"Notice the different outputs on lines 2 and 4 each time we call <code>console.log(tvShow)</code>. In the first one on line 2, the output is \"Black Mirror\", but after  we change the value of tvShow to \"Parks and Recreation\" on line 3, we get a  different output for our <code>console.log(tvShow)</code>.  Why are we getting different outputs for the same exact console.log?  As you can see on line 3, we reassigned the value of tvShow from \"Black Mirror\" to \"Parks and Recreation.\" Once we change the value of a variable to a new value, it will remain that value until it is changed again."]},{"subheading":"Let & Const","subcontent":["<code>let</code> and <code>const</code> were introduced with the release of ECMAScript 2015, or more commonly, ES6.  You'll see this term quite a lot while you're learning JavaScript, but for now, don't worry too much about it, it's just a version of JavaScript.  We'll go more into detail on what that means in a later lesson.","In the example below, you can see that the value of variables declared with the <code>var</code> and <code>let</code> keywords may be reassigned.",{"codeBlock":"let fridge = \"empty\";\nconsole.log(fridge) // => \"empty\"\nfridge = \"full\";\nconsole.log(fridge) // => \"full\"\n\nvar house = \"dirty\";\nconsole.log(house) // => \"dirty\"\nhouse = \"clean\";\nconsole.log(house) // => \"clean\""},"At this point you may be asking \"what's the difference between <code>let</code> and <code>var</code>?\" This is a more advanced topic relating to how <code>let</code> and <code>var</code> (and <code>const</code>) are scoped. You'll learn more about scope in later lessons.","While using the <code>var</code> and <code>let</code> keywords allows us to reassign a variable's value, <code>const</code> operates a bit differently.","The <code>const</code> keyword is used to create a constant.  Now, while a <code>const</code> declaration looks mainly the same as <code>let</code> and <code>var</code> variables, the value of a constant cannot be changed throughout the code.  Like <code>let</code>, <code>const</code> is also limited to the scope in which it is declared.","Consider the following:",{"codeBlock":"const pet = \"cat\";\n\npet = \"dog\";  // => TypeError: Assignment to constant variable."},"This would result in the error <code>\"Assignment to constant variable\"</code>"]},{"subheading":"Knowing What to Use and When","subcontent":["In JavaScript today, it is considered best practice to <strong>avoid using var</strong>.  You should try and use <code>let</code> and <code>const</code> whenever possible.  Just remember to use <code>let</code> when you will be changing the value of the variable and <code>const</code> when you won't be changing the value.  Getting in the habit of using <code>let</code> and <code>const</code> properly now in the early stages of your learning will help you keep your code easier to manage."]},{"subheading":"5 Rules for Naming Variables and Constants","subcontent":["There are a few things to know about naming your variables and constants.","<strong>1. Variable names are case-sensitive</strong>. This means <code>a</code> and <code>A</code> are two different variables, regardless which keyword (<code>var</code>, <code>let</code> or <code>const</code>) that was used to define them.",{"codeBlock":"let a = \"hello\";\nlet A = \"goodbye\";\n\nconsole.log(a); // => \"hello\"\nconsole.log(A); // => \"goodbye\""},"<strong>2. Variable names should begin with a lowercase character.</strong>","<strong>3. Variable names cannot begin with a number.</strong>","<strong>4. Variable names cannot contain symbols.</strong>",{"codeBlock":"// VALID\nlet user;\nlet applicant3;\nlet favoriteCandy;\n\n// INVALID\nlet 3applicant;\nlet fav-candy"},"<strong>5. camelCased variable names are best practice</strong>.  <em>camelCase</em> is a naming convention in which a name is formed by connecting multiple words together as a single word with the first letter of each of the multiple words capitalized so that each word that makes up the name can easily be read. The only word not capitalized is the first.",{"codeBlock":"// YES\nlet favFood;\nlet camelCasedVariable;\nlet userName;\n\n// NO\nlet favoriterestaurant;\nlet tobecompleted;"}]},{"subheading":"Conclusion","subcontent":["We've covered A LOT of material here!  Now we're going to spend the next 3 challenges practicing declaring variables and constants.  It may seem overwhelming right now, but don't worry, we'll take it slow, and you'll be a pro in no time."]}]},"precourse-what-is-js":{"subunitId":"precourse-what-is-js","heading":"Javascript: What is it?","read":[{"subheading":"JavaScript is Everywhere!","subcontent":["Not to be confused with Java, JavaScript is the language of the modern web. Along with HTML and CSS, it has become an essential web technology.  If you want to get into web development, it is necessary that you learn JavaScript.","Users today expect a lot from their online experience.  They want web applications that are fast, responsive and efficient.  This is what JavaScript does, and for now, there’s no replacement.","You use JavasScript every day, whether you know it or not. It might be something to make your life easier, like your calendar app, or maybe it’s something to help you stay in contact with your friends like Instagram.  Whether you’re sharing documents, catching up on the world by reading a digital news site, watching videos online, or any of the million things we do online daily, you’re encountering and working with JavaScript somewhere behind the scenes."]},{"subheading":"The Modern Web","subcontent":["Modern web architecture is comprised of three key ingredients: HTML, CSS, and JavaScript.","Think about it like this. If our webpage is a car, HTML is the frame of the car, CSS is the styling of the car, the color of the car, the rims of the car, etc, and JavaScript is the engine.  It’s what makes our car do what a car is supposed to do: DRIVE!"]},{"subheading":"HTML","subcontent":["HTML, Hypertext Markup Language, is the backbone of the web. It’s right underneath the surface of everything you see on the web. HTML is a markup language, which means that it tells the browser how to display information. Whether it’s the text of a paragraph, or a link, HTML is what gives our sites their content."]},{"subheading":"CSS","subcontent":["CSS stands for Cascading Style Sheets with an emphasis on “Style.”  While HTML is used to structure a webpage, CSS comes through and specifies your document’s style.  Page layouts, colors, and fonts are all determined with CSS. Think of HTML as the foundation (every house has one), and CSS as the aesthetic choices."]},{"subheading":"JavaScript","subcontent":["JavaScript, or \"JS\" for short, is a full-fledged dynamic programming language that, when applied to an HTML document, can provide dynamic interactivity on websites.","What you can do with JavaScript in the browser can be broken down into two categories. First, is JavaScript’s ability to interact with the browser elements we mentioned before (HTML/CSS). Second, is the ability JavaScript gives us in shaping and manipulating data.","Let’s say someone named Brandon visited our website and entered his name into the an HTML text field. With the power of JavaScript we can read his entry and create interactive content that is unique to him! Now, whenever Brandon visits our website again we will be able to display a greeting, such as, ‘Welcome back, Brandon!’","When combining JavaScript with HTML & CSS, software engineers are able to make interactive web applications that are creative, powerful, fast, and unique! This is just the beginning of a very exciting journey."]}]},"recursion-performance":{"subunitId":"recursion-performance","heading":"Introduction to Recursion (cont.) - getLength","watch":["https://www.youtube.com/embed/1lx3VAs_lBM",{"description":["Let's continue to break down recursion - watch George explain performance in JavaScript."]}]},"slack-community":{"subunitId":"slack-community","heading":"Slack/Facebook Community","read":["In addition to the weekly workshops, the CSX slack community is a great place to ask questions, compare approaches, and share resources with other CSX students. CSX Mentors will also be active in the slack and responding to questions and giving insight.","Slack is a wonderful tool to stay connected and engaged in the community no matter where you are located - join the CSX Slack <a href=\"https://share.codesmith.io/csxslack\" target=\"_blank\">here</a>.","We also encourage students to join the CSX Facebook group <a href=\"https://www.facebook.com/groups/460331961030253/\" target=\"_blank\">here</a>."]},"solution-after":{"subunitId":"solution-after","heading":"Solution: after","watch":["https://www.youtube.com/embed/thmw-aEuQe0",{"description":["After you've completed the challenge, watch our CSX Mentor, Mitchel, explain his solution for after.","Please note that this solution video describes one way to solve this challenge, not the only way. There are many ways to solve every challenge!"]}]},"solution-ajax-simulate":{"subunitId":"solution-ajax-simulate","heading":"Solution: ajaxSimulate","watch":["https://www.youtube.com/embed/zFqx7aWyiWs",{"description":["After you've completed the challenge, watch our CSX Mentor, Jon, explain the solution for ajaxSimulate.","Please note that this solution video describes one way to solve this challenge, not the only way. There are many ways to solve every challenge!"]}]},"solution-array-builder":{"subunitId":"solution-array-builder","heading":"Solution: arrayBuilder","watch":["https://www.youtube.com/embed/pG1JCk4G0W8",{"description":["After you've completed the challenge, watch our CSX Mentor, Ruth, explain her solution for arrayBuilder!","If you prefer to read through Ruth's approach, please <a href=\"https://codesmith.io/blog/arrayBuilder-csx\" target=\"_blank\">click here to read her blog post</a> detailing her solution to the arrayBuilder challenge.","Please note that this solution video describes one way to solve this challenge, not the only way. There are many ways to solve every challenge!"]}]},"solution-censor":{"subunitId":"solution-censor","heading":"Solution: censor","watch":["https://www.youtube.com/embed/cyjaWV_H-78",{"description":["After you've completed the challenge, watch our CSX Mentor, Sara, explain her solution for censor.","Please note that this solution video describes one way to solve this challenge, not the only way. There are many ways to solve every challenge!"]}]},"solution-create-function":{"subunitId":"solution-create-function","heading":"Solution: createFunction","watch":["https://www.youtube.com/embed/Sn0bbIU6DvI",{"description":["After you've completed the challenge, watch our CSX Mentor, Phillip, explain his solution for createFunction.","Please note that this solution video describes one way to solve this challenge, not the only way. There are many ways to solve every challenge!"]}]},"solution-cycle-iterator":{"subunitId":"solution-cycle-iterator","heading":"Solution: cycleIterator","watch":["https://www.youtube.com/embed/4u0lHYkhVoU",{"description":["After you've completed the challenge watch our CSX Mentor, Mejin, explain the solution for cycleIterator.","Please note that this solution video describes one way to solve this challenge, not the only way. There are many ways to solve every challenge!"]}]},"solution-date-stamp":{"subunitId":"solution-date-stamp","heading":"Solution: dateStamp","watch":["https://www.youtube.com/embed/PrRM9ciNSgE",{"description":["After you've completed the challenge, watch our CSX Mentor, Heidi, explain her solution for dateStamp.","Please note that this solution video describes one way to solve this challenge, not the only way. There are many ways to solve every challenge!"]}]},"solution-disemvowel":{"subunitId":"solution-disemvowel","heading":"Solution: disemvowel","watch":["https://www.youtube.com/embed/f2tYPU-0qV4",{"description":["After you've completed the challenge, watch our CSX Mentor, Xavyr, explain his solution for disemvowel.","Please note that this solution video describes one way to solve this challenge, not the only way. There are many ways to solve every challenge!"]}]},"solution-either-callback":{"subunitId":"solution-either-callback","heading":"Solution: eitherCallback","watch":["https://www.youtube.com/embed/d47lDekXf4E",{"description":["After you've completed the challenge, watch our CSX Mentor, Jared, explain the solution for eitherCallback.","Please note that this solution video describes one way to solve this challenge, not the only way. There are many ways to solve every challenge!"]}]},"solution-factorial":{"subunitId":"solution-factorial","heading":"Solution: Factorial","watch":["https://www.youtube.com/embed/S1hXOyvgl5o",{"description":["After you have completed the challenge, watch George dive into his solution to Factorial.","Please note that this solution video describes one way to solve this challenge, not the only way. There are many ways to solve every challenge!"]}]},"solution-flow":{"subunitId":"solution-flow","heading":"Solution: flow","watch":["https://www.youtube.com/embed/pwftU5vjMY0",{"description":["After you've completed the challenge, watch our CSX Mentor, Samantha, explain her solution for flow.","Please note that this solution video describes one way to solve this challenge, not the only way. There are many ways to solve every challenge!"]}]},"solution-for-each":{"subunitId":"solution-for-each","heading":"Solution: forEach","watch":["https://www.youtube.com/embed/xjvizrVY3Qs",{"description":["After you've completed the challenge, watch our CSX Mentor, Ben, explain the solution for forEach.","Please note that this solution video describes one way to solve this challenge, not the only way. There are many ways to solve every challenge!"]}]},"solution-for-each-async":{"subunitId":"solution-for-each-async","heading":"Solution: forEach","watch":["https://www.youtube.com/embed/ASmSIU-A2wc",{"description":["After you've completed the challenge, watch our CSX Mentor, Dan, explain the solution to forEach.","Please note that this solution video describes one way to solve this challenge, not the only way. There are many ways to solve every challenge!"]}]},"solution-for-loops-arrays":{"subunitId":"solution-for-loops-arrays","heading":"Solution: For Loops and Arrays","watch":["https://www.youtube.com/embed/gaAcOR5yWxw",{"description":["After you've completed the challenge, watch our CSX Mentor, Pauline, explain her solution for For Loops and Arrays.","Please note that this solution video describes one way to solve this challenge, not the only way. There are many ways to solve every challenge!"]}]},"solution-for-loops-fundamentals":{"subunitId":"solution-for-loops-fundamentals","heading":"Solution: For Loops - Fundamentals","watch":["https://www.youtube.com/embed/P-iMJN1Yad4",{"description":["After you've completed the challenge, watch our CSX Mentor, Nisa, explain her solution for For Loops - Fundamentals.","Please note that this solution video describes one way to solve this challenge, not the only way. There are many ways to solve every challenge!"]}]},"solution-function-with-input":{"subunitId":"solution-function-with-input","heading":"Solution: createFunctionWithInput","watch":["https://www.youtube.com/embed/0YEabRrrpEk",{"description":["After you've completed the challenge, watch our CSX Mentor, Phillip, explain his solution for createFunctionWithInput.","Please note that this solution video describes one way to solve this challenge, not the only way. There are many ways to solve every challenge!"]}]},"solution-functions-short-circuiting-a-loop":{"subunitId":"solution-functions-short-circuiting-a-loop","heading":"Solution: Short-Circuiting a Loop","watch":["https://www.youtube.com/embed/SoFJPtHJi8w",{"description":["After you've completed the challenge, watch our CSX Mentor, Ryan,  explain the solution for Short-Circuiting a Loop.","Please note that this solution video describes one way to solve this challenge, not the only way. There are many ways to solve every challenge!"]}]},"solution-get-length":{"subunitId":"solution-get-length","heading":"Solution: getLength","watch":["https://www.youtube.com/embed/noDwyiUUYGA",{"description":["After you've completed the challenge, watch our CSX Mentor, Pete, explain the solution for getLength.","Please note that this solution video describes one way to solve this challenge, not the only way. There are many ways to solve every challenge!"]}]},"solution-group-by":{"subunitId":"solution-group-by","heading":"Solution: groupBy","watch":["https://www.youtube.com/embed/5AzgSa6olDo",{"description":["After you've completed the challenge, watch our CSX Mentor, Katrina, explain the solution for groupBy.","Please note that this solution video describes one way to solve this challenge, not the only way. There are many ways to solve every challenge!"]}]},"solution-intersection":{"subunitId":"solution-intersection","heading":"Solution: intersection","watch":["https://www.youtube.com/embed/Xm-rT8ncaTc",{"description":["After you've completed the challenge, watch our CSX Mentor, Kyle, explain the solution for intersection.","Please note that this solution video describes one way to solve this challenge, not the only way. There are many ways to solve every challenge!"]}]},"solution-invoking-functions":{"subunitId":"solution-invoking-functions","heading":"Solution: Invoking Functions","watch":["https://www.youtube.com/embed/NUqFKYTeTs0",{"description":["After you've completed the challenge, watch our CSX Mentor, Xavyr, explain his solution for Invoking Functions.","Please note that this solution video describes one way to solve this challenge, not the only way. There are many ways to solve every challenge!"]}]},"solution-map":{"subunitId":"solution-map","heading":"Solution: map","watch":["https://www.youtube.com/embed/PhbNDieKAOk",{"description":["After you've completed the challenge, watch our CSX Mentor, Schno, explain the solution for map.","Please note that this solution video describes one way to solve this challenge, not the only way. There are many ways to solve every challenge!"]}]},"solution-multi-map":{"subunitId":"solution-multi-map","heading":"Solution: multiMap","watch":["https://www.youtube.com/embed/CJXQ2tYHDf0",{"description":["After you've completed the challenge, watch our CSX Mentor, Denis, explain the solution for multiMap.","Please note that this solution video describes one way to solve this challenge, not the only way. There are many ways to solve every challenge!"]}]},"solution-multiply-all":{"subunitId":"solution-multiply-all","heading":"Solution: multiplyAll","watch":["https://www.youtube.com/embed/A4mSdIyM8PY",{"description":["After you've completed the challenge, watch our CSX Mentor, Rob, explain the solution for multiplyAll.","Please note that this solution video describes one way to solve this challenge, not the only way. There are many ways to solve every challenge!"]}]},"solution-obj-adding-properties":{"subunitId":"solution-obj-adding-properties","heading":"Solution: Objects - Adding Properties","watch":["https://www.youtube.com/embed/RPaYQaidxXA",{"description":["After you've completed the challenge, watch our CSX Mentor, Aki, explain the solution for Objects - Adding Properties.","Please note that this solution video describes one way to solve this challenge, not the only way. There are many ways to solve every challenge!"]}]},"solution-obj-of-matches":{"subunitId":"solution-obj-of-matches","heading":"Solution: objOfMatches","watch":["https://www.youtube.com/embed/euRZldF1o3U",{"description":["After you've completed the challenge, watch our CSX Mentor, Matthew, explain the solution for objOfMatches.","Please note that this solution video describes one way to solve this challenge, not the only way. There are many ways to solve every challenge!"]}]},"solution-once":{"subunitId":"solution-once","heading":"Solution: once","watch":["https://www.youtube.com/embed/iFslomR92E0",{"description":["After you've completed the challenge, watch our CSX Mentor, Mejin, explain her solution for cycleIterator.","Please note that this solution video describes one way to solve this challenge, not the only way. There are many ways to solve every challenge!"]}]},"solution-person-constructor":{"subunitId":"solution-person-constructor","heading":"Solution: PersonConstructor","watch":["https://www.youtube.com/embed/Mc6zn8fkHXc",{"description":["After you've completed the challenge, watch our CSX Mentor, Mejin, explain her solution for PersonConstructor.","Please note that this solution video describes one way to solve this challenge, not the only way. There are many ways to solve every challenge!"]}]},"solution-person-from-person-store":{"subunitId":"solution-person-from-person-store","heading":"Solution: personFromPersonStore","watch":["https://www.youtube.com/embed/OO_hGJWb05M",{"description":["After you've completed the challenge, watch our CSX Mentor, Erik, explain the solution for personFromPersonStore.","Please note that this solution video describes one way to solve this challenge, not the only way. There are many ways to solve every challenge!"]}]},"solution-reduce":{"subunitId":"solution-reduce","heading":"Solution: reduce","watch":["https://www.youtube.com/embed/ELX-FBXZ-3g",{"description":["After you've completed the challenge, watch our CSX Mentor, Luis, explain the solution for reduce.","Please note that this solution video describes one way to solve this challenge, not the only way. There are many ways to solve every challenge!"]}]},"solution-repeater":{"subunitId":"solution-repeater","heading":"Solution: Repeater","watch":["https://www.youtube.com/embed/Ks252i3zY1U",{"description":["After you have completed the challenge, watch CSX Mentor, Billy, explain his solution for repeater."]}]},"solution-run-in-order":{"subunitId":"solution-run-in-order","heading":"Solution: runInOrder","watch":["https://www.youtube.com/embed/micF_oeeeko",{"description":["After you've completed the challenge, watch our CSX Mentor, Jon, explain the solution for runInOrder.","Please note that this solution video describes one way to solve this challenge, not the only way. There are many ways to solve every challenge!"]}]},"solution-save-output":{"subunitId":"solution-save-output","heading":"Solution: saveOutput","watch":["https://www.youtube.com/embed/ww3yb3qNPyM",{"description":["After you've completed the challenge, watch our CSX Mentor, Keiran, explain the solution for saveOutput.","Please note that this solution video describes one way to solve this challenge, not the only way. There are many ways to solve every challenge!"]}]},"solution-union":{"subunitId":"solution-union","heading":"Solution: union","watch":["https://www.youtube.com/embed/AHAcaJUG_Qo",{"description":["After you've completed the challenge, watch our CSX Mentor, Casey, explain her solution for union.","Please note that this solution video describes one way to solve this challenge, not the only way. There are many ways to solve every challenge!"]}]},"what-now-additional-information-info-sessions-and-alumni-advisor-calls":{"subunitId":"what-now-additional-information-info-sessions-and-alumni-advisor-calls","heading":"Additional Information - Info Sessions and Alumni Advisor Calls","read":[{"subheading":"Info Sessions","subcontent":["In addition to the JavaScript workshops you have attended throughout your time working on CSX, Codesmith also offers other <a href=\"https://app.codesmith.io/coding-events\" target=\"_blank\" >free events</a>, such as program info sessions, community study groups, and technical interview workshops.","If you aren’t able to attend a live session, we recommend visiting our <a href=\"https://www.youtube.com/c/Codesmith-School/videos\" target=\"_blank\" >YouTube Channel</a>  for recordings of selected sessions.  <br> <br>"]},{"subheading":"Alumni Advisor Calls","subcontent":["For a more customized approach, we recommend you schedule a call with an  <a href=\"https://calendly.com/codesmith-program/alumni-advisor-call\" target=\"_blank\">Alumni Advisor</a>. They can help you  determine your particular learning to code path and answer your questions about Codesmith programs.  In addition, Alumni Advisors can help you determine which concepts to focus on, what may be your next step,  and give advice from their own personal experience of becoming a Software Engineer."]}]},"what-now-software-engineering-as-a-career":{"subunitId":"what-now-software-engineering-as-a-career","heading":"Software Engineering as a Career","read":["As you prepare for your career as a Software Engineer, you should attend  additional workshops - check out our <a href=\"https://codesmith.io/coding-events?page=1\" target=\"_blank\" rel=\"noopener noreferrer\">events page</a> for more!","If you are not able to attend a live session, our <a href=\"https://www.youtube.com/c/Codesmith-School/videos\" target=\"_blank\" rel=\"noopener noreferrer\">YouTube channel</a>  features recorded panels and workshops. We recommend starting with  <a href=\"https://www.youtube.com/live/pOybyexT7DA\" target=\"_blank\" rel=\"noopener noreferrer\">“Upleveling Your Tech Career,”</a> where Shaundai Person, a senior engineer at Netflix, shares tips on career growth and balancing ambitious goals.","While CSX focuses on the “why” of JavaScript, we encourage you to continue learning by  <a href=\"https://codesmith.io/software-engineering-bootcamp-projects\" target=\"_blank\" rel=\"noopener noreferrer\">building projects</a>,  like those created by students in Codesmith’s Software Engineering Immersive, and moving on to  advanced resources like <a href=\"https://www.interviewcake.com/data-structures-and-algorithms-guide\" target=\"_blank\" rel=\"noopener noreferrer\">Interview Cake</a>  and <a href=\"https://javascript30.com/\" target=\"_blank\" rel=\"noopener noreferrer\">JavaScript30</a>.","You may also find it valuable to continue engaging with the <a href=\"https://share.codesmith.io/csxslack\" target=\"_blank\" rel=\"noopener noreferrer\">CSX Slack</a>  community and mentoring those who are still in their CSX journey through the  csx-challenge-help channel. This will allow you to review key concepts and practice your technical communication skills  while helping others whose shoes you were just in.","Please keep in mind that coding is a lifelong journey of perfecting your craft, and that there will always  be new tools and technologies to learn! By starting your journey with CSX and engaging in hard-learning,  you are nurturing your ability to become a lifelong learner.","Remember to stay motivated and stay involved! Completing CSX is a great first step to becoming a Software  Engineer and Codesmith is here to support you on the rest of your journey as well."]},"what-now-structured-programs":{"subunitId":"what-now-structured-programs","heading":"Structured Programs","read":["Congratulations on making it through CSX! You should now be ready to apply for one of Codesmith’s flagship  <a href=\"https://www.codesmith.io/software-engineering-ai-immersive\" target=\"_blank\">Software Engineering Immersive Programs</a>,  taught remotely full-time and part-time.","The program teaches full-stack JavaScript and computer science to prepare you for mid- and senior-level software engineering roles.  The expertly designed curriculum and supportive community immerses you in modern web technologies, such as React and Node.js,  and encourages you to tackle unique and unfamiliar problems to prepare you for the ever-changing tech landscape.","The inclusion of four different <a href=\"https://codesmith.io/software-engineering-bootcamp-projects\" target=\"_blank\">types of projects</a> is one of the key  elements that sets Codesmith’s curriculum apart and prepares students for mid- and senior-level software engineering roles.","Codesmith also offers an extensive <a href=\"https://www.codesmith.io/graduate-outcomes\" target=\"_blank\">hiring support program</a> that guides students through the job search process,  including interview strategies, portfolio development, and post-graduation check-ins. By the end of the program,  you will be an autonomous engineer, ready to make an impact at innovative tech companies worldwide.","In the next subunit, we’ll discuss how to prepare for the <a href=\"https://www.codesmith.io/software-engineering-ai-immersive\" target=\"_blank\">Software Engineering Immersive Program</a> technical interview!"]},"what-now-technical-interview-prep":{"subunitId":"what-now-technical-interview-prep","heading":"Technical Interview Prep","read":["In each Unit’s overview card on the CSX Homepage, you can see which concepts are ‘always,’ ‘sometimes,’ or ‘never’  tested on the Codesmith Technical Interview. You can learn more at our “How to Pass the Technical Interview” workshops  that are scheduled roughly every five weeks!  Keep an eye on our workshops page for the next event.","The following concepts are always tested on the Technical Interview for Codesmith’s Software Engineering Immersive:",{"list":["Functions and Execution Context","Callbacks & Higher-order Functions","Closure, Scope & Execution Context","Recursion","Object Oriented Programming"]},"Apart from the technical elements, we also look for technical communication skills and the ability to debug,  which you can practice in a <a href=\"https://www.codesmith.io/free-resources#Events\" target=\"_blank\">pair programming session</a>  or through the <a href=\"https://share.codesmith.io/csxslack\" target=\"_blank\">CSX Slack</a> pair-programming and csx-challenge-help channels.","To learn more about the Immersive program we recommend <a href=\"https://app.codesmith.io/coding-events?location=all&series=Learn+About+Codesmith\" target=\"_blank\">attending an Information Session</a>   or <a href=\"https://calendly.com/codesmith-program/alumni-advisor-call\" target=\"_blank\" >scheduling a call with an Alumni Advisor.</a> <br> <br>",{"subheading":"CS Prep","subcontent":["If you are looking for more structured supplemental instruction before applying for an Immersive program,  you may want to consider <a href=\"https://www.codesmith.io/cs-prep\" target=\"_blank\">CS Prep</a>, our live intermediate to advanced prep program.","CS Prep is a 2-week program covering JavaScript concepts, engineering best practices, and technical communication.  The program includes live-online instruction, daily problem-solving workshops, and a passionate coding community to  help you prepare for top coding boot camps such as our selective Software Engineering Immersive programs,  and equips you with the tools to solve real-world problems.","We do not require any coding experience to apply to CS Prep, but we strongly encourage completing up through  Callbacks & Higher-Order Functions. CS Prep moves quickly, as there is a lot of ground to cover taking you from  introductory to intermediate JS, so the more familiarity you have with these concepts the better! Don’t worry though,  in the program we’ll discuss JavaScript fundamentals like functions and data types, closures, callbacks, recursion,  and algorithms at length."]}]},"workshop-async":{"subunitId":"workshop-async","heading":"Workshop - JavaScript the Hard Parts Async & Promises","read":["During the <a href=\"https://www.youtube.com/watch?v=77hFfvADd6E\" target=\"_blank\">JavaScript the Hard Parts: Async & Promises</a> workshop video, we will explore asynchronous JavaScript under-the-hood. This is one of our most advanced workshops in this series - to get the most out of it, we recommend that you be comfortable with concepts covered in the earlier units such as callbacks and closure. In this video we will cover:",{"list":["The challenge with single-threadedness in JavaScript","How asynchronicity enables much of modern web development","The challenge with asynchronicity in JavaScript and how promises fix the problem of inversion of control"]},"We will begin the workshop by experimenting with a native timer function called <code>setTimeout</code>, and then we will explore how events such as HTTP responses and button clicks be paired with asynchronous callbacks to update the Document Object Model (DOM) in order to give feedback to the user.","Our mental models of asynchronicity in javascript - the event loop, callback queue - are no longer enough. We have to augment them with the new world of native promises and async/await and understand them intuitively. In this video, we’ll do this so you can write readable code and debug effectively.","<img class=\"img-responsive\" src=/assets/async-1.png>"]},"workshop-callbacks":{"subunitId":"workshop-callbacks","heading":"Workshop - JavaScript The Hard Parts: Callbacks and Higher Order Functions","read":["Congratulations on graduating from Codesmith’s “Intro to JavaScript” series to the “Javascript the Hard Parts” series! The first video workshop in this series is <a href=\"https://www.youtube.com/watch?v=S52nfiaPskY\" target=\"_blank\">JavaScript the Hard Parts: Callbacks and Higher Order Functions</a>. Understanding how callbacks and higher order functions work under the hood will provide a solid foundation to comprehend more advanced topics such as closure, object oriented programming and asynchronous JavaScript later in this series. This video workshop will cover core concepts like:",{"list":["Building functions like map, reduce, and filter from scratch","Using higher order functions to keep code clean even in complex situations","How to diagram through higher order functions and callbacks scenarios"]},"In addition to Callbacks and Higher Order Functions being an essential building block of JavaScript, they’re also always tested on the Codesmith Immersive Program technical interview. This video workshop is key to understanding both how these functions work as well as what level of technical communication on them we are expecting to see during your interview.","<img class=\"img-responsive\" src=/assets/callbacks-1.png>"]},"workshop-closures":{"subunitId":"workshop-closures","heading":"Workshop - JavaScript The Hard Parts - Closure, Scope, and Execution Context","read":["Closure is one of the most important yet misunderstood features of JavaScript. You have probably already seen closure in action or will soon in classic challenges like once, memoize, and password-protected functions.","Most students watch <a href=\"https://www.youtube.com/watch?v=44vOEtW6tcw\" target=\"_blank\">JavaScript The Hard Parts: Closure, Scope, and Execution Context</a> multiple times in order to fully grasp these concepts.","The specifics of this workshop include:",{"list":["How closure works under the hood","Core JavaScript runtime features - execution context, the JavaScript execution model and the variable environment","How to wield, optimize and debug popular pro utility functions like once and memoize","How to implement the module pattern - one of the cleanest and most resilient design patterns in JavaScript"]},"These concepts, especially closure, are always tested in the technical interview for the Codesmith immersive program, which makes this video workshop an essential part of your CSX and Codesmith journey.","<img class=\"img-responsive\" src=/assets/closures-1.png>"]},"workshop-functions-and-objects":{"subunitId":"workshop-functions-and-objects","heading":"Intro to Coding: The Ingredients and Recipes of JavaScript","read":["The video workshop that pairs with this CSX unit is <a href=\"https://www.youtube.com/watch?v=EuxM2TdEm08\" target=\"_blank\">Intro to Coding: The Ingredients and Recipes of JavaScript</a>.","This workshop is designed to dive under-the-hood of Functions so even if you’ve been programming with functions or are completely new to them, you can learn more about how they work.","In this video, we will cover:",{"list":["What happens when our code runs in the browser?","A closer look at objects","Objects and arrays","Reusing our logic (declaring/invoking functions)"]},"Now that you are becoming familiar with the basics of Javascript, this is a great time to start practicing your technical communication skills. Attending live workshops will give you the opportunity to explain your code to others so that you can work on the clarity of your explanation.","<a href=\"https://www.codesmith.io/free-resources#Events\" target=\"_blank\">See upcoming sessions and RSVP here!</a>","<img class=\"img-responsive\" src=/assets/functions-ex-2.png>"]},"workshop-intro-to-javascript":{"subunitId":"workshop-intro-to-javascript","heading":"Workshop - Intro to Javascript: Variables, Control Flow, and Looping","read":["The video workshop that pairs with CSX Precourse - Part 1 is Codesmith’s <a href=\"https://www.youtube.com/watch?v=7gj34mStSNQ\" target=\"_blank\">Intro to Javascript: Variables, Control Flow, and Looping</a> workshop.","During this video, we will cover:",{"list":["The web and how it is comprised of HTML, CSS, and JavaScript","Variables (const/let)","Objects and arrays","For loops and conditional logic (if/else)"]},"<a href=\"https://www.codesmith.io/free-resources?_gl=1*2nvuqo*_gcl_aw*R0NMLjE3NTYxNDU4MTcuQ2p3S0NBandrN0RGQmhCQUVpd0FlWWJKc2QwQ3otcXBKMkl1RGh3WGJ3d3lxY1FBUW5uQ2pGVW9MRWliQzBYZHlBcTd0OV9jQjMtWmtCb0NBa01RQXZEX0J3RQ..*_gcl_au*MTkzOTI2MTI4Ni4xNzU1MDE5Nzc0LjY3MDc0NzY0Ni4xNzU4NjMzOTgwLjE3NTg2MzQ3ODU.#Events\" target=\"_blank\">See upcoming events and RSVP here.</a>","<img class=\"img-responsive\" src=/assets/functions-ex-2.png>"]},"workshop-js-fundamentals-pt1":{"subunitId":"workshop-js-fundamentals-pt1","heading":"Intro to JS Pt. 1","watch":["https://www.youtube.com/embed/TwLcYFFvPdo?start=0",{"description":["If you are unable to attend a live workshop,  you may find it useful to watch the following recording of Online Instructor Jinsung  to gain insight on these topics."]}]},"workshop-jshp-oop-pt1":{"subunitId":"workshop-jshp-oop-pt1","heading":"JSHP: OOP Pt. 1","watch":["https://www.youtube.com/embed/MSmpf47YaFY",{"description":["If you are unable to attend a live workshop,  you may find it useful to watch the following recording of the Chief Academic Officer at Codesmith, Phillip,  to gain insight on these topics."]}]},"workshop-jshp-oop-pt2":{"subunitId":"workshop-jshp-oop-pt2","heading":"JSHP: OOP Pt. 2","watch":["https://www.youtube.com/embed/3qgYKLf9w-Y",{"description":["If you are unable to attend a live workshop,  you may find it useful to watch the following recording of the Chief Academic Officer at Codesmith, Phillip,  to gain insight on these topics."]}]},"workshop-oop":{"subunitId":"workshop-oop","heading":"Workshop - JavaScript the Hard Parts Classes and Prototypes","read":["It’s time to go under the hood of Object Oriented Programming (OOP) and the prototype chain with Codesmith’s <a href=\"https://www.youtube.com/watch?v=wUEycYnfouA\" target=\"_blank\">JavaScript the Hard Parts: Classes and Prototypes</a> video workshop! This is one of our most advanced workshops, so we encourage you to watch it as many times as you need.","We’ll cover:",{"list":["4 approaches to object-oriented programming in JavaScript","Prototype, __proto__ and the prototype chain","Factories, constructors and classes","ES5 and ES6 approaches"]},"As an advanced workshop in the JavaScript the Hard Parts series, we highly recommend attending it live. Attendance is helpful for any level of experience with OOP! This is also a great way to work on your technical communication and continue pair programming.","<img class=\"img-responsive\" src=/assets/functions-ex-1.png>"]},"workshop-recursion":{"subunitId":"workshop-recursion","heading":"Workshop - Exploring Recursion in JavaScript","read":["The next video workshop in our series is <a href=\"https://www.youtube.com/watch?v=gm9p_5E3kh0\" target=\"_blank\">Exploring Recursion in JavaScript</a>. In this video, we’ll delve into one of the most powerful, but often confusing concepts in programming: functions that call themselves! Recursion is a hard concept to grasp so we recommend reviewing this video as many times as you need.","Specifically, we'll be covering:",{"list":["When to use looping vs. recursion","How to set up recursive functions","How you can return a value out of a recursive call"]},"<img class=\"img-responsive\" src=/assets/recursion-workshop.gif>"]}}}