{"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","ai-literacy","dev-env-and-version-control"],"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"]}],"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"]}],"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>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>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>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"]},"ai-literacy":{"unitId":"ai-literacy","header":"AI Literacy and Learning with AI","level":"Advanced","tagline":["In this unit we’ll build a strong foundation in the principles of prompt engineering."],"completeNotification":"Congrats on finishing the AI Literacy Unit! You're killing it - keep it up and share your success","learnTime":"1 - 2 hours","description":[{"list":["Introduction to Large Language Models","Prompting fundamentals","Building a system prompt","Building your own AI Tutor"]}],"subunits":["unit-11-ai-literacy-1","unit-11-ai-literacy-2","unit-11-ai-literacy-3","unit-11-ai-literacy-4","unit-11-ai-literacy-5","unit-11-ai-literacy-6"]},"dev-env-and-version-control":{"unitId":"dev-env-and-version-control","header":"Developer Environment and Version Control","level":"Advanced","tagline":["In this unit we'll leave the browser behind and step into the tools real developers use every day: VSCode, the terminal, Git, and GitHub. We'll take it one step at a time, and make sure you're comfortable using  these tools on your computer before we ever touch a remote repository,  so that by the end you can navigate, save, and share your work with  confidence."],"completeNotification":"Congrats on finishing the Developer Environment and Version Control Unit! That wasn't an easy lift - keep it up and share your success","learnTime":"1 - 2 hours","description":[{"list":["Downloading and tour through VSCode","Working in your computer's terminal","Understanding Git basics","Learning version control with GitHub"]}],"subunits":["unit-12-dev-env-1","unit-12-dev-env-2","unit-12-dev-env-3","unit-12-dev-env-4","unit-12-dev-env-5","unit-12-dev-env-6","unit-12-dev-env-7","unit-12-dev-env-8","unit-12-dev-env-9","unit-12-dev-env-10","unit-12-dev-env-11"]}},"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\" target=\"_blank\" rel=\"noopener noreferrer\">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\" target=\"_blank\" rel=\"noopener noreferrer\">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\" target=\"_blank\" rel=\"noopener noreferrer\">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-help channel on the <a href=\"https://share.codesmith.io/csxslack\" target=\"_blank\" rel=\"noopener noreferrer\">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":["Outside of CSX, Codesmith offers 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://www.udemy.com/course/javascript-for-beginners-the-complete-intro-course-2022/?couponCode=MT260629G2\" target=\"_blank\" rel=\"noopener noreferrer\">JavaScript for Beginners -</a>","JavaScript for Beginners (JSB) 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 and build a future in software engineering.","We recommend getting started with our Precourse - Part 1 Unit to familiarize yourself with JavaScript syntax so you can hit the ground running.","<a href=\"https://www.codesmith.io/software-engineering-ai-immersive\">Software Engineering Immersive Program -</a>","Our flagship 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 program, 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 program we recommend attending an Information Session.","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"]},""]},"intro":{"subunitId":"intro","heading":"What is CSX?","read":["Welcome to CSX, we’re so happy to have you here! CSX is both an online 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 the instructor teams at <a href=\"https://codesmith.io/\" target=\"_blank\" rel=\"noopener noreferrer\">Codesmith</a> and Future Code NY. 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. (Precourse Part 2 Unit and Functions & Execution Context Unit)","Intermediate to advanced concepts for further independent learning and preparation for our <a href=\"https://www.codesmith.io/software-engineering-ai-immersive\" target=\"_blank\" rel=\"noopener noreferrer\">Software Engineering Immersive Program</a> and Future Code NY (Callbacks & Higher-order Functions Unit, Closure, Scope & Execution Context Unit, Asynchronous JavaScript Unit, Object-Oriented Programming Unit, and AI Fundamentals)"]},{"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\" rel=\"noopener noreferrer\">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."]}]},"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.","<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!","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!"]}]},"unit-11-ai-literacy-1":{"subunitId":"unit-11-ai-literacy-1","heading":"Introduction: Why AI Literacy Comes First","read":["So far throughout CSX, you've built real programming skills: variables, functions, closures, recursion, and your first project (maybe even grown some gray hairs  along the way!). From this unit on, you'll keep building those skills, but now  you'll do it the way a lot of modern developers actually work: with an AI assistant!","There are better and worse ways to use AI. Used poorly, it becomes a crutch: you paste in code you don't understand, it runs sometimes, and you learn approximately nothing. That is the exact trap that we DON'T want you to fall into. Used well, AI can be an incredible learning and building tool. The difference comes down to one thing: <b>understanding</b>.","That's the philosophy behind everything in Units 11-14: <b>Empowerment over dependence, process over polish, and putting your understanding first.</b>","This is the very first unit of the AI track. You won't touch VSCode, a terminal, Git, or GitHub just yet. If those words currently sound like someone dropped a toolbox down the stairs, totally fine. All of that comes in Unit 12. <b>Unit 11 stays entirely in your browser, with zero new tooling to install.</b> So why does AI come <i>before</i> the developer tools?",{"orderedList":["You meet your most powerful helper first. Unit 12, with the terminal, Git, and GitHub, is one of the steeper climbs in the track. Walking into it with an AI assistant you already know how to use makes the climb much less dramatic.","It's a gentle on-ramp. Everything here happens in a browser tab, with nothing to install and very little to accidentally break. A beautiful little sandbox. We love a sandbox.","The habits you build here will support you throughout the rest of the unit  and onward. You'll explain things before you move on and you won't just blindly trust the first response you get from an AI chatbot."]},"By the end of this unit, you'll build something useful, <b>your own JavaScript tutor bot</b>, an AI helper that you design and define entirely through a set of written instructions called a <i>System prompt</i>.","The bot that you build will be a <b>hints-only</b> tutor. When you're stuck on a JavaScript problem, it will not simply hand you the answer.  It will ask what you've tried, nudge you toward the next step, and make <i>you</i> do the thinking because that is how you <i>actually</i> learn, and learning is what you're here for!","Why is building your own bot such an effective way to learn?",{"orderedList":["You learn prompting by doing it. You'll write, test, and rewrite real instructions, then watch how the bot's behavior changes.","A hints-only tutor bot will actually help you build knowledge instead of  just giving you the answer. It's designed to make you explain and think, not copy and paste your way into a future bug museum.","You walk away with a study tool that you can use for the rest of CSX and beyond."]},"After this introduction, you'll move on through:","<b><i>Part 2: What an LLM Is (and Isn't)</i></b>",{"list":["An LLM is a <i>pattern-completer</i> trained on text, not a fact database","Prompt, context, and output as a single pipeline","Why AI <i>hallucinates</i> and how to verify its claims","\"Confident is not the same as correct\"","Probabilistic AI vs. the deterministic, traditional code you've written so far","A quick map of the four kinds of AI coding tools: browser chatbot, IDE assistant, Copilot-style autocomplete, and agentic tools"]},"<b><i>Part 3: Set Up Your Prompting Tool</i></b>",{"list":["A five-minute setup of a free browser tool that keeps the System prompt and User prompt visibly separate","Confirming your prompting workspace actually works"]},"<b><i>Part 4: Prompting Basics: System vs. User</i></b>",{"list":["System prompts vs. User prompts, and why the difference matters","Watching the exact same question produce very different answers depending on the standing rules you give the assistant"]},"<b><i>Part 5: The Anatomy of a System Prompt</i></b>",{"list":["The four parts of a strong prompt: Role, Goal, Instructions, Output format","Prompting as an iterative skill. Vague in, vague out. A classic."]},"<b><i>Part 6: Build Your JavaScript Tutor Bot</i></b>",{"list":["Writing the System prompt that defines your bot's behavior","Testing it against real learning road blocks and refining it","Tuning it so it gives <i>hints instead of answers</i>"]},"We'll start where every good AI user starts, by understanding what these systems actually are. Once you know how an AI model works, you'll be much better at deciding when to trust it, when to question it, and when to ask it to show its work like it's back in math class. Let's get to it!"]},"unit-11-ai-literacy-2":{"subunitId":"unit-11-ai-literacy-2","heading":"What an LLM Is (and Isn't)","read":["Last section, we promised you'd build your own tutor bot. Before you can direct an AI well, though, it helps to know what you're actually talking to. So let's pop the hood.","<b>An LLM (Large Language Model) is a pattern-completer.</b> ","It was trained by reading a truly staggering amount of text. Its main purpose is predicting what text most plausibly comes next.","You already know a tiny version of this. Think of the autocomplete on your phone suggesting the next word in a text message. An LLM is like that idea turned up to a thousand. Instead of guessing one word, it can continue a whole explanation, a paragraph, or a chunk of JavaScript, one plausible piece at a time.","When you ask an LLM \"what does this function return?\", it is <i>not</i> looking the answer up in some internal database of facts. There is no filing cabinet in there. It is generating the most likely continuation to your question based on the patterns it learned. A lot of the time the most likely continuation <i>is</i> the correct answer, because the truth showed up often in its training. But not always, and that's what causes the most common problems.","Almost every surprising thing an AI does makes sense the moment you remember it is <i>completing patterns, not retrieving facts.</i>","<b>Prompt, context, output: the pipeline</b>","Whenever you use an AI, three things are always in play:",{"list":["<b>Prompt</b>: what you ask. The question or instruction you type in.","<b>Context</b>: everything the model can \"see\" right now, which is your prompt plus the conversation so far plus any code or additional resources you've pasted in. Crucially, it only knows what is in front of it. It cannot see your screen, your other files, or what you meant but didn't actually say.","<b>Output</b>: its best guess at a plausible continuation, given that prompt and that context."]},"Picture it as a short pipeline, prompt and context go in, output comes out. This hands us the first practical rule of prompting, which we'll cover more in the next section: <b>vague in, vague out.</b> If the context is thin, like just asking about \"my code\" without pasting any code, the output has no choice but to be vague right back. Feeding the model the relevant snippet is how you prevent half of the disappointing answers you'll ever get.","","<b>Why the same question can give two different answers</b>","Every function you've written in CSX so far has been <b>deterministic</b>: same input, same output, every single time. Run it now, run it tomorrow, or even  on the moon, and you get the same result. That predictability is exactly what makes it easier to debug.","An LLM is <b>probabilistic</b> instead. Ask it the exact same question twice and you may get two different answers, both reasonable, just worded differently or taking a slightly different approach. This surprises people, and occasionally annoys them. It is not a bug and nothing is broken; it is simply how these systems work. The repeatability you're used to from your JavaScript  code does not fully apply here.","<b>When AI confidently makes things up</b>","Because the model produces what is <i>plausible</i>, and plausible is not the same as <i>true</i>, it will sometimes invent things out of thin air. It might make up a JavaScript method that doesn't exist (rest in peace, <i>array.shuffle()</i>, which sounds real, feels real, and would honestly  be pretty cool to have... is very much <b>not</b> real). Or the model might misremember how a built-in works, or state something flatly wrong with total confidence. This has a name: a <b>hallucination</b>. 😶‍🌫️","When the model hallucinates, it's not intentionally lying to you, it's just doing what  models do, generating plausible text, and this time \"plausible\" simply landed on something false. Same machine, same process, sometimes it just gets it wrong.","<b>Confident is not the same as correct</b>","People get hung up on the fact that AI output <i>sounds</i> authoritative. Smooth, well-organized sentences read like true sentences, even when they happen to be nonsense. So just remember that <b>confident  is not the same as correct.</b>","Whenever the AI states a fact about your code, quietly ask yourself: \"How would I actually check whether this is true?\" Run the code. Read the official docs. Test one tiny example. It's our job as developers to verify  the output we receive. If the AI has made a mistake, it's our job to catch it  and fix it.","<b>A map for the road ahead</b>","There are four main categories of AI coding tool:",{"orderedList":["<b>Browser chatbot</b>: if you've used ChatGPT before, this will feel familiar. You type in a browser tab, it replies, and it only knows what you paste in.","<b>IDE assistant</b>: an AI that lives inside your code editor and can actually see your project's files.","<b>Copilot-style autocomplete</b>: suggests lines of code as you type, like your phone's autocomplete but for programming.","<b>Agentic tools</b>: the most capable of the bunch. These can take multi-step actions on their own, reading files, running commands, and making changes across a whole project."]},"For this first unit, you'll be working mainly with the first tool on the list, the browser chatbot. The rest of the map will unfold throughout the rest of the course.","To put this all simply, an AI model is a fluent, confident, occasionally-wrong pattern-completer that only knows what's in front of it and won't always answer the same way twice. In the next section, we'll dive into the anatomy of a prompt and how small, deliberate changes to what you ask produce big changes in what you get."]},"unit-11-ai-literacy-3":{"subunitId":"unit-11-ai-literacy-3","heading":"Set Up Your Prompting Tool","read":["In the last section, we learned what an LLM is (and isn't). Before we can put that understanding to work, dissecting prompts and building your tutor bot, you need a place to actually run one. So this section is just a quick, five-minute setup.","<b>Why not just any chatbot?</b>","You may already have a browser chatbot you like. So why are we sending you somewhere new? Because of one important feature. In a plain consumer chatbot  (like ChatGPT), everything you type goes into a single box. For this unit we need a tool that keeps <i>two</i> things visibly separate:",{"list":["<b>The System prompt</b> - the rules the AI assistant follows <i>every single time</i>.","<b>The User prompt</b> - the message or question the user sends to the model."]},"If that feels a little unclear, don't worry. Seeing the two separate from one another during this set up will help a lot!","For this activity, we'll be using <b>Google AI Studio</b>, a free tool from Google that gives us access to the <b>System Instructions</b> field (aka the \"System prompt\"). It's free to use in the browser, and signing in just needs a Google account, no payment details required.","<b>Setting up Google AI Studio</b>",{"list":["Go to <b>aistudio.google.com</b> in your browser.","Sign in with a Google account. If you don't have one, create a free\n one, it takes a minute and needs no credit card.","The first time in, you may be asked to accept some terms. Read and\n accept them to continue.","Look at the right side of the screen for the <b>Run settings</b> panel."]},"<img class=\"img-responsive\" src=/assets/unit-11/run-settings-panel.png>",{"list":["If it's collapsed, click the settings or \"tune\" icon in the top-right to expand it."]},"<img class=\"img-responsive\" src=/assets/unit-11/tuner-button.png>",{"list":["Inside, find the <b>System Instructions</b> field. This is\n where the standing rules will go, and it's the field we came here for.","Now notice the separate chat box near the bottom (it usually says\n something like \"Start typing to see what our models can do\") and a <b>Run</b> button next to it.\n That box is for your one-off questions, the User message."]},"That's the whole setup. Two fields and a Run button.","<b>Confirm it works</b>","Let's make sure it works. Leave the System Instructions field <i>empty</i> for now, type a simple question into the chat box, something like <i>How can I make a perfect grilled cheese sandwich?</i>, and click <b>Run</b>. After a few seconds you should see a reply appear. <img class=\"img-responsive\" src=/assets/unit-11/google-resp1.png alt=\"Screenshot of a sample model reply\">That's it: you have a working prompting workspace, and you're ready for the hands-on part of this unit!","One important note, treat this like any public tool and don't paste anything private into it, no passwords, personal details, or real secrets. Free tools sometimes use what you type to help improve their models, so assume anything you enter could be seen.","Notice that you left the System Instructions field empty this time. In the next section we'll start filling it in, and you'll watch the <i>exact same</i> question produce very different answers depending on the standing rules you give the assistant. Congratulations, you're on your way to becoming a prompt engineer! <img class=\"img-responsive\" src=/assets/unit-11/trustengineer.gif>"]},"unit-11-ai-literacy-4":{"subunitId":"unit-11-ai-literacy-4","heading":"Prompting Basics: System vs. User","read":["Last section you got your workspace running but we left the System Instructions field empty. Now we'll fill it in! We'll start with a small experiment. Let's ask the model the <i>exact same question</i> twice, change only the standing rules between the two runs, and watch the answer transform.","<b>Round 1: a question with no rules</b>","First, the baseline. We want to see what the model does when you give it no guidance at all.",{"orderedList":["Make sure the <b>System Instructions</b> field is completely empty.","In the chat box at the bottom (the User message), type: <i>How can I make a perfect grilled cheese sandwich?</i>","Click <b>Run</b> and read what comes back."]},"<img class=\"img-responsive\" src=/assets/unit-11/google-resp1.png alt=\"Screenshot of the model response with an empty System Instructions field\">","Take a moment to review the reply. How long is it? Who does it seem to be talking to, a beginner or an experienced chef? Is the tone chatty or textbook? You didn't ask for any of that, so the model just picked its own defaults. With no standing rules, it fills in the blanks however it wants to. Let's give it some rules to make the response a little more beginner-friendly.","<b>Round 2: same question, new rules</b>","Copy this into the <b>System Instructions</b> field, exactly as written:","<i>You are an enthusiastic chef helping an absolute beginner. Keep your answer to three short sentences.</i>","<b>We're not going to change the question.</b> Type <i>How can I make a perfect grilled cheese sandwich?</i> exactly as it was in the chat box, and click <b>Run</b> again.","<img class=\"img-responsive\" src=/assets/unit-11/post-instruction-response.png alt=\"Screenshot of the model response after adding System Instructions\">","Look at the difference. You asked the same question but got a completely different answer. This one is shorter, friendlier, and aimed at someone who's just learning to cook. The only thing that changed was the set of standing rules sitting in the System Instructions field, and that was enough to reshape the role the assistant played, the tone it used, and the length of its reply.","Before reading on, think about what changed between the two answers, and which rule do you think caused it?","<b>Just to review the difference:</b>",{"list":["<b>The System prompt</b> (the System Instructions field) holds the <i>standing rules</i>, the guidance the assistant follows on every single turn, no matter what the user asks.","<b>The User prompt</b> (the chat box) is the <i>one-off ask</i>, the specific question you're sending this time."]},"There's a big difference between the two. We don't often have access to a model's system  prompt (like when using ChatGPT). That's why we're using the Google AI Studio. In the following section we'll dive deeper into the anatomy of a System prompt one piece at a time, adding a Role, Goal, Instructions, and an Output format. You'll see how each change alters the model's behavior.","Have a little fun with it before moving on! Change a few words in the System Instructions, make it <i>an angry pirate who teaches cooking</i>, and Run the same question again. Same question, very different vibe. Once you've gotten your sea legs, we'll set sail for the next section. 🙃 🏴‍☠️"]},"unit-11-ai-literacy-5":{"subunitId":"unit-11-ai-literacy-5","heading":"The Anatomy of a System Prompt","read":["Last section you watched a single set of standing rules reshape an answer. That was the <i>power</i> of a System prompt. This section is about the <i>parts</i> it's made of, and the <i>method</i> for building a good one: on purpose, one piece at a time, instead of dumping everything in at once and hoping it works out.","<b>The four parts of a System prompt</b>","Every strong System prompt is built from a few named pieces. You'll lean on this same vocabulary for the rest of the track, so let's meet the four that matter most. You may run into slightly different names for them elsewhere, but the ideas don't change. To make them concrete, we'll use a running example: an assistant that tells you fun facts about animals.",{"list":["<b>Role</b> - who the assistant is being. <i>\"An enthusiastic museum guide who loves animals.\"</i> Note: a Role doesn't give the model new skills or knowledge it didn't already have. The purpose is to help shape the model's tone and delivery.","<b>Goal</b> - what success actually looks like. <i>\"Help the user walk away remembering one genuinely surprising fact.\"</i>","<b>Instructions</b> - the specific dos and don'ts. <i>\"Keep it short, and skip anything gross or scary.\"</i>","<b>Output format</b> - how the reply should be shaped. <i>\"A headline, then three facts formatted in bullets\"</i>"]},"We're not going to write all four at once. We'll add them one at a time and watch each one work so we can see how each one brings us closer to our desired output.","Here's something you need to get in the habit of practicing early on when  iterating on prompts: <b>predict before you run.</b> Before each change, think about what impact that change might have. Then run it and check. If you were right, great! You've learned  a little more about how the model responds to that kind of change. If you were wrong, that's useful too.  You'll find yourself repeating this cycle over and over:","<b>Predict → Run → Check → Improve.</b>","As you gain experience, you'll start noticing patterns in how different prompt changes affect the output. Professional AI engineers follow this same process, just in a more structured way. Instead of relying just   on memory, they'll often save different versions of their prompts and the model's responses. That makes it  easier to compare results, see what worked, and make smarter improvements over time!","Clear the <b>System Instructions</b> field so it's empty, and in the chat box type this question: <i>Tell me about hamsters.</i>","One thing won't change for the rest of this activity: <b>the question.</b> The User prompt stays exactly the same on every run. The only thing we touch is the System prompt. That's the part <i>you</i> design and grow while the  user's question is just the input you test it against.","Run it once now, with the System Instructions still empty, just to see the \"before.\" Its answer will be fine but probably pretty generic. That's our baseline.","<b>Keep a prompt-iteration log</b>","For each iteration on your prompt, keep a short log, four lines each. This little record is meant to help you identify the different parts that make up a good System prompt while also getting you in the habit of logging your process like real developers do. Eventually you'll be using fancy code to  do this but, for now, let's just build the habit. Here's what to write down:",{"list":["<b>What I added</b> - which part of the prompt (Role, Goal, and so on).","<b>What I predicted</b> - your guess, written <i>before</i> you run it.","<b>What actually changed</b> - what the new answer did differently.","<b>Did my prediction hold?</b> - yes, no, or \"sort of,\" plus one word on why."]},"<b>Round 1: add a Role</b>","Paste this into the <b>System Instructions</b> field, exactly as written:","<i>You are an enthusiastic museum guide who loves sharing cool facts about animals.</i>","Predict first: what do you think changes when the model knows <i>who</i> it's supposed to be? Write your guess in the log, then click <b>Run</b>.","Read the reply and notice two things.",{"list":["<b>What changed?</b> The voice probably got warmer and more excited, more like a person showing you around.","<b>What didn't?</b> Maybe it was still a long answer. Maybe the answer was too short. Maybe none of the facts were all that surprising or memorable."]},"That gap is the point. A Role tells the assistant who to be, but it never said what to aim for or how to shape the answer, so we'll focus on that next.","<b>Round 2: add a Goal and Instructions</b>","Now we tell it what success looks like and give it a couple of concrete rules. Paste the additional lines below into your System Instructions (the Role line stays; we're stacking on top of it):","<i>Your goal is to help me walk away remembering one genuinely surprising fact.<br>Keep it to a few facts a curious kid would find amazing, and skip anything gross or scary.</i>","Predict, then Run. The <b>Goal</b> (\"help me remember one surprising fact\") points the assistant at a target, and the <b>Instructions</b> (\"just a few facts,\" \"nothing gross or scary\") are the specific dos and don'ts that get it there. Watch the <i>substance</i> change: instead of everything it knows, you should get a tighter, more curated handful. Maybe even something surprising! Remember  to log what changed and whether your guess was correct.","You may still notice the answer is shaped however the model feels like shaping it, sometimes a paragraph, sometimes a list. We haven't said anything about <i>shape</i> yet. We'll focus on that next.","<b>Round 3: constrain the Output format</b>","Last round. We tell it exactly how the reply should be <i>shaped</i>. Add these to  your stack of existing System Instructions:","<i>Shape every reply as a fact card: a one-line headline, then exactly three short  facts as a bulleted list, then a single line that starts with \"Wow:\" and gives the most surprising fact of all.</i>","Predict, then Run one last time. The <b>Output format</b> is the rule that controls the <i>structure</i> of the reply, and it's often the one that makes an answer suddenly feel finished and usable. You asked the very same question you started with, but the reply should now be a clean, tidy, predictable card every single time! Maybe something like this:","<img class=\"img-responsive\" src=/assets/unit-11/response-hamster-final.png alt=\"Screenshot of the assistant reply formatted as a fact card: a headline, three bulleted facts, and a Wow line\">","<b>Read your log top to bottom</b>","You asked the same question every single time, made three rounds of changes to the standing rules, and ended up with a completely different response at the bottom than the one you started with. Those changes introduced the four parts of a System prompt, added in order and observed one at a time:",{"list":["<b>Role</b> - who it is.","<b>Goal</b> - what it's aiming for.","<b>Instructions</b> - the specific dos and don'ts.","<b>Output format</b> - how the reply is shaped."]},"<img class=\"img-responsive\" src=/assets/unit-11/hamster.gif alt=\"A hamster stuffing its mouth with carrots\">\n The point is, a good System prompt usually isn't written all at once from a template. \n It's <i>grown</i>: you add a piece, watch what the model does, and let what you see \n tell you what to add next. You just did a miniature version of that, and you'll do it again on \n bigger, more useful projects later on. In fact, in the next section, you'll use this \n strategy to build something that you can <i>really</i> use! Let's go! 🦾"]},"unit-11-ai-literacy-6":{"subunitId":"unit-11-ai-literacy-6","heading":"Build Your JavaScript Tutor Bot","read":["This is the one we've been building toward. Last section we led you through building a fun  little animal-facts bot, grown one piece at a time. Now you'll use the method you learned to build <b>your own hints-only JavaScript tutor bot.</b> It's the centerpiece of this whole unit, and unlike the animal-facts bot, this is a tool you might find genuinely helpful for the rest of CSX and beyond.","So what is a \"hints-only\" tutor? In our case, it's a bot whose entire job is to make <i>you</i> do the thinking. When you're stuck, it won't hand you a finished answer to copy and paste. It nudges. It asks what you've tried. It gives you one clue and then waits for you to take the next step yourself. This is a tool that will reinforce the value of \"hard learning\". It's the exact opposite of the vibe-coding trap we warned you about back in the introduction. You're about to build the anti-vibe-coding mentor with your own two hands.","This time, <b>you will write the System prompt yourself.</b> We're not going to hand you the text to paste in. You don't need us to, because you already have everything required, the build method from last section and the four-part vocabulary you've been learning. This bot is yours. Let's design it.","<b>Design your four parts</b>","Here's how to think about each one for a tutor bot. Write each in your own words as you go. While there will <i>definitely</i> be some \"wrong answers\", there are no perfect \"right answers\" here, and figuring out the wording <i>is</i> the skill.",{"list":["<b>Role</b> - who should your tutor be? Give it an identity in a sentence. Remember, the role does not give the model any special powers or knowledge. The purpose is to shape the tone and delivery. Is your Tutor bot patient and encouraging, or blunt and direct? Is it a peer, a mentor, or a teacher? Which of these (or any others you come up with) will hold the most value toward achieving your goal?","<b>Goal</b> - what counts as success? Be careful here, because this will define just how helpful your tutor bot will be.  Success should <i>not</i> be \"the student gets the answer.\" A real tutor's job is to make sure you actually reach a level of understanding. How can you define a goal that guides the student toward finding the answer on their own? Put that target into words, since it shapes everything the bot does.","<b>Instructions</b> - the specific dos and don'ts that keep it hints-only. This is the heart of the bot, so we'll brainstorm it just below.","<b>Output format</b> - how should every reply be shaped so it stays a nudge instead of a lecture? A popular choice for a tutor bot is one hint, followed by a single guiding question, but the shape is yours to decide. State it clearly."]},"Instructions will be very important here, so give them some real thought. Think back to your favorite teacher in elementary school. When you were stuck, how did they lead you to find the right answer without giving it away?  Here are some ideas to get the wheels turning:",{"list":["Should the tutor offer one clue at a time, then pause and let you try it?","Should it ask you to explain what you've already tried, or what you think should happen next?","What if you ask it about hamsters instead of JavaScript and programming? (it is a <i>JavaScript</i> tutor after all, if it could answer everything it would just be a regular chatbot)."]},"Feel free to use any of these that you agree with, along with the ones you come up with on your own.  Put them all together into clear instructions for the model. The more specific you are, the better your bot will behave.","<b>Build it the way you practiced</b>","Don't paste all four parts in at once. Grow the prompt exactly the way you grew the animal-facts bot, one piece at a time, with a <b>predict → run → check</b> on every step and a line in your iteration log for each one. A good order:",{"orderedList":["Clear the <b>System Instructions</b> field. Add only your <b>Role</b>, predict what it'll change, then Run.","Stack on your <b>Goal</b> and <b>Instructions</b>, predict, then Run again.","Add your <b>Output format</b> last, predict, then Run one final time."]},"To test it on each run, you'll need a genuine challenge to throw at it. Use a real problem you're struggling with right now if you have one. If not, congratulations! Apparently you know everything there is to know about JavaScript! 🧐. But if you're having trouble coming up with something right away, you can paste this sample User prompt every time so the only thing changing is your System prompt:","<i>I'm trying to write a function that returns the largest number in an array, but I'm not sure how to start.</i>","Here's an example of the type of response you should be aiming for once the prompt is doing its job:","<img class=\"img-responsive\" src=/assets/unit-11/tutor-bot-hint-example.png alt=\"Screenshot of the tutor bot responding to a stuck student with a single hint followed by a guiding question, rather than the full solution\">","(The picture above shows the <i>behavior</i> we're after. How you get your bot there is up to you.)","<b>Test that it behaves</b>","A bot that \"sounds\" like a tutor but coughs up the full answer hasn't done its job, so check it honestly against your challenge prompt. Did the reply hand you a hint and a guiding question, or did it just dump working code you could paste without understanding a line of it?","If it's over-helping, that's not a success either. Find the Instruction that should have kept it in check, make it sharper and more explicit, and Run again. Remember, <b>predict → run → check</b>. Keep nudging until the behavior matches what you set out to build.","<b>Save your Tutor Bot!</b>","This bot will be a useful tool throughout your learning journey, so hang on to it!","Just to be safe, copy and paste your System prompt into a document to save locally on your computer. If you've enabled Google Drive to save your chats, you should be able to return to this chat with the System prompt intact, but it's always good to have a backup. You can also save the entire chat transcript if you want to keep a record of your iteration log.","<img class=\"img-responsive\" src=/assets/unit-11/unhelpful-robot.gif alt=\"Robot being unhelpful\">\n Take a beat and appreciate this: you just built a working AI tool, defined\n entirely by instructions you wrote yourself. Now you have a healthy study partner you can ask for help with tricky JavaScript\n concepts going forward. If you find yourself in need of assistance with technologies other than JavaScript, now you know how to adjust your System prompt to fit your needs! In fact, you might find it pretty helpful in the next unit, where you'll be setting up your own development environment and learning to use Git and GitHub."]},"unit-12-dev-env-1":{"subunitId":"unit-12-dev-env-1","heading":"Introduction: Why This Unit Is Heavy (and How We Paced It)","read":["Up to this point, nearly all of CSX has taken place in your browser  (with the exception of lightly using a text editor in the Chrome Extension Unit). Starting now, you're leaving the browser and stepping into the tools  real developers use every day: <b>VSCode, the terminal, Git, and GitHub.</b>","<b>This is the heaviest unit in the track.</b> It’s going to introduce you to four new tools, a new way of talking to your computer, and a couple of mental models that take some time and repetition to get comfortable with. If it feels like a lot, that doesn’t mean that you’re falling behind. You’ll get there with time and consistency.","We paced this unit out to help make this introduction to these tools less overwhelming. So, instead of handing you VSCode, the terminal, Git, <i>and</i> GitHub all at once,  this unit is split into two phases:","<ul><li><b>12a: Your local machine.</b> Just you, your computer, VSCode, the terminal, and Git running locally. Nothing leaves your computer.</li> <li><b>12b: Collaborating remotely.</b> We’ll get our hands dirty with GitHub, along with forking, cloning, branches, and making your first pull request.</li></ul>","Between the two phases is a <b>checkpoint gate</b>: before you're allowed to move into 12b, you need to be able to navigate to a folder in the terminal, make a commit, and explain in plain English what that commit did. This step is really important because pushing a commit to GitHub means  nothing if you can't <i>explain</i> what a commit <i>is</i>. In other words, get 12a  down, and 12b will make far more sense.","A couple of things to note before you start. First: if you've never used a command line before, that's completely normal! Second: Mac and Windows differ here. Paths, some commands, and setup steps won't always perfectly match so don't assume something is broken just because your screen doesn't look exactly like an example built on the other operating system.","And don’t forget, you just built an AI Tutor that can help you out! We had you build it  first so you’d have a study buddy for this unit. You may need to tweak the system prompt so that your conversations aren't scoped to <i>only</i> JavaScript. Feel free to use it for explaining an error, or telling you what a command is about to do before you run it. It's important that you <b>never paste a secret, password, or token into an AI chat.</b> Authentication steps in 12b are the one place you should always type things yourself rather than involving an AI. <img class=\"img-responsive\" src=/assets/unit-12/api-key-meme.png alt=\"Jack Sparrow running from pirates\">","By the end of this unit, you'll be able to open a project, move around inside it, save your work with Git, get it onto GitHub, and explain in plain English what each step did. That’s a lot, but it’s a big hurdle and it’s really going to pay off in Unit 13!"]},"unit-12-dev-env-10":{"subunitId":"unit-12-dev-env-10","heading":"Branch, Commit, Push","read":["Alright! You've now got <i>two</i> copies of the practice project. One on your fork on GitHub, and one on your computer, sitting in the <b>learn-github-repo</b> folder you cloned last subunit. They match perfectly right now, but neither of them has any of <i>your</i> work in it yet. So, in this subunit you're going to make a small edit on your computer, snapshot it with a commit, and then send that commit up to your fork on GitHub using the <b>push</b> command.","Before we get started, let's talk a little bit about <b>branches</b>.","<h4>What's a branch, and why bother?</h4>","A <b>branch</b> is a parallel line of work in a Git project. Every repo starts with one branch, usually called <b>main</b>, and up until now that's the only branch you've had. When you want to try something new, like adding a feature or fixing a bug, you can make a <i>new</i> branch off of main, do all your work there, and leave main completely untouched while you experiment. If it works out, you can bring the branch's work back into main. If it doesn't, you can just throw the branch away, and main is exactly like it was before you started. <img class=\"img-responsive\" src=/assets/unit-12/new-branch.png alt=\"A diagram of a new branch being created off of a main branch\">","<b>You might be thinking, \"If I'm the only one working on this, why branch at all?\"</b> Fair question. There are a couple of reasons  why. First off, this is the workflow professional developers use even on solo projects, so it's good to build the habit now.  Second, branches give you the ability to create <b>pull requests</b>, which you'll be doing in the next subunit. A pull request is essentially asking the <b>main</b> branch to pull in the work from a <b>new</b> branch. Without having a separate branch, we won't be able to safely merge changes into our main branch. So let's make one!","<h4>Step 1: Check where you are</h4>","Before we create a new branch, let's check what branch we're currently on. Open your VSCode terminal (if it isn't already), and make sure you're inside the <b>learn-github-repo</b> folder we cloned last subunit. Hopefully you've been starting to build the habit, but you can check with:","<pre><code>pwd</code></pre>","You want to see a path ending in <b>learn-github-repo</b>. If you don't, <b>cd</b> your way over to it. Once you're standing in the right place, check your Git status:","<pre><code>git status</code></pre>","The very first line of the output tells you the branch you're currently on. It should say something like <b>On branch main</b>. That's your starting point. Every branch you make going forward will be a separate timeline, starting from where you left off, on the main branch. That way, you can freely experiment with new changes without breaking something on the main branch. <img class=\"img-responsive\" src=/assets/unit-12/git-status-on-main.png alt=\"A terminal showing git status output with the first line reading On branch main and a clean working tree\">","<h4>Step 2: Create a branch</h4>","To create a new branch <i>and</i> hop onto it in one move, use <b>git switch -c</b>, followed by a name for your branch. The <b>-c</b> is short for \"create.\" Let's name our branch something that describes the work we're about to do. We're going to add your name to the <b>hello.txt</b> file, so:","<pre><code>git switch -c add-my-name</code></pre>","Git will respond with something like \"Switched to a new branch 'add-my-name'.\" That means two things happened at once! Git made a fresh new branch called <b>add-my-name</b>, and then it moved you onto it. You are no longer on the <b>main</b> branch, and any commits you make from here on out will only be added to the <b>add-my-name</b> branch. <img class=\"img-responsive\" src=/assets/unit-12/git-switch-c-output.png alt=\"A terminal showing git switch -c add-my-name creating and switching to a new branch\">","Run <b>git status</b> again:","<pre><code>git status</code></pre>","The first line should now read <b>On branch add-my-name</b>.","<b>Heads up:</b> if you read other Git tutorials online, you'll often see people use <b>git checkout -b add-my-name</b> instead. That's an older way of doing the exact same thing. Both ways still work fine, but we prefer <b>git switch</b> because it's specifically for switching branches, and the name makes the command way easier to remember.","<h4>Step 3: Make a small change</h4>","In VSCode's Explorer on the left, click <b>hello.txt</b> to open it. It's probably a very short file, just a line or two. Add a new line at the bottom with your name and a quick note. Something like:","<pre><code>Hi from [your name]! This is my first commit on a branch.</code></pre>","Save the file (<b>Ctrl + S</b> / <b>Cmd + S</b>, unless you already have auto-save on). For the sake of this lesson, that's the only change we'll make. We want to focus on the workflow around it, not the edit itself.","<h4>Step 4: Commit it</h4>","Once again, start by checking your Git status:","<pre><code>git status</code></pre>","Git should list <b>hello.txt</b> under \"Changes not staged for commit.\" That means Git knows you've made edits to a file but haven't added it to the staging area yet. Let's add it. Run:","<pre><code>git add .</code></pre>","Then take the snapshot with a message that describes what this commit will do:","<pre><code>git commit -m \"Add my name to hello.txt\"</code></pre>","Git should respond with a short summary of the commit, one file changed and however many lines added. That's your snapshot, safely saved into your project's history on the <b>add-my-name</b> branch. <img class=\"img-responsive\" src=/assets/unit-12/git-commit-branch-output.png alt=\"A terminal showing git commit -m output with the branch name add-my-name in the summary line\">","The commit we just made only exists on <i>your computer</i>, on the <b>add-my-name</b> branch. Right now, if you looked at your fork on GitHub, it wouldn't know anything about this change at all. Neither the new branch nor the commit exist online yet. The two copies are officially out of sync! To bring them back together, we need to <b>push</b> the version on your computer up to GitHub.","<h4>Step 5: The push</h4>","Most of the Git commands we've used up until now, <b>init</b>, <b>add</b>, <b>commit</b>, have been Git working entirely on your computer, offline. <b>Push</b> will  actually reach out over the internet, talk to GitHub, and send your commits up to your fork.","from and to?\" You should be thinking something like, \"The copy on my computer isn't changing at all, about to travel from my computer up to my fork on GitHub.\" If that's making sense, go ahead and run the  command:","<pre><code>git push -u origin add-my-name</code></pre>","Let's break this down. <b>git push</b> is the command itself, \"send my commits somewhere.\" <b>origin</b> is Git's default nickname for the copy on GitHub that you cloned from. And <b>add-my-name</b> is the branch you want to send. So the full command reads \"Push my <b>add-my-name</b> branch up to the copy called <b>origin</b>, which is my fork on GitHub.\" If you need to repeat that to yourself a couple of times for it to make sense, go ahead... most of us do!","What about that <b>-u</b> flag? That's short for \"upstream,\" and it's how you tell Git to remember where this branch belongs. You only need it on the very <i>first</i> push of a new branch. Think of it as setting a shortcut. After this, for any future commits you make on <b>add-my-name</b>, you can just type <b>git push</b> by itself and Git will already know where to send them.","<h4>Step 6: The auth pop-up</h4>","This is the very first time you're asking Git to actually talk to GitHub on your behalf, and before GitHub lets you write to your fork, it needs to check that you are, in fact, you. <img class=\"img-responsive\" src=/assets/unit-12/auth-popup.png alt=\"A VSCode popup asking the user to sign into GitHub\">","On most modern setups, a <b>browser window will pop open automatically</b> asking you to sign in to GitHub and authorize Git to act on your behalf.  Sign in with your GitHub account. <img class=\"img-responsive\" src=/assets/unit-12/github-login.png alt=\"A GitHub login page in a browser asking the user to sign in with their GitHub account\">","Click the green \"Authorize\" button. <img class=\"img-responsive\" src=/assets/unit-12/github-permission.png alt=\"A GitHub page asking the user to authorize VSCode to access their account with a green Authorize button\">","Now you can go back to your terminal. After a moment, Git should finish the push. When it does, you'll see the output that mentions your branch name being sent and something along the lines of <b>Branch 'add-my-name' set up to track 'origin/add-my-name'</b>. That last bit is the <b>-u</b> shortcut being saved. <img class=\"img-responsive\" src=/assets/unit-12/git-push-success.png alt=\"A terminal showing a successful git push output with the branch being set up to track origin/add-my-name\">","You only have to authorize once. From here on out, Git will remember, and every future push in this unit (and the next few) will happen with no browser popup at all.","<h4>A gentle warning</h4>","Before we celebrate, let's revisit something we talked about a while ago and haven't reinforced.","<b>You should never paste a password, token, or credential into an AI chat.</b> Not your tutor bot, not ChatGPT, not Claude, not any AI, ever.","When it comes to Authentication, you should always be doing the work yourself. Your AI helper is great for reading error messages, explaining commands, and walking you through what a step means, but the moment credentials are involved, you should only trust yourself to handle them. If you get an error while trying to push and you find yourself Googling \"Personal Access Token\" or getting instructions to generate one, you should never paste the token into a chat window.","We're only emphasizing this because it's possible for credentials to leak if they end up in your AI chat history.  There's no \"undo\" for that. If you accidentally add your password to an AI chat, you should change it. This will be important in the next unit when you generate your first API key, and even more important anytime you handle secrets in your career.","<h4>If the push errors out</h4>","If your terminal spits out an error instead of a success message, don't panic, this is very common on a first push. Here's a safe way to get unstuck:","<ol>\n  <li><b>Read the error text carefully first.</b> Git errors are usually pretty descriptive if you\n  slow down and actually read them.</li>\n  <li>If it still doesn't make sense, <b>copy just the error text</b> (not any commands you ran, and\n  absolutely not any tokens, passwords, or usernames) and paste it into your AI tutor bot with a\n  note like \"I ran git push and got this error. What does it mean and what should\n  I check next?\"</li>\n  <li>Check the AI's suggested steps one at a time before taking any action</li>\n</ol>","<h4>Step 7: See the branch on GitHub</h4>","Assuming your push went through, let's go take a look at what changed. Open your browser and head back to your fork on GitHub (<b>your-username/learn-github-repo</b>). At first, it may still look exactly like it did before, that's because GitHub is showing you the <b>main</b> branch by default, and main is still exactly like it was. If you see a yellow banner that says something like, \"add-my-name had recent pushes 3 seconds ago\", you can go ahead and click the green <b>Compare & pull request</b> button.","If not, look for the branch dropdown, it's a button near the top left of the file list, and it currently says <b>main</b>. Click it. You should now see two branches listed: <b>main</b> and <b>add-my-name</b>. Click <b>add-my-name</b>. <img class=\"img-responsive\" src=/assets/unit-12/github-branch-dropdown.png alt=\"The GitHub branch dropdown open on the forked repo showing both main and add-my-name branches\">","The page should refresh to show you the project's files <i>on the new branch</i>. Click <b>hello.txt</b>. You should see the new line of text that you added earlier. That is your commit, on your branch, on your fork, on GitHub! <img class=\"img-responsive\" src=/assets/unit-12/github-hello-updated.png alt=\"The hello.txt file on GitHub viewed on the add-my-name branch showing the newly added line\">","<h4>Recap</h4>","Let's talk through everything we just did one more time:","<ul>\n  <li><b>Before you started</b>, both copies were identical. Your computer and your fork on GitHub\n  matched, both sitting on the <b>main</b> branch with no work of your own on either one.</li>\n  <li><b>After git switch -c add-my-name</b>, a new branch appeared on your computer, and you were\n  standing on it. The copy on GitHub knew nothing about it yet.</li>\n  <li><b>After git commit</b>, your snapshot was saved into the history on your computer, on the\n  <b>add-my-name</b> branch. The two copies were now officially out of sync.</li>\n  <li><b>After git push -u origin add-my-name</b>, your commit and the branch itself finally\n  traveled up to your fork on GitHub. The two copies are back in sync, now with your work on both.</li>\n</ul>","<h4>Quick self-check</h4> <ul>\n  <li>In your own words, what is a branch, and why did we make one for such a small change?</li>\n  <li>When you ran <b>git switch -c add-my-name</b>, what two things happened at once?</li>\n  <li>You ran <b>git commit</b> and then <b>git push</b>. What did each\n  of those commands do, and which copy did it change?</li>\n  <li>What does the <b>-u</b> in <b>git push -u origin add-my-name</b> do, and why do you only need\n  it on the first push of a new branch?</li>\n  <li>What should you never paste into an AI chat?</li>\n</ul>","If any of those felt shaky, jump back to the relevant section and re-read it before moving on. If they felt solid, you did it! You've officially completed a full round trip of the Git/GitHub workflow. This is most of the workflow that we use as developers every day!","In the next subunit, we'll do the last piece. You'll be opening a <b>pull request</b> to bring your <b>add-my-name</b> branch's work into your fork's main branch. Let's go!"]},"unit-12-dev-env-11":{"subunitId":"unit-12-dev-env-11","heading":"Open a Pull Request","read":["Last subunit, you pushed your <b>add-my-name</b> branch up to your fork on GitHub. Both copies are back in sync, both know about the branch, and both have your commit on it. There's just one thing left. Right now, your work only lives on the <b>add-my-name</b> branch. The <b>main</b> branch on your fork still doesn't know anything about your change. In this subunit, we're going to fix that by opening your very first <b>pull request</b>.","<h4>What's a pull request?</h4>","A <b>pull request</b> (or <b>PR</b> for short) is exactly what it sounds like. It's a request to <i>pull</i> the work from one branch into another. In our case, we're going to ask the <b>main</b> branch on our fork to pull in the commit sitting on our <b>add-my-name</b> branch. That's it. Once main pulls it in, the change lives on main, and both branches will be back in sync.","In a real team, this is where <i>other developers</i> would come in. Someone on your team would open a PR, and a teammate would look at the code, leave comments, ask questions, maybe request some changes, and eventually approve the PR so it can be merged into main. This process is called <b>code review</b>, and it's an important part of professional software development.","Because you're currently working on your own, there's no teammate to review your code on the other side of the PR. So in this case <b>you</b> are going to be both the person opening the PR <i>and</i> the person reviewing it. It may come as no surprise to you that this is called <b>self-review</b>! You should treat this as if you were reviewing a teammate's PR. You'll read your own <b>diff</b> like a stranger wrote it, ask yourself what changed and why, and catch anything sloppy before it gets pulled into main.","<b>Something to look out for.</b> When we open our PR, we're going to be careful to point it at <i>our own fork's</i> main branch, not the original CodesmithLLC repo. GitHub is going to try to direct this PR to the original repo, because that's the default behavior for a fork. We'll change it. You don't want your practice PR showing up on Codesmith's actual repository. It doesn't hurt anything, but it's not what we want to do here.","<h4>Step 1: Head back to your fork on GitHub</h4>","Open your browser and go to your fork's page:","<pre><code>https://github.com/your-username/learn-github-repo</code></pre>","(Replace <b>your-username</b> in the URL with your actual GitHub username, of course.) There's most likely still a yellow banner near the top of the page that says something like <b>\"add-my-name had recent pushes\"</b> with a green <b>Compare &amp; pull request</b> button. If you see that, go ahead and click that button. <img class=\"img-responsive\" src=/assets/unit-12/github-compare-pr-banner.png alt=\"The yellow GitHub banner on a fork showing add-my-name had recent pushes with a green Compare and pull request button\">","If the banner isn't there, no problem. Just click the <b>Pull requests</b> tab near the top of the repo page, then click the green <b>New pull request</b> button. Either path takes you to the same \"Open a pull request\" screen. <img class=\"img-responsive\" src=/assets/unit-12/github-new-pr-button.png alt=\"The Pull requests tab on GitHub with the green New pull request button highlighted\">","<h4>Step 2: Point the PR at the right place</h4>","Take a look at the top of the page. You should see two dropdowns with an arrow between them. On the left is <b>base</b>, on the right is <b>compare</b>. The way to read it is \"pull the work <i>from</i> compare <i>into</i> base.\" <img class=\"img-responsive\" src=/assets/unit-12/github-pr-base-compare-defaults.png alt=\"The GitHub PR base and compare dropdowns showing CodesmithLLC learn-github-repo main as base and the users fork add-my-name as compare\">","Now, look closely at what those dropdowns say. There's a good chance the <b>base repository</b> says <b>CodesmithLLC/learn-github-repo</b> and the <b>base</b> branch says <b>main</b>. That means right now, GitHub is set up to open a PR against <i>Codesmith's</i> original repo, not your fork. We need to change that.","<b>Pause and predict.</b> Before you click anything ask yourself, which copy of the project should this PR touch? You should be thinking something like, \"Not Codesmith's original repo. My own fork. I want to pull my <b>add-my-name</b> branch into the <b>main</b> branch <i>on my fork</i>.\" If that feels clear to you, let's go ahead and set that up.","Click the <b>base repository</b> dropdown (the one currently showing <b>CodesmithLLC/learn-github-repo</b>) and select <b>your-username/learn-github-repo</b> from the list instead. <img class=\"img-responsive\" src=/assets/unit-12/github-pr-base-repo-dropdown.png alt=\"The GitHub base repository dropdown open, showing the users own fork learn-github-repo as a selectable option\">","The page will refresh. Now check all four dropdowns and confirm they read like this, left to right: <ul>\n  <li><b>base repository:</b> your-username/learn-github-repo</li>\n  <li><b>base:</b> main</li>\n  <li><b>head repository:</b> your-username/learn-github-repo</li>\n  <li><b>compare:</b> add-my-name</li>\n</ul>","Read the whole thing out loud, \"Pull the work from my <b>add-my-name</b> branch on my fork into the <b>main</b> branch on my fork.\" That's exactly what we want.  <img class=\"img-responsive\" src=/assets/unit-12/github-pr-base-compare-fixed.png alt=\"The GitHub PR dropdowns after being fixed, showing both base and head repository pointing to the users own fork\"> If your base and compare dropdowns match the list above, and you see a green \"Create pull request\" button, go ahead and click it. This should take you to the \"Open a pull request\" page if you aren't there already. <img class=\"img-responsive\" src=/assets/unit-12/github-open-pr-page.png alt=\"The GitHub Open a pull request page\">","<h4>Step 3: Write a title and description</h4>","Just below the branch dropdowns, GitHub will show you a preview of the changes and give you a form to fill out. There's an <b>Add a title</b> field at the top and a bigger <b>Add a description</b> field below it.","GitHub has probably auto-filled the title with your commit message, \"Add my name to hello.txt\". That's a perfectly good title. Leave it, or tweak it if you'd like.","The description is where you write your <b>PR summary</b>. A good PR summary tells a reviewer (in this case,  future you) three things: <i>what</i> changed, <i>why</i> it changed, and <i>how</i> to check that it works. It doesn't have to be long. A few plain-English sentences work just fine.","Something like this is great:","<pre><code>What: Added a greeting line with my name to hello.txt.\n\nWhy: Practicing the full Git and GitHub workflow (e.g., branch, commit, push, PR).\n\nHow to verify: Open hello.txt on the add-my-name branch and confirm the new line is there.</code></pre>","Type that (or something like it, in your own words) into the description box. <img class=\"img-responsive\" src=/assets/unit-12/github-pr-title-description.png alt=\"The GitHub PR title and description fields filled in with a short What Why and How to verify summary\">","<h4>Step 4: Read the diff (this is the self-review)</h4>","Scroll down. Below the title and description, GitHub shows you the <b>diff</b>. This is a side-by-side (or top-to-bottom) view of exactly what your PR is proposing to change. Lines that were added show up in green and lines that were removed show up in red.","For this tiny PR, the diff should show just one new green line in <b>hello.txt</b>, and that's it. If you see anything else, extra files, changes to files you didn't touch, or something you don't recognize, stop and figure out what happened before you keep going.","<h4>Step 5: Open the pull request</h4>","Click the green <b>Create pull request</b> button.","The page will refresh and drop you onto your brand new pull request. It has a number now, probably <b>#1</b> since it's the first one on your fork. Take a second to look around. You'll see your title at the top, your description below it, the <b>Conversation</b>, <b>Commits</b>, and <b>Files changed</b> tabs, and, near the bottom, a green <b>Merge pull request</b> button. <img class=\"img-responsive\" src=/assets/unit-12/github-pr-open-view.png alt=\"A newly opened GitHub pull request page showing the title, description, tabs, and green Merge pull request button\">","You've officially opened your first pull request!","<h4>Step 6 (optional): Leave a self-review comment</h4>","You can leave inline comments directly on your own diff. Click on the <b>Files changed</b> tab. Then, hover over any line in the diff and you'll see a little blue <b>+</b> button appear in the gutter. If you click it, a comment box pops up right on that line. <img class=\"img-responsive\" src=/assets/unit-12/github-pr-inline-comment.png alt=\"A GitHub PR diff with an inline comment box open on the newly added line in hello.txt\">","This is optional for this PR, but you should try it once so you know how it feels. Leave a short comment on your added line, something like \"Just my name and a note that this is my first branch commit.\" Click <b>Start a review</b> or <b>Add single comment</b>. On a real team, this is how reviewers ask questions or leave feedback tied to a specific line.","<h4>Step 7: Merge your own PR</h4>","On a real team, this is where things would pause. A teammate would look at your PR, maybe ask for changes, and then approve it. Only then would it get merged into main. For our self-review workflow, <i>you're</i> the reviewer and you've already read the diff so, if you're happy with it, you're good to merge! If you left a self-review comment, go ahead and click the green <b>Submit review</b> button and submit your review. <img class=\"img-responsive\" src=/assets/unit-12/submit-review-button.png alt=\"The green Submit review button\">","<b>Let's reflect one more time.</b> Which copy is about to change when you click merge? You should be thinking, \"The <b>main</b> branch on my fork is about to change. It's going to pull in the commit from <b>add-my-name</b>\". Your computer, on the other hand, has no idea any of this is happening. Its <b>main</b> branch is going to be out of date the moment you click that button. Now, on the \"Add my name to hello.txt\" page, scroll down and click <b>Merge pull request</b>. <img class=\"img-responsive\" src=/assets/unit-12/github-pr-merge-button.png alt=\"The green Merge pull request button on the GitHub PR page\">","GitHub will ask you to confirm with a <b>Confirm merge</b> button. Click that too. <img class=\"img-responsive\" src=/assets/unit-12/github-pr-confirm-merge.png alt=\"The Confirm merge button on GitHub after clicking Merge pull request\">","The page will refresh, and the PR banner will now be purple and say <b>Merged</b>. That's it. Your <b>add-my-name</b> branch has been merged into <b>main</b> on your fork! <img class=\"img-responsive\" src=/assets/unit-12/github-pr-merged-state.png alt=\"A GitHub pull request page showing the purple Merged banner after a successful merge\">","GitHub will also offer you a <b>Delete branch</b> button. You can click it if you want, it's a common thing to do after a branch has been merged. Remember though, it only deletes the branch on GitHub, not the copy on your computer. For now, feel free to leave it or delete it, either way is fine.","<h4>Step 8: Confirm main actually changed</h4>","Let's go check with our own eyes. Click the repo name near the top of the page to head back to your fork's landing page. Make sure the branch dropdown near the top left says <b>main</b> (not <b>add-my-name</b>). Click <b>hello.txt</b>. <img class=\"img-responsive\" src=/assets/unit-12/github-main-after-merge.png alt=\"The hello.txt file on the main branch of the users fork on GitHub, now showing the merged line\">","Your line should be sitting right there, on <b>main</b>. You created a new branch on your computer, added a change, committed that change, pushed up to a branch on your fork, opened a PR into <b>main</b>, merged in those changes, and now you see that change reflected in <b>main</b>!","<h4>One small thing about your computer</h4>","Remember what we said before hitting merge? The <b>main</b> branch <i>on your computer</i> doesn't know any of this happened. It still looks exactly like it did when you first cloned the repo. Your fork's <b>main</b> on GitHub is one commit ahead of your computer's <b>main</b> right now, and the two copies are officially out of sync again.","We're not going to leave it like that. You already know that <b>push</b> sends work up. It has a matching move that brings work back down, and it's the last Git move of this unit: <b>pull</b>.","<h4>Step 9: Pull it back down</h4>","Head back to VSCode and open the integrated terminal. First, confirm you're standing in the right place. You know the drill:","<pre><code>pwd</code></pre>","You want a path ending in <b>learn-github-repo</b>. Now run <b>git status</b> and look at the first line. It probably says <b>On branch add-my-name</b>. You've been standing on your feature branch this whole time! The commit we merged went into <b>main</b>, so that's where we need to be standing to receive it. To switch to a branch that already exists, use git switch <i>without</i> the -c flag (remember, -c is only for creating a brand-new branch):","<pre><code>git switch main</code></pre>","Before pulling anything, open <b>hello.txt</b> in VSCode and look at it.  <img class=\"img-responsive\" src=/assets/unit-12/git-switch-missing-code.png alt=\"The terminal showing git switch main with hello.txt open in VSCode, but the new line is not there yet\">","Your line isn't there! Don't panic, this is exactly what we expected. Your computer's copy of <b>main</b> is still the old version. The merged commit only exists on GitHub right now.","<b>One last pause and predict.</b> Which copy is about to change, and which direction is the work moving? You should be thinking, \"The copy on GitHub isn't changing at all. The merged commit is about to travel <i>down</i> from my fork's main to the main on my computer.\" Push sends commits up, pull brings commits down. Let's run it:","<pre><code>git pull</code></pre>","You'll see a few lines of output mentioning <b>hello.txt</b> and a summary of what changed. Now look at <b>hello.txt</b> in VSCode again. There's your line! Your computer's <b>main</b> just pulled down the commit from your fork, and the two copies are back in sync, this time with your work on both. <img class=\"img-responsive\" src=/assets/unit-12/git-pull-terminal.png alt=\"The terminal showing git pull, with output listing the hello.txt change pulled down from the fork\">","By the way, notice that you typed plain <b>git pull</b> with no extra words. When you cloned this repo, Git automatically wired your local <b>main</b> to the <b>main</b> on your fork, so it already knows where to pull from. It's the same way the -u flag set that up for your add-my-name branch when you pushed.","<h4>Recap</h4>","Let's walk through what we just did:","<ul>\n  <li><b>Before you started</b>, your <b>add-my-name</b> branch was up on your fork, but your\n  fork's <b>main</b> branch didn't know anything about your change.</li>\n  <li><b>You opened a pull request</b>, pointed it at your own fork's <b>main</b> (not\n  Codesmith's), with a short summary explaining what changed and why.</li>\n  <li><b>You reviewed your own diff</b>, confirmed the only change was the line you meant to\n  add, and (if you did Step 6) left yourself an inline comment.</li>\n  <li><b>You merged the PR</b>, which pulled your commit from <b>add-my-name</b> into <b>main</b>\n  on your fork. Both branches on GitHub (main and add-my-name) now match each other perfectly.</li>\n  <li><b>You switched back to main and ran git pull</b>, bringing the merged commit down to your\n  computer. Both copies of the project are in sync, with your work on both.</li>\n</ul>","<h4>Quick self-check</h4> <ul>\n  <li>In your own words, what is a pull request, and what does it actually do when you merge it?</li>\n  <li>Why did we have to change the <b>base repository</b> dropdown before creating the PR? What\n  would have happened if we didn't?</li>\n  <li>What are the three things a good PR summary tells a reviewer?</li>\n  <li>Right after you clicked <b>Confirm merge</b>, which copy of the project was out of date,\n  and which command brought it back in sync?</li>\n  <li>In terms of the two-places model, what's the difference between <b>push</b> and\n  <b>pull</b>?</li>\n  <li>What's the difference between <b>git switch main</b> and <b>git switch -c main</b>?</li>\n</ul>","<h4>What's next</h4>","That's the end of Unit 12. Nice work! We know this one was pretty dense, but look at what you can do now: you just ran the complete developer loop. Branch, commit, push, pull request, self-review, merge, and pull. That's the same loop professional developers run every single day. In Unit 13, we'll turn on the next tool in the belt: an <b>agentic, codebase-aware</b> AI assistant called <b>OpenCode</b>. You'll finally install <b>Node</b> (told you it was coming!), create your first <b>API key</b>, connect it to OpenCode, and use it to explore a codebase you didn't write, one file at a time. You'll also exercise those Git and GitHub muscles you just built to commit, push, branch, and open PRs on the work you do there. See you in Unit 13!"]},"unit-12-dev-env-2":{"subunitId":"unit-12-dev-env-2","heading":"Setup: VSCode, Git, and a GitHub Account","read":["Before we touch the terminal or make our first commit, we need to get your machine set up. This subunit is just setup: two installs and one account signup. So, don't worry, no new concepts... yet. Some of this may feel a little tedious but take it slow and confirm each step actually worked before you move on to the next one.","By the end of this subunit you'll have three things ready to go: <b>VSCode</b>, an Integrated Development Environment (IDE) where you'll write and edit code; <b>Git</b>, the tool that saves snapshots of your work; and a <b>GitHub account</b>, where those snapshots will live online. We won't use Git or GitHub for anything just yet. That's what the <i>rest</i> of Unit 12 is for. Right now, we're just getting the tools installed and confirming they're there. <img class=\"img-responsive\" src=/assets/unit-12/the-right-tools.png alt=\"Tim Taylor holding a strange tool\">","<b>A note on your operating system:</b> the steps below differ slightly depending on whether you're on a Mac or a Windows machine. Find your OS below and follow those instructions. And, again, don't worry if your screen doesn't match a screenshot from the other OS, that's expected.","<h4>Step 1: Install VSCode</h4>","<b>Already have VSCode installed?</b> We made an optional recommendation of using VSCode in the earlier Chrome extension unit, so you may already have it on your machine. If you do have it, make sure it's the latest version by opening VSCode and going to <b>Help → Check for Updates</b>. If it says you're up to date, you can skip forward to Step 2.  If not, follow the prompts to update and restart the application before moving on.","<b>To install on Mac:</b> <ul>\n  <li>Go to <a target=\"_blank\"\n  href=\"https://code.visualstudio.com/\">code.visualstudio.com</a> and\n  download the Mac version.</li><li>Open the downloaded file and drag the\n  VSCode icon into your Applications folder.</li><li>Open VSCode from\n  Applications (or Spotlight search) to confirm it launches.\n  </li>\n</ul>","<b>To install on Windows:</b>\n  <ul>\n    <li>Go to <a target=\"_blank\"\n    href=\"https://code.visualstudio.com/\">code.visualstudio.com</a> and\n    download the Windows version.</li><li>Run the installer. When prompted,\n    check the boxes for \"Add to PATH\" and \"Add 'Open with Code' action\". These\n    make things easier later.</li><li>Open VSCode from the Start menu to\n    confirm it launches.\n    </li>\n  </ul>","<b>Success check:</b> VSCode opens and you see a welcome tab. That's it! You don't need to touch any settings yet.","<img class=\"img-responsive\" src=/assets/unit-12/vs-code-welcome.png>","<i>Nice to have (Mac):</i> If you're on a Mac, open VSCode and press <b>Cmd+Shift+P</b>  to open the Command Palette. Then type <i>shell command</i>, and select <b>Shell Command: Install 'code' command in PATH</b>. This lets you open any folder in VSCode by typing <b>code .</b> in the terminal, which will come in handy later in this unit. If you're on Windows, don't worry, you already did this when you checked the \"Add to PATH\" box during the installer in Step 1. <img class=\"img-responsive\" src=/assets/unit-12/add-code-to-path-ios.png>","<h4>Step 2: Install Git</h4>","Git is a tool for tracking your changes over time. Think of it like clicking \"save\" as you update a Word document, except each save is a snapshot that you can look back at (or return to) later. We'll start using it later in this unit. Eventually, you'll be using it every day as you build  out applications.","<b>Mac:</b> Git usually comes pre-installed. Open VSCode's built-in terminal (we'll cover this properly later in this unit, but for now: View → Terminal) <img class=\"img-responsive\" src=/assets/unit-12/open-terminal.png alt=\"A terminal window opened in VSCode\"> Then type <b>git --version</b>. If you see a version number, you're done. If not, follow the prompt that appears. It will offer to install the Xcode Command Line Tools, which include Git.","<b>Windows:</b> Git does not come pre-installed. Go to <a target=\"_blank\"  href=\"https://git-scm.com/download/win\">git-scm.com</a> and download Git for Windows. Run the installer. The default options are fine for everyone in this program, so it's safe to click through using the defaults. This install also gives you Git Bash, a terminal you may see referenced later (we'll cover what a terminal is later in this unit).","<b>Success check (both OS):</b> open a terminal and type <b>git --version</b>. Seeing something like <b>git version 2.43.0</b> means it worked (the exact number doesn't matter).","<img class=\"img-responsive\" src=/assets/unit-12/git-version.png alt=\"A terminal showing the output of git --version\">","<h4>Step 3: Create a GitHub Account</h4>","GitHub is a separate thing from Git. Don't worry, we'll unpack that distinction properly later on. For now, just know you need an account there, the same way you'd need an account on any website.","Go to <a target=\"_blank\" href=\"https://github.com\">github.com</a> and sign up with an email address you check regularly. Choose a username you're comfortable being professionally associated with (future employers will probably see this). The free plan is all you'll ever need for this program.","<b>Success check:</b> you can log in to github.com and see your profile page. <img class=\"img-responsive\" src=/assets/unit-12/github-account-created.png alt=\"A newly created GitHub account\">","<h4>You're set up. Now what?</h4>","If all three success checks above worked, you're ready to move on. In the next few subunits, we'll build the mental model you need and then start actually using the terminal and VSCode together. If any step didn't work, that's completely normal. In fact, this is a great time to dive deep and start getting comfortable reading error messages. Ask your AI tutor for step-by-step help, paste the exact error you're seeing, ask questions, and check each suggested step <i>before</i> running it."]},"unit-12-dev-env-3":{"subunitId":"unit-12-dev-env-3","heading":"Files and Folders as a Tree","read":["In the last subunit you installed your tools. Before we open the terminal and start typing commands, we're going to slow down and solidify an important mental model: <b>how your computer actually organizes your files.</b> This might sound obvious, but many people use computers for years without ever getting a clear picture of it and it's a big reason why the terminal can feel confusing. So if this is fuzzy for you right now, let's clear it up.","The files and folders on your computer are arranged as a <b>tree</b>. A folder can hold files, and it can also hold <i>other folders</i>, which can hold their <i>own</i> files and folders, and so on. That nesting, folders inside folders, is the whole concept. Everything on your machine lives somewhere in this branching structure.","You've probably seen this without thinking of it as a tree. Your <b>Desktop</b>, <b>Documents</b>, and <b>Downloads</b> are folders. Open Documents and you might find more folders inside it. Each of those is a branch, and the branches keep splitting the deeper you go.","Every tree has a starting point that everything else grows out of. On your computer, all of your files and folders ultimately live inside one top-level location, and everything branches down from there. You rarely need to think about the very top, but it helps to know the tree isn't floating in space, it has a base and every file has a path back to it.","Imagine a project folder called <b>my-first-project</b>. Inside it, the tree might look like this:","<ul>\n  <li><b>my-first-project/</b>\n    <ul>\n      <li><b>images/</b>\n        <ul>\n          <li>logo.png</li>\n          <li>banner.png</li>\n        </ul>\n      </li>\n      <li>index.html</li>\n      <li>notes.txt</li>\n    </ul>\n  </li>\n</ul>","Read that from the top down. <b>my-first-project</b> is a folder. Inside of it are two files (<i>index.html</i> and <i>notes.txt</i>) and one more folder (<i>images</i>). Inside <i>images</i> are two more files. The folder that contains something is often called its <b>parent</b>, and the things inside are its <b>children</b>, so <i>my-first-project</i> is the parent of <i>images</i>, and <i>logo.png</i> is a child of <i>images</i>.","<img class=\"img-responsive\" src=/assets/unit-12/file-tree-diagram.png alt=\"A folder tree showing my-first-project containing an images folder and two files\">","You already have a tool that shows you this tree visually. Open VSCode and open a folder (File → Open Folder, then pick any folder on your machine). The panel that appears on the left, the <b>Explorer</b>, is this exact tree. Folders have little arrows you can click to expand or collapse them, revealing the files and folders nested inside. Clicking around in there is the same thing we just drew, only interactive.","<img class=\"img-responsive\" src=/assets/unit-12/vscode-file-explorer.png alt=\"The VSCode Explorer panel showing a nested folder structure\">","<b>At any given moment, you are always somewhere in this tree.</b> Your specific position will always be the folder you're currently sitting inside of. When you use the terminal in a couple of subunits, every command you type will run relative to wherever you happen to be standing in the tree. So knowing your position is important for understanding how each command will work.","For example, let's say you're \"in\" your my-first-project folder. Many users are used to seeing that folder in Finder or File Explorer, like this:","<img class=\"img-responsive\" src=/assets/unit-12/my-first-project-gui.png alt=\"A folder labeled my-first-project in an IOS GUI\">","But, in your terminal, being \"in\" your my-first-project folder looks like this:","<img class=\"img-responsive\" src=/assets/unit-12/my-first-project-terminal.png alt=\"A folder labeled my-first-project in a terminal\">","Now, any commands you run in your terminal will be relative to the folder you are currently in (my-first-project). Here, you can run commands like listing all of my-first-project's children, navigating into a different folder, and a bunch more that we'll get into later.","When you're working with file systems, you'll often hear the word <b>path</b>. A path is just an address, the route from one point in the tree to a specific file or folder, with each level separated by a slash. For example, the banner image above lives at <b>my-first-project/images/banner.png</b>. Start at the project folder, go into <i>images</i>, and there's the file. If you can read that as a set of directions through the tree, you've got the idea.","<b>A quick note on your operating system:</b> Mac and Linux write paths with forward slashes (<b>images/banner.png</b>), while Windows traditionally uses backslashes (<b>images\\banner.png</b>). So don't let the slash direction throw you if an example doesn't match your screen exactly.","<b>Quick self-check:</b> <ul>\n  <li>In your own words, what does it mean that files and folders form a tree?</li>\n  <li>In the example above, what is the parent of <i>logo.png</i>?</li>\n  <li>What does it mean to say you are \"in\" a particular folder right now?</li>\n  <li>Read this path out loud as a set of directions: <i>my-first-project/images/logo.png</i>. Where do you start, and where do you end up?</li>\n</ul>","Now that we've covered the mental model, we're ready to get comfortable in the tool you'll be doing all of this in. In the next subunit, we'll take a full tour of VSCode. Right after that, we'll finally open the terminal and put this tree to work, asking the computer \"where am I?\", \"what's in here?\", \"take me there,\" and \"make a new folder.\" Every one of those commands is just a way of navigating through the tree.","<img class=\"img-responsive\" src=/assets/unit-12/sloth-in-tree.gif alt=\"A sloth in a tree\">"]},"unit-12-dev-env-4":{"subunitId":"unit-12-dev-env-4","heading":"A Tour of VSCode","read":["In the last subunit you learned that your files live in a <b>tree</b>, and you used one panel of VSCode, the Explorer, to look at one. Now we're going to slow down and get comfortable in the rest of that window. By the end of this subunit, you should be able to look at any part of VSCode and understand what it's for.","You may already have a simple text editor on your computer, like TextEdit on a Mac or Notepad on Windows. Those programs let you type and save text, including code. VSCode is basically a much more powerful version of that. It lets you write code too, but it also highlights your code with colors, suggests what to type next, helps you find mistakes, and includes a bunch of tools that make programming much easier.","<b>Open a folder first.</b> VSCode is most useful when it's pointed at a <i>folder</i>. There's a menu for this (<b>File → Open Folder</b>), or you can open a fresh VSCode window, then <b>drag a folder off your desktop and drop it right onto the middle of the window.</b> Pick any folder you already have (<i>Documents</i> or <i>Desktop</i> is fine). We'll make a real project folder in the next subunit, so don't worry about picking the \"right\" one. Below, we're dropping in a folder labeled \"articles\" which just has a few simple txt files.","<img class=\"img-responsive\" src=/assets/unit-12/vscode-drag-folder.gif alt=\"A folder being dragged from the desktop and dropped onto an empty VSCode window, filling in the Explorer tree\">","VSCode may ask whether you trust the authors of the files in this folder. It's your own folder, so yes. And notice what dropping it in <i>didn't</i> do. It <i>didn't</i> move the folder, copy it, or change anything inside it. VSCode is simply <i>pointing at it</i> now so we can make edits to it.","<b>Now try dragging in a single file</b>, any file on your desktop. Watch what's different. The file opens in a tab in the middle, but the tree on the left doesn't change. <b>Drop a file, you get that file. Drop a folder, you get the whole tree.</b> A folder arrives with all of its children, a file arrives alone. It's also the reason we open <i>folders</i> and not files when we're working on a project. You want the whole tree in front of you, not one leaf.","<img class=\"img-responsive\" src=/assets/unit-12/vs-code-drag-file.gif alt=\"A file being dragged from the desktop and dropped into VSCode\">","Here's VSCode, with its parts named:","<img class=\"img-responsive\" src=/assets/unit-12/vscode-window-labeled.png alt=\"The VSCode window with the Activity Bar, Side Bar, Editor, Panel, and Status Bar labeled\">","<ul>\n  <li><b>The Activity Bar</b> is the vertical strip of icons on the far left. Each icon changes <i>what the panel next to it shows</i>. The top icon (the two stacked pages) is the Explorer.</li>\n  <li><b>The Side Bar</b> is the panel right next to it. By default it's showing the <b>Explorer</b>: the file tree that we just dropped in.</li>\n  <li><b>The Editor</b> is the big area in the middle. This is where files open when you click them, each one in its own <b>tab</b> across the top.</li>\n  <li><b>The Panel</b> is the drawer along the bottom. It's usually hidden. It holds a few things, and the one we care about is the <b>integrated terminal</b>.</li>\n  <li><b>The Status Bar</b> is the thin strip at the very bottom. It quietly reports things about your project. Ignore it for now, but know it's there, because later in this unit it will start telling you useful things about Git.</li>\n</ul>","That's the whole window. Five parts. You don't need to master any of them today but you'll want to be able to name them since you'll be using them a lot moving forward.","<b>Open the integrated terminal.</b> Go to <b>View → Terminal</b>, or use the keyboard shortcut: <code>Ctrl + `</code> (that's the backtick key, usually just above <i>Tab</i> on the left side of your keyboard) — this works on both Mac and Windows. (<code>Cmd + J</code> also toggles the whole Panel on Mac.) The Panel slides up from the bottom, and inside it you'll see some text ending in a cursor.","<img class=\"img-responsive\" src=/assets/unit-12/vscode-integrated-terminal.png alt=\"The VSCode integrated terminal open in the bottom panel, showing a prompt and a blinking cursor\">","<b>Don't type anything yet.</b> We'll learn what to have that cursor say in the next subunit. But notice one thing, the terminal opened <i>inside the folder you have open in VSCode</i>. Remember that you are always standing somewhere in the tree? The integrated terminal starts you standing in the folder you opened (in our case, my-first-project). That's why developers use the terminal <i>inside</i> the editor instead of as a separate app. The editor and the terminal are already looking at the same place.","Now let's talk about <b>the Command Palette.</b> Press <code>Cmd + Shift + P</code> (Mac) or <code>Ctrl + Shift + P</code> (Windows / Linux). A box drops down from the top of the window. Make sure you can see the greater-than symbol (>). That's how you know you're actually in command mode.","<img class=\"img-responsive\" src=/assets/unit-12/vscode-command-palette.png alt=\"The VSCode Command Palette open at the top of the window with a search box\">","Every single thing VSCode can do lives in that box, and you find it by typing what you want rather than by hunting through menus. Rename a file, change your color theme, split the editor, open the terminal, run Git commands. All of it is searchable by name. If you only memorize one keyboard shortcut from this entire unit, make it this one. It means you never have to remember <i>where</i> anything is, only roughly what it's called.","<b>Let's run one command.</b> With the palette open, type <i>new file</i> and choose <b>File: New File...</b> from the list. The file appears in the Explorer on the left and you're prompted to give it a name. Give it the name <i>hello.txt</i>  and press enter. You'll notice that the file is already open in the Editor.  Type a sentence into it, anything you like. There are other ways to create folders and files and we'll definitely be looking at that later on in the unit.","<img class=\"img-responsive\" src=/assets/unit-12/vscode-hello-file.png alt=\"A file named hello.txt open in the VSCode editor and visible in the Explorer file tree\">","Notice how <b>hello.txt</b> is now in the Explorer tree, right where you'd expect it, because the Explorer and the folder on your computer are the same thing viewed two ways. If you haven't yet saved your changes, the file's tab has a small filled <b>dot</b> on it instead of an ✕. That dot is VSCode telling you <i>this file has changes you haven't saved yet.</i> It disappears the moment you save. This tends to trip people up, especially beginners. Don't forget to look for that dot. So, if you haven't yet, save with <code>Cmd + S</code> (Mac)  or <code>Ctrl + S</code> (Windows / Linux). You can also turn on \"Auto Save\" by going to <b>File → Auto Save</b> and then you don't ever really need to worry about it.","<b>Quick little AI teaching moment here!</b> Remember, if something isn't where we said it would be, that's a perfect thing to ask your AI assistant about. For example:","<ul>\n  <li><i>\"I'm on Windows, using VSCode. I'm trying to open the integrated terminal, but View → Terminal isn't doing anything. Where should I look?\"</i></li>\n</ul>","In that example, you're giving context to your assistant: your operating system,  your tool, what you were trying to do, and what actually happened. If you don't  give enough context to the model, it won't always be able to give you a reliable answer,  especially as you move on to more complicated workflows. Vague in, vague out. And speaking of \"assistants\", you'll meet the <i>actual</i> assistant that lives <i>inside</i>  VSCode a little later in this unit. For now, your browser assistant that you built in unit 11 is the right tool.","<b>Quick self-check:</b> <ul>\n  <li>Without looking back, can you name the 5 parts of the VSCode window and what they do?</li>\n  <li>Which part of the window shows you the file tree you learned about in the last subunit?</li>\n  <li>In one sentence, what is the Command Palette, and what keys open it on <i>your</i> machine?</li>\n  <li>You opened the integrated terminal. Which folder in the tree is it standing in, and how do you know?</li>\n  <li>What does a filled dot on a file's tab mean?</li>\n</ul>","The list of tools you can use and customizations you can make in VSCode is endless but how cool that  you've now started to get to know the space that you'll be working in for the foreseeable future?! In the next subunit we're going to finally start using one of the tools in it. We'll type into that terminal and walk the tree from the last subunit for real, asking the computer \"where am I?\", \"what's in here?\", \"take me there,\" and \"make me a new folder.\" VSCode and the integrated terminal are about to become your own little workshop!","<img class=\"img-responsive\" src=/assets/unit-12/little-workshop.gif alt=\"A man dancing in a workshop\">"]},"unit-12-dev-env-5":{"subunitId":"unit-12-dev-env-5","heading":"Walk the Tree in the Terminal","read":["In the last subunit you toured VSCode and opened the integrated terminal, but we told you not to type anything into it yet. Now you're going to! In this subunit, you'll finally talk to your computer by typing one line at a time and start walking through an actual file tree.","For a lot of people, the terminal is the scariest part of this whole unit. A blinking cursor on a mostly-empty screen, no buttons to click, maybe even a little fear of typing the \"wrong thing\" and breaking your computer. If that's you, we got you! <b>None of the commands we're learning today delete or overwrite anything that already exists.</b> So don't worry.","<h4>What the terminal actually is</h4>","Everything you do on your computer, you do through some kind of interface. Creating a folder, deleting a file, opening a program, all of it. Normally that interface is a mouse and a screen full of icons and buttons. The terminal is just a <i>different</i> interface to the exact same computer. But instead of pointing and clicking, you tell your computer what to do by <i>typing</i>. Anything you can do with clicks, you can do with a typed command. The terminal can even do a few things clicks can't. You type one line, press Enter, and the computer does that one thing and then waits for your next line. That's basically it! <b>Type a command, press Enter, read what comes back, type the next one.</b> It feels like rocket surgery (lol) but it's really just a different way of talking to your computer.","In VSCode, open the integrated terminal again the way you learned last subunit (<code>View → Terminal</code>, or <code>Ctrl + `</code>, which works on both Mac and Windows). (<code>Cmd + J</code> also toggles the whole Panel on Mac.) You'll see a line of text ending in a cursor. That line is called the <b>prompt</b>. It's the computer's way of saying \"I'm ready, what next?\" The prompt usually shows a hint about where you are in the tree, and it ends in a symbol (often <b>%</b> on a Mac and <b>$</b> or <b>></b> for Windows) followed by your cursor. You type <i>after</i> that symbol. In the example below, you will see a <b>~</b> symbol after your-name@MacBook-Pro, which is shorthand for your <b>home directory</b> (this works the same way in Git Bash on Windows and on Linux, too), the default folder your account always starts in. That symbol is immediately followed by the prompt symbol, <b>%</b>, which is your computer's way of saying \"okay, tell me what to do!\" <img class=\"img-responsive\" src=/assets/unit-12/terminal-prompt-labeled.png alt=\"A terminal prompt with the current location and the prompt symbol labeled\">","This integrated terminal isn't a special VSCode invention either. It's the same terminal program your computer already has (Terminal.app on Mac, PowerShell/Command Prompt on Windows), just conveniently built into the editor so you don't have to switch windows. That becomes really helpful for developers because, as you'll soon find out, you'll be using your terminal a LOT during development. Below you'll see both terminals side-by-side. <img class=\"img-responsive\" src=/assets/unit-12/system-and-integrated-terminals.png alt=\"The system terminal and the VSCode integrated terminal shown side-by-side\">","<h4>Five questions, five commands</h4>","Earlier, we said that moving around the terminal is really just asking the computer a handful of questions: <i>\"where am I?\"</i>, <i>\"what's in here?\"</i>, <i>\"take me there,\"</i> <i>\"make a new folder,\"</i> and <i>\"make a new file.\"</i> Each of those is a single command.","<ul>\n  <li><b>pwd</b>: \"where am I?\" (<i>print working directory</i>)</li>\n  <li><b>ls</b>: \"what's in here?\" (<i>list</i>)</li>\n  <li><b>cd</b>: \"take me there\" (<i>change directory</i>)</li>\n  <li><b>mkdir</b>: \"make a new folder here\" (<i>make directory</i>)</li>\n  <li><b>touch</b>: \"make a new, empty file here\"</li>\n</ul>","If you didn't know it already, <b>directory</b> is just the fancy, technical word for <b>folder</b>. They mean the same thing. So \"change directory\" just means \"go into that folder\" and \"make directory\" means \"make a new folder\".","<h4>pwd: \"where am I?\"</h4>","Remember what we said earlier, <b>'at any moment, you're always standing somewhere in the tree.'</b> Your position in that tree is exactly what <b>pwd</b> is for. It shows you which <b>directory</b> (aka 'folder') you are currently standing in. Type it and press Enter:","<pre><code>pwd</code></pre>","It prints the full path to the folder you're currently standing in, from the top of the tree all the way down to you. Because you opened this terminal <i>inside</i> the folder you have open in VSCode, that's the path you'll see. Since no project is open, you'll most likely land in your <b>home directory</b>, the default folder your account always starts in. That's a perfectly sensible place to build a practice project. <img class=\"img-responsive\" src=/assets/unit-12/run-pwd.png alt=\"The output of the pwd command showing the home directory path\">","Strong developers run this command constantly in order to confirm where they are before doing anything else. Get comfortable answering \"where am I?\" <i>before</i> every other move. It will save you a lot of headaches in the future.","<h4>Build something first</h4>","Commands like \"what's in here?\" and \"take me there\" aren't very interesting on an empty folder. So before we practice looking around, let's actually give ourselves a small file tree to look around <i>in</i>. We can do this with two commands: <b>mkdir</b> and <b>touch</b>.","First, <b>mkdir</b> makes a brand-new, empty folder inside the folder you're currently standing in:","<pre><code>mkdir my-first-project</code></pre>","Step inside it with <b>cd</b>, then make a folder inside <i>that</i> one too:","<pre><code>cd my-first-project</code></pre>","<pre><code>mkdir images</code></pre>","Now let's put some files in here. <b>touch</b> makes a brand-new, empty file (as opposed to <b>mkdir</b>, which makes a brand-new, empty folder):","<pre><code>touch hello.txt</code></pre>","<pre><code>touch notes.txt</code></pre>","Notice that none of those commands printed anything back at you. In the terminal, no news is usually good news, a command that runs without any output or error is quietly telling you it did exactly what you asked.","Run <b>ls</b> and take a look. You should see <b>images</b>, <b>hello.txt</b>, and <b>notes.txt</b>, all sitting inside <b>my-first-project</b>, all built by typing instead of right-clicking. <img class=\"img-responsive\" src=/assets/unit-12/mkdir-output.png alt=\"A terminal running mkdir and touch to build the my-first-project folder, then ls showing the new contents\">","Last step: get VSCode actually looking at the folder you just made, the same way you opened a folder in the last subunit, by dragging it into a VSCode window. Open your file browser (Finder or File Explorer), find <b>my-first-project</b>, and drag it onto this VSCode window. VSCode will reload with that folder as your project, Explorer and all.","<img class=\"img-responsive\" src=/assets/unit-12/build-your-own-explorer.gif alt=\"The VSCode Explorer showing the newly built my-first-project folder with an images subfolder, hello.txt, and notes.txt\">","Keep this window open. For the rest of this lesson, every example we show you is happening inside this exact folder, so your terminal should be showing you the exact same thing ours is. In this new VSCode window, open the integrated terminal again.  Can you remember the command for that? VSCode will automatically open the terminal in the folder you have open in the Explorer.  So once the terminal is open, you should be standing in the <b>my-first-project</b> directory.  <img class=\"img-responsive\" src=/assets/unit-12/my-first-project-location.png alt=\"The VSCode Explorer and terminal showing the my-first-project folder\">","<h4>ls: \"what's in here?\"</h4>","Now that you know where you are, let's see what's around you. You just ran this command in the section above,  but just to give you a little more context: <b>ls</b> lists the contents of the folder you're currently standing in. It'll show you the files and the folders inside it:","<pre><code>ls</code></pre>","You'll see the names of everything that lives directly inside your current folder, the same <b>images</b>, <b>hello.txt</b>, and <b>notes.txt</b> you just built. This is the exact same information as the Explorer panel on the left of VSCode, just printed as text instead of drawn as a tree. <img class=\"img-responsive\" src=/assets/unit-12/ls-output.png alt=\"A terminal showing the output of ls next to the matching VSCode Explorer tree\">","So far we've learned how to ask the computer \"where am I?\" (pwd) and \"what's here?\" (ls) without changing anything at all. You've just been looking. But how can we actually move around? We know that we're always standing somewhere in the tree so how can we move to a different directory?","<h4>cd: \"take me there\"</h4>","<b>cd</b> moves you from the folder you're in <i>into</i> a folder that's sitting inside of it. This is how you navigate through the branches of a tree. <b>ls</b> just showed us a folder named <i>images</i>. We can step into it with:","<pre><code>cd images</code></pre>","Now run <b>pwd</b> again. Notice how the path is one level longer than it was a moment ago. You successfully moved into the <b>images</b> folder! This will be a great habit to get into: run <b>cd</b> to move, then <b>pwd</b> to confirm you landed where you expected. <img class=\"img-responsive\" src=/assets/unit-12/cd-output.png alt=\"A terminal showing changing from the my-first-project to images directory\">","Run <b>ls</b> again in here. It's empty, which makes sense, we made <b>images</b> but never put anything inside it.","To go back <i>up</i> to the parent folder, the one that contains the folder you're in, use two dots:","<pre><code>cd ..</code></pre>","Those two dots are shorthand for \"my parent.\" So <b>cd images</b> walks you down into a child, and <b>cd ..</b> walks you back up to the parent. Run <b>pwd</b> after each move until it stops feeling like a surprise. Take a look at the example below to track the whole process of how we moved from one directory to the next, and then back. <img class=\"img-responsive\" src=/assets/unit-12/cd-navigation.png alt=\"A terminal showing cd into a folder and cd back up, with pwd confirming the location each time\">","<h4>A note on your operating system</h4>","In a bash-style terminal (macOS Terminal and Git Bash on Windows), these five commands (<b>pwd</b>, <b>ls</b>, <b>cd</b>, <b>mkdir</b>, and <b>touch</b>) work the same, so everyone can follow the same steps today. If you're on Windows and a command like <b>touch</b> isn't recognized, open a new terminal in VSCode and switch the profile to <b>Git Bash</b>. A few things will still look a little different: your prompt symbol may be <b>$</b> or <b>&gt;</b>, and the paths that <b>pwd</b> prints use forward slashes on a Mac (<b>/Users/you/Desktop</b>) and backslashes on Windows (<b>C:\\Users\\you\\Desktop</b>). The idea is the same. You're navigating the  same tree with slightly different punctuation. I promise, nothing is broken.","<h4>A word of caution</h4>","The commands we used today are all safe, but as you explore, your AI tutor (or a random tutorial online) might eventually suggest a command you don't recognize. Before you run <i>any</i> unfamiliar command, especially one that might delete or overwrite something, just ask, <i>\"What exactly does this command do, and is it safe to run in my project folder?\"</i> and read the answer before pressing Enter. Curiosity is lovely, but it's never a good idea to blindly copy-paste into the terminal.","<b>Quick self-check:</b> <ul>\n  <li>Which command answers \"where am I right now?\" and why did we ask you to run it as a reflex?</li>\n  <li>What's the difference between <b>ls</b> and <b>cd</b>, in your own words?</li>\n  <li>You run <b>cd images</b> and then <b>cd ..</b> Where do you end up, relative to where you started?</li>\n  <li>What's the difference between <b>mkdir</b> and <b>touch</b>?</li>\n  <li>You ran a command and \"nothing happened\", no error, no message. Why is that often totally normal in the terminal?</li>\n</ul>","Let's recap what you did in this lesson. You talked to your computer by typing, built a small file tree, and walked up and down it on your own. Everything so far has been about <i>creating and moving around</i>. In the next subunit, we finally do something more <i>with</i> that <b>my-first-project</b> folder, we'll add real content and take our very first snapshot with Git. You now know the commands that will give you the answers to \"What's here?\", \"Take me there\",\n \"Create something new\", and \"Where am I?\". Now if only there were a terminal command for \"<b>Who</b> am I?\"...\n<img class=\"img-responsive\" src=/assets/unit-12/who-am-i.gif alt=\"Zoolander saying 'Who am I?' in a mirror.\">"]},"unit-12-dev-env-6":{"subunitId":"unit-12-dev-env-6","heading":"Your First Commit","read":["In the last subunit you talked to your computer by typing, built the <b>my-first-project</b> folder, and walked up and down its tree with <b>pwd</b>, <b>ls</b>, <b>cd</b>, <b>mkdir</b>, and <b>touch</b>. Everything so far has been about <i>creating and moving around</i>. Now we're going to put a little bit of real content in it and take our very first <b>snapshot</b> with Git.","This is also the last Git lesson of Phase 12a (woohoo!). This subunit is the checkpoint gate before you move on to Phase 12b. By the end of this lesson you'll have made your first commit and, just as importantly, you'll be able to explain <i>in plain English</i> what that commit actually did. Once you're comfortable with that, you'll be ready to move on to 12b where you'll actually push that commit up to GitHub so it lives online, not just  on your laptop, and you'll pick up the skills that make working with other  developers possible like forking, cloning, branching, and opening your very first pull request!","<h4>A quick reminder: what Git actually is</h4>","Back when you installed it, we compared Git to clicking \"save\" on a Word document, except each save is a <b>snapshot</b> that you can look back at or return to later. As you build projects, you'll make changes, break things, fix them, and change your mind. Git lets you take a labeled snapshot of your whole project at a moment in time. That way you always have a record of what it looked like when you were working. You edit your project, take that snapshot, and now you can always go back to that version later on, even if you take more snapshots. Each of those snapshots is called a <b>commit</b>.","Git runs <i>locally</i>, right on your computer. It has nothing to do with the internet yet, and nothing to do with GitHub. We're staying entirely on your own machine for this whole subunit.","<h4>First: \"Who am I?\"</h4>","We ended the last subunit with a joke: you'd learned \"where am I?\", \"what's here?\", \"take me there,\" and \"make something new,\" but not \"<b>who</b> am I?\" Here's the thing though. When you use Git, every commit you make gets <i>stamped</i> with a name and an email, so that later on, anyone looking at a project's history can see who took which snapshot. Before Git will let you start making commits, it needs to know who you are.","Now, real quick, let's take a second to connect two things. Back in the setup subunit, you <i>installed</i> Git, so it's a program sitting on your computer  right now, just like VSCode is. And in the last subunit you learned that the terminal is for walking around folders as well as talking to your computer and the programs on it by typing. So to set up  Git, we don't open some settings window with buttons to click. Instead, we <i>talk to the Git program directly through the terminal.</i> Every command we run in this lesson starts with the word <b>git</b>, which  is just how we specify that the following command is for Git! Next, we'll use the terminal to hand Git a couple of  <b>configurations</b>, settings that tell it who you are. You only have to do this  once. In your VSCode terminal, run these two commands, swapping in your own name and the email you signed up for GitHub with:","<pre><code>git config --global user.name \"Your Name\"</code></pre>","<pre><code>git config --global user.email \"you@example.com\"</code></pre>","The <b>--global</b> flag just means \"use this for every project on this computer,\" so you won't have to repeat it for your next project.","You can check and make sure Git stored these settings by typing:","<pre><code>git config --global --list</code></pre>","<img class=\"img-responsive\" src=/assets/unit-12/git-config-identity.png alt=\"A terminal running git config to set the user name and email\">","<h4>Turn a folder into a project Git is watching: git init</h4>","Right now, <b>my-first-project</b> is just a plain folder. Git isn't paying any attention to it yet. To ask Git to start tracking a folder, you <i>initialize</i> it. First make sure you're standing in the right place, this is exactly why we drilled <b>pwd</b> so hard last time. In the integrated terminal, type:","<pre><code>pwd</code></pre>","You want to see a path ending in <b>my-first-project</b>. If you don't, use <b>cd</b> to walk into it before going any further. Once you're standing inside <b>my-first-project</b>, run:","<pre><code>git init</code></pre>","That single command turns the folder you're currently standing in into a <b>repository</b> (usually shortened to \"repo\"), which is just a fancy word for \"a folder that Git is now watching.\" Behind the scenes, Git created a hidden folder named <b>.git</b> inside of my-first-project to keep its records. You don't ever need to open or touch that folder, just know that its presence is what makes this folder a repo. <img class=\"img-responsive\" src=/assets/unit-12/git-init-output.png alt=\"A terminal showing git init initializing an empty repository in my-first-project\">","An important note: you run <b>git init</b> <i>once per project</i>, in that project's top folder. You <b>only</b> run it on folders you want to track (so, not your Home or Desktop folders). If you ever see a message about a repository already existing, that's Git telling you this folder is already being watched, and that's fine.","<b>Quick tip:</b> If you ever want to clear your terminal so that it doesn't get too crowded, just run the <b>clear</b> command.","<h4>Ask Git what it sees: git status</h4>","This is a command that you're going to use a lot. <b>git status</b> tells you, right now, what Git thinks is going on in your project. For example, what's changed, what it's about to save, and what it isn't tracking yet. Run it:","<pre><code>git status</code></pre>","Because you <i>just</i> turned my-first-project into a Git repo, Git will report that your files (the ones you made last subunit, like <b>hello.txt</b> and <b>notes.txt</b>) are <b>untracked</b>. \"Untracked\" just means Git can see the files sitting there but isn't saving them into commits (snapshots) yet. Developers use <b>git status</b> all the time to check the <i>state of their project</i>. <img class=\"img-responsive\" src=/assets/unit-12/git-status-untracked.png alt=\"A terminal showing git status listing untracked files in the new repository\">","<h4>Give yourself something worth snapshotting</h4>","A snapshot of empty files is pretty useless so let's put some real content in one! Open <b>notes.txt</b> in VSCode by clicking it in the Explorer, type a sentence or two, anything you like, and save it (remember the filled dot on the tab means unsaved changes). Something as simple as this is perfect:","<pre><code>This is my very first project that Git is tracking.</code></pre>","Now run git status again. You’ll still see notes.txt listed as an untracked file.  That’s because Git knows the file exists, but it hasn’t started keeping a version  of it yet. Once we add the file to the staging area, Git will include its current contents in the snapshot we’re preparing. <h4>The staging area: git add</h4>","Making a commit happens in two small steps. Before Git takes the snapshot, you tell it <i>which</i> changes belong in this snapshot. That's what <b>git add</b> does. Picture lining people up for a group photo: <b>git add</b> is you waving the files you want into the frame, and the commit (next step) is the camera actually taking the photo. The lineup area even has a name. It's called the <b>staging area</b>.","To wave <i>everything</i> that changed into the frame, run:","<pre><code>git add .</code></pre>","That lone dot means \"everything in the folder I'm currently standing in.\" which, in this case, should be my-first-project. So the <b>.</b> just means <b>here</b>. Run <b>git status</b> one more time and now you'll see your files listed under \"Changes to be committed\". They're in the lineup now, ready for the photo, but the picture hasn't been taken yet. Nothing is saved into history until the next command. <img class=\"img-responsive\" src=/assets/unit-12/git-add-staged.png alt=\"A terminal showing git status with files staged and ready to be committed\"> <b>Note:</b> If there are ever  changes you've made to files that you do <b>not</b> want to add to a commit, you can always stage the files you <b>do</b> want to add one at a time with <b>git add &lt;filename&gt;</b>. If we ran <b>git add notes.txt</b> then ONLY notes.txt would have been added to the staging area and hello.txt would remain unstaged.  <img class=\"img-responsive\" src=/assets/unit-12/git-add-staged-text-only.png alt=\"A terminal showing git status with a hello.txt staged and ready to be committed\">","<h4>Take the snapshot: git commit</h4>","Now the moment we've been building toward. <b>git commit</b> takes the snapshot of everything you staged and saves it into your project's history, along with a short message describing what this snapshot is. Run it exactly like this:","<pre><code>git commit -m \"My first commit\"</code></pre>","The <b>-m</b> flag is short for \"message,\" and the text in quotes is <i>your</i> note to your future self about what this snapshot represents. Always include <b>-m</b> with your message like we did here. If you forget it, Git will try to open a text editor to make you write one, and the editor it opens can be confusing to get out of for a beginner. Save yourself the headache and type the message inline every time. <img class=\"img-responsive\" src=/assets/unit-12/git-commit-output.png alt=\"A terminal showing git commit creating the first commit with a message\">","It's best to write your commit messages like you're writing for a human, ideally future-you. \"My first commit\" is fine for today, but as you start to build real things, a good message finishes the sentence \"This commit will...\", for example <i>\"Add a homepage heading\"</i> or <i>\"Fix the broken image link\"</i>. You'll thank yourself later when you're scrolling back through a project's history trying to remember what you changed and why.","Now run <b>git status</b> one final time. Git should tell you there's \"nothing to commit, working tree clean.\" That's Git's way of saying \"everything here is safely snapshotted, no unsaved changes.\" You now have your first commit sitting in your project's history.","<h4>See your work: git log</h4>","Want proof the snapshot exists? Run:","<pre><code>git log</code></pre>","You'll see your commit listed including the message you wrote, your name, email, and the date. If the output takes over the screen and gives you a blinking line at the bottom, just press <b>q</b> to quit back to your normal prompt. This log is the history you've started building. Right now it's one snapshot long, but every commit you make in this project will stack up in a list exactly like this. <img class=\"img-responsive\" src=/assets/unit-12/git-log-output.png alt=\"A terminal showing git log with the first commit, its message, author, and date\">","<h4>Let's do it again</h4>","Open <b>notes.txt</b> again and add a second line, then save. Something like:","<pre><code>And now I'm adding this line!</code></pre>","Now run <b>git status</b>:","<pre><code>git status</code></pre>","Notice that Git spotted your edit right away, and it's listing <b>notes.txt</b> under \"Changes not staged for commit.\" This is because after you committed a minute ago, that emptied the lineup. Git took the photo and everyone left the staging area. Your new edit is a fresh change that Git can see but hasn't been waved into the frame yet. A commit only ever captures what was staged <i>at the moment you ran it</i>, so this new line isn't in your history at all. <img class=\"img-responsive\" src=/assets/unit-12/git-status-modified.png alt=\"A terminal showing git status listing notes.txt as changed but not staged\">","Stage the change:","<pre><code>git add .</code></pre>","Run <b>git status</b> one more time to confirm the change switched from \"not staged\" up into \"Changes to be committed.\" It's back in the staging area, ready for the next photo.","Then take the snapshot, with a message that describes <i>this</i> change:","<pre><code>git commit -m \"Add a second line to notes.txt\"</code></pre> <img class=\"img-responsive\" src=/assets/unit-12/git-second-commit.png alt=\"A terminal showing the second commit being created with a descriptive message\">","<h4>The Checkpoint Gate</h4>","And that's the basics of working with Git! <b>Change something, stage it with add, snapshot it with commit.</b> Then do it again. Every time you make a new change, you stage it again, because each commit only captures what's in the staging area at that exact moment.  Alright! We're almost ready to move on to Phase 12b! But first, you need to be able to do three things on your own:","<ul>\n  <li><b>Navigate through a project folder in the terminal.</b> Open a new project in VSCode, and use <b>pwd</b>, <b>cd</b>, <b>mkdir</b>, <b>touch</b>, and <b>ls</b> to move around, add to, and see what's in that project folder.</li>\n  <li><b>Make a commit.</b> Stage a change with <b>git add</b> and snapshot it with <b>git commit -m</b>, on your own.</li>\n  <li><b>Explain, in plain English, what that commit did.</b> Your commit message should clearly finish the sentence, \"This commit will...\"\n  (e.g., <b>git commit -m \"Add message to notes.txt\"</b>) </li>\n</ul>","If you can produce your own version of that, in your words, you're ready for 12b. If you still feel a little shaky, that's totally normal and it's the best possible time to slow down. If you find it helpful, you can delete the practice folder, remake it from scratch, and walk the whole path again: <b>init</b>, edit a file, <b>status</b>, <b>add</b>, <b>commit</b>. Repetition is super helpful when it comes to  learning just about anything in software development. You can also ask your AI tutor to quiz you and help clarify any gaps in your understanding of what we did in this lesson. Just remember, it's a study partner, not a replacement for being able to explain it yourself.","<b>Quick self-check:</b> <ul>\n  <li>In your own words, what is a commit?</li>\n  <li>What does <b>git init</b> do to a folder, and how often do you run it for a given project?</li>\n  <li>What's the difference between <b>git add</b> and <b>git commit</b>? Use the group photo analogy if it helps.</li>\n  <li>Why do we always include <b>-m \"your message\"</b> when we commit?</li>\n  <li>You ran <b>git status</b> and it said \"nothing to commit, working tree clean.\" What does that tell you?</li>\n</ul>","Okay! That was a lot! You set up your Git identity, turned a folder into a repo, staged a change, and took your very first snapshot, all by typing. Everything up until now has been on your own computer. In Phase 12b, we're going to take these commits <i>online</i>. You'll finally meet GitHub and push your work somewhere the rest of the world can see it. But before that, you're going to meet your first IDE AI Assistant. See you on the other side! <img class=\"img-responsive\" src=/assets/unit-12/checkpoint-cleared.gif alt=\"A video game 'checkpoint reached' celebration\">"]},"unit-12-dev-env-7":{"subunitId":"unit-12-dev-env-7","heading":"Meet Your IDE Assistant","read":["You cleared the checkpoint gate. You can navigate a project in the terminal, and you can make a commit and explain in plain English what it did. Before we start working on GitHub, there's one more tool we want to introduce you to inside of VSCode, an <b>AI assistant that lives inside your Integrated Development Environment (IDE).</b>","<h4>Wait, haven't we already met the AI assistant?</h4>","Sort of, but not like this. Back in Unit 11 you built a tutor bot in your browser. That bot only knows what you paste into it. If you wanted help with a file, you had to copy the whole thing, switch over to a browser tab, paste it in, and copy the answer back. <b>An IDE assistant skips all of that.</b> It lives right inside VSCode, so it can already see the file you have open, sometimes even the whole project.","This isn't a replacement for your browser tutor bot, they're just suited for different jobs. Your browser bot is still a great place to ask things like \"what is a closure again?\". But the IDE assistant's superpower is that it's already looking at <i>your</i> code, so it's the better choice when your question is about something sitting right in front of you.","<h4>Find it</h4>","Most versions of VSCode come with some form of AI assistant panel already built in, usually opened from an icon in the Activity Bar (that strip of icons on the far left) or from <b>View → Chat</b>  in the top menu. If you don't see one, open the Command Palette and search for  <i>Chat: Open Chat</i>. Open it now and just look around, you don't need to type anything yet. <img class=\"img-responsive\" src=/assets/unit-12/vscode-ide-assistant-panel.png alt=\"The VSCode chat panel open in the sidebar, showing an empty conversation\">","<b>A quick note:</b> exactly what this panel looks like, and what it's called, can vary a bit depending on your version of VSCode and what's installed. That's fine. If you still can't find it, that's a perfectly good question to bring to your AI tutor from Unit 11!","<h4>Give yourself something to ask about</h4>","Let's get an idea of what this baby can do. We're going to add one more file to <b>my-first-project</b>, a tiny JavaScript file with a bug hiding in it on purpose. Back in your terminal, make sure you're still inside of <b>my-first-project</b> and run:","<pre><code>touch math.js</code></pre>","Open <b>math.js</b> in the Explorer and paste in this exact code:","<pre><code>function average(numbers) {\n  let total = 0;\n  for (let i = 0; i <= numbers.length; i++) {\n    total += numbers[i];\n  }\n  return total / numbers.length;\n}\nconsole.log(average([2, 4, 6]));</code></pre>","Save the file. Now, <b>a quick note before you go looking for a \"run\" button:</b> actually executing a <b>.js</b> file on your machine needs a tool called <b>Node</b>, and we haven't installed that yet on purpose. <b>Let's walk through the code.</b>","Look at that <b>average</b> function line by line and predict, on paper or out loud, exactly what <b>console.log(average([2, 4, 6]))</b> would print if you could run it right now. Walk the loop yourself. What is <b>i</b> on each pass, what is <b>numbers[i]</b> on each pass, and what does <b>total</b> add up to by the end? Once you think you know what's going on with this function continue reading. <b>NOTE:</b> remember, you can always open a <a href=\"https://csbin.io\" target=\"_blank\">CSBin</a> if you'd like to run the code and play around with it before we install Node in the next unit.","If you traced it carefully, you probably noticed the loop asks for <b>numbers[3]</b> on its last pass, a spot that doesn't exist in a 3-item array. JavaScript hands back <b>undefined</b> for a missing index like that, and adding <b>undefined</b> into <b>total</b> poisons the whole sum. In real JavaScript, that would print <b>NaN</b>, \"Not a Number,\" instead of a real average. Don't fix it yet, and don't ask your assistant to fix it either. First, we're going to practice a <b>very</b> important habit.","<h4>Ask for an explanation, not a fix</h4>","You're still in the process of solidifying your understanding of JavaScript and software development in general. Learning is the  priority here so we want hints and explanations, not answers. Select the code inside <b>math.js</b> (or just make sure the file is open and active), then in the chat panel, ask something like:","<ul>\n  <li><i>\"I walked through this function and I think it returns NaN instead of the average, because the loop \n  reaches one index past the end of the array. Can you check my thinking and explain what's actually going on, \n  without fixing it for me?\"</i></li>\n</ul>","This question states your own prediction, it points at exactly where you think the problem is, and it explicitly asks for an explanation instead of a rewrite. Plenty of IDE assistants will happily rewrite your whole file if you let them, but that's not a habit we're trying to get into right now. Just telling the assistant, \"fix my code\" invites a wall of new code that you didn't write and can't explain. A specific question invites an explanation you can actually learn from.","<h4>Judge the explanation before you touch anything</h4>","Read whatever the assistant gives back. Somewhere in there it should point at the loop condition, <b>i <= numbers.length</b>, and explain that this lets the loop run one time too many, reaching past the end of the array into a spot that doesn't exist, which adds <b>undefined</b> into the total and turns the whole thing into <b>NaN</b>.","Before you change any code, ask yourself, <b>\"does the explanation actually match what the code says?\"</b>. Scroll back up to <b>math.js</b> and check it line by line against what the assistant just told you. It's always a good idea to verify the response. An IDE assistant will usually <i>sound</i> confident, but that's not the same as being correct. Believe it or not, AI assistants make plenty of mistakes, no matter how sure they sound, so double check.","<b>Now, before moving on</b> in your own words, why does looping while <b>i <= numbers.length</b> reach one step too far? If you're still not really sure, ask some follow-up questions in the chat panel before moving forward, that's exactly what it's there for!","<h4>Now make the fix yourself</h4>","Once you can explain the bug in your own words, you make the edit, not the assistant. Change the loop condition so it stops one step earlier.","<h4>Snapshot it</h4>","You already know this next part from last subunit! Back in the terminal:","<pre><code>git status</code></pre>","You should see <b>math.js</b> listed as untracked (a brand new file) or changed, depending on exactly when you last checked. Stage it and commit it, with a message that finishes the sentence, \"This commit will...\":","<pre><code>git add .</code></pre>","<pre><code>git commit -m \"Fix off-by-one loop bug in average function\"</code></pre>","<h4>Stick to the habit</h4>","You now have two different AI helpers. Your Unit 11 browser tutor bot only knows what you paste in, while this IDE assistant can already see the file in front of you. But the exact same rule applies to both, <b>ask for an explanation before a fix, verify that explanation against the real thing, and then make the change yourself.</b> That's going to be our workflow while we're learning, regardless of which AI tool we're using.","<b>Quick self-check:</b> <ul>\n  <li>What's the practical difference between your Unit 11 browser tutor bot and the IDE assistant you just used?</li>\n  <li>In your own words, why was <b>i <= numbers.length</b> a bug?</li>\n  <li>Why did we ask the assistant to explain the bug instead of asking it to fix it?</li>\n  <li>What does it mean to \"verify\" an AI's explanation, and how did you do that with <b>math.js</b>?</li>\n</ul>","You're now officially done with Phase 12a. You've navigated VSCode, walked the terminal, made commits, gotten a little bit of JavaScript review in 😉 and now used an AI assistant <b>responsibly</b> right inside of your editor. Next, these commits you've been making are going to stop living <i>only</i> on your computer. Time to meet GitHub! <img class=\"img-responsive\" src=/assets/unit-12/github-hello.gif alt=\"A celebratory animation marking the end of Phase 12a\">"]},"unit-12-dev-env-8":{"subunitId":"unit-12-dev-env-8","heading":"The Two Places Model: Your Computer & GitHub","read":["Welcome to <b>Phase 12b</b>. Hopefully you're starting to feel like you're getting a handle on your local machine now, VSCode, the terminal, Git, and an AI assistant right there in your editor. Everything you've done so far has been on your computer. That's about to change.","<h4>Git is not GitHub</h4>","First, it's important to remember that, even though they <i>sound</i> the same, Git and GitHub are two different things.","<ul>\n  <li><b>Git</b> is the <i>tool</i> you've been using. It's a program that runs on your computer and watches a\n  folder so you can save snapshots of it (commits). Every <b>git</b> command you've\n  typed so far, <b>git init</b>, <b>git add</b>, <b>git commit</b>, has been Git working on your machine, totally offline,\n  and not talking to anything on the internet.</li>\n  <li><b>GitHub</b> is a <i>website</i>. It's a place on the internet that hosts copies of Git projects so people\n  can share them, back them up, and collaborate on them. GitHub is owned by Microsoft, but it's just one of a few\n  services that do this (GitLab and Bitbucket are others). It's not part of Git itself, it's a separate product\n  built on top of it.</li>\n</ul>","A good way to think about it is, <b>Git is the tool, GitHub is the place.</b> You could use Git for the rest of your life and never once open GitHub. Lots of solo developers do exactly that. But the moment you want another human, or another machine, to see your code, you need somewhere on the internet to put it, and GitHub is where we're going to put it!","<h4>The two-places model</h4>","So, from this point on, your project is going to live in <b>two places at once</b>:","<ul>\n  <li><b>Your computer.</b> This is the copy you've been working on. It's where you edit files in VSCode, run\n  commands in the terminal, and make commits with Git. It's yours, it's <b>local</b>, and only you can see it.</li>\n  <li><b>GitHub.</b> This is a second copy of the same project. It's <b>remote</b>, sitting on GitHub's servers on the internet.\n  Anyone you allow (including future you, on a different computer) can see it.</li>\n</ul>","<img class=\"img-responsive\" src=/assets/unit-12/two-places-diagram.png alt=\"A diagram showing a laptop on the left and the GitHub logo on the right, with a two-way arrow between them labeled 'commits travel here'\">","Almost everything you're about to learn in this half of the unit is really just <b>a way of moving work between those two copies</b>.","<h4>Commits are what travel</h4>","Remember, a commit is a saved snapshot of your project at a specific moment, with a message describing it. Commits aren't just for you and your local history, <b>commits are also the unit of work that travels between your computer and GitHub</b>.","When you want to send work up to GitHub, you don't upload the whole project every time. You send your new commits, and GitHub adds them to its copy so both sides are in sync again. Moving work the other direction (from GitHub down to your computer) works the same way in reverse. Your computer pulls down any commits it doesn't have yet, and the two copies match up again. You won't really have much reason to move work in that direction during this unit, since you're the only person working on your project, but it's the same process.","This is why we spent so much time in Phase 12a making sure you could actually <i>make</i> a commit and <i>explain</i> what it did. You're going to be sending commits back and forth from here on out.","<h4>A quick preview of what's coming</h4>","You don't need to memorize any of these yet because we'll look at them one at a time in the next few lessons. But it's helpful to see before we start our walk through. Almost all of these are really just a specific direction of travel between your two copies (fork is the one exception, moving work between two spots on GitHub before your computer is even involved):","<ol>\n  <li><b>fork</b>: make your own copy of someone else's project on GitHub. (This one moves work between two\n  spots <i>on GitHub</i>, before your computer is even involved)</li>\n  <li><b>clone</b>: copy a project down <i>from GitHub onto your computer</i>, so you have a local copy to\n  work on.</li>\n  <li><b>push</b>: send your local commits <i>up from your computer to GitHub</i>.</li>\n  <li><b>pull</b>: bring commits <i>down from GitHub to your computer</i>.</li>\n</ol> <img class=\"img-responsive\" src=/assets/unit-12/github-directions.png alt=\"A diagram showing the difference between forking, cloning, pushing, and pulling repositories on GitHub\">","where is the work moving from and to?\"","<h4>Why we introduced the model first</h4>","In the next subunit you're going to fork a repo and clone it down, and it's going to be really tempting to just type what we tell you and keep it moving but PLEASE resist that. Before every command, we're going to ask you to say out loud (or in your head), \"Which copy is about to change and where is the work going?\". If you can answer that, you understand the command. If you can't, come back here and look at the diagram again.","<b>Quick self-check</b> <ul>\n  <li>What's the difference between Git and GitHub?</li>\n  <li>Where do the two copies of your project live in the two-places model?</li>\n  <li>What actually travels between those two copies when you send work back and forth?</li>\n  <li>You haven't learned <b>push</b> yet, but based on the preview above, take a guess at which copy\n  <b>push</b> changes, and in what direction the work is moving?</li>\n</ul>","If any of those felt shaky, scroll back up and sit with the diagram for another minute before you move on. If they felt solid, you're ready. Next, you'll make your own copy of a project on GitHub, and then pull it down to your computer so you can actually work on it."]},"unit-12-dev-env-9":{"subunitId":"unit-12-dev-env-9","heading":"Fork and Clone","read":["In the last subunit we talked about how your project lives in two copies, one on your <b>computer</b> and one on <b>GitHub</b>, and Git commands are really just ways of moving work between them. Now we're going to actually put that model to work. By the end of this subunit, you'll have a real project living in both places, ready to be worked on.","We're going to do this in two moves:","<ol>\n  <li><b>Fork</b> a practice repository we've set up for you, so you have <i>your own copy</i> of it on GitHub.</li>\n  <li><b>Clone</b> that copy down onto your computer, so you have a local copy you can actually edit in VSCode.</li>\n</ol>","Before each command, we're going to pause and ask, <b>\"which copy is about to change, and where is the work moving from and to?\"</b> If you can answer that, you understand the command. Let's gooo!","<h4>Step 1: Find the practice repo</h4>","We've prepared a small practice repository for you to work with for the rest of this unit. It's not much, just a tiny project with a couple of files, but it's enough to walk the full GitHub workflow with.","Open your browser and go to:","<a href=\"https://github.com/CodesmithLLC/learn-github-repo\" target=\"_blank\" rel=\"noopener noreferrer\">CodesmithLLC/learn-github-repo</a>","Take a second to look around the page. You should see a file tree in the middle of the screen (this is <i>someone else's</i> repository right now, sitting on GitHub). You should see a <b>README.md</b> that GitHub is displaying below the file list, and a row of buttons up near the top right that includes <b>Fork</b>. <img class=\"img-responsive\" src=/assets/unit-12/practice-repo-landing.png alt=\"The learn-github-repo landing page on GitHub with the Fork button highlighted in the top right\">","<b>Pause and predict.</b> Before you click anything, look at the diagram from the last subunit below. Right now, this project exists on GitHub, but not on <i>your</i> GitHub. It belongs to <b>CodesmithLLC</b>. And it definitely doesn't exist on your computer yet. So which direction will this project move in first? <img class=\"img-responsive\" src=/assets/unit-12/github-directions.png alt=\"A diagram from the last subunit showing the difference between forking, cloning, pushing, and pulling repositories on GitHub\">","<h4>Step 2: Fork the repo</h4>","A <b>fork</b> is your own personal copy of someone else's project, made on GitHub. It's like grabbing a book off a library shelf and photocopying the whole thing, you now have a copy you can scribble in, and the original one on the shelf stays totally untouched.","<b>Forking happens entirely on GitHub.</b> Your computer isn't involved yet at all. Both the original and your fork live on GitHub's servers. This is the one operation in our diagram above that moves work between two spots <i>on GitHub</i>.","Click the <b>Fork</b> button in the top right of the page. GitHub will take you to a screen that asks where you'd like to fork it to and what to name it. The defaults are fine, your own GitHub username as the owner, and <b>learn-github-repo</b> as the name. Leave the \"Copy the main branch only\" checkbox checked. Then click the green <b>Create fork</b> button at the bottom. <img class=\"img-responsive\" src=/assets/unit-12/fork-create-screen.png alt=\"The GitHub Create a new fork screen with the owner set to the student's username and the default repository name\">","Give it a second, and GitHub will drop you on a new page that looks almost identical to the one you were just on, <i>except</i> the name at the top now reads <b>your-username / learn-github-repo</b> instead of <b>CodesmithLLC / learn-github-repo</b>. Right underneath that name, in smaller text, you should see something like \"forked from CodesmithLLC/learn-github-repo\". That little line tells you where this copy of the repo came from. <img class=\"img-responsive\" src=/assets/unit-12/forked-repo-landing.png alt=\"The forked repository page showing the student's username as the owner and a forked from label pointing to CodesmithLLC\">","At this point, on GitHub, there are <i>two</i> copies of this project. The original that belongs to Codesmith, and your fork that belongs to you. It still does not exist on your computer. Forking a repository doesn't touch your machine at all. That's the next step.","<h4>Step 3: Grab the clone URL</h4>","To copy your fork down to your computer, you're going to use <b>git clone</b>. But first, Git needs to know <i>which</i> repository to copy, and where it lives. That's what the <b>clone URL</b> is for.","On your fork's page, look for the green <b>&lt;&gt; Code</b> button, near the top right of the file list. Click it. A little dropdown will appear with a few tabs, HTTPS, SSH, and GitHub CLI. Stay on the <b>HTTPS</b> tab (the default). You'll see a URL that looks something like:","<pre><code>https://github.com/your-username/learn-github-repo.git</code></pre>","Click the little copy icon on the right side of that URL to copy it to your clipboard. <img class=\"img-responsive\" src=/assets/unit-12/code-button-clone-url.png alt=\"The green Code button on GitHub expanded to show the HTTPS clone URL with a copy icon\">","<h4>Step 4: Pick a home for it on your computer</h4>","Now hop over to VSCode and open its integrated terminal (<b>View → Terminal</b>, or <b>Ctrl + `</b>). Before you clone anything, ask <b>pwd</b> where you are:","<pre><code>pwd</code></pre>","Wherever <b>pwd</b> prints, that's where the cloned folder is about to land. If that's fine with you (your home folder, a projects folder, wherever), great. If you'd rather keep this project alongside <b>my-first-project</b> from Phase 12a, <b>cd</b> your way into the parent folder of <b>my-first-project</b>.","Once again, ask yourself which copy is about to change, and where is the work moving? You should be able to say something like, \"The copy on GitHub isn't changing at all. A new copy is about to appear on my computer, in whatever folder <b>pwd</b> just printed.\" If it makes sense to you, you're ready.","<h4>Step 5: Clone</h4>","In the terminal, type <b>git clone</b>, then a space, then paste the URL you copied. It'll look something like this:","<pre><code>git clone https://github.com/your-username/learn-github-repo.git</code></pre>","Hit enter. You should see a few lines of output that mention \"Cloning into 'learn-github-repo'...\" and some counting of objects. When your prompt comes back, the clone is done.","Confirm it worked with two quick commands:","<pre><code>ls</code></pre>","You should now see a <b>learn-github-repo</b> folder that wasn't there a minute ago. Step into it:","<pre><code>cd learn-github-repo</code></pre>","<pre><code>ls</code></pre>","You should see the same files here that you saw on the GitHub page, the <b>README.md</b> and <b>hello.txt</b>. Those files traveled from GitHub down to your computer. You now have a local copy of your fork on your computer.","<h4>Open it in VSCode</h4>","Still in the terminal, open the whole folder in VSCode with:","<pre><code>code .</code></pre>","The dot means \"this folder, right here.\" VSCode should open with the project's file tree visible in the Explorer on the left. Click the <b>README.md</b> file to open it. This is the same README we just saw on GitHub, only now you're looking at the raw file on your own machine.  <img class=\"img-responsive\" src=/assets/unit-12/cloned-repo-in-vscode.png alt=\"VSCode open on the cloned practice repo with the README.md file open in the editor\">","<b>If <code>code .</code> doesn't work</b>, that just means the shortcut isn't wired up on your machine yet, which is common on a fresh install. No problem, you can open the folder from your file explorer instead. On <b>Mac</b>, run:","<pre><code>open .</code></pre>","On <b>Windows</b>, run:","<pre><code>explorer .</code></pre>","Either one will pop open a file window on the folder you're in. From there, drag that folder onto your VSCode icon, or open VSCode and use <b>File → Open Folder</b> to point it at <b>learn-github-repo</b>, just like you did earlier in this unit.","A few subunits ago, you had to run <b>git init</b> to turn <b>my-first-project</b> into a Git repository. You don't need to do that here. When Git clones a project, <b>it copies the Git history along with the files</b>, which means this folder is already being watched by Git.","Back in the terminal, from inside the <b>learn-github-repo</b> folder, run:","<pre><code>git status</code></pre>","You should see something like \"On branch main\" and \"nothing to commit, working tree clean.\" Git is already here, already tracking this folder, and it agrees with GitHub about the current state of the project. No <b>init</b> needed. Cloning gives you the files <i>and</i> the Git history of the project all in one command.","<h4>Recap</h4>","Let's replay the whole thing against the diagram from last subunit:","<ul>\n  <li><b>Before you started</b>, the project existed in <i>one</i> spot: on GitHub, owned by CodesmithLLC.\n  It was not on your computer yet.</li>\n  <li><b>After Fork</b>, the project existed in <i>two</i> spots on GitHub: the original, and your personal\n  copy. Your computer still had nothing. Fork didn't touch your machine.</li>\n  <li><b>After Clone</b>, the project existed in <i>three</i> spots: the original on CodesmithLLC, your fork on\n  GitHub, and a local copy of your fork on your computer. The clone is the piece that finally bridged GitHub and your machine.</li>\n</ul>","From now on, the copy on your computer and the copy on <i>your fork</i> on GitHub are the two copies from the two-places model. You're going to be moving work between those two copies for the rest of this unit. The original CodesmithLLC copy is just where you started from; you won't be interacting with it again.","<h4>Quick self-check</h4> <ul>\n  <li>In your own words, what's the difference between <b>fork</b> and <b>clone</b>?</li>\n  <li>When you forked the repo, where did the new copy go?</li>\n  <li>When you cloned it, where did the work move from and to?</li>\n  <li>Why didn't you need to run <b>git init</b> in the cloned folder?</li>\n  <li>How many copies of this project exist right now, and where are they?</li>\n</ul>","If any of those felt shaky, jump back up to the diagram before moving on. If they felt solid, you're in great shape. In the next subunit, you're going to make a change to the local copy, snapshot it with a commit (just like you did in 12a!), and then finally <b>push</b> that commit up to your fork on GitHub, closing the loop between your two copies for the first time."]},"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>"]}}}