diff --git a/client/i18n/locales/english/intro.json b/client/i18n/locales/english/intro.json
index 3beb0672b3d..2362b777d06 100644
--- a/client/i18n/locales/english/intro.json
+++ b/client/i18n/locales/english/intro.json
@@ -429,6 +429,13 @@
"Working with asynchronous programming is a core fundamental of JavaScript. In this project, you will gain proficiency in asynchronous concepts by building a freeCodeCamp forum leaderboard.",
"This project will cover the Fetch API, promises, Async/Await, and the try...catch statement."
]
+ },
+ "learn-basic-string-and-array-methods-by-building-a-music-player": {
+ "title": "Learn Basic String and Array Methods by Building a Music Player",
+ "intro": [
+ "Mastering essential string and array methods like the find(), forEach(), map(), and join() methods is crucial for developing dynamic web applications.",
+ "In this project you will build out a basic MP3 player using HTML, CSS, and JavaScript. The project covers fundamental concepts such as handling audio playback, managing a playlist, implementing play, pause, next, previous, and shuffle functionalities, as well as dynamically updating the user interface based on the current song."
+ ]
}
}
},
@@ -528,7 +535,10 @@
"In these projects, you'll need to fetch data and parse a dataset, then use D3 to create different data visualizations. Finish them all to earn your Data Visualization certification."
]
},
- "d3-dashboard": { "title": "D3 Dashboard", "intro": ["", ""] }
+ "d3-dashboard": {
+ "title": "D3 Dashboard",
+ "intro": ["", ""]
+ }
}
},
"relational-database": {
diff --git a/client/src/pages/learn/2022/javascript-algorithms-and-data-structures/learn-basic-string-and-array-methods-by-building-a-music-player/index.md b/client/src/pages/learn/2022/javascript-algorithms-and-data-structures/learn-basic-string-and-array-methods-by-building-a-music-player/index.md
new file mode 100644
index 00000000000..011e8042ffd
--- /dev/null
+++ b/client/src/pages/learn/2022/javascript-algorithms-and-data-structures/learn-basic-string-and-array-methods-by-building-a-music-player/index.md
@@ -0,0 +1,10 @@
+---
+title: Introduction to the Learn Basic String and Array Methods by Building a Music Player
+block: learn-basic-string-and-array-methods-by-building-a-music-player
+superBlock: 2022/javascript-algorithms-and-data-structures
+isBeta: true
+---
+
+## Introduction to the Learn Basic String and Array Methods by Building a Music Player
+
+This is a test for the new project-based curriculum.
diff --git a/curriculum/challenges/_meta/learn-basic-string-and-array-methods-by-building-a-music-player/meta.json b/curriculum/challenges/_meta/learn-basic-string-and-array-methods-by-building-a-music-player/meta.json
new file mode 100644
index 00000000000..924f50874e7
--- /dev/null
+++ b/curriculum/challenges/_meta/learn-basic-string-and-array-methods-by-building-a-music-player/meta.json
@@ -0,0 +1,349 @@
+{
+ "name": "Learn Basic String and Array Methods by Building a Music Player",
+ "isUpcomingChange": true,
+ "usesMultifileEditor": true,
+ "hasEditableBoundaries": true,
+ "dashedName": "learn-basic-string-and-array-methods-by-building-a-music-player",
+ "order": 70,
+ "time": "5 hours",
+ "template": "",
+ "required": [],
+ "superBlock": "2022/javascript-algorithms-and-data-structures",
+ "superOrder": 4,
+ "isBeta": true,
+ "challengeOrder": [
+ {
+ "id": "652f948489abbb81e6bf5a01",
+ "title": "Step 1"
+ },
+ {
+ "id": "652fa2aee6374ad29b5d49b4",
+ "title": "Step 2"
+ },
+ {
+ "id": "652fa3c4968fa9d6f8f6d873",
+ "title": "Step 3"
+ },
+ {
+ "id": "655dc43318591b975cdfe2d8",
+ "title": "Step 4"
+ },
+ {
+ "id": "65606d06666e118ba86162be",
+ "title": "Step 5"
+ },
+ {
+ "id": "65606ed6ea2baca053327e9b",
+ "title": "Step 6"
+ },
+ {
+ "id": "65327e9c7ea42e125256b29a",
+ "title": "Step 7"
+ },
+ {
+ "id": "653281af14be5f2055310f8e",
+ "title": "Step 8"
+ },
+ {
+ "id": "656071d679089ebd9d5035a0",
+ "title": "Step 9"
+ },
+ {
+ "id": "656073a2b98232c8aca72267",
+ "title": "Step 10"
+ },
+ {
+ "id": "653fb19b515fde28243f727a",
+ "title": "Step 11"
+ },
+ {
+ "id": "65420b821b14f25a6b35c3b3",
+ "title": "Step 12"
+ },
+ {
+ "id": "65420dcfc60580678dad7a92",
+ "title": "Step 13"
+ },
+ {
+ "id": "654210a9eda99477f5697a94",
+ "title": "Step 14"
+ },
+ {
+ "id": "654212b82fb5cf872f77148f",
+ "title": "Step 15"
+ },
+ {
+ "id": "654213f2fad2d48f74d6c239",
+ "title": "Step 16"
+ },
+ {
+ "id": "654215fe7b4a899ddceb3b60",
+ "title": "Step 17"
+ },
+ {
+ "id": "6567055f59d39f07d1c542dc",
+ "title": "Step 18"
+ },
+ {
+ "id": "654218753c255fabb81f57ca",
+ "title": "Step 19"
+ },
+ {
+ "id": "653283d07b8f9d294aafa83b",
+ "title": "Step 20"
+ },
+ {
+ "id": "65362bfd67d61d517deef191",
+ "title": "Step 21"
+ },
+ {
+ "id": "653635c731206b718659d3d5",
+ "title": "Step 22"
+ },
+ {
+ "id": "653639d63a45a077333312c8",
+ "title": "Step 23"
+ },
+ {
+ "id": "656472ed8f552d2f2b3f7883",
+ "title": "Step 24"
+ },
+ {
+ "id": "653641509b6e7681a9333245",
+ "title": "Step 25"
+ },
+ {
+ "id": "655235c2e607297f00316650",
+ "title": "Step 26"
+ },
+ {
+ "id": "65364566e84e378837fbaf2a",
+ "title": "Step 27"
+ },
+ {
+ "id": "65422ba173a18b1bedef1bb6",
+ "title": "Step 28"
+ },
+ {
+ "id": "6552127b2576c2fbc5ecc2ea",
+ "title": "Step 29"
+ },
+ {
+ "id": "65672136535209761a5cf02b",
+ "title": "Step 30"
+ },
+ {
+ "id": "65521badc7b7470edf952372",
+ "title": "Step 31"
+ },
+ {
+ "id": "65521ec3bb117c195c4f6cb5",
+ "title": "Step 32"
+ },
+ {
+ "id": "655220a3fa5c3c200bc8e938",
+ "title": "Step 33"
+ },
+ {
+ "id": "6552303a9a78704f8ff072e9",
+ "title": "Step 34"
+ },
+ {
+ "id": "655487f686aabfc2a10ba887",
+ "title": "Step 35"
+ },
+ {
+ "id": "6552385244ccf89b77d6b332",
+ "title": "Step 36"
+ },
+ {
+ "id": "655243068222c2c1166b90b0",
+ "title": "Step 37"
+ },
+ {
+ "id": "655476e1ff522252fdcce5e4",
+ "title": "Step 38"
+ },
+ {
+ "id": "655479aa3e1e0360ae38b7a6",
+ "title": "Step 39"
+ },
+ {
+ "id": "65547ee197840478a1b95f4b",
+ "title": "Step 40"
+ },
+ {
+ "id": "6554815fe2472f8bfdab7642",
+ "title": "Step 41"
+ },
+ {
+ "id": "655482742cc5499726e3f347",
+ "title": "Step 42"
+ },
+ {
+ "id": "655483ebf0096ba02b2c3d4c",
+ "title": "Step 43"
+ },
+ {
+ "id": "655485321913feabbc5f00f8",
+ "title": "Step 44"
+ },
+ {
+ "id": "6554860ea4dfbab2f4786fc8",
+ "title": "Step 45"
+ },
+ {
+ "id": "65548f747a4cdafd186948d1",
+ "title": "Step 46"
+ },
+ {
+ "id": "655490f55c36900779336988",
+ "title": "Step 47"
+ },
+ {
+ "id": "65671421254eeb489875cdd8",
+ "title": "Step 48"
+ },
+ {
+ "id": "655492e6b90c7a198c587943",
+ "title": "Step 49"
+ },
+ {
+ "id": "655494d5a15d6a2567e1ea60",
+ "title": "Step 50"
+ },
+ {
+ "id": "655495a6bd96e42bc3baa795",
+ "title": "Step 51"
+ },
+ {
+ "id": "6555d17af9ff06a14d399f6d",
+ "title": "Step 52"
+ },
+ {
+ "id": "6555d458687cb3b357834df9",
+ "title": "Step 53"
+ },
+ {
+ "id": "6555d729c9bfd7c3195f1948",
+ "title": "Step 54"
+ },
+ {
+ "id": "6555d7e384056dc9c581fadf",
+ "title": "Step 55"
+ },
+ {
+ "id": "6555d8faed60b9d3e4a6cefb",
+ "title": "Step 56"
+ },
+ {
+ "id": "6555dd138e70cae6b546966d",
+ "title": "Step 57"
+ },
+ {
+ "id": "6555de565387a2efe90a6ccc",
+ "title": "Step 58"
+ },
+ {
+ "id": "6555e04aeb225bfbae237344",
+ "title": "Step 59"
+ },
+ {
+ "id": "6555e0bfe4d69904410f7cd3",
+ "title": "Step 60"
+ },
+ {
+ "id": "6555e39a5f4c6f138c7d9405",
+ "title": "Step 61"
+ },
+ {
+ "id": "6555e57d3e6d9d221c4735be",
+ "title": "Step 62"
+ },
+ {
+ "id": "6555e6cec786da2aadc11ea0",
+ "title": "Step 63"
+ },
+ {
+ "id": "6555e7acdbae972d3e8e0f5b",
+ "title": "Step 64"
+ },
+ {
+ "id": "6555e9197bf1d7416bdd76e0",
+ "title": "Step 65"
+ },
+ {
+ "id": "6555ebf07ec610585a626f72",
+ "title": "Step 66"
+ },
+ {
+ "id": "65571e742fbf4532d8f98e90",
+ "title": "Step 67"
+ },
+ {
+ "id": "655720534347cb3f31cdfb3d",
+ "title": "Step 68"
+ },
+ {
+ "id": "65572399a8e16d50bc2c1ff3",
+ "title": "Step 69"
+ },
+ {
+ "id": "6557421eb6a7a0f0500e3106",
+ "title": "Step 70"
+ },
+ {
+ "id": "655724bac464795a0ad91082",
+ "title": "Step 71"
+ },
+ {
+ "id": "655727b2e1e49d6adf584442",
+ "title": "Step 72"
+ },
+ {
+ "id": "65672adafbaa37a6cef886f7",
+ "title": "Step 73"
+ },
+ {
+ "id": "655729e68e49b277a6b448bd",
+ "title": "Step 74"
+ },
+ {
+ "id": "65572bb34a7e488224b937fc",
+ "title": "Step 75"
+ },
+ {
+ "id": "65572e5aaf022790fb4a81b1",
+ "title": "Step 76"
+ },
+ {
+ "id": "655737cd004591b0271d6826",
+ "title": "Step 77"
+ },
+ {
+ "id": "65573a97c59ddbbf028ca95e",
+ "title": "Step 78"
+ },
+ {
+ "id": "65573d0abe4d38cd6fa13f44",
+ "title": "Step 79"
+ },
+ {
+ "id": "655b49333d9f265bc1512152",
+ "title": "Step 80"
+ },
+ {
+ "id": "655b4bbff1dbf66cb2ed4dac",
+ "title": "Step 81"
+ },
+ {
+ "id": "655b4c8f636d9675953a0388",
+ "title": "Step 82"
+ },
+ {
+ "id": "655b4dad1d38ff7cdd65cbfe",
+ "title": "Step 83"
+ }
+ ],
+ "helpCategory": "JavaScript"
+}
\ No newline at end of file
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/652f948489abbb81e6bf5a01.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/652f948489abbb81e6bf5a01.md
new file mode 100644
index 00000000000..a2bbdcc90fd
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/652f948489abbb81e6bf5a01.md
@@ -0,0 +1,558 @@
+---
+id: 652f948489abbb81e6bf5a01
+title: Step 1
+challengeType: 0
+dashedName: step-1
+---
+
+# --description--
+
+In this project you will learn basic string and array methods by building a music player app. You will be able to play, pause, skip, and shuffle songs.
+
+The HTML and CSS of this project have been provided for you, so you can focus on the JavaScript.
+
+Start by accessing the `#playlist-songs`, `#play`, and `#pause` elements with the `getElementById()` method. Assign them to variables `playlistSongs`, `playButton` and `pauseButton` respectively.
+
+
+# --hints--
+
+You should use `document.getElementById()` to get the `#playlist-songs` element.
+
+```js
+assert.match(code, /document\.getElementById\(\s*('|"|`)playlist\-songs\1\)/);
+```
+
+You should assign the `#playlist-songs` element to the variable `playlistSongs`. Don't forget to use `const` to declare the variable.
+
+```js
+assert.match(code, /const\s+playlistSongs\s*\=\s*document\.getElementById\(\s*('|"|`)playlist\-songs\1\)/);
+```
+
+You should use `document.getElementById()` to get the `#play` element.
+
+```js
+assert.match(code, /document\.getElementById\(\s*('|"|`)play\1\)/);
+```
+
+You should assign the `#play` element to the variable `playButton`. Don't forget to use `const` to declare the variable.
+
+```js
+assert.match(code, /const\s+playButton\s*\=\s*document\.getElementById\(\s*('|"|`)play\1\)/);
+```
+
+You should use `document.getElementById()` to get the `#pause` element.
+
+```js
+assert.match(code, /document\.getElementById\(\s*('|"|`)pause\1\)/);
+```
+
+You should assign the `#pause` element to the variable `pauseButton`. Don't forget to use `const` to declare the variable.
+
+```js
+assert.match(code, /const\s+pauseButton\s*\=\s*document\.getElementById\(\s*('|"|`)pause\1\)/);
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+--fcc-editable-region--
+
+--fcc-editable-region--
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/652fa2aee6374ad29b5d49b4.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/652fa2aee6374ad29b5d49b4.md
new file mode 100644
index 00000000000..ce95018b8fd
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/652fa2aee6374ad29b5d49b4.md
@@ -0,0 +1,559 @@
+---
+id: 652fa2aee6374ad29b5d49b4
+title: Step 2
+challengeType: 0
+dashedName: step-2
+---
+
+# --description--
+
+Continuing with the pattern, access the `#next`, `#previous` and `#shuffle` elements from the HTML file.
+
+Assign them to the `nextButton`, `previousButton`, and `shuffleButton` variables respectively.
+
+# --hints--
+
+You should use `document.getElementById()` to get the `#next` element.
+
+```js
+assert.match(code, /document\.getElementById\(\s*('|"|`)next\1\)/);
+```
+
+You should assign the `#next` element to the variable `nextButton`. Don't forget to use `const` to declare the variable.
+
+```js
+assert.match(code, /const\s+nextButton\s*\=\s*document\.getElementById\(\s*('|"|`)next\1\)/);
+```
+
+You should use `document.getElementById()` to get the `#previous` element.
+
+```js
+assert.match(code, /document\.getElementById\(\s*('|"|`)previous\1\)/);
+```
+
+You should assign the `#previous` element to the variable `previousButton`. Don't forget to use `const` to declare the variable.
+
+```js
+assert.match(code, /const\s+previousButton\s*\=\s*document\.getElementById\(\s*('|"|`)previous\1\)/);
+```
+
+You should use `document.getElementById()` to get the `#shuffle` element.
+
+```js
+assert.match(code, /document\.getElementById\(\s*('|"|`)shuffle\1\)/);
+```
+
+You should assign the `#shuffle` element to the variable `shuffleButton`. Don't forget to use `const` to declare the variable.
+
+```js
+assert.match(code, /const\s+shuffleButton\s*\=\s*document\.getElementById\(\s*('|"|`)shuffle\1\)/);
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+
+--fcc-editable-region--
+
+--fcc-editable-region--
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/652fa3c4968fa9d6f8f6d873.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/652fa3c4968fa9d6f8f6d873.md
new file mode 100644
index 00000000000..a16b4acf194
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/652fa3c4968fa9d6f8f6d873.md
@@ -0,0 +1,532 @@
+---
+id: 652fa3c4968fa9d6f8f6d873
+title: Step 3
+challengeType: 0
+dashedName: step-3
+---
+
+# --description--
+
+Next, create an array to store all the songs.
+
+Create an empty `allSongs` array.
+
+# --hints--
+
+You should use `const` to create an empty `allSongs` array.
+
+```js
+assert.match(code, /const\s+allSongs\s*=\s*\[\s*\]/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+--fcc-editable-region--
+
+--fcc-editable-region--
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65327e9c7ea42e125256b29a.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65327e9c7ea42e125256b29a.md
new file mode 100644
index 00000000000..ed737e6f83a
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65327e9c7ea42e125256b29a.md
@@ -0,0 +1,614 @@
+---
+id: 65327e9c7ea42e125256b29a
+title: Step 7
+challengeType: 0
+dashedName: step-7
+---
+
+# --description--
+
+All the songs are now in the `allSongs` array. The next step is to initialize the Web Audio API .
+
+The Audio API is a component of the Web Audio API specification, offering a high-level interface for processing and synthesizing audio within web applications.
+
+Use `const` to create a variable named `audio` and set it equal to `new Audio()`. This will create a new HTML5 audio element.
+
+# --hints--
+
+You should use the `new` keyword to intialize the web audio API
+
+```js
+assert.match(code, /new\s*Audio\(\);?/)
+```
+
+You should set the intialization to a constant named `audio`.
+
+```js
+assert.match(code, /const\s+audio\s*=\s*new\s*Audio\(\);?/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+
+--fcc-editable-region--
+
+--fcc-editable-region--
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/653281af14be5f2055310f8e.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/653281af14be5f2055310f8e.md
new file mode 100644
index 00000000000..72d4d0beec4
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/653281af14be5f2055310f8e.md
@@ -0,0 +1,607 @@
+---
+id: 653281af14be5f2055310f8e
+title: Step 8
+challengeType: 0
+dashedName: step-8
+---
+
+# --description--
+
+Create a `userData` object that will contain the songs, the current song playing, and the time of the current song.
+
+Declare an empty `userData` object using the `let` keyword.
+
+# --hints--
+
+You should use the `let` keyword to create an empty `userData` object.
+
+```js
+assert.match(code, /let\s*userData\s*=\s*\{\s*\};?/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+
+--fcc-editable-region--
+
+--fcc-editable-region--
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/653283d07b8f9d294aafa83b.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/653283d07b8f9d294aafa83b.md
new file mode 100644
index 00000000000..6478aa494bf
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/653283d07b8f9d294aafa83b.md
@@ -0,0 +1,661 @@
+---
+id: 653283d07b8f9d294aafa83b
+title: Step 20
+challengeType: 0
+dashedName: step-20
+---
+
+# --description--
+
+It's time to begin implementing the functionality for playing the displayed songs.
+
+Define a `playSong` function using `const`. The function should take an `id` parameter which will represent the unique identifier of the song you want to play.
+
+# --hints--
+
+You should use `const` to create an empty function named `playSong`.
+
+```js
+assert.match(code, /const\s+playSong\s*=\s*/)
+```
+
+`playSong` should be a function.
+
+```js
+assert.isFunction(playSong)
+```
+
+Your `playSong` function should use an arrow syntax.
+
+```js
+assert.match(code, /const\s+playSong\s*=\s*\(.*\)\s*=>\s*/)
+```
+
+Your `playSong` function should take an `id` parameter.
+
+```js
+assert.match(code, /const\s+playSong\s*=\s*\(id/)
+```
+
+Your `playSong` function should be empty.
+
+```js
+assert.match(code, /const\s+playSong\s*=\s*\(id\)\s*=>\s*\{\n?\s*?\};?/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+--fcc-editable-region--
+
+--fcc-editable-region--
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+renderSongs(userData?.songs);
+
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65362bfd67d61d517deef191.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65362bfd67d61d517deef191.md
new file mode 100644
index 00000000000..eee366340dd
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65362bfd67d61d517deef191.md
@@ -0,0 +1,669 @@
+---
+id: 65362bfd67d61d517deef191
+title: Step 21
+challengeType: 0
+dashedName: step-21
+---
+
+# --description--
+
+The find() method retrieves the first element within an array that fulfills the conditions specified in the provided callback function. If no element satisfies the condition, the method returns `undefined`.
+
+In the example below, the `find()` method is used to find the first number greater than 25:
+
+```js
+const numbers = [10, 20, 30, 40, 50];
+
+// Find the first number greater than 25
+const foundNumber = numbers.find((number) => number > 25);
+console.log(foundNumber); // Output: 30
+```
+
+Use `const` to create a variable named `song` and assign it result of the `find()` method call on the `userData?.songs` array. Use `song` as the parameter of the `find()` callback and check if `song.id` is strictly equal to `id`.
+
+This will iterate through the `userData?.songs` array, searching for a song that corresponds to the `id` passed into the `playSong` function.
+
+# --hints--
+
+You should use the `find` method on `userData?.songs`.
+
+```js
+assert.match(code, /userData\?\.songs\.find\(/)
+```
+
+Your `find` method should have `song` as the parameter of its arrow function callback.
+
+```js
+assert.match(code, /userData\?\.songs\.find\(\(?song\)?/)
+```
+
+Your `find` method should use strict equality to check if `song.id` is equal to `id`.
+
+```js
+assert.match(code, /userData\?\.songs\.find\(\(?song\)?\s*=>\s*song.id\s*===\s*id\);?|userData\?\.songs\.find\(\(?song\)?\s*=>\s*id\s*===\s*song\.id\);?/)
+```
+
+Your `find` method should be assigned to a `song` constant.
+
+```js
+assert.match(code, /const\s*song\s*=\s*userData\?\.songs\.find\(\(?song\)?\s*=>\s*song.id\s*===\s*id\);?|userData\?\.songs\.find\(\(?song\)?\s*=>\s*id\s*===\s*song\.id\);?/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+--fcc-editable-region--
+const playSong = (id) => {
+
+};
+--fcc-editable-region--
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+renderSongs(userData?.songs);
+
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/653635c731206b718659d3d5.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/653635c731206b718659d3d5.md
new file mode 100644
index 00000000000..166afe8a4eb
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/653635c731206b718659d3d5.md
@@ -0,0 +1,652 @@
+---
+id: 653635c731206b718659d3d5
+title: Step 22
+challengeType: 0
+dashedName: step-22
+---
+
+# --description--
+
+Inside the `playSong` function, set the `audio.src` property equal to `song.src`. This tells the audio element where to find the audio data for the selected song.
+
+Also, set the `audio.title` property equal to `song.title`. This tells the audio element what to display as the title of the song.
+
+# --hints--
+
+You should not modify the exist `playSong` function and its content.
+
+```js
+assert.match(code, /const\s*playSong\s*=\s*\(id\)\s*=>\s*\{\s*const\s*song\s*=\s*userData\?\.songs\.find\(\(song\)\s=>\s*song.id\s===\s*id\);?/)
+```
+
+You should set `audio.src` to `song.src`.
+
+```js
+assert.match(code, /const\s*playSong\s*=\s*\(id\)\s*=>\s*\{\s*const\s*song\s*=\s*userData\?\.songs\.find\(\(song\)\s=>\s*song.id\s===\s*id\);?\s*audio\.src\s*=\s*song\.src;?/)
+```
+
+You should set `audio.title` to `song.title`.
+
+```js
+assert.match(code, /const\s*playSong\s*=\s*\(id\)\s*=>\s*\{\s*const\s*song\s*=\s*userData\?\.songs\.find\(\(song\)\s=>\s*song.id\s===\s*id\);?\s*audio\.src\s*=\s*song\.src;?\s*audio\.title\s*=\s*song\.title;?\s*\};?/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+--fcc-editable-region--
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+
+};
+--fcc-editable-region--
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+renderSongs(userData?.songs);
+
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/653639d63a45a077333312c8.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/653639d63a45a077333312c8.md
new file mode 100644
index 00000000000..bd5796d816d
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/653639d63a45a077333312c8.md
@@ -0,0 +1,650 @@
+---
+id: 653639d63a45a077333312c8
+title: Step 23
+challengeType: 0
+dashedName: step-23
+---
+
+# --description--
+
+Before playing the song, you need to make sure it starts from the beginning. This can be achieved by the use of the `currentTime` property of the `audio` object.
+
+Add an `if` statement to check whether the `userData?.currentSong` is `null` or if `userData?.currentSong.id` is strictly not equal `song.id`. Inside `if` block, set the `currentTime` property of the `audio` object to `0`.
+
+
+# --hints--
+
+You should create an `if` statement with the condition `userData?.currentSong === null || userData?.currentSong.id !== song.id`.
+
+```js
+assert.match(code, /if\s*\(userData\?\.currentSong\s*===\s*null\s*\|\|\s*userData\?\.currentSong\.id\s*!==\s*song\.id\)\s*\{\s*/)
+```
+
+You should set `audio.currentTime` to `0` inside your `if` block.
+
+```js
+assert.match(code, /if\s*\(userData\?\.currentSong\s*===\s*null\s*\|\|\s*userData\?\.currentSong\.id\s*!==\s*song\.id\)\s*\{\s*audio\.currentTime\s*=\s*0;?\s*\}/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ --fcc-editable-region--
+
+ --fcc-editable-region--
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+renderSongs(userData?.songs);
+
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/653641509b6e7681a9333245.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/653641509b6e7681a9333245.md
new file mode 100644
index 00000000000..90ecb99e8d0
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/653641509b6e7681a9333245.md
@@ -0,0 +1,648 @@
+---
+id: 653641509b6e7681a9333245
+title: Step 25
+challengeType: 0
+dashedName: step-25
+---
+
+# --description--
+
+You need to update the current song being played as well as the appearance of the `playButton` element.
+
+Start by accessing the `userData` object and its `currentSong` property. Set its value equal to the `song` variable.
+
+# --hints--
+
+You should set `userData.currentSong` to `song`.
+
+```js
+assert.match(code, /userData\.currentSong\s*=\s*song;?/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ --fcc-editable-region--
+
+ --fcc-editable-region--
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+renderSongs(userData?.songs);
+
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65364566e84e378837fbaf2a.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65364566e84e378837fbaf2a.md
new file mode 100644
index 00000000000..bd8e3a93a28
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65364566e84e378837fbaf2a.md
@@ -0,0 +1,665 @@
+---
+id: 65364566e84e378837fbaf2a
+title: Step 27
+challengeType: 0
+dashedName: step-27
+---
+
+# --description--
+
+You need to hook up the `playSong` function to a `click` event listener so the songs will start playing when the play button is clicked.
+
+Add a click event listener to the `playButton` element, then use arrow syntax to pass in a callback with an empty pair of curly braces.
+
+# --hints--
+
+You should call the `addEventListener()` method on your `playButton` variable.
+
+```js
+assert.match(code, /playButton\.addEventListener\(/)
+```
+
+Your event listener should listen for a `click` event.
+
+```js
+assert.match(code, /playButton\.addEventListener\(('|"|`)click\1/)
+```
+
+You should use arrow syntax to pass in an empty callback into your event listener. Don't forget you also need an empty pair of curly braces.
+
+```js
+assert.match(code, /playButton\.addEventListener\(('|"|`)click\1,\s*\(\)\s*=>\s*\{\s*\}\);?/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ audio.play();
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+ --fcc-editable-region--
+
+ --fcc-editable-region--
+
+renderSongs(userData?.songs);
+
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/653fb19b515fde28243f727a.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/653fb19b515fde28243f727a.md
new file mode 100644
index 00000000000..7017506b68e
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/653fb19b515fde28243f727a.md
@@ -0,0 +1,660 @@
+---
+id: 653fb19b515fde28243f727a
+title: Step 11
+challengeType: 0
+dashedName: step-11
+---
+
+# --description--
+
+Now you need to show songs to be played in the UI. For this, you'll need to create a `renderSongs` function with an arrow function syntax.
+
+An arrow function is a shorter and more concise way to write functions in JavaScript. It uses the variable keywords (`var`, `let`, and `const`) and fat arrow syntax (`=>`):
+
+```js
+// Traditional function
+function add(a, b) {
+ return a + b;
+}
+console.log(add(3, 5)); // Output: 8
+
+// Arrow function
+const addArrow = (a, b) => {
+ return a + b
+};
+console.log(addArrow(3, 5)); // Output: 8
+```
+
+If the function body consists of a single expression, you don't need the curly braces and the `return` keyword. This is called an `implicit return`.
+
+```js
+const addArrow = (a, b) => a + b;
+console.log(addArrow(3, 5)); // Output: 8
+```
+
+Use the arrow function syntax to create a `renderSongs` function that takes in `array` as its parameter.
+
+# --hints--
+
+You should use `const` to create an empty function named `renderSongs`.
+
+```js
+assert.match(code, /const\s+renderSongs\s*=\s*/)
+```
+
+`renderSongs` should be a function.
+
+```js
+assert.isFunction(renderSongs)
+```
+
+Your `renderSongs` function should use an arrow syntax.
+
+```js
+assert.match(code, /const\s+renderSongs\s*=\s*\(.*\)\s*=>\s*/)
+```
+
+Your `renderSongs` function should take an `array` parameter.
+
+```js
+assert.match(code, /const\s+renderSongs\s*=\s*\(array/)
+```
+
+Your `renderSongs` function should be empty.
+
+```js
+assert.match(code, /const\s+renderSongs\s*=\s*\(array\)\s*=>\s*\{\n?\s*?\};?/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+--fcc-editable-region--
+
+--fcc-editable-region--
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65420b821b14f25a6b35c3b3.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65420b821b14f25a6b35c3b3.md
new file mode 100644
index 00000000000..162d0dec075
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65420b821b14f25a6b35c3b3.md
@@ -0,0 +1,641 @@
+---
+id: 65420b821b14f25a6b35c3b3
+title: Step 12
+challengeType: 0
+dashedName: step-12
+---
+
+# --description--
+
+Now you should loop through the array. You will call the `renderSongs` function with the songs array inside the `userData` object. For this we will use the `map()` method.
+
+The `map()` method is used to iterate through an array and return a new array. It's helpful when you want to create a new array based on the values of an existing array. For example:
+
+```js
+const numbers = [1, 2, 3];
+const doubledNumbers = numbers.map((number) => number * 2); // doubledNumbers will be [2, 4, 6]
+```
+
+Inside the `renderSongs` function, use `const` to create another `songsHTML` function and assign it to `array.map()`. Pass in `song` as the parameter of the `map()` method, a fat arrow, and an empty curly braces.
+
+# --hints--
+
+You should use the `map()` method on `array`.
+
+```js
+assert.match(code, /array.map\(/)
+```
+
+Your `map()` method should have a `song` parameter in it's callback function.
+
+```js
+assert.match(code, /array.map\(\(?song\)?/)
+```
+
+The callback function of your `map()` method should use arrow function syntax.
+
+```js
+assert.match(code, /array.map\(\(?song\)?\s*=>\s*\{\s*\}\)/)
+```
+
+You should assign your `array.map` to a `songsHTML` constant.
+
+```js
+assert.match(code, /const\s+songsHTML\s*=\s*array.map\(\(?song\)?\s*=>\s*\{\s*\}\)/);
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const renderSongs = (array) => {
+ --fcc-editable-region--
+
+ --fcc-editable-region--
+};
+
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65420dcfc60580678dad7a92.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65420dcfc60580678dad7a92.md
new file mode 100644
index 00000000000..40cd2b57633
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65420dcfc60580678dad7a92.md
@@ -0,0 +1,636 @@
+---
+id: 65420dcfc60580678dad7a92
+title: Step 13
+challengeType: 0
+dashedName: step-13
+---
+
+# --description--
+
+Inside the `map()`, add a `return` statement with backticks where you will interpolate all the elements responsible to displaying the song details.
+
+Inside the backticks, create an `li` tag with the id `song-${song.id}` as the first attribute. Also, add the class `playlist-song` as the second attribute.
+
+# --hints--
+
+You should add a `return` statement with an empty pair of backticks.
+
+```js
+assert.match(code, /return\s*`/)
+```
+
+You should create an `li` tag inside the backticks.
+
+```js
+assert.match(code, /return\s*`\s*\s*<\/li>\s*`;?/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array.map((song)=> {
+--fcc-editable-region--
+
+--fcc-editable-region--
+ })
+};
+
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/654210a9eda99477f5697a94.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/654210a9eda99477f5697a94.md
new file mode 100644
index 00000000000..73f2de0fb03
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/654210a9eda99477f5697a94.md
@@ -0,0 +1,640 @@
+---
+id: 654210a9eda99477f5697a94
+title: Step 14
+challengeType: 0
+dashedName: step-14
+---
+
+# --description--
+
+Create a `button` element with class `playlist-song-info`. Inside the `button`, add a `span` element with the class `playlist-song-title`, then interpolate `song.title` as the text.
+
+# --hints--
+
+You should create a `button` with the class `playlist-song-info`.
+
+```js
+assert.match(code, /\s*/)
+```
+
+You should create a `span` element inside your `button` element.
+
+```js
+assert.match(code, /\s*\s*/)
+```
+
+You should interpolate `song.title` as the content of your `span` element.
+
+```js
+assert.match(code, /\s*\$\{song\.title\}\s*<\/span>\s*<\/button>/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+ --fcc-editable-region--
+
+ --fcc-editable-region--
+
+
+ `;
+ })
+};
+
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/654212b82fb5cf872f77148f.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/654212b82fb5cf872f77148f.md
new file mode 100644
index 00000000000..6bc262972bf
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/654212b82fb5cf872f77148f.md
@@ -0,0 +1,648 @@
+---
+id: 654212b82fb5cf872f77148f
+title: Step 15
+challengeType: 0
+dashedName: step-15
+---
+
+# --description--
+
+Inside the `button`, create two more `span` elements. The first span element should have class `playlist-song-artist` and interpolate `song.artist`. The second span element should have class `playlist-song-duration` and interpolate `song.duration`.
+
+# --hints--
+
+You should not modify the existing `button` element and its content.
+
+```js
+assert.match(code, /\s*\$\{song\.title\}\s*<\/span>\s*.*\s*.*\s*<\/button>/)
+```
+
+You should create a `span` element with the class `playlist-song-artist`.
+
+```js
+assert.match(code, //)
+```
+
+Your `span` element with the class `playlist-song-artist` should interpolate `song.artist` as its content.
+
+```js
+assert.match(code, /\s*\$\{song\.artist\}\s*<\/span>/)
+```
+
+You should create a `span` element with the class `playlist-song-duration`.
+
+```js
+assert.match(code, /\s*/)
+```
+
+Your `span` element with the class `playlist-song-duration` should interpolate `song.duration` as its content.
+
+```js
+assert.match(code, /\s*\$\{song\.duration\}<\/span>/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+ --fcc-editable-region--
+
+ ${song.title}
+
+
+ --fcc-editable-region--
+
+ `;
+ })
+};
+
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/654213f2fad2d48f74d6c239.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/654213f2fad2d48f74d6c239.md
new file mode 100644
index 00000000000..a23c321eacb
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/654213f2fad2d48f74d6c239.md
@@ -0,0 +1,642 @@
+---
+id: 654213f2fad2d48f74d6c239
+title: Step 16
+challengeType: 0
+dashedName: step-16
+---
+
+# --description--
+
+Create another `button` element with the class `playlist-song-delete` and the `aria-label` attribute set to `Delete` interpolated with `song.title`. For the content of the delete icon, paste in the following SVG:
+
+```html
+
+```
+
+# --hints--
+
+You should create a `button` element with the class `playlist-song-delete` as its first attribute and value.
+
+```js
+assert.match(code, //)
+```
+
+You should paste in the provided `svg` as the content of your `button` element.
+
+```js
+assert.match(code, /\s*\s* \s* \s*<\/svg>\s*<\/button>\s*/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+ --fcc-editable-region--
+
+ --fcc-editable-region--
+
+ `;
+ })
+};
+
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/654215fe7b4a899ddceb3b60.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/654215fe7b4a899ddceb3b60.md
new file mode 100644
index 00000000000..1f6f2231387
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/654215fe7b4a899ddceb3b60.md
@@ -0,0 +1,639 @@
+---
+id: 654215fe7b4a899ddceb3b60
+title: Step 17
+challengeType: 0
+dashedName: step-17
+---
+
+# --description--
+
+Use the `join()` method to combine the `songsHTML` markup into a single string.
+
+The `join()` method is used to concatenate all the elements of an array into a single string. It takes an optional parameter called `separator` which is used to separate each element of the array. For example:
+
+```js
+const exampleArr = ["This", "is", "a", "sentence"];
+const sentence = exampleArray.join(" "); // Separator takes a space character
+console.log(sentence); // Output: "This is a sentence"
+```
+
+Chain the `join()` method to your `map()` method and pass in an empty string for the separator.
+
+# --hints--
+
+You should add `join("")` to the existing code.
+
+```js
+assert.match(code, /\s*\s* \s* \s*<\/svg>\s*<\/button>\s*<\/li>\s*`;?\s*\}\)\s*.join\(('|")\2\);?/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ --fcc-editable-region--
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ --fcc-editable-region--
+};
+
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/654218753c255fabb81f57ca.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/654218753c255fabb81f57ca.md
new file mode 100644
index 00000000000..364dabdd346
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/654218753c255fabb81f57ca.md
@@ -0,0 +1,653 @@
+---
+id: 654218753c255fabb81f57ca
+title: Step 19
+challengeType: 0
+dashedName: step-19
+---
+
+# --description--
+
+Now you need to call the `renderSongs` function and pass in `userData?.songs` in order to finally display the songs in the UI.
+
+Optional chaining (`?.`) helps prevent errors when accessing nested properties that might be null or undefined. For example:
+
+```js
+const user = {
+ name: "Quincy",
+ address: {
+ city: "San Francisco",
+ state: "CA",
+ country: "USA",
+ },
+};
+
+// Accessing nested properties without optional chaining
+const state = user.address.state; // CA
+
+// Accessing a non-existent nested property with optional chaining
+const zipCode = user.address?.zipCode; // Returns undefined instead of throwing an error
+```
+
+Call the `renderSongs` function with the `songs` property of `userData`. This will render the songs in the playlist.
+
+# --hints--
+
+You should call your `renderSongs` function with `userData?.songs`.
+
+```js
+assert.match(code, /renderSongs\(userData\?\.songs\)/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+--fcc-editable-region--
+
+--fcc-editable-region--
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65422ba173a18b1bedef1bb6.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65422ba173a18b1bedef1bb6.md
new file mode 100644
index 00000000000..eaece9b6efa
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65422ba173a18b1bedef1bb6.md
@@ -0,0 +1,662 @@
+---
+id: 65422ba173a18b1bedef1bb6
+title: Step 28
+challengeType: 0
+dashedName: step-28
+---
+
+# --description--
+
+Within the arrow function of the event listener, add an `if` to check if `userData?.currentSong` is `null`.
+
+Inside the `if` block, call the `playSong()` function with the `id` of the first song in the `userData.songs` array. This will ensure the first song in the playlist is played first.
+
+# --hints--
+
+You should create an `if` statement with the condition `userData?.currentSong === null`.
+
+```js
+assert.match(code, /if\s*\(userData\?\.currentSong\s*===\s*null\)\s*\{/)
+```
+
+You should call the `playSong` function with `userData?.songs[0].id` inside your `if` block.
+
+```js
+assert.match(code, /if\s*\(userData\?\.currentSong\s*===\s*null\)\s*\{\s*playSong\(userData\?.songs\[0\]\.id\);?\s*\}/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ audio.play();
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+playButton.addEventListener("click", () => {
+ --fcc-editable-region--
+
+ --fcc-editable-region--
+});
+
+
+renderSongs(userData?.songs);
+
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6552127b2576c2fbc5ecc2ea.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6552127b2576c2fbc5ecc2ea.md
new file mode 100644
index 00000000000..5d81a703ccf
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6552127b2576c2fbc5ecc2ea.md
@@ -0,0 +1,672 @@
+---
+id: 6552127b2576c2fbc5ecc2ea
+title: Step 29
+challengeType: 0
+dashedName: step-29
+---
+
+# --description--
+
+Add an `else` block. Inside the `else` block, call the `playSong` function with the `id` of the currently playing song as an argument.
+
+This ensures that the currently playing song will continue to play when the play button is clicked.
+
+# --hints--
+
+You should not modify the existing `if` statement and its content.
+
+```js
+assert.match(code, /if\s*\(userData\?\.currentSong\s*===\s*null\)\s*\{\s*playSong\(userData\?.songs\[0\]\.id\);?\s*\}/)
+```
+
+You should add an `else` block to your `if` statement.
+
+```js
+assert.match(code, /if\s*\(userData\?\.currentSong\s*===\s*null\)\s*\{\s*playSong\(userData\?.songs\[0\]\.id\);?\s*\}\s*else\s*\{/)
+```
+
+You should call the `playSong` function with `userData?.currentSong.id` in the `else` block of your `if` statement.
+
+
+```js
+assert.match(code, /if\s*\(userData\?\.currentSong\s*===\s*null\)\s*\{\s*playSong\(userData\?.songs\[0\]\.id\);?\s*\}\s*else\s*\{\s*playSong\(userData\?\.currentSong\.id\);?\s*\}/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ audio.play();
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+playButton.addEventListener("click", () => {
+--fcc-editable-region--
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ }
+
+--fcc-editable-region--
+});
+
+
+renderSongs(userData?.songs);
+
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65521badc7b7470edf952372.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65521badc7b7470edf952372.md
new file mode 100644
index 00000000000..d213f6a0b3f
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65521badc7b7470edf952372.md
@@ -0,0 +1,680 @@
+---
+id: 65521badc7b7470edf952372
+title: Step 31
+challengeType: 0
+dashedName: step-31
+---
+
+# --description--
+
+Now you need to work on pausing the currently playing song.
+
+Define a `pauseSong` function using the `const` keyword and arrow function sysntax. The function should take no parameters.
+
+# --hints--
+
+You should use `const` to create an empty function named `pauseSong`.
+
+```js
+assert.match(code, /const\s+pauseSong\s*=\s*/)
+```
+
+`pauseSong` should be a function.
+
+```js
+assert.isFunction(pauseSong)
+```
+
+Your `pauseSong` function should use an arrow syntax.
+
+```js
+assert.match(code, /const\s+pauseSong\s*=\s*\(\)\s*=>\s*/)
+```
+
+Your `pauseSong` function should be empty.
+
+```js
+assert.match(code, /const\s+pauseSong\s*=\s*\(\)\s*=>\s*\{\n?\s*?\};?/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ audio.play();
+};
+
+--fcc-editable-region--
+
+--fcc-editable-region--
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+
+renderSongs(userData?.songs);
+
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65521ec3bb117c195c4f6cb5.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65521ec3bb117c195c4f6cb5.md
new file mode 100644
index 00000000000..833085c6231
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65521ec3bb117c195c4f6cb5.md
@@ -0,0 +1,668 @@
+---
+id: 65521ec3bb117c195c4f6cb5
+title: Step 32
+challengeType: 0
+dashedName: step-32
+---
+
+# --description--
+
+To store the current time of the song when it is paused paused, set the `songCurrentTime` of the `userData` object to the `currentTime` of the `audio` variable.
+
+# --hints--
+
+You should not modify the existing `pauseSong` function and its content.
+
+```js
+assert.match(code, /const\s+pauseSong\s*=\s*\(\)\s*=>\s*\{\s*.*\s*\};?/)
+```
+
+You should set `userData.songCurrentTime` to `audio.currentTime`.
+
+```js
+assert.match(code, /userData\.songCurrentTime\s*=\s*audio\.currentTime;?/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ audio.play();
+};
+
+--fcc-editable-region--
+const pauseSong = () => {
+
+};
+--fcc-editable-region--
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+
+renderSongs(userData?.songs);
+
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655220a3fa5c3c200bc8e938.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655220a3fa5c3c200bc8e938.md
new file mode 100644
index 00000000000..dcdbe345dfe
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655220a3fa5c3c200bc8e938.md
@@ -0,0 +1,677 @@
+---
+id: 655220a3fa5c3c200bc8e938
+title: Step 33
+challengeType: 0
+dashedName: step-33
+---
+
+# --description--
+
+Use `classList` and `remove()` method to remove the `.playing` class from the `playButton`, since the song will be paused at this point.
+
+To finally pause the song, use the `pause()` method on the `audio` variable. `pause()` is a method of the Web Audio API for pausing music files.
+
+# --hints--
+
+You should not modify the existing `pauseSong` function and its content.
+
+```js
+assert.match(code, /const\s+pauseSong\s*=\s*\(\)\s*=>\s*\{\s*userData\.songCurrentTime\s*=\s*audio\.currentTime;?\s*.*\s*.*\s*\};?/)
+```
+
+You should use the `classList` property and the `remove()` method to remove the class `playing` from the `playButton`.
+
+```js
+assert.match(code, /playButton\.classList\.remove\(('|")playing\1\);?/)
+```
+
+You should use the `pause()` method on your `audio` variable.
+
+```js
+assert.match(code, /audio\.pause\(\)/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ audio.play();
+};
+
+--fcc-editable-region--
+const pauseSong = () => {
+ userData.songCurrentTime = audio.currentTime;
+
+};
+--fcc-editable-region--
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+
+renderSongs(userData?.songs);
+
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6552303a9a78704f8ff072e9.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6552303a9a78704f8ff072e9.md
new file mode 100644
index 00000000000..d708289b5f1
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6552303a9a78704f8ff072e9.md
@@ -0,0 +1,679 @@
+---
+id: 6552303a9a78704f8ff072e9
+title: Step 34
+challengeType: 0
+dashedName: step-34
+---
+
+# --description--
+
+You need to hook up the `pauseSong` function to an event listener to make it work.
+
+Add a `click` event listener to the `pauseButton` element, then pass in `pauseSong` as the second parameter of the event listener. This is the function the event listener will run.
+
+# --hints--
+
+You should call the `addEventListener()` method on your `pauseButton` variable.
+
+```js
+assert.match(code, /pauseButton\.addEventListener\(/)
+```
+
+Your event listener should listen for a `click` event.
+
+```js
+assert.match(code, /pauseButton\.addEventListener\(('|"|`)click\1/)
+```
+
+You should pass in `pauseSong` as the second parameter of your `addEventListener` method.
+
+```js
+assert.match(code, /pauseButton\.addEventListener\(('|"|`)click\1,\s*pauseSong\)/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ audio.play();
+};
+
+const pauseSong = () => {
+ userData.songCurrentTime = audio.currentTime;
+
+ playButton.classList.remove("playing");
+ audio.pause();
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+--fcc-editable-region--
+
+--fcc-editable-region--
+
+renderSongs(userData?.songs);
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655235c2e607297f00316650.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655235c2e607297f00316650.md
new file mode 100644
index 00000000000..7dddd761fda
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655235c2e607297f00316650.md
@@ -0,0 +1,656 @@
+---
+id: 655235c2e607297f00316650
+title: Step 26
+challengeType: 0
+dashedName: step-26
+---
+
+# --description--
+
+Next, use the `classList` property and the `add()` method to add the `playing` class to the `playButton` element. This will look for the class `playing` in the CSS file and add it to the `playButton` element.
+
+To finally play the song, use the `play()` method on the `audio` variable. `play()` is a method from the web audio API for playing an mp3 file.
+
+# --hints--
+
+You should use the `classList` property and the `add` method to add the class `playing` to `playButton`.
+
+```js
+assert.match(code, /playButton\.classList\.add\(("|')playing\1\);?/)
+```
+
+You should use the `play()` method on the `audio` variable.
+
+```js
+assert.match(code, /audio\.play\(\);?/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+
+ userData.currentSong = song;
+--fcc-editable-region--
+
+--fcc-editable-region--
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+renderSongs(userData?.songs);
+
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6552385244ccf89b77d6b332.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6552385244ccf89b77d6b332.md
new file mode 100644
index 00000000000..bca282adc60
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6552385244ccf89b77d6b332.md
@@ -0,0 +1,689 @@
+---
+id: 6552385244ccf89b77d6b332
+title: Step 36
+challengeType: 0
+dashedName: step-36
+---
+
+# --description--
+
+You need to work on playing the next song and the previous song. For this, you will need a `playNextSong` and `playPreviousSong` function.
+
+Use `const` and arrow syntax to create an empty `playNextSong` function.
+
+# --hints--
+
+You should use `const` to create an empty function named `playNextSong`.
+
+```js
+assert.match(code, /const\s+playNextSong\s*=\s*/)
+```
+
+`playNextSong` should be a function.
+
+```js
+assert.isFunction(playNextSong)
+```
+
+Your `playNextSong` function should use an arrow syntax.
+
+```js
+assert.match(code, /const\s+playNextSong\s*=\s*\(\)\s*=>\s*/)
+```
+
+Your `playNextSong` function should be empty.
+
+```js
+assert.match(code, /const\s+playNextSong\s*=\s*\(\)\s*=>\s*\{\n?\s*?\};?/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ audio.play();
+};
+
+const pauseSong = () => {
+ userData.songCurrentTime = audio.currentTime;
+
+ playButton.classList.remove("playing");
+ audio.pause();
+};
+
+--fcc-editable-region--
+
+--fcc-editable-region--
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+pauseButton.addEventListener("click", pauseSong);
+
+renderSongs(userData?.songs);
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655243068222c2c1166b90b0.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655243068222c2c1166b90b0.md
new file mode 100644
index 00000000000..e001ffe24e0
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655243068222c2c1166b90b0.md
@@ -0,0 +1,689 @@
+---
+id: 655243068222c2c1166b90b0
+title: Step 37
+challengeType: 0
+dashedName: step-37
+---
+
+# --description--
+
+Inside the `playNextSong` function, create an `if` statement to check if the `currentSong` of `userData` is strictly equal to `null`. This will check if there's no current song playing in the `userData` object.
+
+If the condition is true, call the `playSong` function with the `id` of the first song in the `userData.songs` array as an argument.
+
+# --hints--
+
+You should not modify the existing `playNextSong` function and its content.
+
+```js
+assert.match(code, /const\s+playNextSong\s*=\s*\(\)\s*=>\s*\{\s*.*\s*.*\s*.*\s*\};?/)
+```
+
+You should create an `if` statement with the condition `userData?.currentSong === null`.
+
+```js
+const splitter = code.split('const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);')
+
+assert.match(splitter[0], /if\s*\(userData\?\.currentSong\s*===\s*null\)\s*\{\s*/)
+```
+
+You should call the `playSong` function with `userData?.songs[0].id` inside the `if` statement.
+
+```js
+const splitter = code.split('const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);')
+
+assert.match(splitter[0], /if\s*\(userData\?\.currentSong\s*===\s*null\)\s*\{\s*playSong\(userData\?\.songs\[0\]\.id\);?\s*\}/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ audio.play();
+};
+
+const pauseSong = () => {
+ userData.songCurrentTime = audio.currentTime;
+
+ playButton.classList.remove("playing");
+ audio.pause();
+};
+
+--fcc-editable-region--
+const playNextSong = () => {
+
+}
+--fcc-editable-region--
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+pauseButton.addEventListener("click", pauseSong);
+
+renderSongs(userData?.songs);
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655476e1ff522252fdcce5e4.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655476e1ff522252fdcce5e4.md
new file mode 100644
index 00000000000..fe1bf864526
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655476e1ff522252fdcce5e4.md
@@ -0,0 +1,694 @@
+---
+id: 655476e1ff522252fdcce5e4
+title: Step 38
+challengeType: 0
+dashedName: step-38
+---
+
+# --description--
+
+Add an `else` block to the `if` statement. Inside the `else` block, call the `getCurrentSongIndex()` function and assign it to a constant named `currentSongIndex`.
+
+# --hints--
+
+You should not modify the existing `if` statement.
+
+```js
+const splitter = code.split('const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);')
+
+assert.match(splitter[0], /if\s*\(userData\?\.currentSong\s*===\s*null\)\s*\{\s*playSong\(userData\?\.songs\[0\]\.id\);?\s*\}/)
+```
+
+You should add an `else` to the existing `if` statement.
+
+```js
+const splitter = code.split('const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);')
+
+assert.match(splitter[0], /if\s*\(userData\?\.currentSong\s*===\s*null\)\s*\{\s*playSong\(userData\?\.songs\[0\]\.id\);?\s*\}\s*else\s*\{\s*/)
+```
+
+You should set the `currentSongIndex` constant to `getCurrentSongIndex()` inside the `else` block.
+
+```js
+const splitter = code.split('const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);')
+
+assert.match(splitter[0], /if\s*\(userData\?\.currentSong\s*===\s*null\)\s*\{\s*playSong\(userData\?\.songs\[0\]\.id\);?\s*\}\s*else\s*\{\s*const\s*currentSongIndex\s*=\s*getCurrentSongIndex\(\);?\s*\}/)
+```
+
+
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ audio.play();
+};
+
+const pauseSong = () => {
+ userData.songCurrentTime = audio.currentTime;
+
+ playButton.classList.remove("playing");
+ audio.pause();
+};
+
+const playNextSong = () => {
+ --fcc-editable-region--
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ }
+
+--fcc-editable-region--
+}
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+pauseButton.addEventListener("click", pauseSong);
+
+renderSongs(userData?.songs);
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655479aa3e1e0360ae38b7a6.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655479aa3e1e0360ae38b7a6.md
new file mode 100644
index 00000000000..59b2f6944c1
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655479aa3e1e0360ae38b7a6.md
@@ -0,0 +1,699 @@
+---
+id: 655479aa3e1e0360ae38b7a6
+title: Step 39
+challengeType: 0
+dashedName: step-39
+---
+
+# --description--
+
+Next, you will need to retrieve the next song in the playlist. For that, you will need to get the index of the current song and then add `1` to it.
+
+Create a constant called `nextSong` and assign `userData?.songs[currentSongIndex + 1]` to it.
+
+Lastly, call the `playSong` function and pass in `nextSong.id` as the argument.
+
+# --hints--
+
+You should not modify the existing `if` statement, its `else` block, and content.
+
+```js
+const splitter = code.split('const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);')
+
+assert.match(splitter[0], /if\s*\(userData\?\.currentSong\s*===\s*null\)\s*\{\s*playSong\(userData\?\.songs\[0\]\.id\);?\s*\}\s*else\s*\{\s*const\s*currentSongIndex\s*=\s*getCurrentSongIndex\(\);?\s*/)
+```
+
+You should assign `userData?.songs[currentSongIndex + 1]` to a `nextSong` constant.
+
+```js
+const splitter = code.split('const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);')
+
+assert.match(splitter[0], /if\s*\(userData\?\.currentSong\s*===\s*null\)\s*\{\s*playSong\(userData\?\.songs\[0\]\.id\);?\s*\}\s*else\s*\{\s*const\s*currentSongIndex\s*=\s*getCurrentSongIndex\(\);?\s*const\s*nextSong\s*=\s*userData\?\.songs\[currentSongIndex\s*\+\s*1\];?\s*/)
+```
+
+You should call the `playSong` function with `nextSong.id`.
+
+```js
+const splitter = code.split('const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);')
+
+assert.match(splitter[0], /if\s*\(userData\?\.currentSong\s*===\s*null\)\s*\{\s*playSong\(userData\?\.songs\[0\]\.id\);?\s*\}\s*else\s*\{\s*const\s*currentSongIndex\s*=\s*getCurrentSongIndex\(\);?\s*const\s*nextSong\s*=\s*userData\?\.songs\[currentSongIndex\s*\+\s*1\];?\s*playSong\(nextSong\.id\);?\s*\}/)
+```
+
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ audio.play();
+};
+
+const pauseSong = () => {
+ userData.songCurrentTime = audio.currentTime;
+
+ playButton.classList.remove("playing");
+ audio.pause();
+};
+
+const playNextSong = () => {
+--fcc-editable-region--
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ const currentSongIndex = getCurrentSongIndex();
+
+ }
+--fcc-editable-region--
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+pauseButton.addEventListener("click", pauseSong);
+
+renderSongs(userData?.songs);
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65547ee197840478a1b95f4b.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65547ee197840478a1b95f4b.md
new file mode 100644
index 00000000000..1fff918ebea
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65547ee197840478a1b95f4b.md
@@ -0,0 +1,695 @@
+---
+id: 65547ee197840478a1b95f4b
+title: Step 40
+challengeType: 0
+dashedName: step-40
+---
+
+# --description--
+
+It's time to hook up the `playNextSong` function to an event listener.
+
+Add a `click` event listener to the `nextButton` element the pass in `playNextSong` as the second parameter of your event listener. This is the function the event listener will run.
+
+# --hints--
+
+You should call the `addEventListener()` method on your `nextButton` variable.
+
+```js
+assert.match(code, /nextButton\.addEventListener\(/)
+```
+
+Your event listener should listen for a `click` event.
+
+```js
+assert.match(code, /nextButton\.addEventListener\(('|"|`)click\1/)
+```
+
+You should pass in `playNextSong` as the second parameter of your `addEventListener` method.
+
+```js
+assert.match(code, /nextButton\.addEventListener\(('|"|`)click\1,\s*playNextSong\)/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ audio.play();
+};
+
+const pauseSong = () => {
+ userData.songCurrentTime = audio.currentTime;
+
+ playButton.classList.remove("playing");
+ audio.pause();
+};
+
+const playNextSong = () => {
+
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ const currentSongIndex = getCurrentSongIndex();
+ const nextSong = userData?.songs[currentSongIndex + 1];
+
+ playSong(nextSong.id);
+ }
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+pauseButton.addEventListener("click", pauseSong);
+
+--fcc-editable-region--
+
+--fcc-editable-region--
+
+renderSongs(userData?.songs);
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6554815fe2472f8bfdab7642.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6554815fe2472f8bfdab7642.md
new file mode 100644
index 00000000000..c8464429f65
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6554815fe2472f8bfdab7642.md
@@ -0,0 +1,701 @@
+---
+id: 6554815fe2472f8bfdab7642
+title: Step 41
+challengeType: 0
+dashedName: step-41
+---
+
+# --description--
+
+Use `const` and arrow syntax to create an empty `playPreviousSong` function.
+
+# --hints--
+
+You should use `const` to create an empty function named `playPreviousSong`.
+
+```js
+assert.match(code, /const\s+playPreviousSong\s*=\s*/)
+```
+
+`playPreviousSong` should be a function.
+
+```js
+assert.isFunction(playPreviousSong)
+```
+
+Your `playPreviousSong` function should use an arrow syntax.
+
+```js
+assert.match(code, /const\s+playPreviousSong\s*=\s*\(\)\s*=>\s*/)
+```
+
+Your `playPreviousSong` function should be empty.
+
+```js
+assert.match(code, /const\s+playPreviousSong\s*=\s*\(\)\s*=>\s*\{\n?\s*?\};?/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ audio.play();
+};
+
+const pauseSong = () => {
+ userData.songCurrentTime = audio.currentTime;
+
+ playButton.classList.remove("playing");
+ audio.pause();
+};
+
+const playNextSong = () => {
+
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ const currentSongIndex = getCurrentSongIndex();
+ const nextSong = userData?.songs[currentSongIndex + 1];
+
+ playSong(nextSong.id);
+ }
+};
+
+--fcc-editable-region--
+
+--fcc-editable-region--
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+pauseButton.addEventListener("click", pauseSong);
+
+nextButton.addEventListener("click", playNextSong);
+
+renderSongs(userData?.songs);
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655482742cc5499726e3f347.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655482742cc5499726e3f347.md
new file mode 100644
index 00000000000..6ebc333a18f
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655482742cc5499726e3f347.md
@@ -0,0 +1,713 @@
+---
+id: 655482742cc5499726e3f347
+title: Step 42
+challengeType: 0
+dashedName: step-42
+---
+
+# --description--
+
+Within the `playPreviousSong` function, add an `if` statement with a condition of `userData?.currentSong === null`. This will check if there is currently no song playing. If there isn't any, exit the function using a `return`.
+
+Inside the `else` block, create a constant named `currentSongIndex` and assign it `getCurrentSongIndex()`.
+
+# --hints--
+
+You should not alter the existing `playPreviousSong` function and its content.
+
+```js
+assert.match(code, /const\s+playPreviousSong\s*=\s*\(\)\s*=>\s*\{\s*/)
+```
+
+You should have an `if` statement with the condition `userData?.currentSong === null` inside your `playPreviousSong` function.
+
+```js
+assert.match(code, /const\s+playPreviousSong\s*=\s*\(\)\s*=>\s*\{\s*if\s*\(userData\?.currentSong\s*===\s*null\)\s*\{?\s*/)
+```
+
+You should have `return` inside the block of your `if` statement.
+
+```js
+assert.match(code, /const\s+playPreviousSong\s*=\s*\(\)\s*=>\s*\{\s*if\s*\(userData\?.currentSong\s*===\s*null\)\s*\{?\s*return;?\s*\}?/)
+```
+
+Your `if` statement should have an `else` block.
+
+```js
+assert.match(code, /const\s+playPreviousSong\s*=\s*\(\)\s*=>\s*\{\s*if\s*\(userData\?.currentSong\s*===\s*null\)\s*\{?\s*return;?\s*\}?\s*else\s*\{\s*/)
+```
+
+You should call `getCurrentSongIndex` and assign it to `currentSongIndex` inside the `else` block of your `if` statement.
+
+```js
+assert.match(code, /const\s+playPreviousSong\s*=\s*\(\)\s*=>\s*\{\s*if\s*\(userData\?.currentSong\s*===\s*null\)\s*\{?\s*return;?\s*\}?\s*else\s*\{\s*const\s*currentSongIndex\s*=\s*getCurrentSongIndex\(\);?\s*/)
+```
+
+
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ audio.play();
+};
+
+const pauseSong = () => {
+ userData.songCurrentTime = audio.currentTime;
+
+ playButton.classList.remove("playing");
+ audio.pause();
+};
+
+const playNextSong = () => {
+
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ const currentSongIndex = getCurrentSongIndex();
+ const nextSong = userData?.songs[currentSongIndex + 1];
+
+ playSong(nextSong.id);
+ }
+};
+
+--fcc-editable-region--
+const playPreviousSong = () => {
+
+};
+--fcc-editable-region--
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+pauseButton.addEventListener("click", pauseSong);
+
+nextButton.addEventListener("click", playNextSong);
+
+renderSongs(userData?.songs);
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655483ebf0096ba02b2c3d4c.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655483ebf0096ba02b2c3d4c.md
new file mode 100644
index 00000000000..baa59d09650
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655483ebf0096ba02b2c3d4c.md
@@ -0,0 +1,701 @@
+---
+id: 655483ebf0096ba02b2c3d4c
+title: Step 43
+challengeType: 0
+dashedName: step-43
+---
+
+# --description--
+
+To get the previous song, subtract `1` from the `currentSongIndex` of `userData?.songs` and assign it to the constant `previousSong`. After that, call the `playSong` function and pass `previousSong.id` as an argument.
+
+# --hints--
+
+You should not modify the existing `if` statement and its content.
+
+```js
+assert.match(code, /if\s*\(userData\?.currentSong\s*===\s*null\)\s*\{?\s*return;?\s*\}?\s*else\s*\{\s*const\s*currentSongIndex\s*=\s*getCurrentSongIndex\(\);?\s*/)
+```
+
+You should assign `userData?.songs[currentSongIndex - 1]` to a `previousSong` constant.
+
+```js
+assert.match(code, /if\s*\(userData\?.currentSong\s*===\s*null\)\s*\{?\s*return;?\s*\}?\s*else\s*\{\s*const\s*currentSongIndex\s*=\s*getCurrentSongIndex\(\);?\s*const\s*previousSong\s*=\s*userData\?\.songs\[currentSongIndex\s*-\s*1\];?\s*/)
+```
+
+You should call the `playSong` function with `previousSong.id`.
+
+```js
+assert.match(code, /if\s*\(userData\?.currentSong\s*===\s*null\)\s*\{?\s*return;?\s*\}?\s*else\s*\{\s*const\s*currentSongIndex\s*=\s*getCurrentSongIndex\(\);?\s*const\s*previousSong\s*=\s*userData\?\.songs\[currentSongIndex\s*-\s*1\];?\s*playSong\(previousSong\.id\);?\s*\}/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ audio.play();
+};
+
+const pauseSong = () => {
+ userData.songCurrentTime = audio.currentTime;
+
+ playButton.classList.remove("playing");
+ audio.pause();
+};
+
+const playNextSong = () => {
+
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ const currentSongIndex = getCurrentSongIndex();
+ const nextSong = userData?.songs[currentSongIndex + 1];
+
+ playSong(nextSong.id);
+ }
+};
+
+const playPreviousSong = () => {
+--fcc-editable-region--
+ if (userData?.currentSong === null) return;
+ else {
+ const currentSongIndex = getCurrentSongIndex();
+
+ }
+--fcc-editable-region--
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+pauseButton.addEventListener("click", pauseSong);
+
+nextButton.addEventListener("click", playNextSong);
+
+renderSongs(userData?.songs);
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655485321913feabbc5f00f8.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655485321913feabbc5f00f8.md
new file mode 100644
index 00000000000..5b5a84fba14
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655485321913feabbc5f00f8.md
@@ -0,0 +1,705 @@
+---
+id: 655485321913feabbc5f00f8
+title: Step 44
+challengeType: 0
+dashedName: step-44
+---
+
+# --description--
+
+Add a `click` event listener to the `previousButton` element, then pass in `playPrevious` song as the second parameter.
+
+# --hints--
+
+You should call the `addEventListener()` method on your `previousButton` variable.
+
+```js
+assert.match(code, /previousButton\.addEventListener\(/)
+```
+
+Your event listener should listen for a `click` event.
+
+```js
+assert.match(code, /previousButton\.addEventListener\(('|"|`)click\1/)
+```
+
+You should pass in `playPreviousSong` as the second parameter of your `addEventListener` method.
+
+```js
+assert.match(code, /previousButton\.addEventListener\(('|"|`)click\1,\s*playPreviousSong\)/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ audio.play();
+};
+
+const pauseSong = () => {
+ userData.songCurrentTime = audio.currentTime;
+
+ playButton.classList.remove("playing");
+ audio.pause();
+};
+
+const playNextSong = () => {
+
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ const currentSongIndex = getCurrentSongIndex();
+ const nextSong = userData?.songs[currentSongIndex + 1];
+
+ playSong(nextSong.id);
+ }
+};
+
+const playPreviousSong = () =>{
+ if (userData?.currentSong === null) return;
+ else {
+ const currentSongIndex = getCurrentSongIndex();
+ const previousSong = userData?.songs[currentSongIndex - 1];
+
+ playSong(previousSong.id);
+ }
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+pauseButton.addEventListener("click", pauseSong);
+
+nextButton.addEventListener("click", playNextSong);
+
+--fcc-editable-region--
+
+--fcc-editable-region--
+
+renderSongs(userData?.songs);
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6554860ea4dfbab2f4786fc8.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6554860ea4dfbab2f4786fc8.md
new file mode 100644
index 00000000000..3409166e3af
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6554860ea4dfbab2f4786fc8.md
@@ -0,0 +1,720 @@
+---
+id: 6554860ea4dfbab2f4786fc8
+title: Step 45
+challengeType: 0
+dashedName: step-45
+---
+
+# --description--
+
+If you check closely, you'd see the currently playing song is not highlighted in the playlist, so you don't really know which song is playing. You can fix this by creating a function to highlight any song that is being played.
+
+Using an arrow syntax, create a `highlightCurrentSong` function. Inside the function, use `querySelectorAll` to get the `.playlist-song` element and assign to a `playlistSongElements` constant.
+
+# --hints--
+
+You should use `const` to create a `highlightCurrentSong` function.
+
+```js
+assert.match(code, /const\s+highlightCurrentSong\s*=\s*/)
+```
+
+`highlightCurrentSong` should be a function.
+
+```js
+assert.isFunction(highlightCurrentSong)
+```
+
+Your `highlightCurrentSong` function should use an arrow syntax.
+
+```js
+assert.match(code, /const\s+highlightCurrentSong\s*=\s*\(\)\s*=>\s*{\s*/)
+```
+
+You should create a `playlistSongElements` constant inside your `highlightCurrentSong` function.
+
+```js
+assert.match(code, /const\s+highlightCurrentSong\s*=\s*\(\)\s*=>\s*{\s*const\s*playlistSongElements\s*=\s*/)
+```
+
+You should use the `querySelectorAll()` method to select the `.playlist-song` element and assign it to the `playlistSongElements` constant.
+
+```js
+assert.match(code, /const\s+highlightCurrentSong\s*=\s*\(\)\s*=>\s*{\s*const\s*playlistSongElements\s*=\s*document\.querySelectorAll\(('|")\.playlist-song\1\);?\s*\};?/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ audio.play();
+};
+
+const pauseSong = () => {
+ userData.songCurrentTime = audio.currentTime;
+
+ playButton.classList.remove("playing");
+ audio.pause();
+};
+
+const playNextSong = () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ const currentSongIndex = getCurrentSongIndex();
+ const nextSong = userData?.songs[currentSongIndex + 1];
+
+ playSong(nextSong.id);
+ }
+};
+
+const playPreviousSong = () => {
+ if (userData?.currentSong === null) return;
+ else {
+ const currentSongIndex = getCurrentSongIndex();
+ const previousSong = userData?.songs[currentSongIndex - 1];
+
+ playSong(previousSong.id);
+ }
+};
+
+--fcc-editable-region--
+
+--fcc-editable-region--
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+pauseButton.addEventListener("click", pauseSong);
+
+nextButton.addEventListener("click", playNextSong);
+
+previousButton.addEventListener("click", playPreviousSong);
+
+renderSongs(userData?.songs);
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655487f686aabfc2a10ba887.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655487f686aabfc2a10ba887.md
new file mode 100644
index 00000000000..ac46246c194
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655487f686aabfc2a10ba887.md
@@ -0,0 +1,689 @@
+---
+id: 655487f686aabfc2a10ba887
+title: Step 35
+challengeType: 0
+dashedName: step-35
+---
+
+# --description--
+
+Before you start working on playing the next and previous song, you need to get the index of each song in the `songs` property of `userData`. Remember this is where you spread in the songs.
+
+Use an arrow syntax to create a `getCurrentSongIndex` function. Then, using implicit return, use the `indexOf()` method on `userData?.songs`, and pass in `userData.currentSong`.
+
+Calling this function will get you the index of each song.
+
+# --hints--
+
+You should use `const` to create a `getCurrentSongIndex` function.
+
+```js
+assert.match(code, /const\s+getCurrentSongIndex\s*/)
+```
+
+Your `getCurrentSongIndex` function should use arrow syntax.
+
+```js
+assert.match(code, /const\s+getCurrentSongIndex\s*=\s*\(\)\s*=>\s*/)
+```
+
+Your `getCurrentSongIndex` function should implicitly use the `indexOf()` method on `userData?.songs`.
+
+```js
+assert.match(code, /const\s+getCurrentSongIndex\s*=\s*\(\)\s*=>\s*userData\?\.songs\.indexOf\(/)
+```
+
+You should pass in `userData.currentSong` into the `indexOf()`.
+
+```js
+assert.match(code, /const\s+getCurrentSongIndex\s*=\s*\(\)\s*=>\s*userData\?\.songs\.indexOf\(userData\.currentSong\);?/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ audio.play();
+};
+
+const pauseSong = () => {
+ userData.songCurrentTime = audio.currentTime;
+
+ playButton.classList.remove("playing");
+ audio.pause();
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+--fcc-editable-region--
+
+--fcc-editable-region--
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+pauseButton.addEventListener("click", pauseSong);
+
+renderSongs(userData?.songs);
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65548f747a4cdafd186948d1.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65548f747a4cdafd186948d1.md
new file mode 100644
index 00000000000..9f6a9ba8e66
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65548f747a4cdafd186948d1.md
@@ -0,0 +1,712 @@
+---
+id: 65548f747a4cdafd186948d1
+title: Step 46
+challengeType: 0
+dashedName: step-46
+---
+
+# --description--
+
+You need to get the `id` of the currently playing song. For this, you can use `userData?.currentSong?.id`.
+
+Use `getElementById()` to get the `id` of the currently playing song, then use template literals to prefix it with `song-`. Assign it to the constant `songToHighlight`.
+
+# --hints--
+
+You should not modify the existing `highlightCurrentSong` function and its content.
+
+```js
+assert.match(code, /const\s+highlightCurrentSong\s*=\s*\(\)\s*=>\s*\s{\s*const\s*playlistSongElements\s*=\s*document\.querySelectorAll\(('|")\.playlist-song\1\);?\s*/)
+```
+
+You should use `document.getElementById()` and pass in \`song-${userData?.currentSong?.id}\`.
+
+```js
+assert.match(code, /document\.getElementById\(\s*`song-\$\{userData\?\.currentSong\?\.id\}`\s*\);?\s*\};?/)
+```
+
+You should assign your `getElementById()` to a `songToHighlight` constant.
+
+```js
+assert.match(code, /const\s*songToHighlight\s*=\s*document\.getElementById\(\s*`song-\$\{userData\?\.currentSong\?\.id\}`\s*\);?\s*\};?/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ audio.play();
+};
+
+const pauseSong = () => {
+ userData.songCurrentTime = audio.currentTime;
+
+ playButton.classList.remove("playing");
+ audio.pause();
+};
+
+const playNextSong = () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ const currentSongIndex = getCurrentSongIndex();
+ const nextSong = userData?.songs[currentSongIndex + 1];
+
+ playSong(nextSong.id);
+ }
+};
+
+const playPreviousSong = () => {
+ if (userData?.currentSong === null) return;
+ else {
+ const currentSongIndex = getCurrentSongIndex();
+ const previousSong = userData?.songs[currentSongIndex - 1];
+
+ playSong(previousSong.id);
+ }
+};
+
+--fcc-editable-region--
+const highlightCurrentSong = () => {
+ const playlistSongElements = document.querySelectorAll(".playlist-song");
+
+
+};
+--fcc-editable-region--
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+pauseButton.addEventListener("click", pauseSong);
+
+nextButton.addEventListener("click", playNextSong);
+
+previousButton.addEventListener("click", playPreviousSong);
+
+renderSongs(userData?.songs);
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655490f55c36900779336988.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655490f55c36900779336988.md
new file mode 100644
index 00000000000..650845785cd
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655490f55c36900779336988.md
@@ -0,0 +1,726 @@
+---
+id: 655490f55c36900779336988
+title: Step 47
+challengeType: 0
+dashedName: step-47
+---
+
+# --description--
+
+Loop through the `playlistSongElements` with a `forEach` method.
+
+The `forEach` method is used to loop through an array and perform a function on each element of the array. For example, suppose you have an array of numbers and you want to log each number to the console.
+
+```js
+const numbers = [1, 2, 3, 4, 5];
+
+// Using forEach to iterate through the array
+numbers.forEach((number) => {
+ console.log(number); // 1, 2, 3, 4, 5
+});
+```
+
+Use the `forEach` method on `playlistSongElements`. Pass in `songEl` as the parameter and use arrow syntax to add in an empty callback.
+
+# --hints--
+
+You should chain `forEach()` to `playlistSongElements`.
+
+```js
+assert.match(code, /playlistSongElements\.forEach\(/)
+```
+
+Your `forEach()` method should have a `songEl` parameter and use arrow syntax.
+
+```js
+assert.match(code, /playlistSongElements\.forEach\(\(?songEl\)?\s*=>\s*/)
+```
+
+Your `forEach` should have an empty pair of curly braces.
+
+```js
+assert.match(code, /playlistSongElements\.forEach\(\(?songEl\)?\s*=>\s*\{\s*\}\);?/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ audio.play();
+};
+
+const pauseSong = () => {
+ userData.songCurrentTime = audio.currentTime;
+
+ playButton.classList.remove("playing");
+ audio.pause();
+};
+
+const playNextSong = () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ const currentSongIndex = getCurrentSongIndex();
+ const nextSong = userData?.songs[currentSongIndex + 1];
+
+ playSong(nextSong.id);
+ }
+};
+
+const playPreviousSong = () => {
+ if (userData?.currentSong === null) return;
+ else {
+ const currentSongIndex = getCurrentSongIndex();
+ const previousSong = userData?.songs[currentSongIndex - 1];
+
+ playSong(previousSong.id);
+ }
+};
+
+const highlightCurrentSong = () => {
+ const playlistSongElements = document.querySelectorAll(".playlist-song");
+ const songToHighlight = document.getElementById(
+ `song-${userData?.currentSong?.id}`
+ );
+
+--fcc-editable-region--
+
+--fcc-editable-region--
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+pauseButton.addEventListener("click", pauseSong);
+
+nextButton.addEventListener("click", playNextSong);
+
+previousButton.addEventListener("click", playPreviousSong);
+
+renderSongs(userData?.songs);
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655492e6b90c7a198c587943.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655492e6b90c7a198c587943.md
new file mode 100644
index 00000000000..3157fed2381
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655492e6b90c7a198c587943.md
@@ -0,0 +1,719 @@
+---
+id: 655492e6b90c7a198c587943
+title: Step 49
+challengeType: 0
+dashedName: step-49
+---
+
+# --description--
+
+Now you need to add the attribute back to the currently playing song.
+
+Create an `if` statement with the condition `songToHighlight`. For the statement, use `setAttribute` on `songToHighlight` to pass in `"aria-current"` and `"true"` as the first and second parameters.
+
+# --hints--
+
+You should create an `if` statement with the condition `songToHighlight`.
+
+```js
+assert.match(code, /if\s*\(songToHighlight\)\s*\{?\s*/)
+```
+
+You should use the `setAttribute()` method on `songToHighlight` inside your `if` statement.
+
+```js
+assert.match(code, /if\s*\(songToHighlight\)\s*\{?\s*songToHighlight\.setAttribute\(/)
+```
+
+You should pass in `"aria-current"` and `"true"` as the first and second parameter of your `setAttribute` method.
+
+```js
+assert.match(code, /if\s*\(songToHighlight\)\s*\{?\s*songToHighlight\.setAttribute\(('|")aria-current\1,\s*\1true\1\)\s*;?\s*\}?/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ audio.play();
+};
+
+const pauseSong = () => {
+ userData.songCurrentTime = audio.currentTime;
+
+ playButton.classList.remove("playing");
+ audio.pause();
+};
+
+const playNextSong = () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ const currentSongIndex = getCurrentSongIndex();
+ const nextSong = userData?.songs[currentSongIndex + 1];
+
+ playSong(nextSong.id);
+ }
+};
+
+const playPreviousSong = () => {
+ if (userData?.currentSong === null) return;
+ else {
+ const currentSongIndex = getCurrentSongIndex();
+ const previousSong = userData?.songs[currentSongIndex - 1];
+
+ playSong(previousSong.id);
+ }
+};
+
+const highlightCurrentSong = () => {
+ const playlistSongElements = document.querySelectorAll(".playlist-song");
+ const songToHighlight = document.getElementById(
+ `song-${userData?.currentSong?.id}`
+ );
+
+ playlistSongElements.forEach((songEl) => {
+ songEl.removeAttribute("aria-current");
+ });
+
+--fcc-editable-region--
+
+--fcc-editable-region--
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+pauseButton.addEventListener("click", pauseSong);
+
+nextButton.addEventListener("click", playNextSong);
+
+previousButton.addEventListener("click", playPreviousSong);
+
+renderSongs(userData?.songs);
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655494d5a15d6a2567e1ea60.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655494d5a15d6a2567e1ea60.md
new file mode 100644
index 00000000000..dda63a85421
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655494d5a15d6a2567e1ea60.md
@@ -0,0 +1,708 @@
+---
+id: 655494d5a15d6a2567e1ea60
+title: Step 50
+challengeType: 0
+dashedName: step-50
+---
+
+# --description--
+
+Inside the `playSong` function, call the `highlightCurrentSong` function.
+
+After that, play around with the control buttons to see how the `highlightCurrentSong` function works.
+
+# --hints--
+
+You should call the `highlightCurrentSong` function.
+
+```js
+assert.match(code, /highlightCurrentSong\(\)/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+--fcc-editable-region--
+
+--fcc-editable-region--
+ audio.play();
+};
+
+const pauseSong = () => {
+ userData.songCurrentTime = audio.currentTime;
+
+ playButton.classList.remove("playing");
+ audio.pause();
+};
+
+const playNextSong = () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ const currentSongIndex = getCurrentSongIndex();
+ const nextSong = userData?.songs[currentSongIndex + 1];
+
+ playSong(nextSong.id);
+ }
+};
+
+const playPreviousSong = () => {
+ if (userData?.currentSong === null) return;
+ else {
+ const currentSongIndex = getCurrentSongIndex();
+ const previousSong = userData?.songs[currentSongIndex - 1];
+
+ playSong(previousSong.id);
+ }
+};
+
+const highlightCurrentSong = () => {
+ const playlistSongElements = document.querySelectorAll(".playlist-song");
+ const songToHighlight = document.getElementById(
+ `song-${userData?.currentSong?.id}`
+ );
+
+ playlistSongElements.forEach((songEl) => {
+ songEl.removeAttribute("aria-current");
+ });
+
+ if (songToHighlight) songToHighlight.setAttribute("aria-current", "true");
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+pauseButton.addEventListener("click", pauseSong);
+
+nextButton.addEventListener("click", playNextSong);
+
+previousButton.addEventListener("click", playPreviousSong);
+
+renderSongs(userData?.songs);
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655495a6bd96e42bc3baa795.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655495a6bd96e42bc3baa795.md
new file mode 100644
index 00000000000..0a7eb00a57c
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655495a6bd96e42bc3baa795.md
@@ -0,0 +1,726 @@
+---
+id: 655495a6bd96e42bc3baa795
+title: Step 51
+challengeType: 0
+dashedName: step-51
+---
+
+# --description--
+
+Next, you need to display the current song title and artist in the player display. Use `const` and arrow syntax to create an empty `setPlayerDisplay` function.
+
+# --hints--
+
+You should use `const` to create an empty function named `setPlayerDisplay`.
+
+```js
+assert.match(code, /const\s+setPlayerDisplay\s*=\s*/)
+```
+
+`setPlayerDisplay` should be a function.
+
+```js
+assert.isFunction(setPlayerDisplay)
+```
+
+Your `setPlayerDisplay` function should use an arrow syntax.
+
+```js
+assert.match(code, /const\s+setPlayerDisplay\s*=\s*\(\)\s*=>\s*/)
+```
+
+Your `setPlayerDisplay` function should be empty.
+
+```js
+assert.match(code, /const\s+setPlayerDisplay\s*=\s*\(\)\s*=>\s*\{\n?\s*?\};?/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ highlightCurrentSong();
+ audio.play();
+};
+
+const pauseSong = () => {
+ userData.songCurrentTime = audio.currentTime;
+
+ playButton.classList.remove("playing");
+ audio.pause();
+};
+
+const playNextSong = () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ const currentSongIndex = getCurrentSongIndex();
+ const nextSong = userData?.songs[currentSongIndex + 1];
+
+ playSong(nextSong.id);
+ }
+};
+
+const playPreviousSong = () => {
+ if (userData?.currentSong === null) return;
+ else {
+ const currentSongIndex = getCurrentSongIndex();
+ const previousSong = userData?.songs[currentSongIndex - 1];
+
+ playSong(previousSong.id);
+ }
+};
+
+--fcc-editable-region--
+
+--fcc-editable-region--
+
+const highlightCurrentSong = () => {
+ const playlistSongElements = document.querySelectorAll(".playlist-song");
+ const songToHighlight = document.getElementById(
+ `song-${userData?.currentSong?.id}`
+ );
+
+ playlistSongElements.forEach((songEl) => {
+ songEl.removeAttribute("aria-current");
+ });
+
+ if (songToHighlight) songToHighlight.setAttribute("aria-current", "true");
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+pauseButton.addEventListener("click", pauseSong);
+
+nextButton.addEventListener("click", playNextSong);
+
+previousButton.addEventListener("click", playPreviousSong);
+
+renderSongs(userData?.songs);
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555d17af9ff06a14d399f6d.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555d17af9ff06a14d399f6d.md
new file mode 100644
index 00000000000..5cf3885dc79
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555d17af9ff06a14d399f6d.md
@@ -0,0 +1,736 @@
+---
+id: 6555d17af9ff06a14d399f6d
+title: Step 52
+challengeType: 0
+dashedName: step-52
+---
+
+# --description--
+
+Inside the function, obtain refrences to the HTML elements responsible for displaying the song title and artist.
+
+Access the `#player-song-title` and `#player-song-artist` elements with the `getElementById()` method. Assign them to variables `playingSong` and `songArtist` respectively.
+
+# --hints--
+
+You should not modify the existing `setPlayerDisplay` function and its content.
+
+```js
+assert.match(code, /const\s+setPlayerDisplay\s*=\s*\(\)\s*=>\s*\{\s*.*\s*.*\s*\};?/)
+```
+
+You should use `document.getElementById()` to get the `#player-song-title` element.
+
+```js
+assert.match(code, /document\.getElementById\(\s*('|"|`)player\-song\-title\1\);?/);
+```
+
+You should assign the `#player-song-title` element to the variable `playingSong`. Don't forget to use `const` to declare the variable.
+
+```js
+assert.match(code, /const\s+playingSong\s*\=\s*document\.getElementById\(\s*('|"|`)player\-song\-title\1\);?/);
+```
+
+You should use `document.getElementById()` to get the `#player-song-artist` element.
+
+```js
+assert.match(code, /document\.getElementById\(\s*('|"|`)player\-song\-artist\1\);?/);
+```
+
+You should assign the `#player-song-artist` element to the variable `songArtist`. Don't forget to use `const` to declare the variable.
+
+```js
+assert.match(code, /const\s+songArtist\s*\=\s*document\.getElementById\(\s*('|"|`)player\-song\-artist\1\);?/);
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ highlightCurrentSong();
+ audio.play();
+};
+
+const pauseSong = () => {
+ userData.songCurrentTime = audio.currentTime;
+
+ playButton.classList.remove("playing");
+ audio.pause();
+};
+
+const playNextSong = () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ const currentSongIndex = getCurrentSongIndex();
+ const nextSong = userData?.songs[currentSongIndex + 1];
+
+ playSong(nextSong.id);
+ }
+};
+
+const playPreviousSong = () => {
+ if (userData?.currentSong === null) return;
+ else {
+ const currentSongIndex = getCurrentSongIndex();
+ const previousSong = userData?.songs[currentSongIndex - 1];
+
+ playSong(previousSong.id);
+ }
+};
+
+--fcc-editable-region--
+const setPlayerDisplay = () => {
+
+};
+--fcc-editable-region--
+
+const highlightCurrentSong = () => {
+ const playlistSongElements = document.querySelectorAll(".playlist-song");
+ const songToHighlight = document.getElementById(
+ `song-${userData?.currentSong?.id}`
+ );
+
+ playlistSongElements.forEach((songEl) => {
+ songEl.removeAttribute("aria-current");
+ });
+
+ if (songToHighlight) songToHighlight.setAttribute("aria-current", "true");
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+pauseButton.addEventListener("click", pauseSong);
+
+nextButton.addEventListener("click", playNextSong);
+
+previousButton.addEventListener("click", playPreviousSong);
+
+renderSongs(userData?.songs);
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555d458687cb3b357834df9.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555d458687cb3b357834df9.md
new file mode 100644
index 00000000000..edc82a2d3cf
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555d458687cb3b357834df9.md
@@ -0,0 +1,730 @@
+---
+id: 6555d458687cb3b357834df9
+title: Step 53
+challengeType: 0
+dashedName: step-53
+---
+
+# --description--
+
+Access the `userData?.currentSong?.title` and `userData?.currentSong?.artist` properties and assign them to a `currentTitle` and `currentArtist` variables respectively.
+
+# --hints--
+
+You should access the `title` of `currentSong` from the `userData` object. Don't forget to use optional chaining.
+
+```js
+assert.match(code, /userData\?\.currentSong\?\.title;?/)
+```
+
+You should assign the `title` of the `currentSong` to a `currentTitle` constant.
+
+```js
+assert.match(code, /const\s+currentTitle\s*=\s*userData\?\.currentSong\?\.title;?/)
+```
+
+You should access the `artist` of `currentSong` from the `userData` object. Don't forget to use optional chaining.
+
+```js
+assert.match(code, /userData\?\.currentSong\?\.artist;?/)
+```
+
+You should assign the `artist` of the `currentSong` to a `currentArtist` constant.
+
+```js
+assert.match(code, /const\s+currentArtist\s*=\s*userData\?\.currentSong\?\.artist;?/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ highlightCurrentSong();
+ audio.play();
+};
+
+const pauseSong = () => {
+ userData.songCurrentTime = audio.currentTime;
+
+ playButton.classList.remove("playing");
+ audio.pause();
+};
+
+const playNextSong = () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ const currentSongIndex = getCurrentSongIndex();
+ const nextSong = userData?.songs[currentSongIndex + 1];
+
+ playSong(nextSong.id);
+ }
+};
+
+const playPreviousSong = () =>{
+ if (userData?.currentSong === null) return;
+ else {
+ const currentSongIndex = getCurrentSongIndex();
+ const previousSong = userData?.songs[currentSongIndex - 1];
+
+ playSong(previousSong.id);
+ }
+};
+
+const setPlayerDisplay = () => {
+ const playingSong = document.getElementById("player-song-title");
+ const songArtist = document.getElementById("player-song-artist");
+--fcc-editable-region--
+
+--fcc-editable-region--
+};
+
+const highlightCurrentSong = () => {
+ const playlistSongElements = document.querySelectorAll(".playlist-song");
+ const songToHighlight = document.getElementById(
+ `song-${userData?.currentSong?.id}`
+ );
+
+ playlistSongElements.forEach((songEl) => {
+ songEl.removeAttribute("aria-current");
+ });
+
+ if (songToHighlight) songToHighlight.setAttribute("aria-current", "true");
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+pauseButton.addEventListener("click", pauseSong);
+
+nextButton.addEventListener("click", playNextSong);
+
+previousButton.addEventListener("click", playPreviousSong);
+
+renderSongs(userData?.songs);
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555d729c9bfd7c3195f1948.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555d729c9bfd7c3195f1948.md
new file mode 100644
index 00000000000..8f42b463f0c
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555d729c9bfd7c3195f1948.md
@@ -0,0 +1,745 @@
+---
+id: 6555d729c9bfd7c3195f1948
+title: Step 54
+challengeType: 0
+dashedName: step-54
+---
+
+# --description--
+
+`textContent` sets the text of a node and allows you to set or retrieve the text content of an HTML element.
+
+```html
+This is some text content
+```
+
+```js
+const element = document.getElementById('example');
+console.log(element.textContent); // Output: This is some text content
+```
+
+Use a `ternary` operator to check if `currentTitle` is truthy. If so, implicitly return `currentTitle` otherwise implicitly return an empty string. Assign this result to `playingSong.textContent`.
+
+Then, use a `ternary` operator to check if `currentArtist` is truthy. If so, implicitly return `currentArtist` otherwise implicitly return an empty string. Assign this result to `songArtist.textContent`.
+
+# --hints--
+
+You should chain the `textContent` property to `playingSong`.
+
+```js
+assert.match(code, /playingSong.textContent\s*/)
+```
+
+You should use the `ternary` operator to set the `textContent` property of `playingSong` to `currentTitle` or `""`.
+
+```js
+assert.match(code, /playingSong.textContent\s*=\s*currentTitle\s*\?\s*currentTitle\s*:\s*('|")\1;?/)
+```
+
+You should chain the `textContent` property to `songArtist`.
+
+```js
+assert.match(code, /songArtist.textContent\s*/)
+```
+
+You should use the `ternary` operator to set the `textContent` property of `songArtist` to `currentArtist` or `""`.
+
+```js
+assert.match(code, /songArtist.textContent\s*=\s*currentArtist\s*\?\s*currentArtist\s*:\s*('|")\1;?/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ highlightCurrentSong();
+ audio.play();
+};
+
+const pauseSong = () => {
+ userData.songCurrentTime = audio.currentTime;
+
+ playButton.classList.remove("playing");
+ audio.pause();
+};
+
+const playNextSong = () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ const currentSongIndex = getCurrentSongIndex();
+ const nextSong = userData?.songs[currentSongIndex + 1];
+
+ playSong(nextSong.id);
+ }
+};
+
+const playPreviousSong = () => {
+ if (userData?.currentSong === null) return;
+ else {
+ const currentSongIndex = getCurrentSongIndex();
+ const previousSong = userData?.songs[currentSongIndex - 1];
+
+ playSong(previousSong.id);
+ }
+};
+
+const setPlayerDisplay = () => {
+ const playingSong = document.getElementById("player-song-title");
+ const songArtist = document.getElementById("player-song-artist");
+ const currentTitle = userData?.currentSong?.title;
+ const currentArtist = userData?.currentSong?.artist;
+--fcc-editable-region--
+
+--fcc-editable-region--
+};
+
+const highlightCurrentSong = () => {
+ const playlistSongElements = document.querySelectorAll(".playlist-song");
+ const songToHighlight = document.getElementById(
+ `song-${userData?.currentSong?.id}`
+ );
+
+ playlistSongElements.forEach((songEl) => {
+ songEl.removeAttribute("aria-current");
+ });
+
+ if (songToHighlight) songToHighlight.setAttribute("aria-current", "true");
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+pauseButton.addEventListener("click", pauseSong);
+
+nextButton.addEventListener("click", playNextSong);
+
+previousButton.addEventListener("click", playPreviousSong);
+
+renderSongs(userData?.songs);
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555d7e384056dc9c581fadf.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555d7e384056dc9c581fadf.md
new file mode 100644
index 00000000000..31638b97df3
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555d7e384056dc9c581fadf.md
@@ -0,0 +1,719 @@
+---
+id: 6555d7e384056dc9c581fadf
+title: Step 55
+challengeType: 0
+dashedName: step-55
+---
+
+# --description--
+
+To ensure the player's display updates whenever a new song begins playing, call the `setPlayerDisplay()` function within the `playSong()` function.
+
+Now you should see the song title and the artist show up in the display.
+
+# --hints--
+
+You should call the `setPlayerDisplay` function inside your `playSong` function.
+
+```js
+assert.match(code, /setPlayerDisplay\(\);?/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ highlightCurrentSong();
+--fcc-editable-region--
+
+--fcc-editable-region--
+ audio.play();
+};
+
+const pauseSong = () => {
+ userData.songCurrentTime = audio.currentTime;
+
+ playButton.classList.remove("playing");
+ audio.pause();
+};
+
+const playNextSong = () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ const currentSongIndex = getCurrentSongIndex();
+ const nextSong = userData?.songs[currentSongIndex + 1];
+
+ playSong(nextSong.id);
+ }
+};
+
+const playPreviousSong = () => {
+ if (userData?.currentSong === null) return;
+ else {
+ const currentSongIndex = getCurrentSongIndex();
+ const previousSong = userData?.songs[currentSongIndex - 1];
+
+ playSong(previousSong.id);
+ }
+};
+
+const setPlayerDisplay = () => {
+ const playingSong = document.getElementById("player-song-title");
+ const songArtist = document.getElementById("player-song-artist");
+ const currentTitle = userData?.currentSong?.title;
+ const currentArtist = userData?.currentSong?.artist;
+
+ playingSong.textContent = currentTitle ? currentTitle : "";
+ songArtist.textContent = currentArtist ? currentArtist : "";
+};
+
+const highlightCurrentSong = () => {
+ const playlistSongElements = document.querySelectorAll(".playlist-song");
+ const songToHighlight = document.getElementById(
+ `song-${userData?.currentSong?.id}`
+ );
+
+ playlistSongElements.forEach((songEl) => {
+ songEl.removeAttribute("aria-current");
+ });
+
+ if (songToHighlight) songToHighlight.setAttribute("aria-current", "true");
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+pauseButton.addEventListener("click", pauseSong);
+
+nextButton.addEventListener("click", playNextSong);
+
+previousButton.addEventListener("click", playPreviousSong);
+
+renderSongs(userData?.songs);
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555d8faed60b9d3e4a6cefb.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555d8faed60b9d3e4a6cefb.md
new file mode 100644
index 00000000000..dddff83c305
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555d8faed60b9d3e4a6cefb.md
@@ -0,0 +1,739 @@
+---
+id: 6555d8faed60b9d3e4a6cefb
+title: Step 56
+challengeType: 0
+dashedName: step-56
+---
+
+# --description--
+
+Use `const` and arrow syntax to define a function called `setPlayButtonAccessibleText`.
+
+This function will set the `aria-label` attribute to the current song, or to the first song in the playlist. And if the playlist is empty, it sets the `aria-label` to `"Play"`.
+
+# --hints--
+
+You should use `const` to create an empty function named `setPlayButtonAccessibleText`.
+
+```js
+assert.match(code, /const\s+setPlayButtonAccessibleText\s*=\s*/)
+```
+
+`setPlayButtonAccessibleText` should be a function.
+
+```js
+assert.isFunction(setPlayButtonAccessibleText)
+```
+
+Your `setPlayButtonAccessibleText` function should use an arrow syntax.
+
+```js
+assert.match(code, /const\s+setPlayButtonAccessibleText\s*=\s*\(\)\s*=>\s*/)
+```
+
+Your `setPlayButtonAccessibleText` function should be empty.
+
+```js
+assert.match(code, /const\s+setPlayButtonAccessibleText\s*=\s*\(\)\s*=>\s*\{\n?\s*?\};?/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ highlightCurrentSong();
+ setPlayerDisplay();
+ audio.play();
+};
+
+const pauseSong = () => {
+ userData.songCurrentTime = audio.currentTime;
+
+ playButton.classList.remove("playing");
+ audio.pause();
+};
+
+const playNextSong = () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ const currentSongIndex = getCurrentSongIndex();
+ const nextSong = userData?.songs[currentSongIndex + 1];
+
+ playSong(nextSong.id);
+ }
+};
+
+const playPreviousSong = () => {
+ if (userData?.currentSong === null) return;
+ else {
+ const currentSongIndex = getCurrentSongIndex();
+ const previousSong = userData?.songs[currentSongIndex - 1];
+
+ playSong(previousSong.id);
+ }
+};
+
+const setPlayerDisplay = () => {
+ const playingSong = document.getElementById("player-song-title");
+ const songArtist = document.getElementById("player-song-artist");
+ const currentTitle = userData?.currentSong?.title;
+ const currentArtist = userData?.currentSong?.artist;
+
+ playingSong.textContent = currentTitle ? currentTitle : "";
+ songArtist.textContent = currentArtist ? currentArtist : "";
+};
+
+const highlightCurrentSong = () => {
+ const playlistSongElements = document.querySelectorAll(".playlist-song");
+ const songToHighlight = document.getElementById(
+ `song-${userData?.currentSong?.id}`
+ );
+
+ playlistSongElements.forEach((songEl) => {
+ songEl.removeAttribute("aria-current");
+ });
+
+ if (songToHighlight) songToHighlight.setAttribute("aria-current", "true");
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+--fcc-editable-region--
+
+--fcc-editable-region--
+
+const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+pauseButton.addEventListener("click", pauseSong);
+
+nextButton.addEventListener("click", playNextSong);
+
+previousButton.addEventListener("click", playPreviousSong);
+
+renderSongs(userData?.songs);
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555dd138e70cae6b546966d.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555dd138e70cae6b546966d.md
new file mode 100644
index 00000000000..3807073d5cb
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555dd138e70cae6b546966d.md
@@ -0,0 +1,735 @@
+---
+id: 6555dd138e70cae6b546966d
+title: Step 57
+challengeType: 0
+dashedName: step-57
+---
+
+# --description--
+
+You need to get the currently playing song or the first song in the playlist. To do that, create a `song` constant and set it to the current song of `userData`, **or** the first song in the `userData?.songs` array.
+
+Don't forget to use optional chaining.
+
+# --hints--
+
+You should not modify the existing `setPlayButtonAccessibleText` and its content.
+
+```js
+assert.match(code, /const\s+setPlayButtonAccessibleText\s*=\s*\(\)\s*=>\s*\{\s*.*\s*\};?/)
+```
+
+You should access `userData?.currentSong` or `userData?.songs[0]`.
+
+```js
+assert.match(code, /userData\?\.currentSong\s*\|\|\s*userData\?\.songs\[0\];?/)
+```
+
+You should assign `userData?.currentSong || userData?.songs[0]` to a `song` constant.
+
+```js
+assert.match(code, /const\s+song\s*=\s*userData\?\.currentSong\s*\|\|\s*userData\?\.songs\[0\];?/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ highlightCurrentSong();
+ setPlayerDisplay();
+ audio.play();
+};
+
+const pauseSong = () => {
+ userData.songCurrentTime = audio.currentTime;
+
+ playButton.classList.remove("playing");
+ audio.pause();
+};
+
+const playNextSong = () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ const currentSongIndex = getCurrentSongIndex();
+ const nextSong = userData?.songs[currentSongIndex + 1];
+
+ playSong(nextSong.id);
+ }
+};
+
+const playPreviousSong = () =>{
+ if (userData?.currentSong === null) return;
+ else {
+ const currentSongIndex = getCurrentSongIndex();
+ const previousSong = userData?.songs[currentSongIndex - 1];
+
+ playSong(previousSong.id);
+ }
+};
+
+const setPlayerDisplay = () => {
+ const playingSong = document.getElementById("player-song-title");
+ const songArtist = document.getElementById("player-song-artist");
+ const currentTitle = userData?.currentSong?.title;
+ const currentArtist = userData?.currentSong?.artist;
+
+ playingSong.textContent = currentTitle ? currentTitle : "";
+ songArtist.textContent = currentArtist ? currentArtist : "";
+};
+
+const highlightCurrentSong = () => {
+ const playlistSongElements = document.querySelectorAll(".playlist-song");
+ const songToHighlight = document.getElementById(
+ `song-${userData?.currentSong?.id}`
+ );
+
+ playlistSongElements.forEach((songEl) => {
+ songEl.removeAttribute("aria-current");
+ });
+
+ if (songToHighlight) songToHighlight.setAttribute("aria-current", "true");
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+--fcc-editable-region--
+const setPlayButtonAccessibleText = () => {
+
+};
+--fcc-editable-region--
+
+const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+pauseButton.addEventListener("click", pauseSong);
+
+nextButton.addEventListener("click", playNextSong);
+
+previousButton.addEventListener("click", playPreviousSong);
+
+renderSongs(userData?.songs);
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555de565387a2efe90a6ccc.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555de565387a2efe90a6ccc.md
new file mode 100644
index 00000000000..fbd83bd56bc
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555de565387a2efe90a6ccc.md
@@ -0,0 +1,742 @@
+---
+id: 6555de565387a2efe90a6ccc
+title: Step 58
+challengeType: 0
+dashedName: step-58
+---
+
+# --description--
+
+Use the `setAttribute` method on the `playButton` element to set an attribute named `aria-label`. For the value, use a `ternary` to set `song?.title` to `Play ${song.title}` or `"Play"` if there's no `song.title` available.
+
+Don't forget you need template interpolation here, so you need to use backticks.
+
+# --hints--
+
+You should not modify the existing `setPlayButtonAccessibleText` function and its content.
+
+```js
+assert.match(code, /const\s+setPlayButtonAccessibleText\s*=\s*\(\)\s*=>\s*\{\s*const\s+song\s*=\s*userData\?\.currentSong\s*\|\|\s*userData\?\.songs\[0\];?\s*.*\s*.*\s*.*\s*.*\s*\};?/)
+```
+
+You should use the `setAttribute()` method on `playButton`.
+
+```js
+assert.match(code, /playButton\.setAttribute\(\s*/)
+```
+
+`"aria-label"` should be the first value of your `setAttribute()` method.
+
+```js
+assert.match(code, /playButton\.setAttribute\(\s*('|")aria-label\1/)
+```
+
+Your `setAttribute` method should have `song?.title ? \`Play ${song.title}\` : "Play"` as the second argument.
+
+```js
+assert.match(code, /playButton\.setAttribute\(\s*('|")aria-label\1,\s*song\?\.title\s*\?\s*`Play\s*\$\{song\.title\}`\s*:\s*\1Play\1\s*\);?\s*/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ highlightCurrentSong();
+ setPlayerDisplay();
+ audio.play();
+};
+
+const pauseSong = () => {
+ userData.songCurrentTime = audio.currentTime;
+
+ playButton.classList.remove("playing");
+ audio.pause();
+};
+
+const playNextSong = () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ const currentSongIndex = getCurrentSongIndex();
+ const nextSong = userData?.songs[currentSongIndex + 1];
+
+ playSong(nextSong.id);
+ }
+};
+
+const playPreviousSong = () =>{
+ if (userData?.currentSong === null) return;
+ else {
+ const currentSongIndex = getCurrentSongIndex();
+ const previousSong = userData?.songs[currentSongIndex - 1];
+
+ playSong(previousSong.id);
+ }
+};
+
+const setPlayerDisplay = () => {
+ const playingSong = document.getElementById("player-song-title");
+ const songArtist = document.getElementById("player-song-artist");
+ const currentTitle = userData?.currentSong?.title;
+ const currentArtist = userData?.currentSong?.artist;
+
+ playingSong.textContent = currentTitle ? currentTitle : "";
+ songArtist.textContent = currentArtist ? currentArtist : "";
+};
+
+const highlightCurrentSong = () => {
+ const playlistSongElements = document.querySelectorAll(".playlist-song");
+ const songToHighlight = document.getElementById(
+ `song-${userData?.currentSong?.id}`
+ );
+
+ playlistSongElements.forEach((songEl) => {
+ songEl.removeAttribute("aria-current");
+ });
+
+ if (songToHighlight) songToHighlight.setAttribute("aria-current", "true");
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+--fcc-editable-region--
+const setPlayButtonAccessibleText = () => {
+ const song = userData?.currentSong || userData?.songs[0];
+
+};
+--fcc-editable-region--
+
+const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+pauseButton.addEventListener("click", pauseSong);
+
+nextButton.addEventListener("click", playNextSong);
+
+previousButton.addEventListener("click", playPreviousSong);
+
+renderSongs(userData?.songs);
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555e04aeb225bfbae237344.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555e04aeb225bfbae237344.md
new file mode 100644
index 00000000000..574e3466950
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555e04aeb225bfbae237344.md
@@ -0,0 +1,727 @@
+---
+id: 6555e04aeb225bfbae237344
+title: Step 59
+challengeType: 0
+dashedName: step-59
+---
+
+# --description--
+
+Now, call the `setPlayButtonAccessibleText` function inside the `playSong` function.
+
+# --hints--
+
+You should call the `setPlayButtonAccessibleText` inside your `playSong` function.
+
+```js
+assert.match(code, /setPlayButtonAccessibleText\(\);?/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ highlightCurrentSong();
+ setPlayerDisplay();
+--fcc-editable-region--
+
+--fcc-editable-region--
+ audio.play();
+};
+
+const pauseSong = () => {
+ userData.songCurrentTime = audio.currentTime;
+
+ playButton.classList.remove("playing");
+ audio.pause();
+};
+
+const playNextSong = () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ const currentSongIndex = getCurrentSongIndex();
+ const nextSong = userData?.songs[currentSongIndex + 1];
+
+ playSong(nextSong.id);
+ }
+};
+
+const playPreviousSong = () =>{
+ if (userData?.currentSong === null) return;
+ else {
+ const currentSongIndex = getCurrentSongIndex();
+ const previousSong = userData?.songs[currentSongIndex - 1];
+
+ playSong(previousSong.id);
+ }
+};
+
+const setPlayerDisplay = () => {
+ const playingSong = document.getElementById("player-song-title");
+ const songArtist = document.getElementById("player-song-artist");
+ const currentTitle = userData?.currentSong?.title;
+ const currentArtist = userData?.currentSong?.artist;
+
+ playingSong.textContent = currentTitle ? currentTitle : "";
+ songArtist.textContent = currentArtist ? currentArtist : "";
+};
+
+const highlightCurrentSong = () => {
+ const playlistSongElements = document.querySelectorAll(".playlist-song");
+ const songToHighlight = document.getElementById(
+ `song-${userData?.currentSong?.id}`
+ );
+
+ playlistSongElements.forEach((songEl) => {
+ songEl.removeAttribute("aria-current");
+ });
+
+ if (songToHighlight) songToHighlight.setAttribute("aria-current", "true");
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+const setPlayButtonAccessibleText = () => {
+ const song = userData?.currentSong || userData?.songs[0];
+
+ playButton.setAttribute(
+ "aria-label",
+ song?.title ? `Play ${song.title}` : "Play"
+ );
+};
+
+const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+pauseButton.addEventListener("click", pauseSong);
+
+nextButton.addEventListener("click", playNextSong);
+
+previousButton.addEventListener("click", playPreviousSong);
+
+renderSongs(userData?.songs);
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555e0bfe4d69904410f7cd3.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555e0bfe4d69904410f7cd3.md
new file mode 100644
index 00000000000..e5d3ad733e7
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555e0bfe4d69904410f7cd3.md
@@ -0,0 +1,749 @@
+---
+id: 6555e0bfe4d69904410f7cd3
+title: Step 60
+challengeType: 0
+dashedName: step-60
+---
+
+# --description--
+
+Using `const` and arrow syntax to create an empty function called `shuffle`.
+
+This function is responsible for shuffling the songs in the playlist and performing necessary state management updates after the shuffling.
+
+# --hints--
+
+You should use `const` to create an empty function named `shuffle`.
+
+```js
+assert.match(code, /const\s+shuffle\s*=\s*/)
+```
+
+`shuffle` should be a function.
+
+```js
+assert.isFunction(shuffle)
+```
+
+Your `shuffle` function should use an arrow syntax and should not take a parameter.
+
+```js
+assert.match(code, /const\s+shuffle\s*=\s*\(\)\s*=>\s*/)
+```
+
+Your `shuffle` function should be empty.
+
+```js
+assert.match(code, /const\s+shuffle\s*=\s*\(\)\s*=>\s*\{\n?\s*?\};?/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ highlightCurrentSong();
+ setPlayerDisplay();
+ setPlayButtonAccessibleText();
+ audio.play();
+};
+
+const pauseSong = () => {
+ userData.songCurrentTime = audio.currentTime;
+
+ playButton.classList.remove("playing");
+ audio.pause();
+};
+
+const playNextSong = () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ const currentSongIndex = getCurrentSongIndex();
+ const nextSong = userData?.songs[currentSongIndex + 1];
+
+ playSong(nextSong.id);
+ }
+};
+
+const playPreviousSong = () =>{
+ if (userData?.currentSong === null) return;
+ else {
+ const currentSongIndex = getCurrentSongIndex();
+ const previousSong = userData?.songs[currentSongIndex - 1];
+
+ playSong(previousSong.id);
+ }
+};
+
+--fcc-editable-region--
+
+--fcc-editable-region--
+
+const setPlayerDisplay = () => {
+ const playingSong = document.getElementById("player-song-title");
+ const songArtist = document.getElementById("player-song-artist");
+ const currentTitle = userData?.currentSong?.title;
+ const currentArtist = userData?.currentSong?.artist;
+
+ playingSong.textContent = currentTitle ? currentTitle : "";
+ songArtist.textContent = currentArtist ? currentArtist : "";
+};
+
+const highlightCurrentSong = () => {
+ const playlistSongElements = document.querySelectorAll(".playlist-song");
+ const songToHighlight = document.getElementById(
+ `song-${userData?.currentSong?.id}`
+ );
+
+ playlistSongElements.forEach((songEl) => {
+ songEl.removeAttribute("aria-current");
+ });
+
+ if (songToHighlight) songToHighlight.setAttribute("aria-current", "true");
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+const setPlayButtonAccessibleText = () => {
+ const song = userData?.currentSong || userData?.songs[0];
+
+ playButton.setAttribute(
+ "aria-label",
+ song?.title ? `Play ${song.title}` : "Play"
+ );
+};
+
+const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+pauseButton.addEventListener("click", pauseSong);
+
+nextButton.addEventListener("click", playNextSong);
+
+previousButton.addEventListener("click", playPreviousSong);
+
+renderSongs(userData?.songs);
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555e39a5f4c6f138c7d9405.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555e39a5f4c6f138c7d9405.md
new file mode 100644
index 00000000000..cd46fb8acc9
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555e39a5f4c6f138c7d9405.md
@@ -0,0 +1,767 @@
+---
+id: 6555e39a5f4c6f138c7d9405
+title: Step 61
+challengeType: 0
+dashedName: step-61
+---
+
+# --description--
+
+The `sort()` method converts elements of an array into strings and sorts them based on their `UTF-16` code units values.
+
+```js
+const numbers = [4, 2, 5, 100, 1, 3];
+
+numbers.sort();
+console.log(numbers); // Output: [1, 100, 2, 3, 4, 5]
+```
+
+You can see `100` comes right after 1, which is not supposed to happen. This is a default behavior of the `sort()` method you can fix by passing in a callback this way:
+
+```js
+const numbers = [4, 2, 5, 100, 1, 3];
+
+numbers.sort((a, b) => a - b);
+console.log(numbers); // Output: [1, 2, 3, 4, 5, 100]
+```
+
+Use the `sort()` method on the `userData?.songs` array. For the callback, introduce `Math.random()`, and subtract `0.5`.
+
+# --hints--
+
+You should not modify the existing `shuffle` function.
+
+```js
+assert.match(code, /const\s+shuffle\s*=\s*\(\)\s*=>\s*\{\s*.*\s*\};?/)
+```
+
+You should use the `sort()` method on `userData?.songs`.
+
+```js
+assert.match(code, /userData\?\.songs\.sort\(/)
+```
+
+Your `sort()` method should have a callback function that uses arrow syntax.
+
+```js
+assert.match(code, /userData\?\.songs\.sort\(\(\)\s*=>\s*/)
+```
+
+The callback of your `sort()` method should implicitly return `Math.random() - 0.5`
+
+```js
+assert.match(code, /userData\?\.songs\.sort\(\(\)\s*=>\s*Math\.random\(\)\s*-\s*0\.5\);?/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ highlightCurrentSong();
+ setPlayerDisplay();
+ setPlayButtonAccessibleText();
+ audio.play();
+};
+
+const pauseSong = () => {
+ userData.songCurrentTime = audio.currentTime;
+
+ playButton.classList.remove("playing");
+ audio.pause();
+};
+
+const playNextSong = () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ const currentSongIndex = getCurrentSongIndex();
+ const nextSong = userData?.songs[currentSongIndex + 1];
+
+ playSong(nextSong.id);
+ }
+};
+
+const playPreviousSong = () => {
+ if (userData?.currentSong === null) return;
+ else {
+ const currentSongIndex = getCurrentSongIndex();
+ const previousSong = userData?.songs[currentSongIndex - 1];
+
+ playSong(previousSong.id);
+ }
+};
+
+--fcc-editable-region--
+const shuffle = () => {
+
+};
+--fcc-editable-region--
+
+const setPlayerDisplay = () => {
+ const playingSong = document.getElementById("player-song-title");
+ const songArtist = document.getElementById("player-song-artist");
+ const currentTitle = userData?.currentSong?.title;
+ const currentArtist = userData?.currentSong?.artist;
+
+ playingSong.textContent = currentTitle ? currentTitle : "";
+ songArtist.textContent = currentArtist ? currentArtist : "";
+};
+
+const highlightCurrentSong = () => {
+ const playlistSongElements = document.querySelectorAll(".playlist-song");
+ const songToHighlight = document.getElementById(
+ `song-${userData?.currentSong?.id}`
+ );
+
+ playlistSongElements.forEach((songEl) => {
+ songEl.removeAttribute("aria-current");
+ });
+
+ if (songToHighlight) songToHighlight.setAttribute("aria-current", "true");
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+const setPlayButtonAccessibleText = () => {
+ const song = userData?.currentSong || userData?.songs[0];
+
+ playButton.setAttribute(
+ "aria-label",
+ song?.title ? `Play ${song.title}` : "Play"
+ );
+};
+
+const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+pauseButton.addEventListener("click", pauseSong);
+
+nextButton.addEventListener("click", playNextSong);
+
+previousButton.addEventListener("click", playPreviousSong);
+
+renderSongs(userData?.songs);
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555e57d3e6d9d221c4735be.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555e57d3e6d9d221c4735be.md
new file mode 100644
index 00000000000..e1e4577811f
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555e57d3e6d9d221c4735be.md
@@ -0,0 +1,740 @@
+---
+id: 6555e57d3e6d9d221c4735be
+title: Step 62
+challengeType: 0
+dashedName: step-62
+---
+
+# --description--
+
+When the shuffle button is pressed, you want to set the `currentSong` to nothing and the `songCurrentTime` to `0`.
+
+Set `userData.currentSong` to `null` and `userData.songCurrentTime` to `0`.
+
+# --hints--
+
+You should set `userData.currentSong` to `null`.
+
+```js
+assert.match(code, /userData\.currentSong\s*=\s*null;?/)
+```
+
+You should set `userData.songCurrentTime` to `0`.
+
+```js
+assert.match(code, /userData\.songCurrentTime\s*=\s*0;?/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ highlightCurrentSong();
+ setPlayerDisplay();
+ setPlayButtonAccessibleText();
+ audio.play();
+};
+
+const pauseSong = () => {
+ userData.songCurrentTime = audio.currentTime;
+
+ playButton.classList.remove("playing");
+ audio.pause();
+};
+
+const playNextSong = () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ const currentSongIndex = getCurrentSongIndex();
+ const nextSong = userData?.songs[currentSongIndex + 1];
+
+ playSong(nextSong.id);
+ }
+};
+
+const playPreviousSong = () =>{
+ if (userData?.currentSong === null) return;
+ else {
+ const currentSongIndex = getCurrentSongIndex();
+ const previousSong = userData?.songs[currentSongIndex - 1];
+
+ playSong(previousSong.id);
+ }
+};
+
+const shuffle = () => {
+ userData?.songs.sort(() => Math.random() - 0.5);
+--fcc-editable-region--
+
+--fcc-editable-region--
+};
+
+const setPlayerDisplay = () => {
+ const playingSong = document.getElementById("player-song-title");
+ const songArtist = document.getElementById("player-song-artist");
+ const currentTitle = userData?.currentSong?.title;
+ const currentArtist = userData?.currentSong?.artist;
+
+ playingSong.textContent = currentTitle ? currentTitle : "";
+ songArtist.textContent = currentArtist ? currentArtist : "";
+};
+
+const highlightCurrentSong = () => {
+ const playlistSongElements = document.querySelectorAll(".playlist-song");
+ const songToHighlight = document.getElementById(
+ `song-${userData?.currentSong?.id}`
+ );
+
+ playlistSongElements.forEach((songEl) => {
+ songEl.removeAttribute("aria-current");
+ });
+
+ if (songToHighlight) songToHighlight.setAttribute("aria-current", "true");
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+const setPlayButtonAccessibleText = () => {
+ const song = userData?.currentSong || userData?.songs[0];
+
+ playButton.setAttribute(
+ "aria-label",
+ song?.title ? `Play ${song.title}` : "Play"
+ );
+};
+
+const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+pauseButton.addEventListener("click", pauseSong);
+
+nextButton.addEventListener("click", playNextSong);
+
+previousButton.addEventListener("click", playPreviousSong);
+
+renderSongs(userData?.songs);
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555e6cec786da2aadc11ea0.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555e6cec786da2aadc11ea0.md
new file mode 100644
index 00000000000..1691603f42b
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555e6cec786da2aadc11ea0.md
@@ -0,0 +1,761 @@
+---
+id: 6555e6cec786da2aadc11ea0
+title: Step 63
+challengeType: 0
+dashedName: step-63
+---
+
+# --description--
+
+You should also re-render the songs, pause the currently playing song, set the player display, and set the play button accessible text again.
+
+Call the `renderSongs` function and pass in `userData?.songs` as an argument. Also, call the `pauseSong`, `setPlayerDisplay`, and `setPlayButtonAccessibleText` functions.
+
+# --hints--
+
+You should not modify the existing `shuffle` function and its content.
+
+```js
+assert.match(code, /const\s+shuffle\s*=\s*\(\)\s*=>\s*\{\s*userData\?\.songs\.sort\(\(\)\s*=>\s*Math\.random\(\)\s*-\s*0\.5\);?\s*userData\.currentSong\s*=\s*null;\s*userData\.songCurrentTime\s*=\s*0;?\s*.*\s*.*\s*.*\s*.*\s*\};?/)
+```
+
+You should call the `renderSongs` function with `userData?.songs`.
+
+```js
+assert.match(code, /const\s+shuffle\s*=\s*\(\)\s*=>\s*\{\s*userData\?\.songs\.sort\(\(\)\s*=>\s*Math\.random\(\)\s*-\s*0\.5\);?\s*userData\.currentSong\s*=\s*null;\s*userData\.songCurrentTime\s*=\s*0;?\s*renderSongs\(userData\?\.songs\);?\s*.*\s*.*\s*.*\s*\};?/)
+```
+
+You should call the `pauseSong` function.
+
+```js
+assert.match(code, /const\s+shuffle\s*=\s*\(\)\s*=>\s*\{\s*userData\?\.songs\.sort\(\(\)\s*=>\s*Math\.random\(\)\s*-\s*0\.5\);?\s*userData\.currentSong\s*=\s*null;\s*userData\.songCurrentTime\s*=\s*0;?\s*renderSongs\(userData\?\.songs\);?\s*pauseSong\(\);?\s*.*\s*.*\s*\};?/)
+```
+
+You should call the `setPlayerDisplay` function.
+
+```js
+assert.match(code, /const\s+shuffle\s*=\s*\(\)\s*=>\s*\{\s*userData\?\.songs\.sort\(\(\)\s*=>\s*Math\.random\(\)\s*-\s*0\.5\);?\s*userData\.currentSong\s*=\s*null;\s*userData\.songCurrentTime\s*=\s*0;?\s*renderSongs\(userData\?\.songs\);?\s*pauseSong\(\);?\s*setPlayerDisplay\(\);?\s*.*\s*\};?/)
+```
+
+You should call the `setPlayButtonAccessibleText` function.
+
+```js
+assert.match(code, /const\s+shuffle\s*=\s*\(\)\s*=>\s*\{\s*userData\?\.songs\.sort\(\(\)\s*=>\s*Math\.random\(\)\s*-\s*0\.5\);?\s*userData\.currentSong\s*=\s*null;\s*userData\.songCurrentTime\s*=\s*0;?\s*renderSongs\(userData\?\.songs\);?\s*pauseSong\(\);?\s*setPlayerDisplay\(\);?\s*setPlayButtonAccessibleText\(\);?\s*\};?/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ highlightCurrentSong();
+ setPlayerDisplay();
+ setPlayButtonAccessibleText();
+ audio.play();
+};
+
+const pauseSong = () => {
+ userData.songCurrentTime = audio.currentTime;
+
+ playButton.classList.remove("playing");
+ audio.pause();
+};
+
+const playNextSong = () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ const currentSongIndex = getCurrentSongIndex();
+ const nextSong = userData?.songs[currentSongIndex + 1];
+
+ playSong(nextSong.id);
+ }
+};
+
+const playPreviousSong = () =>{
+ if (userData?.currentSong === null) return;
+ else {
+ const currentSongIndex = getCurrentSongIndex();
+ const previousSong = userData?.songs[currentSongIndex - 1];
+
+ playSong(previousSong.id);
+ }
+};
+
+--fcc-editable-region--
+const shuffle = () => {
+ userData?.songs.sort(() => Math.random() - 0.5);
+ userData.currentSong = null;
+ userData.songCurrentTime = 0;
+
+
+};
+--fcc-editable-region--
+
+const setPlayerDisplay = () => {
+ const playingSong = document.getElementById("player-song-title");
+ const songArtist = document.getElementById("player-song-artist");
+ const currentTitle = userData?.currentSong?.title;
+ const currentArtist = userData?.currentSong?.artist;
+
+ playingSong.textContent = currentTitle ? currentTitle : "";
+ songArtist.textContent = currentArtist ? currentArtist : "";
+};
+
+const highlightCurrentSong = () => {
+ const playlistSongElements = document.querySelectorAll(".playlist-song");
+ const songToHighlight = document.getElementById(
+ `song-${userData?.currentSong?.id}`
+ );
+
+ playlistSongElements.forEach((songEl) => {
+ songEl.removeAttribute("aria-current");
+ });
+
+ if (songToHighlight) songToHighlight.setAttribute("aria-current", "true");
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+const setPlayButtonAccessibleText = () => {
+ const song = userData?.currentSong || userData?.songs[0];
+
+ playButton.setAttribute(
+ "aria-label",
+ song?.title ? `Play ${song.title}` : "Play"
+ );
+};
+
+const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+pauseButton.addEventListener("click", pauseSong);
+
+nextButton.addEventListener("click", playNextSong);
+
+previousButton.addEventListener("click", playPreviousSong);
+
+renderSongs(userData?.songs);
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555e7acdbae972d3e8e0f5b.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555e7acdbae972d3e8e0f5b.md
new file mode 100644
index 00000000000..c0c08fbbb0c
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555e7acdbae972d3e8e0f5b.md
@@ -0,0 +1,754 @@
+---
+id: 6555e7acdbae972d3e8e0f5b
+title: Step 64
+challengeType: 0
+dashedName: step-64
+---
+
+# --description--
+
+Add a `click` event listener to the `shuffleButton` element. For the function to run, pass in the `shuffle` function.
+
+**Note**: You don't need a callback inside this particular event listener. You also don't need to call the `shuffle` function, just pass in its identifier.
+
+# --hints--
+
+You should chain the `addEventListener()` method to `shuffleButton`.
+
+```js
+assert.match(code, /shuffleButton\.addEventListener\(/)
+```
+
+Your event listener should listen for a `click` event.
+
+```js
+assert.match(code, /shuffleButton\.addEventListener\(('|")click\1/)
+```
+
+You should pass in `shuffle` as the second value of your `click` event listener.
+
+```js
+assert.match(code, /shuffleButton\.addEventListener\(('|")click\1,\s*shuffle\);?/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ highlightCurrentSong();
+ setPlayerDisplay();
+ setPlayButtonAccessibleText();
+ audio.play();
+};
+
+const pauseSong = () => {
+ userData.songCurrentTime = audio.currentTime;
+
+ playButton.classList.remove("playing");
+ audio.pause();
+};
+
+const playNextSong = () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ const currentSongIndex = getCurrentSongIndex();
+ const nextSong = userData?.songs[currentSongIndex + 1];
+
+ playSong(nextSong.id);
+ }
+};
+
+const playPreviousSong = () => {
+ if (userData?.currentSong === null) return;
+ else {
+ const currentSongIndex = getCurrentSongIndex();
+ const previousSong = userData?.songs[currentSongIndex - 1];
+
+ playSong(previousSong.id);
+ }
+};
+
+const shuffle = () => {
+ userData?.songs.sort(() => Math.random() - 0.5);
+ userData.currentSong = null;
+ userData.songCurrentTime = 0;
+
+ renderSongs(userData?.songs);
+ pauseSong();
+ setPlayerDisplay();
+ setPlayButtonAccessibleText();
+};
+
+const setPlayerDisplay = () => {
+ const playingSong = document.getElementById("player-song-title");
+ const songArtist = document.getElementById("player-song-artist");
+ const currentTitle = userData?.currentSong?.title;
+ const currentArtist = userData?.currentSong?.artist;
+
+ playingSong.textContent = currentTitle ? currentTitle : "";
+ songArtist.textContent = currentArtist ? currentArtist : "";
+};
+
+const highlightCurrentSong = () => {
+ const playlistSongElements = document.querySelectorAll(".playlist-song");
+ const songToHighlight = document.getElementById(
+ `song-${userData?.currentSong?.id}`
+ );
+
+ playlistSongElements.forEach((songEl) => {
+ songEl.removeAttribute("aria-current");
+ });
+
+ if (songToHighlight) songToHighlight.setAttribute("aria-current", "true");
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+const setPlayButtonAccessibleText = () => {
+ const song = userData?.currentSong || userData?.songs[0];
+
+ playButton.setAttribute(
+ "aria-label",
+ song?.title ? `Play ${song.title}` : "Play"
+ );
+};
+
+const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+pauseButton.addEventListener("click", pauseSong);
+
+nextButton.addEventListener("click", playNextSong);
+
+previousButton.addEventListener("click", playPreviousSong);
+
+--fcc-editable-region--
+
+--fcc-editable-region--
+
+renderSongs(userData?.songs);
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555e9197bf1d7416bdd76e0.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555e9197bf1d7416bdd76e0.md
new file mode 100644
index 00000000000..43622792c67
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555e9197bf1d7416bdd76e0.md
@@ -0,0 +1,768 @@
+---
+id: 6555e9197bf1d7416bdd76e0
+title: Step 65
+challengeType: 0
+dashedName: step-65
+---
+
+# --description--
+
+It's time to implement a delete functionality for the playlist. This would manage the removal of a song from the playlist, handle other related actions when a song is deleted, and create a `Reset Playlist` button.
+
+Use `const` and arrow syntax to create an empty `deleteSong` function and pass in `id` as a parameter.
+
+# --hints--
+
+You should use `const` to create an empty function named `deleteSong`.
+
+```js
+assert.match(code, /const\s+deleteSong\s*=\s*/)
+```
+
+`deleteSong` should be a function.
+
+```js
+assert.isFunction(deleteSong)
+```
+
+Your `deleteSong` function should use an arrow syntax.
+
+```js
+assert.match(code, /const\s+deleteSong\s*=\s*\(.*\)\s*=>\s*/)
+```
+
+Your `deleteSong` function should take an `id` parameter.
+
+```js
+assert.match(code, /const\s+deleteSong\s*=\s*\(id/)
+```
+
+Your `deleteSong` function should be empty.
+
+```js
+assert.match(code, /const\s+deleteSong\s*=\s*\(id\)\s*=>\s*\{\n?\s*?\};?/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ highlightCurrentSong();
+ setPlayerDisplay();
+ setPlayButtonAccessibleText();
+ audio.play();
+};
+
+const pauseSong = () => {
+ userData.songCurrentTime = audio.currentTime;
+
+ playButton.classList.remove("playing");
+ audio.pause();
+};
+
+const playNextSong = () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ const currentSongIndex = getCurrentSongIndex();
+ const nextSong = userData?.songs[currentSongIndex + 1];
+
+ playSong(nextSong.id);
+ }
+};
+
+const playPreviousSong = () => {
+ if (userData?.currentSong === null) return;
+ else {
+ const currentSongIndex = getCurrentSongIndex();
+ const previousSong = userData?.songs[currentSongIndex - 1];
+
+ playSong(previousSong.id);
+ }
+};
+
+const shuffle = () => {
+ userData?.songs.sort(() => Math.random() - 0.5);
+ userData.currentSong = null;
+ userData.songCurrentTime = 0;
+
+ renderSongs(userData?.songs);
+ pauseSong();
+ setPlayerDisplay();
+ setPlayButtonAccessibleText();
+};
+
+--fcc-editable-region--
+
+--fcc-editable-region--
+
+const setPlayerDisplay = () => {
+ const playingSong = document.getElementById("player-song-title");
+ const songArtist = document.getElementById("player-song-artist");
+ const currentTitle = userData?.currentSong?.title;
+ const currentArtist = userData?.currentSong?.artist;
+
+ playingSong.textContent = currentTitle ? currentTitle : "";
+ songArtist.textContent = currentArtist ? currentArtist : "";
+};
+
+const highlightCurrentSong = () => {
+ const playlistSongElements = document.querySelectorAll(".playlist-song");
+ const songToHighlight = document.getElementById(
+ `song-${userData?.currentSong?.id}`
+ );
+
+ playlistSongElements.forEach((songEl) => {
+ songEl.removeAttribute("aria-current");
+ });
+
+ if (songToHighlight) songToHighlight.setAttribute("aria-current", "true");
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+const setPlayButtonAccessibleText = () => {
+ const song = userData?.currentSong || userData?.songs[0];
+
+ playButton.setAttribute(
+ "aria-label",
+ song?.title ? `Play ${song.title}` : "Play"
+ );
+};
+
+const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+pauseButton.addEventListener("click", pauseSong);
+
+nextButton.addEventListener("click", playNextSong);
+
+previousButton.addEventListener("click", playPreviousSong);
+
+shuffleButton.addEventListener("click", shuffle);
+
+renderSongs(userData?.songs);
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555ebf07ec610585a626f72.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555ebf07ec610585a626f72.md
new file mode 100644
index 00000000000..9d37dbcdaa1
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555ebf07ec610585a626f72.md
@@ -0,0 +1,779 @@
+---
+id: 6555ebf07ec610585a626f72
+title: Step 66
+challengeType: 0
+dashedName: step-66
+---
+
+# --description--
+
+Use the `filter()` method to remove the song object that matches the `id` parameter from the `userData.songs` array.
+
+The `filter` method keeps only the elements of an array that satisfy the callback function passed to it:
+
+```js
+const numArr = [1, 10, 8, 3, 4, 5]
+const numsGreaterThanThree = numArr.filter((num) => num > 3);
+
+console.log(numsGreaterThanThree) // Output: [10, 8, 4, 5]
+```
+
+Use the `filter()` method on `userData?.songs`. Pass in `song` as the parameter of the arrow function callback and use implicit return to check if `song.id` is strictly not equal to `id`. Assign all of that to the userData.songs.
+
+# --hints--
+
+You should not modify the existing `deleteSong` function.
+
+```js
+assert.match(code, /const\s+deleteSong\s*=\s*\(id\)\s*=>\s*\{\s*.*\s*\};?/)
+```
+
+You should use the `filter()` method on `userData?.songs`.
+
+```js
+assert.match(code, /userData\?\.songs\.filter\(/)
+```
+
+The callback function of your `filter()` method should use arrow syntax and have a `song` parameter.
+
+```js
+assert.match(code, /userData\?\.songs\.filter\(\(?song\)?\s*=>\s*/)
+```
+
+Your filter method should implicitly return `song.id !== id`.
+
+```js
+assert.match(code, /userData\?\.songs\.filter\(\(?song\)?\s*=>\s*song\.id\s*!==\s*id\);?/)
+```
+
+You should assign the `filter()` method you used on `userData?.songs` to `userData.songs`.
+
+```js
+assert.match(code, /userData\.songs\s*=\s*userData\?\.songs\.filter\(\(?song\)?\s*=>\s*song\.id\s*!==\s*id\);?/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ highlightCurrentSong();
+ setPlayerDisplay();
+ setPlayButtonAccessibleText();
+ audio.play();
+};
+
+const pauseSong = () => {
+ userData.songCurrentTime = audio.currentTime;
+
+ playButton.classList.remove("playing");
+ audio.pause();
+};
+
+const playNextSong = () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ const currentSongIndex = getCurrentSongIndex();
+ const nextSong = userData?.songs[currentSongIndex + 1];
+
+ playSong(nextSong.id);
+ }
+};
+
+const playPreviousSong = () => {
+ if (userData?.currentSong === null) return;
+ else {
+ const currentSongIndex = getCurrentSongIndex();
+ const previousSong = userData?.songs[currentSongIndex - 1];
+
+ playSong(previousSong.id);
+ }
+};
+
+const shuffle = () => {
+ userData?.songs.sort(() => Math.random() - 0.5);
+ userData.currentSong = null;
+ userData.songCurrentTime = 0;
+
+ renderSongs(userData?.songs);
+ pauseSong();
+ setPlayerDisplay();
+ setPlayButtonAccessibleText();
+};
+
+--fcc-editable-region--
+const deleteSong = (id) => {
+
+};
+--fcc-editable-region--
+
+const setPlayerDisplay = () => {
+ const playingSong = document.getElementById("player-song-title");
+ const songArtist = document.getElementById("player-song-artist");
+ const currentTitle = userData?.currentSong?.title;
+ const currentArtist = userData?.currentSong?.artist;
+
+ playingSong.textContent = currentTitle ? currentTitle : "";
+ songArtist.textContent = currentArtist ? currentArtist : "";
+};
+
+const highlightCurrentSong = () => {
+ const playlistSongElements = document.querySelectorAll(".playlist-song");
+ const songToHighlight = document.getElementById(
+ `song-${userData?.currentSong?.id}`
+ );
+
+ playlistSongElements.forEach((songEl) => {
+ songEl.removeAttribute("aria-current");
+ });
+
+ if (songToHighlight) songToHighlight.setAttribute("aria-current", "true");
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+const setPlayButtonAccessibleText = () => {
+ const song = userData?.currentSong || userData?.songs[0];
+
+ playButton.setAttribute(
+ "aria-label",
+ song?.title ? `Play ${song.title}` : "Play"
+ );
+};
+
+const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+pauseButton.addEventListener("click", pauseSong);
+
+nextButton.addEventListener("click", playNextSong);
+
+previousButton.addEventListener("click", playPreviousSong);
+
+shuffleButton.addEventListener("click", shuffle);
+
+renderSongs(userData?.songs);
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65571e742fbf4532d8f98e90.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65571e742fbf4532d8f98e90.md
new file mode 100644
index 00000000000..a56133694f9
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65571e742fbf4532d8f98e90.md
@@ -0,0 +1,767 @@
+---
+id: 65571e742fbf4532d8f98e90
+title: Step 67
+challengeType: 0
+dashedName: step-67
+---
+
+# --description--
+
+You need to re-render the songs, highlight it and set the play button's accessible text since the song list will change.
+
+Call the `renderSongs` function and pass in the `userData?.songs` array as an argument, this displays the modified playlist.
+
+After that, call the `highlightCurrentSong` function to highlight the current song if there is any also and the `setPlayButtonAccessibleText` function to update the play button's accessible text.
+
+# --hints--
+
+You should not modify the existing `deleteSong` function and its content.
+
+```js
+assert.match(code, /const\s+deleteSong\s*=\s*\(id\)\s*=>\s*\{\s*userData\.songs\s*=\s*userData\?\.songs\.filter\(\(song\)\s*=>\s*song\.id\s*!==\s*id\);?\s*.*\s*.*\s*.*\s*\};?/)
+```
+
+You should call the `renderSongs` function with `userData?.songs`.
+
+```js
+assert.match(code, /const\s+deleteSong\s*=\s*\(id\)\s*=>\s*\{\s*userData\.songs\s*=\s*userData\?\.songs\.filter\(\(song\)\s*=>\s*song\.id\s*!==\s*id\);?\s*renderSongs\(userData\?\.songs\);?\s*.*\s*.*\s*\};?/)
+```
+
+You should call the `highlightCurrentSong` function.
+
+```js
+assert.match(code, /const\s+deleteSong\s*=\s*\(id\)\s*=>\s*\{\s*userData\.songs\s*=\s*userData\?\.songs\.filter\(\(song\)\s*=>\s*song\.id\s*!==\s*id\);?\s*renderSongs\(userData\?\.songs\);?\s*highlightCurrentSong\(\);?\s*.*\s*\};?/)
+```
+
+You should call the `setPlayButtonAccessibleText` function.
+
+```js
+assert.match(code, /const\s+deleteSong\s*=\s*\(id\)\s*=>\s*\{\s*userData\.songs\s*=\s*userData\?\.songs\.filter\(\(song\)\s*=>\s*song\.id\s*!==\s*id\);?\s*renderSongs\(userData\?\.songs\);?\s*highlightCurrentSong\(\);?\s*setPlayButtonAccessibleText\(\);?\s*\};?/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ highlightCurrentSong();
+ setPlayerDisplay();
+ setPlayButtonAccessibleText();
+ audio.play();
+};
+
+const pauseSong = () => {
+ userData.songCurrentTime = audio.currentTime;
+
+ playButton.classList.remove("playing");
+ audio.pause();
+};
+
+const playNextSong = () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ const currentSongIndex = getCurrentSongIndex();
+ const nextSong = userData?.songs[currentSongIndex + 1];
+
+ playSong(nextSong.id);
+ }
+};
+
+const playPreviousSong = () => {
+ if (userData?.currentSong === null) return;
+ else {
+ const currentSongIndex = getCurrentSongIndex();
+ const previousSong = userData?.songs[currentSongIndex - 1];
+
+ playSong(previousSong.id);
+ }
+};
+
+const shuffle = () => {
+ userData?.songs.sort(() => Math.random() - 0.5);
+ userData.currentSong = null;
+ userData.songCurrentTime = 0;
+
+ renderSongs(userData?.songs);
+ pauseSong();
+ setPlayerDisplay();
+ setPlayButtonAccessibleText();
+};
+
+--fcc-editable-region--
+const deleteSong = (id) => {
+ userData.songs = userData?.songs.filter((song) => song.id !== id);
+
+};
+--fcc-editable-region--
+
+const setPlayerDisplay = () => {
+ const playingSong = document.getElementById("player-song-title");
+ const songArtist = document.getElementById("player-song-artist");
+ const currentTitle = userData?.currentSong?.title;
+ const currentArtist = userData?.currentSong?.artist;
+
+ playingSong.textContent = currentTitle ? currentTitle : "";
+ songArtist.textContent = currentArtist ? currentArtist : "";
+};
+
+const highlightCurrentSong = () => {
+ const playlistSongElements = document.querySelectorAll(".playlist-song");
+ const songToHighlight = document.getElementById(
+ `song-${userData?.currentSong?.id}`
+ );
+
+ playlistSongElements.forEach((songEl) => {
+ songEl.removeAttribute("aria-current");
+ });
+
+ if (songToHighlight) songToHighlight.setAttribute("aria-current", "true");
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+const setPlayButtonAccessibleText = () => {
+ const song = userData?.currentSong || userData?.songs[0];
+
+ playButton.setAttribute(
+ "aria-label",
+ song?.title ? `Play ${song.title}` : "Play"
+ );
+};
+
+const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+pauseButton.addEventListener("click", pauseSong);
+
+nextButton.addEventListener("click", playNextSong);
+
+previousButton.addEventListener("click", playPreviousSong);
+
+shuffleButton.addEventListener("click", shuffle);
+
+renderSongs(userData?.songs);
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655720534347cb3f31cdfb3d.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655720534347cb3f31cdfb3d.md
new file mode 100644
index 00000000000..499c67027ae
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655720534347cb3f31cdfb3d.md
@@ -0,0 +1,752 @@
+---
+id: 655720534347cb3f31cdfb3d
+title: Step 68
+challengeType: 0
+dashedName: step-68
+---
+
+# --description--
+
+Before deleting a song, you need to check if the song is currently playing. If it is, you need to pause the song and play the next song in the playlist.
+
+Use an `if` statement to check if the `userData?.currentSong?.id` is equal to the `id` of the song you want to delete.
+
+# --hints--
+
+You should create an empty `if` statement with the condition `userData?.currentSong?.id === id`.
+
+```js
+assert.match(code, /if\s*\(userData\?\.currentSong\?\.id\s*===\s*id\)\s*\{\s*\}/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ highlightCurrentSong();
+ setPlayerDisplay();
+ setPlayButtonAccessibleText();
+ audio.play();
+};
+
+const pauseSong = () => {
+ userData.songCurrentTime = audio.currentTime;
+
+ playButton.classList.remove("playing");
+ audio.pause();
+};
+
+const playNextSong = () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ const currentSongIndex = getCurrentSongIndex();
+ const nextSong = userData?.songs[currentSongIndex + 1];
+
+ playSong(nextSong.id);
+ }
+};
+
+const playPreviousSong = () => {
+ if (userData?.currentSong === null) return;
+ else {
+ const currentSongIndex = getCurrentSongIndex();
+ const previousSong = userData?.songs[currentSongIndex - 1];
+
+ playSong(previousSong.id);
+ }
+};
+
+const shuffle = () => {
+ userData?.songs.sort(() => Math.random() - 0.5);
+ userData.currentSong = null;
+ userData.songCurrentTime = 0;
+
+ renderSongs(userData?.songs);
+ pauseSong();
+ setPlayerDisplay();
+ setPlayButtonAccessibleText();
+};
+
+const deleteSong = (id) => {
+--fcc-editable-region--
+
+--fcc-editable-region--
+
+ userData.songs = userData?.songs.filter((song) => song.id !== id);
+ renderSongs(userData?.songs);
+ highlightCurrentSong();
+ setPlayButtonAccessibleText();
+
+};
+
+const setPlayerDisplay = () => {
+ const playingSong = document.getElementById("player-song-title");
+ const songArtist = document.getElementById("player-song-artist");
+ const currentTitle = userData?.currentSong?.title;
+ const currentArtist = userData?.currentSong?.artist;
+
+ playingSong.textContent = currentTitle ? currentTitle : "";
+ songArtist.textContent = currentArtist ? currentArtist : "";
+};
+
+const highlightCurrentSong = () => {
+ const playlistSongElements = document.querySelectorAll(".playlist-song");
+ const songToHighlight = document.getElementById(
+ `song-${userData?.currentSong?.id}`
+ );
+
+ playlistSongElements.forEach((songEl) => {
+ songEl.removeAttribute("aria-current");
+ });
+
+ if (songToHighlight) songToHighlight.setAttribute("aria-current", "true");
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+const setPlayButtonAccessibleText = () => {
+ const song = userData?.currentSong || userData?.songs[0];
+
+ playButton.setAttribute(
+ "aria-label",
+ song?.title ? `Play ${song.title}` : "Play"
+ );
+};
+
+const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+pauseButton.addEventListener("click", pauseSong);
+
+nextButton.addEventListener("click", playNextSong);
+
+previousButton.addEventListener("click", playPreviousSong);
+
+shuffleButton.addEventListener("click", shuffle);
+
+renderSongs(userData?.songs);
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65572399a8e16d50bc2c1ff3.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65572399a8e16d50bc2c1ff3.md
new file mode 100644
index 00000000000..bfa2283147d
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65572399a8e16d50bc2c1ff3.md
@@ -0,0 +1,777 @@
+---
+id: 65572399a8e16d50bc2c1ff3
+title: Step 69
+challengeType: 0
+dashedName: step-69
+---
+
+# --description--
+
+If there is a match then set `userData.currentSong` to `null` and `userData.songCurrentTime` to `0`.
+
+Afther that, call the `pauseSong()` function to stop the playback and the `setPlayerDisplay()` function to update the player display.
+
+# --hints--
+
+You should not modify the existing `if` statement and its content.
+
+```js
+assert.match(code, /if\s*\(userData\?\.currentSong\?\.id\s*===\s*id\)\s*\{\s*.*\s*.*\s*.*\s*.*\s*\}/)
+```
+
+You should set `userData.currentSong` to `null`.
+
+```js
+assert.match(code, /if\s*\(userData\?\.currentSong\?\.id\s*===\s*id\)\s*\{\s*userData\.currentSong\s*=\s*null;?\s*.*\s*.*\s*.*\s*\}/)
+```
+
+You should set `userData.songCurrentTime` to `0`.
+
+```js
+assert.match(code, /if\s*\(userData\?\.currentSong\?\.id\s*===\s*id\)\s*\{\s*userData\.currentSong\s*=\s*null;?\s*userData\.songCurrentTime\s*=\s*0;?\s*.*\s*.*\s*\}/)
+```
+
+You should call the `pauseSong` function.
+
+```js
+assert.match(code, /if\s*\(userData\?\.currentSong\?\.id\s*===\s*id\)\s*\{\s*userData\.currentSong\s*=\s*null;?\s*userData\.songCurrentTime\s*=\s*0;?\s*pauseSong\(\);?\s*.*\s*\}/)
+```
+
+You should call the `setPlayerDisplay` function.
+
+```js
+assert.match(code, /if\s*\(userData\?\.currentSong\?\.id\s*===\s*id\)\s*\{\s*userData\.currentSong\s*=\s*null;?\s*userData\.songCurrentTime\s*=\s*0;?\s*pauseSong\(\);?\s*setPlayerDisplay\(\);?\s*\}/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ highlightCurrentSong();
+ setPlayerDisplay();
+ setPlayButtonAccessibleText();
+ audio.play();
+};
+
+const pauseSong = () => {
+ userData.songCurrentTime = audio.currentTime;
+
+ playButton.classList.remove("playing");
+ audio.pause();
+};
+
+const playNextSong = () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ const currentSongIndex = getCurrentSongIndex();
+ const nextSong = userData?.songs[currentSongIndex + 1];
+
+ playSong(nextSong.id);
+ }
+};
+
+const playPreviousSong = () =>{
+ if (userData?.currentSong === null) return;
+ else {
+ const currentSongIndex = getCurrentSongIndex();
+ const previousSong = userData?.songs[currentSongIndex - 1];
+
+ playSong(previousSong.id);
+ }
+};
+
+const shuffle = () => {
+ userData?.songs.sort(() => Math.random() - 0.5);
+ userData.currentSong = null;
+ userData.songCurrentTime = 0;
+
+ renderSongs(userData?.songs);
+ pauseSong();
+ setPlayerDisplay();
+ setPlayButtonAccessibleText();
+};
+
+const deleteSong = (id) => {
+--fcc-editable-region--
+ if (userData?.currentSong?.id === id) {
+
+ }
+--fcc-editable-region--
+ userData.songs = userData?.songs.filter((song) => song.id !== id);
+ renderSongs(userData?.songs);
+ highlightCurrentSong();
+ setPlayButtonAccessibleText();
+
+};
+
+const setPlayerDisplay = () => {
+ const playingSong = document.getElementById("player-song-title");
+ const songArtist = document.getElementById("player-song-artist");
+ const currentTitle = userData?.currentSong?.title;
+ const currentArtist = userData?.currentSong?.artist;
+
+ playingSong.textContent = currentTitle ? currentTitle : "";
+ songArtist.textContent = currentArtist ? currentArtist : "";
+};
+
+const highlightCurrentSong = () => {
+ const playlistSongElements = document.querySelectorAll(".playlist-song");
+ const songToHighlight = document.getElementById(
+ `song-${userData?.currentSong?.id}`
+ );
+
+ playlistSongElements.forEach((songEl) => {
+ songEl.removeAttribute("aria-current");
+ });
+
+ if (songToHighlight) songToHighlight.setAttribute("aria-current", "true");
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+const setPlayButtonAccessibleText = () => {
+ const song = userData?.currentSong || userData?.songs[0];
+
+ playButton.setAttribute(
+ "aria-label",
+ song?.title ? `Play ${song.title}` : "Play"
+ );
+};
+
+const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+pauseButton.addEventListener("click", pauseSong);
+
+nextButton.addEventListener("click", playNextSong);
+
+previousButton.addEventListener("click", playPreviousSong);
+
+shuffleButton.addEventListener("click", shuffle);
+
+renderSongs(userData?.songs);
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655724bac464795a0ad91082.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655724bac464795a0ad91082.md
new file mode 100644
index 00000000000..35b135022ff
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655724bac464795a0ad91082.md
@@ -0,0 +1,760 @@
+---
+id: 655724bac464795a0ad91082
+title: Step 71
+challengeType: 0
+dashedName: step-71
+---
+
+# --description--
+
+Next, you need to check if the playlist is empty. If it is, you should reset the `userData` object to its original state.
+
+Use an `if` statement to check if the `userData.songs` has a length of `0`.
+
+# --hints--
+
+You should create an empty `if` statement with the condition `userData.songs.length === 0`
+
+```js
+assert.match(code, /if\s*\(userData\.songs\.length\s*===\s*0\)\s*\{\s*\}/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ highlightCurrentSong();
+ setPlayerDisplay();
+ setPlayButtonAccessibleText();
+ audio.play();
+};
+
+const pauseSong = () => {
+ userData.songCurrentTime = audio.currentTime;
+
+ playButton.classList.remove("playing");
+ audio.pause();
+};
+
+const playNextSong = () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ const currentSongIndex = getCurrentSongIndex();
+ const nextSong = userData?.songs[currentSongIndex + 1];
+
+ playSong(nextSong.id);
+ }
+};
+
+const playPreviousSong = () =>{
+ if (userData?.currentSong === null) return;
+ else {
+ const currentSongIndex = getCurrentSongIndex();
+ const previousSong = userData?.songs[currentSongIndex - 1];
+
+ playSong(previousSong.id);
+ }
+};
+
+const shuffle = () => {
+ userData?.songs.sort(() => Math.random() - 0.5);
+ userData.currentSong = null;
+ userData.songCurrentTime = 0;
+
+ renderSongs(userData?.songs);
+ pauseSong();
+ setPlayerDisplay();
+ setPlayButtonAccessibleText();
+};
+
+const deleteSong = (id) => {
+ if (userData?.currentSong?.id === id) {
+ userData.currentSong = null;
+ userData.songCurrentTime = 0;
+
+ pauseSong();
+ setPlayerDisplay();
+ }
+
+ userData.songs = userData?.songs.filter((song) => song.id !== id);
+ renderSongs(userData?.songs);
+ highlightCurrentSong();
+ setPlayButtonAccessibleText();
+
+--fcc-editable-region--
+
+--fcc-editable-region--
+
+};
+
+const setPlayerDisplay = () => {
+ const playingSong = document.getElementById("player-song-title");
+ const songArtist = document.getElementById("player-song-artist");
+ const currentTitle = userData?.currentSong?.title;
+ const currentArtist = userData?.currentSong?.artist;
+
+ playingSong.textContent = currentTitle ? currentTitle : "";
+ songArtist.textContent = currentArtist ? currentArtist : "";
+};
+
+const highlightCurrentSong = () => {
+ const playlistSongElements = document.querySelectorAll(".playlist-song");
+ const songToHighlight = document.getElementById(
+ `song-${userData?.currentSong?.id}`
+ );
+
+ playlistSongElements.forEach((songEl) => {
+ songEl.removeAttribute("aria-current");
+ });
+
+ if (songToHighlight) songToHighlight.setAttribute("aria-current", "true");
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+const setPlayButtonAccessibleText = () => {
+ const song = userData?.currentSong || userData?.songs[0];
+
+ playButton.setAttribute(
+ "aria-label",
+ song?.title ? `Play ${song.title}` : "Play"
+ );
+};
+
+const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+pauseButton.addEventListener("click", pauseSong);
+
+nextButton.addEventListener("click", playNextSong);
+
+previousButton.addEventListener("click", playPreviousSong);
+
+shuffleButton.addEventListener("click", shuffle);
+
+renderSongs(userData?.songs);
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655727b2e1e49d6adf584442.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655727b2e1e49d6adf584442.md
new file mode 100644
index 00000000000..22f07507dab
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655727b2e1e49d6adf584442.md
@@ -0,0 +1,791 @@
+---
+id: 655727b2e1e49d6adf584442
+title: Step 72
+challengeType: 0
+dashedName: step-72
+---
+
+# --description--
+
+If the playlist is empty, you need to create a `resetButton` element and a text for it. This button will only show up if the playlist is empty.
+
+`createElement()` is a DOM method you can use to dynamically create an element using JavaScript. To use `createElement()`, you call it, then pass in the tag name as a string:
+
+```js
+// syntax
+document.createElement(tagName)
+
+// example
+document.createElement('div')
+```
+
+You can also assign it to a variable:
+
+```js
+const divElement = document.createElement('div')
+```
+
+Inside your `if` statement, declare a `resetButton` constant, then use `createElement()` to create a `button`.
+
+
+# --hints--
+
+You should not modify the existing `if` statement and its content.
+
+```js
+assert.match(code, /if\s*\(userData\.songs\.length\s*===\s*0\)\s*\{\s*.*\s*\}/)
+```
+
+You should use the `createElement` method to create a `button`.
+
+```js
+assert.match(code, /document\.createElement\(('|")button\1\);?/)
+```
+
+You should assign your newly created `button` element to a `resetButton` constant.
+
+```js
+assert.match(code, /const\s+resetButton\s*=\s*document\.createElement\(('|")button\1\);?/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ highlightCurrentSong();
+ setPlayerDisplay();
+ setPlayButtonAccessibleText();
+ audio.play();
+};
+
+const pauseSong = () => {
+ userData.songCurrentTime = audio.currentTime;
+
+ playButton.classList.remove("playing");
+ audio.pause();
+};
+
+const playNextSong = () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ const currentSongIndex = getCurrentSongIndex();
+ const nextSong = userData?.songs[currentSongIndex + 1];
+
+ playSong(nextSong.id);
+ }
+};
+
+const playPreviousSong = () => {
+ if (userData?.currentSong === null) return;
+ else {
+ const currentSongIndex = getCurrentSongIndex();
+ const previousSong = userData?.songs[currentSongIndex - 1];
+
+ playSong(previousSong.id);
+ }
+};
+
+const shuffle = () => {
+ userData?.songs.sort(() => Math.random() - 0.5);
+ userData.currentSong = null;
+ userData.songCurrentTime = 0;
+
+ renderSongs(userData?.songs);
+ pauseSong();
+ setPlayerDisplay();
+ setPlayButtonAccessibleText();
+};
+
+const deleteSong = (id) => {
+ if (userData?.currentSong?.id === id) {
+ userData.currentSong = null;
+ userData.songCurrentTime = 0;
+
+ pauseSong();
+ setPlayerDisplay();
+ }
+
+ userData.songs = userData?.songs.filter((song) => song.id !== id);
+ renderSongs(userData?.songs);
+ highlightCurrentSong();
+ setPlayButtonAccessibleText();
+
+--fcc-editable-region--
+ if (userData.songs.length === 0) {
+
+ }
+--fcc-editable-region--
+
+};
+
+const setPlayerDisplay = () => {
+ const playingSong = document.getElementById("player-song-title");
+ const songArtist = document.getElementById("player-song-artist");
+ const currentTitle = userData?.currentSong?.title;
+ const currentArtist = userData?.currentSong?.artist;
+
+ playingSong.textContent = currentTitle ? currentTitle : "";
+ songArtist.textContent = currentArtist ? currentArtist : "";
+};
+
+const highlightCurrentSong = () => {
+ const playlistSongElements = document.querySelectorAll(".playlist-song");
+ const songToHighlight = document.getElementById(
+ `song-${userData?.currentSong?.id}`
+ );
+
+ playlistSongElements.forEach((songEl) => {
+ songEl.removeAttribute("aria-current");
+ });
+
+ if (songToHighlight) songToHighlight.setAttribute("aria-current", "true");
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+const setPlayButtonAccessibleText = () => {
+ const song = userData?.currentSong || userData?.songs[0];
+
+ playButton.setAttribute(
+ "aria-label",
+ song?.title ? `Play ${song.title}` : "Play"
+ );
+};
+
+const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+pauseButton.addEventListener("click", pauseSong);
+
+nextButton.addEventListener("click", playNextSong);
+
+previousButton.addEventListener("click", playPreviousSong);
+
+shuffleButton.addEventListener("click", shuffle);
+
+renderSongs(userData?.songs);
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655729e68e49b277a6b448bd.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655729e68e49b277a6b448bd.md
new file mode 100644
index 00000000000..ae325b157ee
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655729e68e49b277a6b448bd.md
@@ -0,0 +1,779 @@
+---
+id: 655729e68e49b277a6b448bd
+title: Step 74
+challengeType: 0
+dashedName: step-74
+---
+
+# --description--
+
+Now that you've created the `resetButton`, you need to assign it an `id` and `aria-label` attributes. JavaScript provides the `id` and `ariaLabel` properties you need to use for this.
+
+For example, `element.id` would set an `id` attribute, and `element.ariaLabel` would set an `aria-label` attribute. Both of them accept their values as a string.
+
+Set the `id` attribute of `resetButton` to `reset` and its `aria-label` attribute to `Reset playlist`.
+
+# --hints--
+
+You should not modify the existing `if` statement and its content.
+
+```js
+assert.match(code, /if\s*\(userData\.songs\.length\s*===\s*0\)\s*\{\s*const\s+resetButton\s*=\s*document\.createElement\(('|")button\1\);?\s*.*\s*.*\s*.*\s*\}/)
+```
+
+You should use `resetButton.id` to create an `id` attribute named `reset` for the `resetButton`.
+
+```js
+assert.match(code, /resetButton\.id\s*=\s*('|")reset\1/)
+```
+
+You should use `resetButton.ariaLabel` to create an `aria-label` attribute named `Reset playlist` for the `resetButton`.
+
+```js
+assert.match(code, /resetButton\.ariaLabel\s*=\s*('|")Reset\s+playlist\1;?/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ highlightCurrentSong();
+ setPlayerDisplay();
+ setPlayButtonAccessibleText();
+ audio.play();
+};
+
+const pauseSong = () => {
+ userData.songCurrentTime = audio.currentTime;
+
+ playButton.classList.remove("playing");
+ audio.pause();
+};
+
+const playNextSong = () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ const currentSongIndex = getCurrentSongIndex();
+ const nextSong = userData?.songs[currentSongIndex + 1];
+
+ playSong(nextSong.id);
+ }
+};
+
+const playPreviousSong = () => {
+ if (userData?.currentSong === null) return;
+ else {
+ const currentSongIndex = getCurrentSongIndex();
+ const previousSong = userData?.songs[currentSongIndex - 1];
+
+ playSong(previousSong.id);
+ }
+};
+
+const shuffle = () => {
+ userData?.songs.sort(() => Math.random() - 0.5);
+ userData.currentSong = null;
+ userData.songCurrentTime = 0;
+
+ renderSongs(userData?.songs);
+ pauseSong();
+ setPlayerDisplay();
+ setPlayButtonAccessibleText();
+};
+
+const deleteSong = (id) => {
+ if (userData?.currentSong?.id === id) {
+ userData.currentSong = null;
+ userData.songCurrentTime = 0;
+
+ pauseSong();
+ setPlayerDisplay();
+ }
+
+ userData.songs = userData?.songs.filter((song) => song.id !== id);
+ renderSongs(userData?.songs);
+ highlightCurrentSong();
+ setPlayButtonAccessibleText();
+
+--fcc-editable-region--
+ if (userData.songs.length === 0) {
+ const resetButton = document.createElement("button");
+ const resetText = document.createTextNode("Reset Playlist");
+
+
+ }
+--fcc-editable-region--
+
+};
+
+const setPlayerDisplay = () => {
+ const playingSong = document.getElementById("player-song-title");
+ const songArtist = document.getElementById("player-song-artist");
+ const currentTitle = userData?.currentSong?.title;
+ const currentArtist = userData?.currentSong?.artist;
+
+ playingSong.textContent = currentTitle ? currentTitle : "";
+ songArtist.textContent = currentArtist ? currentArtist : "";
+};
+
+const highlightCurrentSong = () => {
+ const playlistSongElements = document.querySelectorAll(".playlist-song");
+ const songToHighlight = document.getElementById(
+ `song-${userData?.currentSong?.id}`
+ );
+
+ playlistSongElements.forEach((songEl) => {
+ songEl.removeAttribute("aria-current");
+ });
+
+ if (songToHighlight) songToHighlight.setAttribute("aria-current", "true");
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+const setPlayButtonAccessibleText = () => {
+ const song = userData?.currentSong || userData?.songs[0];
+
+ playButton.setAttribute(
+ "aria-label",
+ song?.title ? `Play ${song.title}` : "Play"
+ );
+};
+
+const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+pauseButton.addEventListener("click", pauseSong);
+
+nextButton.addEventListener("click", playNextSong);
+
+previousButton.addEventListener("click", playPreviousSong);
+
+shuffleButton.addEventListener("click", shuffle);
+
+renderSongs(userData?.songs);
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65572bb34a7e488224b937fc.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65572bb34a7e488224b937fc.md
new file mode 100644
index 00000000000..6dd0fe3278e
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65572bb34a7e488224b937fc.md
@@ -0,0 +1,795 @@
+---
+id: 65572bb34a7e488224b937fc
+title: Step 75
+challengeType: 0
+dashedName: step-75
+---
+
+# --description--
+
+You need to add the `resetText` to the `resetButton` element as a child, and also the `resetButton` to the `playlistSongs` element as a child. For this, there is an `appendChild()` method to use.
+
+`appendChild()` lets you add a node or an element as the child of another element. In the example below, the text "Click me" would be attached to the button:
+
+```js
+const parentElement = document.createElement("button")
+const parentElementText = document.createTextNode("Click me")
+
+// attach the text "Click me" to the button
+parentElement.appendChild(parentElementText)
+```
+
+Use `appendChild()` to attach `resetText` to `resetButton` element, and `resetButton` to the `playlistSongs` element.
+
+# --hints--
+
+You should use the `appendChild()` method on `resetButton`.
+
+```js
+assert.match(code, /resetButton\.appendChild\(/)
+```
+
+You should pass in `resetText` as the value of your first `appendChild()`.
+
+```js
+assert.match(code, /resetButton\.appendChild\(resetText\);?/)
+```
+
+You should use the `appendChild()` method on `playlistSongs`.
+
+```js
+assert.match(code, /playlistSongs\.appendChild\(/)
+```
+
+You should pass in `resetButton` as the value of your second `appendChild()`.
+
+```js
+assert.match(code, /playlistSongs\.appendChild\(resetButton\);?/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ highlightCurrentSong();
+ setPlayerDisplay();
+ setPlayButtonAccessibleText();
+ audio.play();
+};
+
+const pauseSong = () => {
+ userData.songCurrentTime = audio.currentTime;
+
+ playButton.classList.remove("playing");
+ audio.pause();
+};
+
+const playNextSong = () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ const currentSongIndex = getCurrentSongIndex();
+ const nextSong = userData?.songs[currentSongIndex + 1];
+
+ playSong(nextSong.id);
+ }
+};
+
+const playPreviousSong = () =>{
+ if (userData?.currentSong === null) return;
+ else {
+ const currentSongIndex = getCurrentSongIndex();
+ const previousSong = userData?.songs[currentSongIndex - 1];
+
+ playSong(previousSong.id);
+ }
+};
+
+const shuffle = () => {
+ userData?.songs.sort(() => Math.random() - 0.5);
+ userData.currentSong = null;
+ userData.songCurrentTime = 0;
+
+ renderSongs(userData?.songs);
+ pauseSong();
+ setPlayerDisplay();
+ setPlayButtonAccessibleText();
+};
+
+const deleteSong = (id) => {
+ if (userData?.currentSong?.id === id) {
+ userData.currentSong = null;
+ userData.songCurrentTime = 0;
+
+ pauseSong();
+ setPlayerDisplay();
+ }
+
+ userData.songs = userData?.songs.filter((song) => song.id !== id);
+ renderSongs(userData?.songs);
+ highlightCurrentSong();
+ setPlayButtonAccessibleText();
+
+ if (userData.songs.length === 0) {
+ const resetButton = document.createElement("button");
+ const resetText = document.createTextNode("Reset Playlist");
+
+ resetButton.id = "reset";
+ resetButton.ariaLabel = "Reset playlist";
+--fcc-editable-region--
+
+--fcc-editable-region--
+ }
+
+};
+
+const setPlayerDisplay = () => {
+ const playingSong = document.getElementById("player-song-title");
+ const songArtist = document.getElementById("player-song-artist");
+ const currentTitle = userData?.currentSong?.title;
+ const currentArtist = userData?.currentSong?.artist;
+
+ playingSong.textContent = currentTitle ? currentTitle : "";
+ songArtist.textContent = currentArtist ? currentArtist : "";
+};
+
+const highlightCurrentSong = () => {
+ const playlistSongElements = document.querySelectorAll(".playlist-song");
+ const songToHighlight = document.getElementById(
+ `song-${userData?.currentSong?.id}`
+ );
+
+ playlistSongElements.forEach((songEl) => {
+ songEl.removeAttribute("aria-current");
+ });
+
+ if (songToHighlight) songToHighlight.setAttribute("aria-current", "true");
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+const setPlayButtonAccessibleText = () => {
+ const song = userData?.currentSong || userData?.songs[0];
+
+ playButton.setAttribute(
+ "aria-label",
+ song?.title ? `Play ${song.title}` : "Play"
+ );
+};
+
+const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+pauseButton.addEventListener("click", pauseSong);
+
+nextButton.addEventListener("click", playNextSong);
+
+previousButton.addEventListener("click", playPreviousSong);
+
+shuffleButton.addEventListener("click", shuffle);
+
+renderSongs(userData?.songs);
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65572e5aaf022790fb4a81b1.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65572e5aaf022790fb4a81b1.md
new file mode 100644
index 00000000000..b8104810cfc
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65572e5aaf022790fb4a81b1.md
@@ -0,0 +1,782 @@
+---
+id: 65572e5aaf022790fb4a81b1
+title: Step 76
+challengeType: 0
+dashedName: step-76
+---
+
+# --description--
+
+Now, it's time to add the reset functionality to the `resetButton`. This will bring back the songs in the playlist when clicked.
+
+Add a click event listener to the `resetButton` variable. Pass in a callback using arrow syntax and leave it empty for now.
+
+# --hints--
+
+You should use the `addEventListener()` method on `resetButton`.
+
+```js
+assert.match(code, /resetButton\.addEventListener\(/)
+```
+
+Your `resetButton` event listener should listen for a `click` event.
+
+```js
+assert.match(code, /resetButton\.addEventListener\(('|")click\1/)
+```
+
+The callback function of your event listener should use arrow syntax and have an empty pair of curly braces.
+
+```js
+assert.match(code, /resetButton\.addEventListener\(('|")click\1,\s*\(\)\s*=>\s*\{\s*\}\);?/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ highlightCurrentSong();
+ setPlayerDisplay();
+ setPlayButtonAccessibleText();
+ audio.play();
+};
+
+const pauseSong = () => {
+ userData.songCurrentTime = audio.currentTime;
+
+ playButton.classList.remove("playing");
+ audio.pause();
+};
+
+const playNextSong = () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ const currentSongIndex = getCurrentSongIndex();
+ const nextSong = userData?.songs[currentSongIndex + 1];
+
+ playSong(nextSong.id);
+ }
+};
+
+const playPreviousSong = () =>{
+ if (userData?.currentSong === null) return;
+ else {
+ const currentSongIndex = getCurrentSongIndex();
+ const previousSong = userData?.songs[currentSongIndex - 1];
+
+ playSong(previousSong.id);
+ }
+};
+
+const shuffle = () => {
+ userData?.songs.sort(() => Math.random() - 0.5);
+ userData.currentSong = null;
+ userData.songCurrentTime = 0;
+
+ renderSongs(userData?.songs);
+ pauseSong();
+ setPlayerDisplay();
+ setPlayButtonAccessibleText();
+};
+
+const deleteSong = (id) => {
+ if (userData?.currentSong?.id === id) {
+ userData.currentSong = null;
+ userData.songCurrentTime = 0;
+
+ pauseSong();
+ setPlayerDisplay();
+ }
+
+ userData.songs = userData?.songs.filter((song) => song.id !== id);
+ renderSongs(userData?.songs);
+ highlightCurrentSong();
+ setPlayButtonAccessibleText();
+
+ if (userData.songs.length === 0) {
+ const resetButton = document.createElement("button");
+ const resetText = document.createTextNode("Reset Playlist");
+
+ resetButton.id = "reset";
+ resetButton.ariaLabel = "Reset playlist";
+ resetButton.appendChild(resetText);
+ playlistSongs.appendChild(resetButton);
+
+--fcc-editable-region--
+
+--fcc-editable-region--
+ }
+
+};
+
+const setPlayerDisplay = () => {
+ const playingSong = document.getElementById("player-song-title");
+ const songArtist = document.getElementById("player-song-artist");
+ const currentTitle = userData?.currentSong?.title;
+ const currentArtist = userData?.currentSong?.artist;
+
+ playingSong.textContent = currentTitle ? currentTitle : "";
+ songArtist.textContent = currentArtist ? currentArtist : "";
+};
+
+const highlightCurrentSong = () => {
+ const playlistSongElements = document.querySelectorAll(".playlist-song");
+ const songToHighlight = document.getElementById(
+ `song-${userData?.currentSong?.id}`
+ );
+
+ playlistSongElements.forEach((songEl) => {
+ songEl.removeAttribute("aria-current");
+ });
+
+ if (songToHighlight) songToHighlight.setAttribute("aria-current", "true");
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+const setPlayButtonAccessibleText = () => {
+ const song = userData?.currentSong || userData?.songs[0];
+
+ playButton.setAttribute(
+ "aria-label",
+ song?.title ? `Play ${song.title}` : "Play"
+ );
+};
+
+const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+pauseButton.addEventListener("click", pauseSong);
+
+nextButton.addEventListener("click", playNextSong);
+
+previousButton.addEventListener("click", playPreviousSong);
+
+shuffleButton.addEventListener("click", shuffle);
+
+renderSongs(userData?.songs);
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655737cd004591b0271d6826.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655737cd004591b0271d6826.md
new file mode 100644
index 00000000000..f02c7131cfa
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655737cd004591b0271d6826.md
@@ -0,0 +1,779 @@
+---
+id: 655737cd004591b0271d6826
+title: Step 77
+challengeType: 0
+dashedName: step-77
+---
+
+# --description--
+
+You need to assign the `userData.songs` property to the initial `allSongs` array. This will reset the playlist to its original state.
+
+Spread `allSongs` into an array and assign it to `userData.songs`.
+
+# --hints--
+
+You should not modify the existing event listener and its content.
+
+```js
+assert.match(code, /resetButton\.addEventListener\(('|")click\1,\s*\(\)\s*=>\s*\{\s*.*\s*\}\);?/)
+```
+
+You should assign `[...allSongs]` to `userData.songs`.
+
+```js
+assert.match(code, /userData\.songs\s*=\s*\[\.\.\.allSongs\]/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ highlightCurrentSong();
+ setPlayerDisplay();
+ setPlayButtonAccessibleText();
+ audio.play();
+};
+
+const pauseSong = () => {
+ userData.songCurrentTime = audio.currentTime;
+
+ playButton.classList.remove("playing");
+ audio.pause();
+};
+
+const playNextSong = () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ const currentSongIndex = getCurrentSongIndex();
+ const nextSong = userData?.songs[currentSongIndex + 1];
+
+ playSong(nextSong.id);
+ }
+};
+
+const playPreviousSong = () => {
+ if (userData?.currentSong === null) return;
+ else {
+ const currentSongIndex = getCurrentSongIndex();
+ const previousSong = userData?.songs[currentSongIndex - 1];
+
+ playSong(previousSong.id);
+ }
+};
+
+const shuffle = () => {
+ userData?.songs.sort(() => Math.random() - 0.5);
+ userData.currentSong = null;
+ userData.songCurrentTime = 0;
+
+ renderSongs(userData?.songs);
+ pauseSong();
+ setPlayerDisplay();
+ setPlayButtonAccessibleText();
+};
+
+const deleteSong = (id) => {
+ if (userData?.currentSong?.id === id) {
+ userData.currentSong = null;
+ userData.songCurrentTime = 0;
+
+ pauseSong();
+ setPlayerDisplay();
+ }
+
+ userData.songs = userData?.songs.filter((song) => song.id !== id);
+ renderSongs(userData?.songs);
+ highlightCurrentSong();
+ setPlayButtonAccessibleText();
+
+ if (userData.songs.length === 0) {
+ const resetButton = document.createElement("button");
+ const resetText = document.createTextNode("Reset Playlist");
+
+ resetButton.id = "reset";
+ resetButton.ariaLabel = "Reset playlist";
+ resetButton.appendChild(resetText);
+ playlistSongs.appendChild(resetButton);
+
+--fcc-editable-region--
+ resetButton.addEventListener("click", () => {
+
+ });
+--fcc-editable-region--
+
+ }
+
+};
+
+const setPlayerDisplay = () => {
+ const playingSong = document.getElementById("player-song-title");
+ const songArtist = document.getElementById("player-song-artist");
+ const currentTitle = userData?.currentSong?.title;
+ const currentArtist = userData?.currentSong?.artist;
+
+ playingSong.textContent = currentTitle ? currentTitle : "";
+ songArtist.textContent = currentArtist ? currentArtist : "";
+};
+
+const highlightCurrentSong = () => {
+ const playlistSongElements = document.querySelectorAll(".playlist-song");
+ const songToHighlight = document.getElementById(
+ `song-${userData?.currentSong?.id}`
+ );
+
+ playlistSongElements.forEach((songEl) => {
+ songEl.removeAttribute("aria-current");
+ });
+
+ if (songToHighlight) songToHighlight.setAttribute("aria-current", "true");
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+const setPlayButtonAccessibleText = () => {
+ const song = userData?.currentSong || userData?.songs[0];
+
+ playButton.setAttribute(
+ "aria-label",
+ song?.title ? `Play ${song.title}` : "Play"
+ );
+};
+
+const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+pauseButton.addEventListener("click", pauseSong);
+
+nextButton.addEventListener("click", playNextSong);
+
+previousButton.addEventListener("click", playPreviousSong);
+
+shuffleButton.addEventListener("click", shuffle);
+
+renderSongs(userData?.songs);
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65573a97c59ddbbf028ca95e.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65573a97c59ddbbf028ca95e.md
new file mode 100644
index 00000000000..4540ab905d5
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65573a97c59ddbbf028ca95e.md
@@ -0,0 +1,798 @@
+---
+id: 65573a97c59ddbbf028ca95e
+title: Step 78
+challengeType: 0
+dashedName: step-78
+---
+
+# --description--
+
+Finally, you should render the songs again, update the play button's accessible text, and remove the reset button from the playlist. You also need to remove the `resetButton` from the DOM.
+
+Call the `renderSongs()` function with `userData?.songs` as an argument to render the songs again.
+
+Call the `setPlayButtonAccessibleText()` function to update the play button's accessible text.
+
+Remove the reset button from the playlist by calling the `remove()` method on the `resetButton` variable.
+
+**Note**: Now you can try removing all the songs to see what happens.
+
+# --hints--
+
+You should not modify the existing event listener and its content.
+
+```js
+assert.match(code, /resetButton\.addEventListener\(('|")click\1,\s*\(\)\s*=>\s*\{\s*userData\.songs\s*=\s*\[\.\.\.allSongs\];?\s*.*\s*.*\s*.*\s*\}\);?/)
+```
+
+You should call the `renderSongs` function with `userData?.songs`.
+
+```js
+assert.match(code, /resetButton\.addEventListener\(('|")click\1,\s*\(\)\s*=>\s*\{\s*userData\.songs\s*=\s*\[\.\.\.allSongs\];?\s*renderSongs\(userData\?\.songs\);?\s*.*\s*.*\s*\}\);?/)
+```
+
+You should call the `setPlayButtonAccessibleText` function.
+
+```js
+assert.match(code, /resetButton\.addEventListener\(('|")click\1,\s*\(\)\s*=>\s*\{\s*userData\.songs\s*=\s*\[\.\.\.allSongs\];?\s*renderSongs\(userData\?\.songs\);?\s*setPlayButtonAccessibleText\(\);?\s*.*\s*\}\);?/)
+```
+
+You should use the `remove()` method to remove the `resetButton` from the DOM.
+
+```js
+assert.match(code, /resetButton\.addEventListener\(('|")click\1,\s*\(\)\s*=>\s*\{\s*userData\.songs\s*=\s*\[\.\.\.allSongs\];?\s*renderSongs\(userData\?\.songs\);?\s*setPlayButtonAccessibleText\(\);?\s*resetButton\.remove\(\);?\s*\}\);?/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ highlightCurrentSong();
+ setPlayerDisplay();
+ setPlayButtonAccessibleText();
+ audio.play();
+};
+
+const pauseSong = () => {
+ userData.songCurrentTime = audio.currentTime;
+
+ playButton.classList.remove("playing");
+ audio.pause();
+};
+
+const playNextSong = () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ const currentSongIndex = getCurrentSongIndex();
+ const nextSong = userData?.songs[currentSongIndex + 1];
+
+ playSong(nextSong.id);
+ }
+};
+
+const playPreviousSong = () =>{
+ if (userData?.currentSong === null) return;
+ else {
+ const currentSongIndex = getCurrentSongIndex();
+ const previousSong = userData?.songs[currentSongIndex - 1];
+
+ playSong(previousSong.id);
+ }
+};
+
+const shuffle = () => {
+ userData?.songs.sort(() => Math.random() - 0.5);
+ userData.currentSong = null;
+ userData.songCurrentTime = 0;
+
+ renderSongs(userData?.songs);
+ pauseSong();
+ setPlayerDisplay();
+ setPlayButtonAccessibleText();
+};
+
+const deleteSong = (id) => {
+ if (userData?.currentSong?.id === id) {
+ userData.currentSong = null;
+ userData.songCurrentTime = 0;
+
+ pauseSong();
+ setPlayerDisplay();
+ }
+
+ userData.songs = userData?.songs.filter((song) => song.id !== id);
+ renderSongs(userData?.songs);
+ highlightCurrentSong();
+ setPlayButtonAccessibleText();
+
+ if (userData.songs.length === 0) {
+ const resetButton = document.createElement("button");
+ const resetText = document.createTextNode("Reset Playlist");
+
+ resetButton.id = "reset";
+ resetButton.ariaLabel = "Reset playlist";
+ resetButton.appendChild(resetText);
+ playlistSongs.appendChild(resetButton);
+
+--fcc-editable-region--
+ resetButton.addEventListener("click", () => {
+ userData.songs = [...allSongs];
+
+ });
+--fcc-editable-region--
+
+ }
+
+};
+
+const setPlayerDisplay = () => {
+ const playingSong = document.getElementById("player-song-title");
+ const songArtist = document.getElementById("player-song-artist");
+ const currentTitle = userData?.currentSong?.title;
+ const currentArtist = userData?.currentSong?.artist;
+
+ playingSong.textContent = currentTitle ? currentTitle : "";
+ songArtist.textContent = currentArtist ? currentArtist : "";
+};
+
+const highlightCurrentSong = () => {
+ const playlistSongElements = document.querySelectorAll(".playlist-song");
+ const songToHighlight = document.getElementById(
+ `song-${userData?.currentSong?.id}`
+ );
+
+ playlistSongElements.forEach((songEl) => {
+ songEl.removeAttribute("aria-current");
+ });
+
+ if (songToHighlight) songToHighlight.setAttribute("aria-current", "true");
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+const setPlayButtonAccessibleText = () => {
+ const song = userData?.currentSong || userData?.songs[0];
+
+ playButton.setAttribute(
+ "aria-label",
+ song?.title ? `Play ${song.title}` : "Play"
+ );
+};
+
+const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+pauseButton.addEventListener("click", pauseSong);
+
+nextButton.addEventListener("click", playNextSong);
+
+previousButton.addEventListener("click", playPreviousSong);
+
+shuffleButton.addEventListener("click", shuffle);
+
+renderSongs(userData?.songs);
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65573d0abe4d38cd6fa13f44.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65573d0abe4d38cd6fa13f44.md
new file mode 100644
index 00000000000..a0a2edba876
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65573d0abe4d38cd6fa13f44.md
@@ -0,0 +1,795 @@
+---
+id: 65573d0abe4d38cd6fa13f44
+title: Step 79
+challengeType: 0
+dashedName: step-79
+---
+
+# --description--
+
+All the core functionalities are now in place. The only issue now is that the next song does not automatically play when the currently playing song ends.
+
+To fix that, you can set up an event listener which will detect when the currently playing song ends. The `ended` event listener is appropriate for this. It is fired when the playback of a media reaches the end.
+
+Add an event listener to the `audio` element which listens for the `ended` event. Pass in a callback using arrow syntax with empty curly braces.
+
+# --hints--
+
+You should chain the `addEventListener()` method to your `audio` variable.
+
+```js
+assert.match(code, /audio\.addEventListener\(/)
+```
+
+The event listener you used on on your `audio` variable should listen for an `ended` event.
+
+```js
+assert.match(code, /audio\.addEventListener\(('|")ended\1/)
+```
+
+You should use arrow syntax to pass in an empty callback to your `ended` event listener.
+
+```js
+assert.match(code, /audio\.addEventListener\(('|")ended\1,\s*\(\)\s*=>\s*\{\s*\}\);?/)
+```
+
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ highlightCurrentSong();
+ setPlayerDisplay();
+ setPlayButtonAccessibleText();
+ audio.play();
+};
+
+const pauseSong = () => {
+ userData.songCurrentTime = audio.currentTime;
+
+ playButton.classList.remove("playing");
+ audio.pause();
+};
+
+const playNextSong = () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ const currentSongIndex = getCurrentSongIndex();
+ const nextSong = userData?.songs[currentSongIndex + 1];
+
+ playSong(nextSong.id);
+ }
+};
+
+const playPreviousSong = () => {
+ if (userData?.currentSong === null) return;
+ else {
+ const currentSongIndex = getCurrentSongIndex();
+ const previousSong = userData?.songs[currentSongIndex - 1];
+
+ playSong(previousSong.id);
+ }
+};
+
+const shuffle = () => {
+ userData?.songs.sort(() => Math.random() - 0.5);
+ userData.currentSong = null;
+ userData.songCurrentTime = 0;
+
+ renderSongs(userData?.songs);
+ pauseSong();
+ setPlayerDisplay();
+ setPlayButtonAccessibleText();
+};
+
+const deleteSong = (id) => {
+ if (userData?.currentSong?.id === id) {
+ userData.currentSong = null;
+ userData.songCurrentTime = 0;
+
+ pauseSong();
+ setPlayerDisplay();
+ }
+
+ userData.songs = userData?.songs.filter((song) => song.id !== id);
+ renderSongs(userData?.songs);
+ highlightCurrentSong();
+ setPlayButtonAccessibleText();
+
+ if (userData.songs.length === 0) {
+ const resetButton = document.createElement("button");
+ const resetText = document.createTextNode("Reset Playlist");
+
+ resetButton.id = "reset";
+ resetButton.ariaLabel = "Reset playlist";
+ resetButton.appendChild(resetText);
+ playlistSongs.appendChild(resetButton);
+
+ resetButton.addEventListener("click", () => {
+ userData.songs = [...allSongs];
+
+ renderSongs(userData?.songs);
+ setPlayButtonAccessibleText();
+ resetButton.remove();
+ });
+
+ }
+
+};
+
+const setPlayerDisplay = () => {
+ const playingSong = document.getElementById("player-song-title");
+ const songArtist = document.getElementById("player-song-artist");
+ const currentTitle = userData?.currentSong?.title;
+ const currentArtist = userData?.currentSong?.artist;
+
+ playingSong.textContent = currentTitle ? currentTitle : "";
+ songArtist.textContent = currentArtist ? currentArtist : "";
+};
+
+const highlightCurrentSong = () => {
+ const playlistSongElements = document.querySelectorAll(".playlist-song");
+ const songToHighlight = document.getElementById(
+ `song-${userData?.currentSong?.id}`
+ );
+
+ playlistSongElements.forEach((songEl) => {
+ songEl.removeAttribute("aria-current");
+ });
+
+ if (songToHighlight) songToHighlight.setAttribute("aria-current", "true");
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+const setPlayButtonAccessibleText = () => {
+ const song = userData?.currentSong || userData?.songs[0];
+
+ playButton.setAttribute(
+ "aria-label",
+ song?.title ? `Play ${song.title}` : "Play"
+ );
+};
+
+const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+pauseButton.addEventListener("click", pauseSong);
+
+nextButton.addEventListener("click", playNextSong);
+
+previousButton.addEventListener("click", playPreviousSong);
+
+shuffleButton.addEventListener("click", shuffle);
+
+--fcc-editable-region--
+
+--fcc-editable-region--
+
+renderSongs(userData?.songs);
+setPlayButtonAccessibleText();
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6557421eb6a7a0f0500e3106.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6557421eb6a7a0f0500e3106.md
new file mode 100644
index 00000000000..3f0247cec82
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6557421eb6a7a0f0500e3106.md
@@ -0,0 +1,756 @@
+---
+id: 6557421eb6a7a0f0500e3106
+title: Step 70
+challengeType: 0
+dashedName: step-70
+---
+
+# --description--
+
+Within the button element in the `renderSongs` function, add an `onclick` attribute as the first attribute. For the value, call the `deleteSong` function and interpolate `song.id`.
+
+# --hints--
+
+You should add an `onclick` attribute as the first attribute of the delete button and pass in `deleteSong(${song.id})`.
+
+```js
+assert.match(code, //)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ highlightCurrentSong();
+ setPlayerDisplay();
+ setPlayButtonAccessibleText();
+ audio.play();
+};
+
+const pauseSong = () => {
+ userData.songCurrentTime = audio.currentTime;
+
+ playButton.classList.remove("playing");
+ audio.pause();
+};
+
+const playNextSong = () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ const currentSongIndex = getCurrentSongIndex();
+ const nextSong = userData?.songs[currentSongIndex + 1];
+
+ playSong(nextSong.id);
+ }
+};
+
+const playPreviousSong = () =>{
+ if (userData?.currentSong === null) return;
+ else {
+ const currentSongIndex = getCurrentSongIndex();
+ const previousSong = userData?.songs[currentSongIndex - 1];
+
+ playSong(previousSong.id);
+ }
+};
+
+const shuffle = () => {
+ userData?.songs.sort(() => Math.random() - 0.5);
+ userData.currentSong = null;
+ userData.songCurrentTime = 0;
+
+ renderSongs(userData?.songs);
+ pauseSong();
+ setPlayerDisplay();
+ setPlayButtonAccessibleText();
+};
+
+const deleteSong = (id) => {
+ if (userData?.currentSong?.id === id) {
+ userData.currentSong = null;
+ userData.songCurrentTime = 0;
+
+ pauseSong();
+ setPlayerDisplay();
+ }
+
+ userData.songs = userData?.songs.filter((song) => song.id !== id);
+ renderSongs(userData?.songs);
+ highlightCurrentSong();
+ setPlayButtonAccessibleText();
+
+};
+
+const setPlayerDisplay = () => {
+ const playingSong = document.getElementById("player-song-title");
+ const songArtist = document.getElementById("player-song-artist");
+ const currentTitle = userData?.currentSong?.title;
+ const currentArtist = userData?.currentSong?.artist;
+
+ playingSong.textContent = currentTitle ? currentTitle : "";
+ songArtist.textContent = currentArtist ? currentArtist : "";
+};
+
+const highlightCurrentSong = () => {
+ const playlistSongElements = document.querySelectorAll(".playlist-song");
+ const songToHighlight = document.getElementById(
+ `song-${userData?.currentSong?.id}`
+ );
+
+ playlistSongElements.forEach((songEl) => {
+ songEl.removeAttribute("aria-current");
+ });
+
+ if (songToHighlight) songToHighlight.setAttribute("aria-current", "true");
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+--fcc-editable-region--
+
+
+
+
+--fcc-editable-region--
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+const setPlayButtonAccessibleText = () => {
+ const song = userData?.currentSong || userData?.songs[0];
+
+ playButton.setAttribute(
+ "aria-label",
+ song?.title ? `Play ${song.title}` : "Play"
+ );
+};
+
+const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+pauseButton.addEventListener("click", pauseSong);
+
+nextButton.addEventListener("click", playNextSong);
+
+previousButton.addEventListener("click", playPreviousSong);
+
+shuffleButton.addEventListener("click", shuffle);
+
+renderSongs(userData?.songs);
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655b49333d9f265bc1512152.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655b49333d9f265bc1512152.md
new file mode 100644
index 00000000000..bd6689cf747
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655b49333d9f265bc1512152.md
@@ -0,0 +1,761 @@
+---
+id: 655b49333d9f265bc1512152
+title: Step 80
+challengeType: 0
+dashedName: step-80
+---
+
+# --description--
+
+Notice that the album art in the HTML and songs in the `allSongs` array have changed. We've swapped out the original songs for shorter ones that you can use to test your app in the upcoming steps.
+
+Next, you need to check if there is a next song to play. Retrieve the current song index by calling the `getCurrentSongIndex()` function, and save it in a `currentSongIndex` constant.
+
+After that, create a `nextSongExists` constant that checks if a next song exists.
+
+# --hints--
+
+You should not modify the existing `ended` event listener and its content.
+
+```js
+assert.match(code, /audio\.addEventListener\(('|")ended\1,\s*\(\)\s*=>\s*\{\s*.*\s*.*\s*\}\);?/)
+```
+
+You should create a `currentSongIndex` constant and set it to the calling of the `getCurrentSongIndex` function.
+
+```js
+assert.match(code, /audio\.addEventListener\(('|")ended\1,\s*\(\)\s*=>\s*\{\s*const\s+currentSongIndex\s*=\s*getCurrentSongIndex\(\);?\s*.*\s*\}\);?/)
+```
+
+You should check if a next song exists with `userData?.songs[currentSongIndex + 1] !== undefined` and set it to a `nextSongExists` constant.
+
+```js
+assert.match(code, /const\s+nextSongExists\s*=\s*userData\?\.songs\[currentSongIndex\s*\+\s*1\]\s*!==\s*undefined;?/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Hello World",
+ artist: "RafaelDavisH",
+ duration: "0:23",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/hello-world.mp3",
+ },
+ {
+ id: 1,
+ title: "In the Zone",
+ artist: "RafaelDavisH",
+ duration: "0:11",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/in-the-zone.mp3",
+ },
+ {
+ id: 2,
+ title: "Camper Cat",
+ artist: "RafaelDavisH",
+ duration: "0:21",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/camper-cat.mp3",
+ },
+ {
+ id: 3,
+ title: "Electronic",
+ artist: "RafaelDavisH",
+ duration: "0:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/electronic.mp3",
+ },
+ {
+ id: 4,
+ title: "Sailing Away",
+ artist: "RafaelDavisH",
+ duration: "0:22",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/sailing-away.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ highlightCurrentSong();
+ setPlayerDisplay();
+ setPlayButtonAccessibleText();
+ audio.play();
+};
+
+const pauseSong = () => {
+ userData.songCurrentTime = audio.currentTime;
+
+ playButton.classList.remove("playing");
+ audio.pause();
+};
+
+const playNextSong = () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ const currentSongIndex = getCurrentSongIndex();
+ const nextSong = userData?.songs[currentSongIndex + 1];
+
+ playSong(nextSong.id);
+ }
+};
+
+const playPreviousSong = () => {
+ if (userData?.currentSong === null) return;
+ else {
+ const currentSongIndex = getCurrentSongIndex();
+ const previousSong = userData?.songs[currentSongIndex - 1];
+
+ playSong(previousSong.id);
+ }
+};
+
+const shuffle = () => {
+ userData?.songs.sort(() => Math.random() - 0.5);
+ userData.currentSong = null;
+ userData.songCurrentTime = 0;
+
+ renderSongs(userData?.songs);
+ pauseSong();
+ setPlayerDisplay();
+ setPlayButtonAccessibleText();
+};
+
+const deleteSong = (id) => {
+ if (userData?.currentSong?.id === id) {
+ userData.currentSong = null;
+ userData.songCurrentTime = 0;
+
+ pauseSong();
+ setPlayerDisplay();
+ }
+
+ userData.songs = userData?.songs.filter((song) => song.id !== id);
+ renderSongs(userData?.songs);
+ highlightCurrentSong();
+ setPlayButtonAccessibleText();
+
+ if (userData.songs.length === 0) {
+ const resetButton = document.createElement("button");
+ const resetText = document.createTextNode("Reset Playlist");
+
+ resetButton.id = "reset";
+ resetButton.ariaLabel = "Reset playlist";
+ resetButton.appendChild(resetText);
+ playlistSongs.appendChild(resetButton);
+
+ resetButton.addEventListener("click", () => {
+ userData.songs = [...allSongs];
+
+ renderSongs(userData?.songs);
+ setPlayButtonAccessibleText();
+ resetButton.remove();
+ });
+
+ }
+
+};
+
+const setPlayerDisplay = () => {
+ const playingSong = document.getElementById("player-song-title");
+ const songArtist = document.getElementById("player-song-artist");
+ const currentTitle = userData?.currentSong?.title;
+ const currentArtist = userData?.currentSong?.artist;
+
+ playingSong.textContent = currentTitle ? currentTitle : "";
+ songArtist.textContent = currentArtist ? currentArtist : "";
+};
+
+const highlightCurrentSong = () => {
+ const playlistSongElements = document.querySelectorAll(".playlist-song");
+ const songToHighlight = document.getElementById(
+ `song-${userData?.currentSong?.id}`
+ );
+
+ playlistSongElements.forEach((songEl) => {
+ songEl.removeAttribute("aria-current");
+ });
+
+ if (songToHighlight) songToHighlight.setAttribute("aria-current", "true");
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+const setPlayButtonAccessibleText = () => {
+ const song = userData?.currentSong || userData?.songs[0];
+
+ playButton.setAttribute(
+ "aria-label",
+ song?.title ? `Play ${song.title}` : "Play"
+ );
+};
+
+const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+pauseButton.addEventListener("click", pauseSong);
+
+nextButton.addEventListener("click", playNextSong);
+
+previousButton.addEventListener("click", playPreviousSong);
+
+shuffleButton.addEventListener("click", shuffle);
+
+--fcc-editable-region--
+audio.addEventListener("ended", () => {
+
+});
+--fcc-editable-region--
+
+renderSongs(userData?.songs);
+setPlayButtonAccessibleText();
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655b4bbff1dbf66cb2ed4dac.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655b4bbff1dbf66cb2ed4dac.md
new file mode 100644
index 00000000000..819b3807d15
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655b4bbff1dbf66cb2ed4dac.md
@@ -0,0 +1,753 @@
+---
+id: 655b4bbff1dbf66cb2ed4dac
+title: Step 81
+challengeType: 0
+dashedName: step-81
+---
+
+# --description--
+
+Use an `if` statement to check if `nextSongExists` exists, then call the `playNextSong()` function in the `if` block. This will automatically play the next song when the current song ends.
+
+# --hints--
+
+You should create an `if` statment with the condition `nextSongExists`.
+
+```js
+assert.match(code, /if\s*\(nextSongExists\)\s*\{\s*/)
+```
+
+You should call the `playNextSong` function inside your `if` statement.
+
+```js
+assert.match(code, /if\s*\(nextSongExists\)\s*\{\s*playNextSong\(\);?\s*\}/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Hello World",
+ artist: "RafaelDavisH",
+ duration: "0:23",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/hello-world.mp3",
+ },
+ {
+ id: 1,
+ title: "In the Zone",
+ artist: "RafaelDavisH",
+ duration: "0:11",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/in-the-zone.mp3",
+ },
+ {
+ id: 2,
+ title: "Camper Cat",
+ artist: "RafaelDavisH",
+ duration: "0:21",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/camper-cat.mp3",
+ },
+ {
+ id: 3,
+ title: "Electronic",
+ artist: "RafaelDavisH",
+ duration: "0:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/electronic.mp3",
+ },
+ {
+ id: 4,
+ title: "Sailing Away",
+ artist: "RafaelDavisH",
+ duration: "0:22",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/sailing-away.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ highlightCurrentSong();
+ setPlayerDisplay();
+ setPlayButtonAccessibleText();
+ audio.play();
+};
+
+const pauseSong = () => {
+ userData.songCurrentTime = audio.currentTime;
+
+ playButton.classList.remove("playing");
+ audio.pause();
+};
+
+const playNextSong = () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ const currentSongIndex = getCurrentSongIndex();
+ const nextSong = userData?.songs[currentSongIndex + 1];
+
+ playSong(nextSong.id);
+ }
+};
+
+const playPreviousSong = () => {
+ if (userData?.currentSong === null) return;
+ else {
+ const currentSongIndex = getCurrentSongIndex();
+ const previousSong = userData?.songs[currentSongIndex - 1];
+
+ playSong(previousSong.id);
+ }
+};
+
+const shuffle = () => {
+ userData?.songs.sort(() => Math.random() - 0.5);
+ userData.currentSong = null;
+ userData.songCurrentTime = 0;
+
+ renderSongs(userData?.songs);
+ pauseSong();
+ setPlayerDisplay();
+ setPlayButtonAccessibleText();
+};
+
+const deleteSong = (id) => {
+ if (userData?.currentSong?.id === id) {
+ userData.currentSong = null;
+ userData.songCurrentTime = 0;
+
+ pauseSong();
+ setPlayerDisplay();
+ }
+
+ userData.songs = userData?.songs.filter((song) => song.id !== id);
+ renderSongs(userData?.songs);
+ highlightCurrentSong();
+ setPlayButtonAccessibleText();
+
+ if (userData.songs.length === 0) {
+ const resetButton = document.createElement("button");
+ const resetText = document.createTextNode("Reset Playlist");
+
+ resetButton.id = "reset";
+ resetButton.ariaLabel = "Reset playlist";
+ resetButton.appendChild(resetText);
+ playlistSongs.appendChild(resetButton);
+
+ resetButton.addEventListener("click", () => {
+ userData.songs = [...allSongs];
+
+ renderSongs(userData?.songs);
+ setPlayButtonAccessibleText();
+ resetButton.remove();
+ });
+
+ }
+
+};
+
+const setPlayerDisplay = () => {
+ const playingSong = document.getElementById("player-song-title");
+ const songArtist = document.getElementById("player-song-artist");
+ const currentTitle = userData?.currentSong?.title;
+ const currentArtist = userData?.currentSong?.artist;
+
+ playingSong.textContent = currentTitle ? currentTitle : "";
+ songArtist.textContent = currentArtist ? currentArtist : "";
+};
+
+const highlightCurrentSong = () => {
+ const playlistSongElements = document.querySelectorAll(".playlist-song");
+ const songToHighlight = document.getElementById(
+ `song-${userData?.currentSong?.id}`
+ );
+
+ playlistSongElements.forEach((songEl) => {
+ songEl.removeAttribute("aria-current");
+ });
+
+ if (songToHighlight) songToHighlight.setAttribute("aria-current", "true");
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+const setPlayButtonAccessibleText = () => {
+ const song = userData?.currentSong || userData?.songs[0];
+
+ playButton.setAttribute(
+ "aria-label",
+ song?.title ? `Play ${song.title}` : "Play"
+ );
+};
+
+const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+pauseButton.addEventListener("click", pauseSong);
+
+nextButton.addEventListener("click", playNextSong);
+
+previousButton.addEventListener("click", playPreviousSong);
+
+shuffleButton.addEventListener("click", shuffle);
+
+audio.addEventListener("ended", () => {
+ const currentSongIndex = getCurrentSongIndex();
+ const nextSongExists = userData?.songs[currentSongIndex + 1] !== undefined;
+--fcc-editable-region--
+
+--fcc-editable-region--
+});
+
+renderSongs(userData?.songs);
+setPlayButtonAccessibleText();
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655b4c8f636d9675953a0388.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655b4c8f636d9675953a0388.md
new file mode 100644
index 00000000000..3b75e62c99c
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655b4c8f636d9675953a0388.md
@@ -0,0 +1,769 @@
+---
+id: 655b4c8f636d9675953a0388
+title: Step 82
+challengeType: 0
+dashedName: step-82
+---
+
+# --description--
+
+If there is no next song in the playlist, use the `else` block to reset the `currentSong` key of `userData` to null, and its `songCurrentTime` property to `0`.
+
+# --hints--
+
+You should not modify the existing `if` statement and its content.
+
+```js
+assert.match(code, /if\s*\(nextSongExists\)\s*\{\s*playNextSong\(\);?\s*.*\s*.*\s*.*\s*\};?/)
+```
+
+Your `if` statement should have an `else` block.
+
+```js
+assert.match(code, /if\s*\(nextSongExists\)\s*\{\s*playNextSong\(\);?\s*\}\s*else\s*\{\s*.*\s*.*\s*\};?/)
+```
+
+You should use dot notation to set the `currentSong` property of `userData` to `null` in the `else` block of your `if` statement.
+
+```js
+assert.match(code, /if\s*\(nextSongExists\)\s*\{\s*playNextSong\(\);?\s*\}\s*else\s*\{\s*userData\.currentSong\s*=\s*null;?\s*.*\s*\};?/)
+```
+
+You should use dot notation to set the `songCurrentTime` property of `userData` to `0` in the `else` block of your `if`statement.
+
+```js
+assert.match(code, /if\s*\(nextSongExists\)\s*\{\s*playNextSong\(\);?\s*\}\s*else\s*\{\s*userData\.currentSong\s*=\s*null;?\s*userData\.songCurrentTime\s*=\s*0;?\s*\};?/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Hello World",
+ artist: "RafaelDavisH",
+ duration: "0:23",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/hello-world.mp3",
+ },
+ {
+ id: 1,
+ title: "In the Zone",
+ artist: "RafaelDavisH",
+ duration: "0:11",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/in-the-zone.mp3",
+ },
+ {
+ id: 2,
+ title: "Camper Cat",
+ artist: "RafaelDavisH",
+ duration: "0:21",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/camper-cat.mp3",
+ },
+ {
+ id: 3,
+ title: "Electronic",
+ artist: "RafaelDavisH",
+ duration: "0:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/electronic.mp3",
+ },
+ {
+ id: 4,
+ title: "Sailing Away",
+ artist: "RafaelDavisH",
+ duration: "0:22",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/sailing-away.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ highlightCurrentSong();
+ setPlayerDisplay();
+ setPlayButtonAccessibleText();
+ audio.play();
+};
+
+const pauseSong = () => {
+ userData.songCurrentTime = audio.currentTime;
+
+ playButton.classList.remove("playing");
+ audio.pause();
+};
+
+const playNextSong = () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ const currentSongIndex = getCurrentSongIndex();
+ const nextSong = userData?.songs[currentSongIndex + 1];
+
+ playSong(nextSong.id);
+ }
+};
+
+const playPreviousSong = () =>{
+ if (userData?.currentSong === null) return;
+ else {
+ const currentSongIndex = getCurrentSongIndex();
+ const previousSong = userData?.songs[currentSongIndex - 1];
+
+ playSong(previousSong.id);
+ }
+};
+
+const shuffle = () => {
+ userData?.songs.sort(() => Math.random() - 0.5);
+ userData.currentSong = null;
+ userData.songCurrentTime = 0;
+
+ renderSongs(userData?.songs);
+ pauseSong();
+ setPlayerDisplay();
+ setPlayButtonAccessibleText();
+};
+
+const deleteSong = (id) => {
+ if (userData?.currentSong?.id === id) {
+ userData.currentSong = null;
+ userData.songCurrentTime = 0;
+
+ pauseSong();
+ setPlayerDisplay();
+ }
+
+ userData.songs = userData?.songs.filter((song) => song.id !== id);
+ renderSongs(userData?.songs);
+ highlightCurrentSong();
+ setPlayButtonAccessibleText();
+
+ if (userData.songs.length === 0) {
+ const resetButton = document.createElement("button");
+ const resetText = document.createTextNode("Reset Playlist");
+
+ resetButton.id = "reset";
+ resetButton.ariaLabel = "Reset playlist";
+ resetButton.appendChild(resetText);
+ playlistSongs.appendChild(resetButton);
+
+ resetButton.addEventListener("click", () => {
+ userData.songs = [...allSongs];
+
+ renderSongs(userData?.songs);
+ setPlayButtonAccessibleText();
+ resetButton.remove();
+ });
+
+ }
+
+};
+
+const setPlayerDisplay = () => {
+ const playingSong = document.getElementById("player-song-title");
+ const songArtist = document.getElementById("player-song-artist");
+ const currentTitle = userData?.currentSong?.title;
+ const currentArtist = userData?.currentSong?.artist;
+
+ playingSong.textContent = currentTitle ? currentTitle : "";
+ songArtist.textContent = currentArtist ? currentArtist : "";
+};
+
+const highlightCurrentSong = () => {
+ const playlistSongElements = document.querySelectorAll(".playlist-song");
+ const songToHighlight = document.getElementById(
+ `song-${userData?.currentSong?.id}`
+ );
+
+ playlistSongElements.forEach((songEl) => {
+ songEl.removeAttribute("aria-current");
+ });
+
+ if (songToHighlight) songToHighlight.setAttribute("aria-current", "true");
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+const setPlayButtonAccessibleText = () => {
+ const song = userData?.currentSong || userData?.songs[0];
+
+ playButton.setAttribute(
+ "aria-label",
+ song?.title ? `Play ${song.title}` : "Play"
+ );
+};
+
+const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+pauseButton.addEventListener("click", pauseSong);
+
+nextButton.addEventListener("click", playNextSong);
+
+previousButton.addEventListener("click", playPreviousSong);
+
+shuffleButton.addEventListener("click", shuffle);
+
+audio.addEventListener("ended", () => {
+ const currentSongIndex = getCurrentSongIndex();
+ const nextSongExists = userData?.songs[currentSongIndex + 1] !== undefined;
+
+--fcc-editable-region--
+ if (nextSongExists) {
+ playNextSong();
+ }
+
+--fcc-editable-region--
+});
+
+renderSongs(userData?.songs);
+setPlayButtonAccessibleText();
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655b4dad1d38ff7cdd65cbfe.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655b4dad1d38ff7cdd65cbfe.md
new file mode 100644
index 00000000000..a9987ccc07e
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655b4dad1d38ff7cdd65cbfe.md
@@ -0,0 +1,1515 @@
+---
+id: 655b4dad1d38ff7cdd65cbfe
+title: Step 83
+challengeType: 0
+dashedName: step-83
+---
+
+# --description--
+
+With everything set in place, call the `pauseSong()`, `setPlayerDisplay()`, `highlightCurrentSong()`, and `setPlayButtonAccessibleText()` functions to correctly update the player.
+
+Congratulations! Your music player is now complete. You still have the shorter songs for testing, but if you'd like to listen to the original songs, you can copy them from an earlier step and paste them into the `allSongs` array.
+
+# --hints--
+
+You should call the `pauseSong` function.
+
+```js
+const splitter = code.split('audio.addEventListener("ended", () => {')
+assert.match(splitter[1], /pauseSong\(\);?/)
+```
+
+You should call the `setPlayerDisplay` function.
+
+```js
+const splitter = code.split('audio.addEventListener("ended", () => {')
+assert.match(splitter[1], /setPlayerDisplay\(\);?/)
+```
+
+You should call the `highlightCurrentSong` function.
+
+```js
+const splitter = code.split('audio.addEventListener("ended", () => {')
+assert.match(splitter[1], /highlightCurrentSong\(\);?/)
+```
+
+You should call the `setPlayButtonAccessibleText` function.
+
+```js
+const splitter = code.split('audio.addEventListener("ended", () => {')
+assert.match(splitter[1], /highlightCurrentSong\(\);?\s*setPlayButtonAccessibleText\(\);?/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Hello World",
+ artist: "RafaelDavisH",
+ duration: "0:23",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/hello-world.mp3",
+ },
+ {
+ id: 1,
+ title: "In the Zone",
+ artist: "RafaelDavisH",
+ duration: "0:11",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/in-the-zone.mp3",
+ },
+ {
+ id: 2,
+ title: "Camper Cat",
+ artist: "RafaelDavisH",
+ duration: "0:21",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/camper-cat.mp3",
+ },
+ {
+ id: 3,
+ title: "Electronic",
+ artist: "RafaelDavisH",
+ duration: "0:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/electronic.mp3",
+ },
+ {
+ id: 4,
+ title: "Sailing Away",
+ artist: "RafaelDavisH",
+ duration: "0:22",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/sailing-away.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ highlightCurrentSong();
+ setPlayerDisplay();
+ setPlayButtonAccessibleText();
+ audio.play();
+};
+
+const pauseSong = () => {
+ userData.songCurrentTime = audio.currentTime;
+
+ playButton.classList.remove("playing");
+ audio.pause();
+};
+
+const playNextSong = () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ const currentSongIndex = getCurrentSongIndex();
+ const nextSong = userData?.songs[currentSongIndex + 1];
+
+ playSong(nextSong.id);
+ }
+};
+
+const playPreviousSong = () =>{
+ if (userData?.currentSong === null) return;
+ else {
+ const currentSongIndex = getCurrentSongIndex();
+ const previousSong = userData?.songs[currentSongIndex - 1];
+
+ playSong(previousSong.id);
+ }
+};
+
+const shuffle = () => {
+ userData?.songs.sort(() => Math.random() - 0.5);
+ userData.currentSong = null;
+ userData.songCurrentTime = 0;
+
+ renderSongs(userData?.songs);
+ pauseSong();
+ setPlayerDisplay();
+ setPlayButtonAccessibleText();
+};
+
+const deleteSong = (id) => {
+ if (userData?.currentSong?.id === id) {
+ userData.currentSong = null;
+ userData.songCurrentTime = 0;
+
+ pauseSong();
+ setPlayerDisplay();
+ }
+
+ userData.songs = userData?.songs.filter((song) => song.id !== id);
+ renderSongs(userData?.songs);
+ highlightCurrentSong();
+ setPlayButtonAccessibleText();
+
+ if (userData.songs.length === 0) {
+ const resetButton = document.createElement("button");
+ const resetText = document.createTextNode("Reset Playlist");
+
+ resetButton.id = "reset";
+ resetButton.ariaLabel = "Reset playlist";
+ resetButton.appendChild(resetText);
+ playlistSongs.appendChild(resetButton);
+
+ resetButton.addEventListener("click", () => {
+ userData.songs = [...allSongs];
+
+ renderSongs(userData?.songs);
+ setPlayButtonAccessibleText();
+ resetButton.remove();
+ });
+
+ }
+
+};
+
+const setPlayerDisplay = () => {
+ const playingSong = document.getElementById("player-song-title");
+ const songArtist = document.getElementById("player-song-artist");
+ const currentTitle = userData?.currentSong?.title;
+ const currentArtist = userData?.currentSong?.artist;
+
+ playingSong.textContent = currentTitle ? currentTitle : "";
+ songArtist.textContent = currentArtist ? currentArtist : "";
+};
+
+const highlightCurrentSong = () => {
+ const playlistSongElements = document.querySelectorAll(".playlist-song");
+ const songToHighlight = document.getElementById(
+ `song-${userData?.currentSong?.id}`
+ );
+
+ playlistSongElements.forEach((songEl) => {
+ songEl.removeAttribute("aria-current");
+ });
+
+ if (songToHighlight) songToHighlight.setAttribute("aria-current", "true");
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+const setPlayButtonAccessibleText = () => {
+ const song = userData?.currentSong || userData?.songs[0];
+
+ playButton.setAttribute(
+ "aria-label",
+ song?.title ? `Play ${song.title}` : "Play"
+ );
+};
+
+const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+pauseButton.addEventListener("click", pauseSong);
+
+nextButton.addEventListener("click", playNextSong);
+
+previousButton.addEventListener("click", playPreviousSong);
+
+shuffleButton.addEventListener("click", shuffle);
+
+audio.addEventListener("ended", () => {
+ const currentSongIndex = getCurrentSongIndex();
+ const nextSongExists = userData?.songs[currentSongIndex + 1] !== undefined;
+
+ if (nextSongExists) {
+ playNextSong();
+ } else {
+ userData.currentSong = null;
+ userData.songCurrentTime = 0;
+--fcc-editable-region--
+
+
+--fcc-editable-region--
+ }
+});
+
+renderSongs(userData?.songs);
+setPlayButtonAccessibleText();
+```
+
+# --solutions--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Hello World",
+ artist: "RafaelDavisH",
+ duration: "0:23",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/hello-world.mp3",
+ },
+ {
+ id: 1,
+ title: "In the Zone",
+ artist: "RafaelDavisH",
+ duration: "0:11",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/in-the-zone.mp3",
+ },
+ {
+ id: 2,
+ title: "Camper Cat",
+ artist: "RafaelDavisH",
+ duration: "0:21",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/camper-cat.mp3",
+ },
+ {
+ id: 3,
+ title: "Electronic",
+ artist: "RafaelDavisH",
+ duration: "0:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/electronic.mp3",
+ },
+ {
+ id: 4,
+ title: "Sailing Away",
+ artist: "RafaelDavisH",
+ duration: "0:22",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/sailing-away.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ highlightCurrentSong();
+ setPlayerDisplay();
+ setPlayButtonAccessibleText();
+ audio.play();
+};
+
+const pauseSong = () => {
+ userData.songCurrentTime = audio.currentTime;
+
+ playButton.classList.remove("playing");
+ audio.pause();
+};
+
+const playNextSong = () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ const currentSongIndex = getCurrentSongIndex();
+ const nextSong = userData?.songs[currentSongIndex + 1];
+
+ playSong(nextSong.id);
+ }
+};
+
+const playPreviousSong = () =>{
+ if (userData?.currentSong === null) return;
+ else {
+ const currentSongIndex = getCurrentSongIndex();
+ const previousSong = userData?.songs[currentSongIndex - 1];
+
+ playSong(previousSong.id);
+ }
+};
+
+const shuffle = () => {
+ userData?.songs.sort(() => Math.random() - 0.5);
+ userData.currentSong = null;
+ userData.songCurrentTime = 0;
+
+ renderSongs(userData?.songs);
+ pauseSong();
+ setPlayerDisplay();
+ setPlayButtonAccessibleText();
+};
+
+const deleteSong = (id) => {
+ if (userData?.currentSong?.id === id) {
+ userData.currentSong = null;
+ userData.songCurrentTime = 0;
+
+ pauseSong();
+ setPlayerDisplay();
+ }
+
+ userData.songs = userData?.songs.filter((song) => song.id !== id);
+ renderSongs(userData?.songs);
+ highlightCurrentSong();
+ setPlayButtonAccessibleText();
+
+ if (userData.songs.length === 0) {
+ const resetButton = document.createElement("button");
+ const resetText = document.createTextNode("Reset Playlist");
+
+ resetButton.id = "reset";
+ resetButton.ariaLabel = "Reset playlist";
+ resetButton.appendChild(resetText);
+ playlistSongs.appendChild(resetButton);
+
+ resetButton.addEventListener("click", () => {
+ userData.songs = [...allSongs];
+
+ renderSongs(userData?.songs);
+ setPlayButtonAccessibleText();
+ resetButton.remove();
+ });
+
+ }
+
+};
+
+const setPlayerDisplay = () => {
+ const playingSong = document.getElementById("player-song-title");
+ const songArtist = document.getElementById("player-song-artist");
+ const currentTitle = userData?.currentSong?.title;
+ const currentArtist = userData?.currentSong?.artist;
+
+ playingSong.textContent = currentTitle ? currentTitle : "";
+ songArtist.textContent = currentArtist ? currentArtist : "";
+};
+
+const highlightCurrentSong = () => {
+ const playlistSongElements = document.querySelectorAll(".playlist-song");
+ const songToHighlight = document.getElementById(
+ `song-${userData?.currentSong?.id}`
+ );
+
+ playlistSongElements.forEach((songEl) => {
+ songEl.removeAttribute("aria-current");
+ });
+
+ if (songToHighlight) songToHighlight.setAttribute("aria-current", "true");
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+const setPlayButtonAccessibleText = () => {
+ const song = userData?.currentSong || userData?.songs[0];
+
+ playButton.setAttribute(
+ "aria-label",
+ song?.title ? `Play ${song.title}` : "Play"
+ );
+};
+
+const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+pauseButton.addEventListener("click", pauseSong);
+
+nextButton.addEventListener("click", playNextSong);
+
+previousButton.addEventListener("click", playPreviousSong);
+
+shuffleButton.addEventListener("click", shuffle);
+
+audio.addEventListener("ended", () => {
+ const currentSongIndex = getCurrentSongIndex();
+ const nextSongExists = userData?.songs[currentSongIndex + 1] !== undefined;
+
+ if (nextSongExists) {
+ playNextSong();
+ } else {
+ userData.currentSong = null;
+ userData.songCurrentTime = 0;
+
+ pauseSong();
+ setPlayerDisplay();
+ highlightCurrentSong();
+ setPlayButtonAccessibleText();
+ }
+});
+
+renderSongs(userData?.songs);
+setPlayButtonAccessibleText();
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655dc43318591b975cdfe2d8.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655dc43318591b975cdfe2d8.md
new file mode 100644
index 00000000000..68b1fbbab97
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655dc43318591b975cdfe2d8.md
@@ -0,0 +1,576 @@
+---
+id: 655dc43318591b975cdfe2d8
+title: Step 4
+challengeType: 0
+dashedName: step-4
+---
+
+# --description--
+
+Inside the `allSongs` array, create an object with the following properties and values:
+
+```js
+id: 0,
+title: "Scratching The Surface",
+artist: "Quincy Larson",
+duration: "4:25",
+src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+```
+
+# --hints--
+
+Your `allSongs` array should have one value.
+
+```js
+assert.equal(allSongs.length, 1);
+```
+
+Your `allSongs` array should have an object as its first value.
+
+```js
+assert.isObject(allSongs[0]);
+```
+
+Your `allSongs` array should have an object with an `id` property set to the number `0`.
+
+```js
+assert.equal(allSongs[0].id, 0);
+```
+
+Your `allSongs` array should have an object with a `title` property set to the string `Scratching The Surface`.
+
+```js
+assert.equal(allSongs[0].title, "Scratching The Surface");
+```
+
+Your `allSongs` array should have an object with an `artist` property set to the string `Quincy Larson`.
+
+```js
+assert.equal(allSongs[0].artist, "Quincy Larson");
+```
+
+Your `allSongs` array should have an object with a `duration` property set to the string `4:25`.
+
+```js
+assert.equal(allSongs[0].duration, "4:25");
+```
+
+Your `allSongs` array should have an object with an `src` property set to the string `https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3`.
+
+```js
+assert.equal(allSongs[0].src, "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3");
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+--fcc-editable-region--
+
+--fcc-editable-region--
+];
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65606d06666e118ba86162be.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65606d06666e118ba86162be.md
new file mode 100644
index 00000000000..01af8592a30
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65606d06666e118ba86162be.md
@@ -0,0 +1,584 @@
+---
+id: 65606d06666e118ba86162be
+title: Step 5
+challengeType: 0
+dashedName: step-5
+---
+
+# --description--
+
+Add a second object with the following keys and values:
+
+```js
+id: 1,
+title: "Can't Stay Down",
+artist: "Quincy Larson",
+duration: "4:15",
+src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+```
+
+# --hints--
+
+Your `allSongs` array should have two values.
+
+```js
+assert.equal(allSongs.length, 2);
+```
+
+Your `allSongs` array should have an object as its second value.
+
+```js
+assert.isObject(allSongs[1]);
+```
+
+The second object in your `allSongs` array should have an `id` property set to the number `1`.
+
+```js
+assert.equal(allSongs[1].id, 1);
+```
+
+The second object in your `allSongs` array should have a `title` property set to the string `Can't Stay Down`.
+
+```js
+assert.equal(allSongs[1].title, "Can't Stay Down");
+```
+
+The second object in your `allSongs` array should have an `artist` property set to the string `Quincy Larson`.
+
+```js
+assert.equal(allSongs[1].artist, "Quincy Larson");
+```
+
+The second object in your `allSongs` array should have a `duration` property set to the string `4:15`.
+
+```js
+assert.equal(allSongs[1].duration, "4:15");
+```
+
+The second object in your `allSongs` array should have an `src` property set to the string `https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3`.
+
+```js
+assert.equal(allSongs[1].src, "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3");
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+
+--fcc-editable-region--
+
+--fcc-editable-region--
+];
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65606ed6ea2baca053327e9b.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65606ed6ea2baca053327e9b.md
new file mode 100644
index 00000000000..305a1d7b573
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65606ed6ea2baca053327e9b.md
@@ -0,0 +1,586 @@
+---
+id: 65606ed6ea2baca053327e9b
+title: Step 6
+challengeType: 0
+dashedName: step-6
+---
+
+# --description--
+
+Add a third object with the following properties and values:
+
+```js
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+```
+
+# --hints--
+
+Your `allSongs` array should have an object as its third value.
+
+```js
+assert.isObject(allSongs[2]);
+```
+
+The third object in your `allSongs` array should have an `id` property set to the number `2`.
+
+```js
+assert.equal(allSongs[2].id, 2);
+```
+
+The third object in your `allSongs` array should have a `title` property set to the string `Still Learning`.
+
+```js
+assert.equal(allSongs[2].title, "Still Learning");
+```
+
+The third object in your `allSongs` array should have an `artist` property set to the string `Quincy Larson`.
+
+```js
+assert.equal(allSongs[2].artist, "Quincy Larson");
+```
+
+The third object in your `allSongs` array should have a `duration` property set to the string `4:15`.
+
+```js
+assert.equal(allSongs[2].duration, "3:51");
+```
+
+The third object in your `allSongs` array should have an `src` property set to the string `https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3`.
+
+```js
+assert.equal(allSongs[2].src, "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3");
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+
+--fcc-editable-region--
+
+--fcc-editable-region--
+];
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/656071d679089ebd9d5035a0.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/656071d679089ebd9d5035a0.md
new file mode 100644
index 00000000000..fa17aed79ae
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/656071d679089ebd9d5035a0.md
@@ -0,0 +1,618 @@
+---
+id: 656071d679089ebd9d5035a0
+title: Step 9
+challengeType: 0
+dashedName: step-9
+---
+
+# --description--
+
+Now you should update the `userData` object to include a `songs` property. For this you will be using the `spread` operator.
+
+The spread operator `...` allows you to create a new array by copying all the elements from an existing array into another array. In the example below, both, `arr1` and `arr2` have been spread into `combinedArr`:
+
+```js
+const arr1 = [1, 2, 3];
+const arr2 = [4, 5, 6];
+
+const combinedArr = [...arr1, ...arr2];
+console.log(combinedArr); // Output: [1, 2, 3, 4, 5, 6]
+```
+
+Inside the `userData` object create a `songs` property. For the value spread `allSongs` into an array.
+
+# --hints--
+
+Your `userData` object should have a `songs` key set to `[...allSongs]`.
+
+```js
+assert.match(code, /songs:\s*\[\.\.\.allSongs\],?/);
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+--fcc-editable-region--
+let userData = {
+
+};
+--fcc-editable-region--
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/656073a2b98232c8aca72267.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/656073a2b98232c8aca72267.md
new file mode 100644
index 00000000000..dbc320e4302
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/656073a2b98232c8aca72267.md
@@ -0,0 +1,620 @@
+---
+id: 656073a2b98232c8aca72267
+title: Step 10
+challengeType: 0
+dashedName: step-10
+---
+
+# --description--
+
+To handle the current song's information and track the song's playback time, create a `currentSong` and `songCurrentTime` properties. Set the values to `null` and `0` respectively.
+
+# --hints--
+
+You should not modify the existing `userData` object and its content.
+
+```js
+assert.match(code, /let\s*userData\s*=\s*\{\s*songs:\s*\[\.\.\.allSongs\],?\s*/);
+```
+
+Your `userData` object should have a `currentSong` key set to `null`.
+
+```js
+assert.propertyVal(userData, "currentSong", null)
+```
+
+Your `userData` object should have a `songCurrentTime` key set to `0`.
+
+```js
+assert.propertyVal(userData, "songCurrentTime", 0)
+```
+
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+--fcc-editable-region--
+let userData = {
+ songs: [...allSongs],
+
+};
+--fcc-editable-region--
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/656472ed8f552d2f2b3f7883.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/656472ed8f552d2f2b3f7883.md
new file mode 100644
index 00000000000..618b4e2bc15
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/656472ed8f552d2f2b3f7883.md
@@ -0,0 +1,659 @@
+---
+id: 656472ed8f552d2f2b3f7883
+title: Step 24
+challengeType: 0
+dashedName: step-24
+---
+
+# --description--
+
+Add an `else` block to handle the current song's position in the playlist.
+
+Within the `else` block, set the `currentTime` property of the `audio` object to the value stored in `userData.songCurrentTime`.
+
+# --hints--
+
+You should not modify the existing `if` statement and its content.
+
+```js
+assert.match(code, /if\s*\(userData\?\.currentSong\s*===\s*null\s*\|\|\s*userData\?\.currentSong\.id\s*!==\s*song\.id\)\s*\{\s*audio\.currentTime\s*=\s*0;?\s*\}/)
+```
+
+You should add an `else` block to the existing `if` block.
+
+```js
+assert.match(code, /if\s*\(userData\?\.currentSong\s*===\s*null\s*\|\|\s*userData\?\.currentSong\.id\s*!==\s*song\.id\)\s*\{\s*audio\.currentTime\s*=\s*0;?\s*\}\s*else\s{/)
+```
+
+You should set `audio.currentTime` to `userData.songCurrentTime` inside the `else` block of your `if` statement.
+
+```js
+assert.match(code, /if\s*\(userData\?\.currentSong\s*===\s*null\s*\|\|\s*userData\?\.currentSong\.id\s*!==\s*song\.id\)\s*\{\s*audio\.currentTime\s*=\s*0;?\s*\}\s*else\s{\s*audio\.currentTime\s*=\s*userData\.songCurrentTime;?\s*\}/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+--fcc-editable-region--
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ }
+
+
+--fcc-editable-region--
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+renderSongs(userData?.songs);
+
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6567055f59d39f07d1c542dc.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6567055f59d39f07d1c542dc.md
new file mode 100644
index 00000000000..04bdebd08ca
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6567055f59d39f07d1c542dc.md
@@ -0,0 +1,634 @@
+---
+id: 6567055f59d39f07d1c542dc
+title: Step 18
+challengeType: 0
+dashedName: step-18
+---
+
+# --description--
+
+Next, you will need to update the playlist in your HTML document to display the songs.
+
+Add `songsHTML` to `playlistSongs`, by using the `innerHTML` property. This will insert the `li` element you just created into the `ul` element in the already provided `HTML` file.
+
+# --hints--
+
+You should use the `innerHTML` property to add `songsHTML` to `playlistSongs`.
+
+```js
+assert.match(code, /playlistSongs\.innerHTML\s*=\s*songsHTML;?/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+--fcc-editable-region--
+
+--fcc-editable-region--
+};
+
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65671421254eeb489875cdd8.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65671421254eeb489875cdd8.md
new file mode 100644
index 00000000000..9eec8b6486f
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65671421254eeb489875cdd8.md
@@ -0,0 +1,711 @@
+---
+id: 65671421254eeb489875cdd8
+title: Step 48
+challengeType: 0
+dashedName: step-48
+---
+
+# --description--
+
+Within the callback function, use the `removeAttribute()` method to remove the `"aria-current"` attribute. This will remove the attribute for each of the songs.
+
+# --hints--
+
+You should not modify the existing `forEach()` and its content.
+
+```js
+assert.match(code, /playlistSongElements\.forEach\(\(songEl\)\s*=>\s*\{\s*/)
+```
+
+You should use the `removeAttribute()` method on `songEl` and pass in `"aria-current"`.
+
+```js
+assert.match(code, /playlistSongElements\.forEach\(\(songEl\)\s*=>\s*\{\s*songEl\.removeAttribute\(('|")aria-current\1\);?\s*\}\);?/)
+```
+
+
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ audio.play();
+};
+
+const pauseSong = () => {
+ userData.songCurrentTime = audio.currentTime;
+
+ playButton.classList.remove("playing");
+ audio.pause();
+};
+
+const playNextSong = () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ const currentSongIndex = getCurrentSongIndex();
+ const nextSong = userData?.songs[currentSongIndex + 1];
+
+ playSong(nextSong.id);
+ }
+};
+
+const playPreviousSong = () => {
+ if (userData?.currentSong === null) return;
+ else {
+ const currentSongIndex = getCurrentSongIndex();
+ const previousSong = userData?.songs[currentSongIndex - 1];
+
+ playSong(previousSong.id);
+ }
+};
+
+const highlightCurrentSong = () => {
+ const playlistSongElements = document.querySelectorAll(".playlist-song");
+ const songToHighlight = document.getElementById(
+ `song-${userData?.currentSong?.id}`
+ );
+
+--fcc-editable-region--
+ playlistSongElements.forEach((songEl) => {
+
+ });
+--fcc-editable-region--
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+pauseButton.addEventListener("click", pauseSong);
+
+nextButton.addEventListener("click", playNextSong);
+
+previousButton.addEventListener("click", playPreviousSong);
+
+renderSongs(userData?.songs);
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65672136535209761a5cf02b.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65672136535209761a5cf02b.md
new file mode 100644
index 00000000000..eeeba9e0374
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65672136535209761a5cf02b.md
@@ -0,0 +1,660 @@
+---
+id: 65672136535209761a5cf02b
+title: Step 30
+challengeType: 0
+dashedName: step-30
+---
+
+# --description--
+
+To play the song anytime the user clicks on it, add an `onclick` attribute to the first button element. Inside the `onclick`, call the `playSong` function with `song.id`.
+
+Don't forget you need to interpolate with the dollar sign here.
+
+# --hints--
+
+You should add an `onclick` with the value `playSong(${song.id})` as the second attribute and value of the `button` element.
+
+```js
+assert.match(code, /\s*\$\{song\.title\}<\/span>\s*\$\{song\.artist\}<\/span>\s*\$\{song\.duration\}<\/span>\s*<\/button>/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ audio.play();
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+--fcc-editable-region--
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+--fcc-editable-region--
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ }else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+
+renderSongs(userData?.songs);
+
+```
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65672adafbaa37a6cef886f7.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65672adafbaa37a6cef886f7.md
new file mode 100644
index 00000000000..2c938e89234
--- /dev/null
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65672adafbaa37a6cef886f7.md
@@ -0,0 +1,788 @@
+---
+id: 65672adafbaa37a6cef886f7
+title: Step 73
+challengeType: 0
+dashedName: step-73
+---
+
+# --description--
+
+Now that you've created the button, you need to assign it a text. To do this, you need to use the `createTextNode()` method of DOM.
+
+The `createTextNode()` method is used to create a text node. To use it, you call it and pass in the text as a string:
+
+```js
+document.createTextNode("your text")
+```
+
+You can also assign it to a variable:
+
+```js
+const myText = document.createTextNode("your text")
+```
+
+Use the `createTextNode()` method to create a `Reset Playlist` text, then assign it to a `resetText` constant.
+
+# --hints--
+
+You should not modify the existing `if` statement and its content.
+
+```js
+assert.match(code, /if\s*\(userData\.songs\.length\s*===\s*0\)\s*\{\s*const\s+resetButton\s*=\s*document\.createElement\(('|")button\1\);?\s*.*\s*\}/)
+```
+
+You should use `document.createTextNode()` to create a `Reset Playlist` text.
+
+```js
+assert.match(code, /document\.createTextNode\(('|")Reset\s+Playlist\1\);?/)
+```
+
+You should assign your created text node to a `resetText` constant.
+
+```js
+assert.match(code, /const\s+resetText\s*=\s*document\.createTextNode\(('|")Reset\s+Playlist\1\);?/)
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+
+
+
+
+
+
+
+
+ Learn Basic String and Array Methods by Building a Music Player App
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```css
+:root {
+ /* colors */
+ --primary-color: #dfdfe2;
+ --secondary-color: #ffffff;
+ --app-background-color: #4d4d62;
+ --background-color: #1b1b32;
+ --foreground-color: #3b3b4f;
+ --highlight-color: #f1be32;
+
+ /* font sizes */
+ --root-font-size: 16px;
+ font-size: var(--root-font-size);
+
+ /* font-families */
+ --font-headline: "Roboto Mono", monospace;
+ --font-family: "Lato", sans-serif;
+}
+
+*,
+*::after,
+*::before {
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--app-background-color);
+ color: var(--primary-color);
+ font-family: var(--font-family);
+}
+
+h1 {
+ font-size: 1.125rem;
+ line-height: 1.6;
+}
+
+h2 {
+ font-size: var(--root-font-size);
+}
+
+ul {
+ margin: 0;
+}
+
+.container {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 5px;
+}
+
+.player,
+.playlist {
+ width: 450px;
+ background-color: var(--background-color);
+ border: 3px solid var(--foreground-color);
+}
+
+.player {
+ height: 260px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+.player-bar,
+.playlist-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 5px;
+ width: 100%;
+ height: 30px;
+ background-color: var(--foreground-color);
+}
+
+.parallel-lines {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 6px;
+ padding: 0 5px;
+}
+
+.parallel-lines > div {
+ height: 2px;
+ width: 100%;
+ min-width: 75px;
+ background-color: var(--highlight-color);
+}
+
+.fcc-title,
+.playlist-title {
+ color: var(--secondary-color);
+ margin: 0 10px;
+ font-family: var(--font-headline);
+}
+
+.player-content {
+ display: flex;
+ background-color: var(--foreground-color);
+ width: 430px;
+ height: 200px;
+ column-gap: 13px;
+ align-items: center;
+ justify-content: center;
+}
+
+#player-album-art {
+ background-color: var(--secondary-color);
+ border: 6px solid var(--background-color);
+}
+
+#player-album-art img {
+ width: 150px;
+ display: block;
+}
+
+.player-display {
+ display: flex;
+ flex-direction: column;
+ row-gap: 20px;
+ padding: 14px;
+ background-color: var(--background-color);
+ height: 153px;
+ width: 226px;
+}
+
+.player-display-song-artist {
+ height: 80px;
+}
+
+.player-buttons svg {
+ fill: var(--primary-color);
+}
+
+.playing > svg {
+ fill: var(--highlight-color);
+}
+
+.player-buttons {
+ display: flex;
+ justify-content: space-around;
+}
+
+button {
+ background: transparent;
+ border: none;
+ color: var(--primary-color);
+ cursor: pointer;
+ font-size: var(--root-font-size);
+ outline-color: var(--highlight-color);
+ text-align: center;
+}
+
+.playlist-song {
+ outline-color: var(--highlight-color);
+}
+
+.playlist li:not(:last-child) {
+ border-bottom: 1px solid var(--background-color);
+}
+
+button:focus,
+.playlist-song:focus {
+ outline-style: dashed;
+ outline-width: 2px;
+}
+
+/* Playlist */
+.playlist {
+ height: auto;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 10px;
+}
+
+#playlist-songs {
+ width: 430px;
+ height: 100%;
+ background-color: var(--foreground-color);
+ display: flex;
+ flex-direction: column;
+ row-gap: 8px;
+ padding: 8px 9px;
+ visibility: visible;
+ justify-content: start;
+ list-style: none;
+}
+
+.playlist-song {
+ display: flex;
+ height: 55px;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px;
+}
+
+[aria-current="true"] {
+ background-color: var(--background-color);
+}
+
+[aria-current="true"] p {
+ color: var(--highlight-color);
+}
+
+.playlist-song-info {
+ height: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-around;
+ column-gap: 7px;
+ padding: 5px 0;
+ font-family: var(--font-family);
+}
+
+#player-song-title,
+#player-song-artist {
+ margin: 0;
+}
+
+#player-song-artist {
+ color: var(--highlight-color);
+ font-size: 0.75rem;
+}
+
+#player-song-title {
+ font-size: 1.125rem;
+}
+
+.playlist-song-title {
+ font-size: 0.85rem;
+ width: 241px;
+ text-align: left;
+}
+
+.playlist-song-artist {
+ font-size: 0.725rem;
+ width: 80px;
+}
+
+.playlist-song-duration {
+ font-size: 0.725rem;
+ margin: auto;
+ font-family: var(--font-headline);
+ width: 30px;
+}
+
+.playlist-song-delete {
+ padding: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.playlist-song-delete,
+.playlist-song-delete {
+ fill: var(--foreground-color);
+}
+
+.playlist-song-delete:hover circle,
+.playlist-song-delete:focus circle {
+ fill: #ff0000;
+}
+
+@media (max-width: 700px) {
+ .player,
+ .playlist {
+ width: 300px;
+ }
+
+ .player {
+ height: 340px;
+ }
+
+ #playlist-songs {
+ height: 280px;
+ padding: 5px 6px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scrollbar-color: var(--background-color) var(--secondary-color);
+ scrollbar-width: thin;
+ }
+
+ #playlist-songs::-webkit-scrollbar {
+ width: 5px;
+ }
+
+ #playlist-songs::-webkit-scrollbar-track {
+ background: var(--background-color);
+ }
+
+ #playlist-songs::-webkit-scrollbar-thumb {
+ background: var(--secondary-color);
+ }
+
+ h1 {
+ font-size: 0.813rem;
+ }
+
+ h2 {
+ font-size: 0.75rem;
+ }
+
+ .player-bar,
+ .playlist-bar,
+ .player-content,
+ #playlist-songs {
+ width: 280px;
+ }
+
+ .playlist-song {
+ justify-content: space-between;
+ }
+
+ .playlist-song-title {
+ width: 140px;
+ }
+
+ .playlist-song-artist {
+ width: 40px;
+ }
+
+ .playlist-song-duration > button {
+ padding: 0;
+ }
+
+ .player-content {
+ display: inline;
+ position: relative;
+ justify-items: center;
+ height: 100%;
+ }
+
+ #player-album-art {
+ z-index: -100;
+ height: 280px;
+ box-shadow: none;
+ background: #000;
+ }
+
+ #player-album-art img {
+ width: 100%;
+ opacity: 0.6;
+ }
+
+ .player-display-song-artist {
+ padding: 0 10px;
+ }
+
+ .player-display-song-artist > p {
+ white-space: pre-wrap;
+ }
+
+ .player-display {
+ position: absolute;
+ width: 100%;
+ z-index: 1000;
+ background-color: transparent;
+ top: 0;
+ height: 280px;
+ justify-content: space-between;
+ text-align: center;
+ }
+}
+```
+
+```js
+const playlistSongs = document.getElementById("playlist-songs");
+const playButton = document.getElementById("play");
+const pauseButton = document.getElementById("pause");
+const nextButton = document.getElementById("next");
+const previousButton = document.getElementById("previous");
+const shuffleButton = document.getElementById("shuffle");
+
+const allSongs = [
+ {
+ id: 0,
+ title: "Scratching The Surface",
+ artist: "Quincy Larson",
+ duration: "4:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3",
+ },
+ {
+ id: 1,
+ title: "Can't Stay Down",
+ artist: "Quincy Larson",
+ duration: "4:15",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3",
+ },
+ {
+ id: 2,
+ title: "Still Learning",
+ artist: "Quincy Larson",
+ duration: "3:51",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3",
+ },
+ {
+ id: 3,
+ title: "Cruising for a Musing",
+ artist: "Quincy Larson",
+ duration: "3:34",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3",
+ },
+ {
+ id: 4,
+ title: "Never Not Favored",
+ artist: "Quincy Larson",
+ duration: "3:35",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3",
+ },
+ {
+ id: 5,
+ title: "From the Ground Up",
+ artist: "Quincy Larson",
+ duration: "3:12",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3",
+ },
+ {
+ id: 6,
+ title: "Walking on Air",
+ artist: "Quincy Larson",
+ duration: "3:25",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3",
+ },
+ {
+ id: 7,
+ title: "Can't Stop Me. Can't Even Slow Me Down.",
+ artist: "Quincy Larson",
+ duration: "3:52",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3",
+ },
+ {
+ id: 8,
+ title: "The Surest Way Out is Through",
+ artist: "Quincy Larson",
+ duration: "3:10",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3",
+ },
+ {
+ id: 9,
+ title: "Chasing That Feeling",
+ artist: "Quincy Larson",
+ duration: "2:43",
+ src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3",
+ },
+];
+
+const audio = new Audio();
+let userData = {
+ songs: [...allSongs],
+ currentSong: null,
+ songCurrentTime: 0,
+};
+
+const playSong = (id) => {
+ const song = userData?.songs.find((song) => song.id === id);
+ audio.src = song.src;
+ audio.title = song.title;
+
+ if (userData?.currentSong === null || userData?.currentSong.id !== song.id) {
+ audio.currentTime = 0;
+ } else {
+ audio.currentTime = userData.songCurrentTime;
+ }
+ userData.currentSong = song;
+ playButton.classList.add("playing");
+
+ highlightCurrentSong();
+ setPlayerDisplay();
+ setPlayButtonAccessibleText();
+ audio.play();
+};
+
+const pauseSong = () => {
+ userData.songCurrentTime = audio.currentTime;
+
+ playButton.classList.remove("playing");
+ audio.pause();
+};
+
+const playNextSong = () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ const currentSongIndex = getCurrentSongIndex();
+ const nextSong = userData?.songs[currentSongIndex + 1];
+
+ playSong(nextSong.id);
+ }
+};
+
+const playPreviousSong = () => {
+ if (userData?.currentSong === null) return;
+ else {
+ const currentSongIndex = getCurrentSongIndex();
+ const previousSong = userData?.songs[currentSongIndex - 1];
+
+ playSong(previousSong.id);
+ }
+};
+
+const shuffle = () => {
+ userData?.songs.sort(() => Math.random() - 0.5);
+ userData.currentSong = null;
+ userData.songCurrentTime = 0;
+
+ renderSongs(userData?.songs);
+ pauseSong();
+ setPlayerDisplay();
+ setPlayButtonAccessibleText();
+};
+
+const deleteSong = (id) => {
+ if (userData?.currentSong?.id === id) {
+ userData.currentSong = null;
+ userData.songCurrentTime = 0;
+
+ pauseSong();
+ setPlayerDisplay();
+ }
+
+ userData.songs = userData?.songs.filter((song) => song.id !== id);
+ renderSongs(userData?.songs);
+ highlightCurrentSong();
+ setPlayButtonAccessibleText();
+
+--fcc-editable-region--
+ if (userData.songs.length === 0) {
+ const resetButton = document.createElement("button");
+
+
+ }
+--fcc-editable-region--
+
+};
+
+const setPlayerDisplay = () => {
+ const playingSong = document.getElementById("player-song-title");
+ const songArtist = document.getElementById("player-song-artist");
+ const currentTitle = userData?.currentSong?.title;
+ const currentArtist = userData?.currentSong?.artist;
+
+ playingSong.textContent = currentTitle ? currentTitle : "";
+ songArtist.textContent = currentArtist ? currentArtist : "";
+};
+
+const highlightCurrentSong = () => {
+ const playlistSongElements = document.querySelectorAll(".playlist-song");
+ const songToHighlight = document.getElementById(
+ `song-${userData?.currentSong?.id}`
+ );
+
+ playlistSongElements.forEach((songEl) => {
+ songEl.removeAttribute("aria-current");
+ });
+
+ if (songToHighlight) songToHighlight.setAttribute("aria-current", "true");
+};
+
+const renderSongs = (array) => {
+ const songsHTML = array
+ .map((song)=> {
+ return `
+
+
+ ${song.title}
+ ${song.artist}
+ ${song.duration}
+
+
+
+
+
+
+ `;
+ })
+ .join("");
+
+ playlistSongs.innerHTML = songsHTML;
+};
+
+const setPlayButtonAccessibleText = () => {
+ const song = userData?.currentSong || userData?.songs[0];
+
+ playButton.setAttribute(
+ "aria-label",
+ song?.title ? `Play ${song.title}` : "Play"
+ );
+};
+
+const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);
+
+playButton.addEventListener("click", () => {
+ if (userData?.currentSong === null) {
+ playSong(userData?.songs[0].id);
+ } else {
+ playSong(userData?.currentSong.id);
+ }
+});
+
+pauseButton.addEventListener("click", pauseSong);
+
+nextButton.addEventListener("click", playNextSong);
+
+previousButton.addEventListener("click", playPreviousSong);
+
+shuffleButton.addEventListener("click", shuffle);
+
+renderSongs(userData?.songs);
+```