diff --git a/Part 13 - Preparation/README.md b/Part 13 - Preparation/README.md
new file mode 100644
index 0000000..af1a047
--- /dev/null
+++ b/Part 13 - Preparation/README.md
@@ -0,0 +1,80 @@
+PERTEMUAN DARK LORD
+Halo, akhirnya kita ketemu. kalian excited kan belajar sama @Dark Lord. Gua yang bakal mentorin kalian sampe phase 3, jadi siap siap kalian bakal kangen banget sama @Harkon | Helper .
+karna harkon udah ga bisa bantu kalian lagi di stage ini hahahaha 😈
+
+Sesampainya kalian disini, berarti kalian sudah menyelesaikan Live Code Phase 0 dan dinyatakan lulus oleh @Harkon | Helper.
+Congratss buat kalian semua yang sampai stage ini 🔥 🔥
+
+Phase 0 itu tidak mudah, gua tau betul perjuangan kalian untuk handle quiz quiz konyol di area phase 0, belum lagi stuck ga nemu nemu jawaban, burn out, kepala pusing, rasa mau muntah stonksss, makanya kalian harus bangga dengan apa yang kalian lalui di phase ini. kalian sudah dapat role @Bisa Ngoding dan kita anggap sudah punya bekal fundamental logic yang lumayan kuat.
+
+Kita expect kalian tidak lagi melakukan error error kecil seperti typo, infinte loop, type undefined, lupa save code, posisi indentasi dan segala macam newbie error. Karna di phase 1 kalian tidak punya waktu banyak untuk handle error error kecil seperti itu.
+dan juga di phase 1 kalian bakal lebih mandiri, ga seperti diphase 0 yang masih di guide @Harkon | Helper dan dibantu secara flow sampai codenya. Kalian akan lebih explore sendiri dan membaca dokumentasi dari setiap materi yang ada (inilah proses awakening kalian di phase 1).
+EXPLORE ADALAH HAL YANG PALING KUAT DI DUNIA PROGRAMMING
+Skill Explore ini bakal ke unlock di phase 1, dan kalian akan pake ini berkali kali sebagai senjata di RPN dari phase 1 - 3.
+
+NEXT STEP
+Sebenarnya dari bekal Phase 0 kalian sudah bisa hajar tugas tugas perkuliahan dengan mudah, karena bahasa pemrograman yang lain syntax nya ga jauh beda. kalian cukup cek dokumentasi bahasa yang lain harus nya langsung mengerti untuk mengerjakan soal dengan bahasa tersebut.
+
+Dan juga kalian sudah ready untuk ngambil path apapun, kalau bosan dengan self learning kalian boleh mencoba bootcamp high level seperti Hacktiv8 or purwadhika, atau bagi yang kuliah bisa mencoba google bangkit & Apple Academy saat semester 6-7.
+(alias mending belajar di RPN 👨🏻🌾 )
+
+NO FLEXING -> TEACHING HABBIT
+Kalian akan merasa lebih jago dari pada newbie newbie, dari tim sepuh RPN kami mohon kepada kalian yang sudah menempuh level ini, ketimbang flexing atau memandang rendah orang lain akan lebih baik mengajar dan membantunya agar ilmu ini bermanfaat.
+
+ADA APA SAJA DI PHASE 1 ?
+Di phase 1 kalian akan belajar tentang backend development. Inilah mengapa kalian awal belajar di RPN memakai Node Js bukan memakai javascript. karena :
+
+JavaScript: Ini adalah bahasa pemrograman yang digunakan untuk membuat interaksi dinamis di dalam browser. Awalnya diciptakan untuk menjadikan halaman web lebih interaktif dengan melakukan perubahan pada elemen HTML dan CSS setelah halaman selesai dimuat.
+
+sedangkan Node Js : Ini adalah lingkungan runtime yang dibangun di atas mesin V8 JavaScript yang dikembangkan oleh Google. Node.js memungkinkan Anda menjalankan JavaScript di luar lingkungan browser, yaitu pada server. Dengan Node.js, Anda dapat membangun aplikasi berbasis server, mengelola berkas, dan berbagai tugas lainnya.
+
+Jadi Node Js itu bahasa yang di gunakan untuk backend development seperti bahasa backend lain kayak PHP, Java, Golang, Rust, Ruby. Kalian harus sudah mengerti disini bahwa html , css adalah bukan bahasa pemrograman okey.
+
+Karena kalian sudah familiar dengan runtime NodeJs maka kita bakal explore lebih banyak power NodeJs ini di Phase 1 dan memakai berbagai macam senjatanya NodeJs buat Backend Development.
+
+
+
+
+
+APA ITU BACKEND DEVELOPMENT ?
+
+Backend development adalah proses pengembangan dan pembangunan komponen dari sebuah aplikasi perangkat lunak yang berfokus pada sisi server. Ini melibatkan pembuatan dan pengelolaan bagian aplikasi yang bertanggung jawab untuk pemrosesan data, logika bisnis, interaksi dengan basis data, dan penyediaan layanan kepada klien atau frontend.
+
+Pada dasarnya, ada dua komponen utama dalam pengembangan perangkat lunak:
+
+Frontend (Sisi Klien): Ini adalah bagian aplikasi yang diakses oleh pengguna akhir. Ini termasuk antarmuka pengguna (UI), interaksi pengguna, dan tampilan yang terlihat oleh pengguna di browser atau aplikasi.
+
+Backend (Sisi Server): Ini adalah bagian aplikasi yang berada di server dan bertanggung jawab atas logika bisnis, pemrosesan data, interaksi dengan basis data, otorisasi, otentikasi, dan berbagai tugas lainnya yang tidak terlihat oleh pengguna akhir tetapi penting untuk menjalankan aplikasi dengan benar.
+
+Tugas utama dalam backend development meliputi:
+
+Pengembangan Server: Membangun server web atau aplikasi menggunakan teknologi seperti Node.js, Python, Java, Ruby, atau bahasa backend lainnya.
+
+Pemrosesan Data: Memproses permintaan dari klien, menjalankan logika bisnis, memanipulasi data, dan menghasilkan respons yang tepat.
+
+Interaksi Basis Data: Berkomunikasi dengan basis data (seperti MySQL, PostgreSQL, MongoDB) untuk menyimpan, mengambil, dan mengelola data aplikasi.
+
+Keamanan: Mengimplementasikan otorisasi (pengaturan izin), otentikasi (verifikasi identitas pengguna), dan langkah-langkah keamanan lainnya untuk melindungi data dan sistem.
+
+API (Application Programming Interface): Membangun dan mengelola API yang memungkinkan frontend dan aplikasi lain berkomunikasi dengan backend.
+
+Pengelolaan Permintaan: Mengelola lalu lintas permintaan dari pengguna, memastikan skala dan kinerja yang baik.
+
+Caching: Menggunakan teknik caching untuk mempercepat akses ke data dengan menyimpan hasil permintaan sebelumnya.
+
+Manajemen Sesi: Melacak sesi pengguna, baik melalui cookie, token, atau mekanisme lainnya.
+
+Backend development sangat penting karena bertanggung jawab atas pengelolaan data, keamanan, dan logika bisnis yang mendukung aplikasi. Frontend dan backend harus bekerja bersama untuk memberikan pengalaman pengguna yang mulus dan fungsional.
+
+
+
+
+BUTUH PERSIAPAN APA SEBELUM PHASE 1 ?
+
+Ada beberapa hal yang harus kita lakukan dulu sebelum belajar di phase 1.
+
+JavaScript ES6 : Karena di phase 1 kita bakal memakai teknologi modern, maka kita harus upgrade syntax kita juga untuk adaptasi build in function terbaru.
+
+Introduction Web Development : Phase 1 ini akan berhubungan dengan Phase 2, makanya kita perlu tahu sedikit tentang web development dasar. kita akan belajar sedikit tentang Html, Css dan Javascript untuk membuat website interaktif sederhana. dan berkenalan dengan DOM Javascript.
+
+English (reading) : Ini ga wajib, tapi kalo kalian punya skill english reading yang lumayan kuat akan sangat membantu di phase 1. Karena di phase 1 kalian sering explore berbagai dokumentasi - dokumentasi pemrograman dan itu biasanya menggunakan english.
\ No newline at end of file
diff --git a/Part 14 - JavaScript ES6/README.md b/Part 14 - JavaScript ES6/README.md
new file mode 100644
index 0000000..9020701
--- /dev/null
+++ b/Part 14 - JavaScript ES6/README.md
@@ -0,0 +1,84 @@
+ES6 (ECMAScript 2015)
+adalah versi dari bahasa pemrograman JavaScript yang menghadirkan banyak fitur baru dan peningkatan sintaksis. Salah satu peningkatan utama dalam ES6 adalah diperkenalkannya arrow function yang sangat bermanfaat dalam memanipulasi array.
+
+Berikut adalah beberapa fitur ES6 dan contoh penggunaan array function:
+
+Arrow Functions
+Arrow functions adalah cara singkat untuk mendefinisikan fungsi dalam JavaScript. Mereka memiliki sintaks yang lebih pendek dan lebih mudah dibaca daripada fungsi biasa.
+
+Contoh:
+// Fungsi biasa
+function multiply(a, b) {
+ return a * b;
+}
+
+// Arrow function
+const multiply = (a, b) => a * b;
+
+
+Let dan Const
+let dan const adalah pengganti var dalam ES6. let digunakan untuk mendeklarasikan variabel yang nilainya dapat diubah, sedangkan const digunakan untuk variabel yang nilainya tidak bisa diubah setelah dideklarasikan.
+
+Contoh:
+let x = 5;
+x = 10; // Nilai x bisa diubah
+
+const y = 20;
+// y = 30; // Akan menyebabkan error, karena y nilainya tidak bisa diubah
+
+
+Template Literals
+Template literals memungkinkan Anda menyisipkan variabel atau ekspresi dalam string dengan menggunakan tanda backtick (`). Ini membuat penggabungan string dan variabel lebih mudah dibaca.
+
+Contoh:
+const name = 'John';
+const age = 25;
+
+const message = `Nama saya ${name} dan saya berusia ${age} tahun.`;
+console.log(message);
+
+
+Spread Operator dan Rest Parameter
+Spread operator (...) dapat digunakan untuk menguraikan elemen array atau objek menjadi beberapa elemen terpisah. Rest parameter juga menggunakan sintaks yang serupa untuk mengumpulkan beberapa argumen menjadi sebuah array.
+
+Contoh:
+const numbers = [1, 2, 3];
+const newArray = [...numbers, 4, 5]; // Menambahkan elemen pada array
+
+function sum(...args) {
+ return args.reduce((total, num) => total + num, 0);
+}
+console.log(sum(1, 2, 3)); // Output: 6
+
+
+Array Methods (Array Function)
+Beberapa method baru diperkenalkan dalam ES6 untuk memanipulasi array dengan lebih efisien.
+
+Contoh:
+const numbers = [1, 2, 3, 4, 5];
+
+const doubled = numbers.map(num => num * 2); // Menghasilkan [2, 4, 6, 8, 10]
+
+const evenNumbers = numbers.filter(num => num % 2 === 0); // Menghasilkan [2, 4]
+
+const sum = numbers.reduce((total, num) => total + num, 0); // Menghasilkan 15
+
+
+Itu adalah beberapa fitur ES6 beserta contoh array function-nya. Masih ada banyak lagi Function" ES6, nah disini kalian sudah mulai belajar habbit explore (phase 1 habbit) . Coba pelajarin ES6 lainnya selain dari materi ini.
+
+EXPLORE RESOURCES:
+W3SCHOOL : https://www.w3schools.com/js/js_es6.asp
+javatpoint : https://www.javatpoint.com/es6
+MDN : https://developer.mozilla.org/en-US/docs/Web/JavaScript
+W3Schools offers free online tutorials, references and exercises in all the major languages of the web. Covering popular subjects like HTML, CSS, JavaScript, Python, SQL, Java, and many, many more.
+Image
+
+www.javatpoint.com
+ES6 Tutorial - javatpoint
+ES6 Tutorial with What is ES6, History of ES6, ES6 Versions, ES6 Loops, Environment Setup, ES6 Syntax, ES6 Operators, ES6 Variables, ES6 Functions, ES6 Cookies, ES6 Strings, ES6 Math etc.
+JavaScript | MDN
+JavaScript (JS) is a lightweight interpreted (or just-in-time compiled) programming language with first-class functions. While it is most well-known as the scripting language for Web pages, many non-browser environments also use it, such as Node.js, Apache CouchDB and Adobe Acrobat. JavaScript is a prototype-based, multi-paradigm, single-threade...
+JavaScript | MDN
+
+
+https://youtube.com/playlist?list=PLFIM0718LjIUGpY8wmE41W7rTJo_3Y46-
\ No newline at end of file
diff --git a/Part 16 - Web Development/Fucking Number Pattern/soal_1.js b/Part 16 - Web Development/Fucking Number Pattern/soal_1.js
new file mode 100644
index 0000000..c800c40
--- /dev/null
+++ b/Part 16 - Web Development/Fucking Number Pattern/soal_1.js
@@ -0,0 +1,77 @@
+/*
+================
+MISSING NUMBER
+================
+description: Sebuah fungsi untuk mencari angka yang hilang berdasarkan pola dari board atau
+papan yang tersedia. Fungsi akan mengembalikan nilai sebuah array yang berisi
+angka-angka yang hilang
+
+examples:
+INPUT =
+[
+ [ 7 ,' ', 5 ],
+ [' ', 8 , 9 ]
+ [ 1 ,' ',' ']
+]
+
+ASUMSI PADA PAPAN SUDAH TERDAPAT RANGE TERBESAR DAN TERKECIL YAITU 1 DAN 9 SEHINGGA
+OUTPUT:
+[ 2, 3, 4, 6]
+
+PADA MASING-MASING TEST CASE SUDAH TERDAPAT RANGE TERBESAR DAN TERKECIL
+*/
+
+function missingNum(arr) {
+ //code here
+ const flattenedArray = arr.flat(); // Flatten the 2D array
+ console.log("flattenedArray =>", flattenedArray);
+ const minNum = Math.min(
+ ...flattenedArray.filter((num) => typeof num === "number")
+ ); // Find the minimum number
+ const maxNum = Math.max(
+ ...flattenedArray.filter((num) => typeof num === "number")
+ ); // Find the maximum number
+ console.log("minNum", minNum);
+ console.log("maxNum", maxNum);
+ const missingNumbers = [];
+
+ for (let i = minNum; i <= maxNum; i++) {
+ if (!flattenedArray.includes(i)) {
+ console.log("i", i);
+ missingNumbers.push(i);
+ }
+ console.log("missingNumbers", missingNumbers);
+ }
+
+ return missingNumbers;
+}
+
+console.log(
+ missingNum([
+ [3, " ", 5],
+ [1, " ", 7],
+ [9, " ", " "],
+ ])
+); // [ 2, 4, 6, 8 ]
+console.log(
+ missingNum([
+ [2, " "],
+ [" ", 5],
+ ])
+); // [ 3, 4 ]
+console.log(
+ missingNum([
+ [11, " ", 13],
+ [17, " ", 19],
+ [" ", 16, " "],
+ ])
+); // [ 12, 14, 15, 18 ]
+console.log(
+ missingNum([
+ [3, " ", 5, 15],
+ [1, " ", 7, 13],
+ [9, " ", " ", 12],
+ [" ", 16, " ", " "],
+ ])
+); // [ 2, 4, 6, 8, 10, 11, 14 ]
+console.log(missingNum([])); // []
diff --git a/Part 16 - Web Development/Fucking Number Pattern/soal_2.js b/Part 16 - Web Development/Fucking Number Pattern/soal_2.js
new file mode 100644
index 0000000..ce60d70
--- /dev/null
+++ b/Part 16 - Web Development/Fucking Number Pattern/soal_2.js
@@ -0,0 +1,104 @@
+/**
+ Square Number
+
+ Diberikan sebuah function squareNumber dimana menerima inputan berupa number.
+ Function ini akan mengembalikan array multidimensi yang isi value tersebut secara
+ proses menyerupai `board snakes and ladders` (angka 1 dimulai dari KOLOM ATAS) TAPI
+ alih-alih menuliskan value angka kamu akan menuliskan simbol/karakter dengan syarat sebagai berikut:
+ - jika value merupakan bilangan genap maka diganti menjadi karakter 'o'
+ - jika value merupakan bilangan ganjil maka diganti menjadi karakter 'x'
+ - jika value merupakan kelipatan 4 maka diganti menjadi simbol '#'
+
+ Contoh 1:
+ ==========
+ input: 3
+ proses:
+ [
+ [ 1, 2, 3 ],
+ [ 6, 5, 4 ],
+ [ 7, 8, 9 ]
+ ]
+ output:
+ [
+ [x, o, x],
+ [o, x, #],
+ [x, #, x]
+ ]
+
+ Contoh 2:
+ ==========
+ input: 4
+ proses:
+ [
+ [ 1, 2, 3, 4 ],
+ [ 8, 7, 6, 5 ],
+ [ 9, 10, 11, 12 ],
+ [ 16, 15, 14, 13 ]
+ ]
+ output:
+ [
+ [ x, o, x, # ],
+ [ #, x, o, x ],
+ [ x, o, x, # ],
+ [ #, x, o, x ]
+ ]
+NOTE:
+ - INPUT PARAMETER MINIMAL 3, JIKA KURANG DARI 3 MAKA RETURN 'Minimal input adalah 3'
+**/
+
+function squareNumber(num) {
+ //code here
+ if (num < 3) {
+ return "Minimal input adalah 3";
+ }
+
+ const board = [];
+ let counter = 1;
+
+ for (let i = 0; i < num; i++) {
+ const row = [];
+ for (let j = 0; j < num; j++) {
+ row.push(counter);
+ counter++;
+ }
+ board.push(row);
+ console.log('row',row);
+ }
+
+ for (let i = 0; i < num; i++) {
+ if (i % 2 !== 0) {
+ console.log('reverse',board[i].reverse());
+ board[i] = board[i].reverse();
+ }
+
+ for (let j = 0; j < num; j++) {
+ if (board[i][j] % 4 === 0) {
+ board[i][j] = "#";
+ } else if (board[i][j] % 2 === 0) {
+ board[i][j] = "o";
+ } else {
+ board[i][j] = "x";
+ }
+ }
+ }
+
+ return board;
+}
+
+console.log(squareNumber(3));
+// [ [x, o, x], [o, x, #], [x, #, x] ]
+
+console.log(squareNumber(4));
+// [ [ x, o, x, # ],
+// [ #, x, o, x ],
+// [ x, o, x, # ],
+// [ #, x, o, x ] ]
+
+console.log(squareNumber(5));
+// [ [ x, o, x, #, x ],
+// [ o, x, #, x, o ],
+// [ x, #, x, o, x ],
+// [ #, x, o, x, # ],
+// [ x, o, x, #, o ] ]
+
+console.log(squareNumber(2)); // Minimal input adalah 3
diff --git a/Part 16 - Web Development/Fucking Number Pattern/soal_3.js b/Part 16 - Web Development/Fucking Number Pattern/soal_3.js
new file mode 100644
index 0000000..6ee83e1
--- /dev/null
+++ b/Part 16 - Web Development/Fucking Number Pattern/soal_3.js
@@ -0,0 +1,83 @@
+/**
+ Square Number
+ Diberikan sebuah function squareNumber dimana menerima inputan berupa angka.
+ Function ini akan mengembalikan array multidimensi angka x angka yang isi value
+ dari array multidimensi tersebut menyerupai `board snakes and ladders`
+ Contoh 1:
+ input: 3
+ output:
+ [
+ [7, 8, 9],
+ [6, 5, 4],
+ [1, 2, 3]
+ ]
+ Contoh 2:
+ input: 4
+ output:
+ [
+ [ 16, 15, 14, 13 ],
+ [ 9, 10, 11, 12 ],
+ [ 8, 7, 6, 5 ],
+ [ 1, 2, 3, 4 ]
+ ]
+NOTE:
+ - INPUT PARAMETER MINIMAL 3, JIKA KURANG DARI 3 MAKA RETURN 'Minimal input adalah 3'
+ - NILAI FULL(100) AKAN DIBERIKAN JIKA BERHASIL MENYELESAIKAN KASUS DIATAS
+ - NILAI 80 AKAN DIBERIKAN JIKA value angka di dalam array tersebut tidak persis
+ menyerupai snakes and ladders TAPI angka 1 harus tetap berada di kolom paling bawah!
+ CONTOH:
+ [
+ [ 13, 14, 15, 16 ],
+ [ 9, 10, 11, 12 ],
+ [ 5, 6, 7, 8 ],
+ [ 1, 2, 3, 4 ]
+ ]
+**/
+
+function squareNumber(num) {
+ //code here
+ if (num < 3) {
+ return "Minimal input adalah 3";
+ }
+
+ // const board = [];
+ // for (let i = 0; i < num; i++) {
+ // const row = new Array(num).fill(0);
+ // board.push(row);
+ // }
+ // const board = new Array(num).fill(null).map(() => new Array(num).fill(0));
+ console.log("board", board);
+ let start = 1;
+
+ for (let row = 0; row < num; row++) {
+ if (row % 2 === 0) {
+ for (let col = 0; col < num; col++) {
+ board[num - row - 1][col] = start++;
+ }
+ } else {
+ for (let col = num - 1; col >= 0; col--) {
+ board[num - row - 1][col] = start++;
+ }
+ }
+ }
+
+ return board;
+}
+
+console.log(squareNumber(3));
+// [ [ 7, 8, 9 ], [ 6, 5, 4 ], [ 1, 2, 3 ] ]
+
+console.log(squareNumber(4));
+// [ [ 16, 15, 14, 13 ],
+// [ 9, 10, 11, 12 ],
+// [ 8, 7, 6, 5 ],
+// [ 1, 2, 3, 4 ] ]
+
+console.log(squareNumber(5));
+// [ [ 21, 22, 23, 24, 25 ],
+// [ 20, 19, 18, 17, 16 ],
+// [ 11, 12, 13, 14, 15 ],
+// [ 10, 9, 8, 7, 6 ],
+// [ 1, 2, 3, 4, 5 ] ]
+
+console.log(squareNumber(2)); // Minimal input adalah 3
diff --git a/Part 16 - Web Development/Quiz Array Dimension/soal_1.js b/Part 16 - Web Development/Quiz Array Dimension/soal_1.js
new file mode 100644
index 0000000..79d4edd
--- /dev/null
+++ b/Part 16 - Web Development/Quiz Array Dimension/soal_1.js
@@ -0,0 +1,51 @@
+/*
+=====================
+DOUBLE REVERSE ARRAY
+=====================
+
+[INSTRUCTION]
+Terdapat function doubleReverse yang menerima parameter berupa array of string,
+function ini akan memutar elemen array, string yang berada di dalam elemen array juga akan dibalik atau diputar jika panjang string GENAP
+
+[EXAMPLE]
+input: ['rabu', 'cinta', 'benci', 'masuk', 'nikmat']
+proses: memutar isi array, dan memutar elemen array yang panjang katanya genap
+output: [ 'tamkin', 'masuk', 'benci', 'cinta', 'ubar' ]
+
+[RULES]
+- Function bawaan javascript yang boleh digunakan hanyalah .push dan .length
+- DILARANG menggunakan .reverse()
+*/
+
+function doubleReverse(arr) {
+ //code here
+ if (!Array.isArray(arr)) {
+ return "invalid input parameter";
+ }
+ let result = [];
+
+ for (let i = arr.length - 1; i >= 0; i--) {
+ let currentElement = arr[i];
+
+ if (currentElement.length % 2 === 0) {
+ let reversedString = "";
+ for (let j = currentElement.length - 1; j >= 0; j--) {
+ reversedString += currentElement[j];
+ }
+ result.push(reversedString);
+ } else {
+ result.push(currentElement);
+ }
+ }
+
+ return result;
+}
+
+console.log(doubleReverse(["rabu", "cinta", "benci", "masuk", "nikmat"]));
+// [ 'tamkin', 'masuk', 'benci', 'cinta', 'ubar' ]
+console.log(doubleReverse(["aku", "sayang", "kamu"]));
+// [ 'umak', 'gnayas', 'aku' ]
+console.log(doubleReverse(["pelakor", "perusak", "rumah", "tangga"]));
+//[ 'anggnat', 'rumah', 'perusak', 'pelakor' ]
+console.log(doubleReverse([]));
+// invalid input parameter
diff --git a/Part 16 - Web Development/Quiz Array Dimension/soal_2.js b/Part 16 - Web Development/Quiz Array Dimension/soal_2.js
new file mode 100644
index 0000000..a25ffd7
--- /dev/null
+++ b/Part 16 - Web Development/Quiz Array Dimension/soal_2.js
@@ -0,0 +1,46 @@
+/*
+==================================
+Array Mastery: Find Not Relative
+==================================
+
+Diberikan sebuah function findNotRelative yang menerima 2 parameter berupa array of number.
+Output adalah array berupa kumpulan angka yang ada di array pertama tetapi tidak ada di array kedua.
+
+Contoh 1:
+input: [ 3, 6, 10, 12, 15 ] dan [ 1, 3, 5, 10, 16 ]
+output: [ 6, 12, 15]
+
+Contoh 2:
+input: [ 10, 20, 36, 59 ] dan [ 5, 10, 15, 59 ]
+output: [20, 36]
+
+RULES:
+ - DILARANG MENGGUNAKAN .map, .filter atau .reduce!
+
+*/
+
+function findNotRelative(arr1, arr2) {
+ //code here
+ let result = [];
+
+ for (let i = 0; i < arr1.length; i++) {
+ let found = false;
+
+ for (let j = 0; j < arr2.length; j++) {
+ if (arr1[i] === arr2[j]) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ result.push(arr1[i]);
+ }
+ }
+
+ return result;
+}
+
+console.log(findNotRelative([3, 6, 10, 12, 15], [1, 3, 5, 10, 16])); // [ 6, 12, 15]
+console.log(findNotRelative([10, 20, 36, 59], [5, 10, 15, 59])); //[20, 36]
+console.log(findNotRelative([1, 2, 3], [2, 1, 3])); //[]
diff --git a/Part 16 - Web Development/Quiz Array Dimension/soal_3.js b/Part 16 - Web Development/Quiz Array Dimension/soal_3.js
new file mode 100644
index 0000000..09af9be
--- /dev/null
+++ b/Part 16 - Web Development/Quiz Array Dimension/soal_3.js
@@ -0,0 +1,68 @@
+/*
+Minimum Distance Between Greatest Element
+
+Diberikan sebuah function minDistanceBetweenGreatest yang menerima sebuah parameter array of number. Dimana array tersebut akan memiliki nilai terbesar yang kemunculannya bisa lebih dari satu kali. Tentukan minimum jarak antara nilai terbesar satu ke nilai terbesar lainnya.
+
+Contoh 1:
+Input : [ 3, 5, 2, 3, 5, 3, 5 ]
+Output : 2
+
+Karena nilai terbesar dari array tersebut adalah 5 dan indeksnya adalah 1, 4 dan 6
+- indeks 1 ke indeks 4, jaraknya adalah 3
+- indeks 4 ke indeks 6, jaraknya adalah 2
+
+Jadi minimum jarak adalah 2
+
+Contoh 2:
+Input : [ 1, 1, 1, 1, 1, 1 ]
+Output : 1
+
+
+Karena nilai terbesar dari array tersebut adalah 1 dan indeksnya adalah 0, 1, 2, 3, 4 dan 5
+- indeks 0 ke indeks 1, jaraknya adalah 1
+- indeks 1 ke indeks 2, jaraknya adalah 1
+- indeks 2 ke indeks 3, jaraknya adalah 1
+- indeks 3 ke indeks 4, jaraknya adalah 1
+- indeks 4 ke indeks 5, jaraknya adalah 1
+
+Jadi minimum jarak adalah 1
+
+RULE:
+ - Dilarang menggunakan .map, .filter dan .reduce
+
+*/
+
+function minDistanceBetweenGreatest(arr) {
+ let maxNumber = arr[0];
+ let maxIndices = [0];
+
+ // Temukan nilai terbesar dan indeksnya
+ for (let i = 1; i < arr.length; i++) {
+ if (arr[i] > maxNumber) {
+ maxNumber = arr[i];
+ maxIndices = [i];
+ } else if (arr[i] === maxNumber) {
+ maxIndices.push(i);
+ }
+ }
+
+ // Hitung minimum jarak antara nilai terbesar
+ if (maxIndices.length <= 1) {
+ return 0;
+ }
+
+ let minDistance = arr.length;
+
+ for (let i = 0; i < maxIndices.length - 1; i++) {
+ let distance = maxIndices[i + 1] - maxIndices[i];
+ if (distance < minDistance) {
+ minDistance = distance;
+ }
+ }
+
+ return minDistance;
+}
+
+console.log(minDistanceBetweenGreatest([3, 5, 2, 3, 5, 3, 5])); //2
+console.log(minDistanceBetweenGreatest([1, 1, 1, 1, 1, 1])); //1
+console.log(minDistanceBetweenGreatest([7, 8, 5, 2, 1, 1])); //0
diff --git a/Part 16 - Web Development/Quiz Array Dimension/soal_4.js b/Part 16 - Web Development/Quiz Array Dimension/soal_4.js
new file mode 100644
index 0000000..84750a8
--- /dev/null
+++ b/Part 16 - Web Development/Quiz Array Dimension/soal_4.js
@@ -0,0 +1,37 @@
+/*
+==================================
+Array Mastery: Average Length Word
+==================================
+Nama:________
+[INSTRUKSI]
+Disediakan sebuah kalimat. Function averageLengthWord akan menerima satu parameter berupa string
+yang berisikan kalimat tersebut, dan akan mendapatkan rata-rata jumlah huruf dari setiap kata,
+kemudian mengembalikan nilai berupa array of string yang berisikan kata mana saja yang jumlahnya
+sama dengan rata-rata jumlah kata.
+
+NOTE:
+ - Spasi tidak dihitung
+ - Jika hasil rata-rata adalah desimal maka dibulatkan
+
+[CONTOH]
+input (kalimat): Do you want to become a great coder.
+rata-rata panjang kata dalam kalimat: 3
+output: ['you']
+
+input (kalimat): You dont know what you have until you lose it!.
+rata-rata panjang kata dalam kalimat: 4
+output: ['dont', 'know', 'what', 'have', 'lose']
+*/
+
+function averageLengthWord(words) {
+ //code here
+ const wordsArray = words.split(' ').filter(word => word !== ''); // Memisahkan kata dan menghilangkan spasi kosong
+ const totalLength = wordsArray.reduce((sum, word) => sum + word.length, 0); // Menghitung total panjang semua kata
+ const averageLength = Math.round(totalLength / wordsArray.length); // Menghitung rata-rata panjang kata
+
+ return wordsArray.filter(word => word.length === averageLength); // Mengembalikan kata-kata dengan panjang yang sama dengan rata-rata
+}
+
+console.log(averageLengthWord('Do you want to become a great coder ?')); // ['you']
+console.log(averageLengthWord('You dont know what you have until you lose it!')); // [ 'dont','know','what','have','lose']
+console.log(averageLengthWord('I am diligent')); // []
\ No newline at end of file
diff --git a/Part 16 - Web Development/Rekursif Harus Menjadi Temanmu Juga/soal_1.js b/Part 16 - Web Development/Rekursif Harus Menjadi Temanmu Juga/soal_1.js
new file mode 100644
index 0000000..2e0bdaa
--- /dev/null
+++ b/Part 16 - Web Development/Rekursif Harus Menjadi Temanmu Juga/soal_1.js
@@ -0,0 +1,39 @@
+/*
+
+Diberikan sebuah function angka terbesar yang menerima satu parameter berupa array.
+fungsi ini akan mengembalikan atau me return nilai berupa angka terbesar dari array.
+Jika array kosong maka akan mengembalikan nilai -1
+
+RULES
+=====
+- Wajib menggunakan metode rekursif
+- Dilarang menambahkan parameter baru
+- Dilarang membuat variable di luar function palindromeRecursive
+- Dilarang mengubah tipe data parameter
+- Dilarang Menggunakan Loop
+*/
+
+function angkaTerbesar(sentence) {
+ //code here
+ // Base case: if the array is empty, return -1
+ if (sentence.length === 0) {
+ return -1;
+ }
+
+ // Base case: if the array has only one element, return that element
+ if (sentence.length === 1) {
+ return sentence[0];
+ }
+
+ // Recursive case: remove the first element from the array and call angkaTerbesar on the rest of the array
+ var maxOfRest = angkaTerbesar(sentence.slice(1));
+
+ // Return the larger of the first element and the maximum of the rest of the array
+ return sentence[0] > maxOfRest ? sentence[0] : maxOfRest;
+}
+
+// TEST CASES
+console.log(angkaTerbesar([2, 3, 7, 6, 5])); // 7
+console.log(angkaTerbesar([9, 3, 7, 4, 1])); // 9
+console.log(angkaTerbesar([2, 1, 7, 2, 8])); // 8
+console.log(angkaTerbesar([])); // -1
diff --git a/Part 16 - Web Development/Rekursif Harus Menjadi Temanmu Juga/soal_2.js b/Part 16 - Web Development/Rekursif Harus Menjadi Temanmu Juga/soal_2.js
new file mode 100644
index 0000000..1ec2ff3
--- /dev/null
+++ b/Part 16 - Web Development/Rekursif Harus Menjadi Temanmu Juga/soal_2.js
@@ -0,0 +1,46 @@
+/**
+ * ////////////////
+ * changeXRecursive
+ * ////////////////
+ * Function ini harus dikerjakan dengan menggunakan rekursif.
+ * Function ini menerima dua parameter, yaitu:
+ * 1. data yang merupakan string dari number
+ * 2. jenis yang merupakan string berisi antara ganjil dan genap
+ *
+ * [EXAMPLE]
+ * Input: data = 012345678922468 dan jenis = ganjil
+ * Process: Karena jenisnya ganjil maka setiap bilangan genap diubah menjadi x
+ * Output: x1x3x5x7x9xxxxx
+ *
+ * [RULES]
+ * 1. Dilarang mengubah tipe parameter function
+ * 2. Dilarang membuat function diluar function yang disediakan
+ * 5. Wajib menggunakan rekursif
+ */
+
+function changeXRecursive(data, jenis) {
+ //code here
+ // Base case: If the string is empty, return an empty string
+ if (data.length === 0) {
+ return "";
+ }
+
+ // Determine the current character to be processed
+ const currentChar = data[0];
+
+ // Determine the replacement character based on 'jenis'
+ let replacementChar;
+ if (jenis === "ganjil") {
+ // Replace even numbers with 'x'
+ replacementChar = parseInt(currentChar) % 2 === 0 ? "x" : currentChar;
+ } else {
+ // Replace odd numbers with 'x'
+ replacementChar = parseInt(currentChar) % 2 !== 0 ? "x" : currentChar;
+ }
+
+ // Recursive call on the remaining substring and prepend the replacement character
+ return replacementChar + changeXRecursive(data.substring(1), jenis);
+}
+
+console.log(changeXRecursive("012345678922468", "ganjil")); //x1x3x5x7x9xxxxx
+console.log(changeXRecursive("0123456789", "genap")); //0x2x4x6x8x
diff --git a/Part 16 - Web Development/Rekursif Harus Menjadi Temanmu Juga/soal_3.js b/Part 16 - Web Development/Rekursif Harus Menjadi Temanmu Juga/soal_3.js
new file mode 100644
index 0000000..b59d492
--- /dev/null
+++ b/Part 16 - Web Development/Rekursif Harus Menjadi Temanmu Juga/soal_3.js
@@ -0,0 +1,52 @@
+/**
+ Vowels Counter Recursive
+ Diberikan sebuah function consonantCounterRecursive(sentences) yang
+ menerima satu parameter berupa
+ string. Function akan me-return jumlah huruf konsonan yang terdapat
+ di dalam parameter inputan.
+ Jika ada karakter selain abjad/alphabet maka tidak akan dihitung.
+- Wajib menggunakan metode rekursif
+ - DILARANG menambahkan parameter baru
+ - DILARANG membuat variable di luar function vowelsCounterRecursive
+ - DILARANG mengubah tipe data parameter
+ - proses looping (while, for, do-while, dan lain-lain) HANYA BOLEH ADA SATU
+ - DILARANG menambahkan function di luar maupun di dalam function vowelsCounterRecursive
+ - DILARANG menggunakan built in function .indexOf atau .includes
+ - DILARANG menggunakan REGEX
+*/
+
+function consonantCounterRecursive(sentences) {
+ //code here
+
+ // Base case: if the string is empty, return 0
+ if (sentences.length === 0) {
+ return 0;
+ }
+
+ // Convert the first character to lowercase for uniformity
+ const firstChar = sentences[0].toLowerCase();
+
+ // Function to check if a character is a vowel
+ function isVowel(char) {
+ return (
+ char === "a" ||
+ char === "e" ||
+ char === "i" ||
+ char === "o" ||
+ char === "u"
+ );
+ }
+
+ // Check if the first character is a consonant (alphabetic and not a vowel)
+ const isConsonant =
+ firstChar >= "a" && firstChar <= "z" && !isVowel(firstChar);
+
+ // Recursive call on the rest of the string, adding 1 if the first character is a consonant
+ return (
+ (isConsonant ? 1 : 0) + consonantCounterRecursive(sentences.substring(1))
+ );
+}
+
+console.log(consonantCounterRecursive("alDi Suka MakAn baksO")); //10
+console.log(consonantCounterRecursive("AziZy")); // 3
+console.log(consonantCounterRecursive("awt6an")); // 3
diff --git a/Part 16 - Web Development/Rekursif Harus Menjadi Temanmu Juga/soal_4.js b/Part 16 - Web Development/Rekursif Harus Menjadi Temanmu Juga/soal_4.js
new file mode 100644
index 0000000..b4b0951
--- /dev/null
+++ b/Part 16 - Web Development/Rekursif Harus Menjadi Temanmu Juga/soal_4.js
@@ -0,0 +1,44 @@
+/*
+================
+Recursive - Hanya Bilangan Terbagi Nol
+================
+
+dividableRecursive adalah sebuah function yang
+ menerima dua parameter berupa array dan num.
+function akan mereturn sebuah sebuah number yang
+hanya sisa baginya nol dari bilangan num
+
+[RULE]
+- Wajib menggunakan recursive
+- Dilarang menggunakan regex .match dan lainnya!
+- Tidak boleh membuat variable diluar function
+- Tidak boleh menambahkan parameter baru
+- Tidak boleh menggunakan looping while/for
+*/
+
+function dividableRecursive(array, num) {
+ //code here
+
+ // Base case: if the array is empty, return an empty string
+ if (array.length === 0) {
+ return "";
+ }
+
+ // Check if the first element of the array is divisible by num
+ const isDividable = array[0] % num === 0;
+
+ // If it is, include it in the result, followed by a space
+ if (isDividable) {
+ // Make a recursive call with the rest of the array and add the current element to the result
+ return array[0] + " " + dividableRecursive(array.slice(1), num);
+ } else {
+ // If it's not, just make a recursive call with the rest of the array
+ return dividableRecursive(array.slice(1), num);
+ }
+}
+
+// DRIVER CODE
+console.log(dividableRecursive([66, 33, 55, 44, 11], 3)); // 66 33
+console.log(dividableRecursive([123, 222, 100, 50, 32], 2)); // 222 100 50 32
+console.log(dividableRecursive([125, 500, 201, 202, 66], 5)); // 125 500
+console.log(dividableRecursive([66, 33, 55, 44, 132], 6)); // 66 132
diff --git a/Part 16 - Web Development/Rekursif Harus Menjadi Temanmu Juga/soal_5.js b/Part 16 - Web Development/Rekursif Harus Menjadi Temanmu Juga/soal_5.js
new file mode 100644
index 0000000..ccd9478
--- /dev/null
+++ b/Part 16 - Web Development/Rekursif Harus Menjadi Temanmu Juga/soal_5.js
@@ -0,0 +1,47 @@
+/**
+ Hapus Simbol Rekursif
+ Diberikan sebuah function hapusSimbol(str) yang menerima satu parameter berupa
+ string. Function akan me-return string yang telah bersih dari berbagai simbol,
+ hanya menyisakan a-z dan angka 0-9.
+ RULES:
+ - Wajib menggunakan metode rekursif
+ - DILARANG menambahkan parameter baru
+ - DILARANG membuat variable di luar function hapusSimbolRec
+ - DILARANG mengubah tipe data parameter
+ - proses looping (while, for, do-while, dan lain-lain) HANYA BOLEH ADA SATU
+ - DILARANG menambahkan function di luar maupun di dalam function hapusSimbolRec
+ - DILARANG menggunakan built in function .indexOf atau .include
+ - DILARANG menggunakan REGEX
+**/
+
+function hapusSimbolRec(str) {
+ //code here
+
+ // Base case: if the string is empty, return an empty string
+ if (str.length === 0) {
+ return "";
+ }
+
+ // Helper function to check if a character is alphanumeric
+ function isAlphanumeric(char) {
+ return (
+ (char >= "a" && char <= "z") ||
+ (char >= "A" && char <= "Z") ||
+ (char >= "0" && char <= "9")
+ );
+ }
+
+ // Convert the first character to lowercase for uniformity and check if it's alphanumeric
+ const firstChar = str[0];
+ const isValidChar = isAlphanumeric(firstChar);
+
+ // Recursive call on the rest of the string
+ // Include the first character if it's alphanumeric, otherwise skip it
+ return (isValidChar ? firstChar : "") + hapusSimbolRec(str.substring(1));
+}
+
+console.log(hapusSimbolRec("test4@aa")); //test4aa
+console.log(hapusSimbolRec("devel0p3r s3j@@ati")); // devel0p3rs3jati
+console.log(hapusSimbolRec("ma@#k!an~")); // makan
+console.log(hapusSimbolRec("coding")); // coding
+console.log(hapusSimbolRec("1+3-5*2=100")); // 1352100
diff --git a/Part 16 - Web Development/Rekursif Harus Menjadi Temanmu Juga/soal_6.js b/Part 16 - Web Development/Rekursif Harus Menjadi Temanmu Juga/soal_6.js
new file mode 100644
index 0000000..e017e99
--- /dev/null
+++ b/Part 16 - Web Development/Rekursif Harus Menjadi Temanmu Juga/soal_6.js
@@ -0,0 +1,55 @@
+/*
+
+Diberikan sebuah function palindromeRecursive(sentenc) yang menerima satu parameter.
+Function tersebut akan mengembalikan nilai true jika kata merupakan palindrome, dan false jika bukan.
+Kata palindrome adalah sebuah kata yang jika dibalik, tetap sama.
+Contoh, 'katak' dibalik tetaplah 'katak'.
+
+RULES
+=====
+- Wajib menggunakan metode rekursif
+- Dilarang menambahkan parameter baru
+- Dilarang membuat variable di luar function palindromeRecursive
+- Dilarang mengubah tipe data parameter
+
+*/
+
+function palindromeRecursive(sentence) {
+ //code here - saran bikin fungsi rekursif didalam sini
+ //lalu bandingkan dengan sentence
+
+ if (sentence.length <= 1) {
+ return true;
+ }
+
+ // Remove spaces for phrases
+ sentence = sentence.replace(/ /g, "");
+
+ // Compare the first and last characters
+ if (
+ sentence[0].toLowerCase() === sentence[sentence.length - 1].toLowerCase()
+ ) {
+ // If they match, perform a recursive call on the substring excluding these two characters
+ return palindromeRecursive(sentence.substring(1, sentence.length - 1));
+ } else {
+ // If the first and last characters do not match, it's not a palindrome
+ return false;
+ }
+
+ if (sentence.length <= 1) {
+ return true;
+ }
+
+ // if (sentence[0] !== sentence[sentence.length - 1]) {
+ // return false;
+ // } else {
+ // return palindromeRecursive(sentence.slice(1, -1));
+ // }
+}
+
+// TEST CASES
+console.log(palindromeRecursive("katak")); // true
+console.log(palindromeRecursive("blanket")); // false
+console.log(palindromeRecursive("civic")); // true
+console.log(palindromeRecursive("kasur rusak")); // true
+console.log(palindromeRecursive("mister")); // false
diff --git a/Part 16 - Web Development/Rekursif Harus Menjadi Temanmu Juga/soal_7.js b/Part 16 - Web Development/Rekursif Harus Menjadi Temanmu Juga/soal_7.js
new file mode 100644
index 0000000..bfdcd38
--- /dev/null
+++ b/Part 16 - Web Development/Rekursif Harus Menjadi Temanmu Juga/soal_7.js
@@ -0,0 +1,43 @@
+/*
+ PARSE NUMBER
+ Parse Number adalah sebuah fungsi untuk memecah atau menguraikan suatu angka. Fungsi akan
+ menerima parameter berupa angka dan keluaran berupa string uraian angka.
+
+ EXAMPLE
+ INPUT: 4321
+ OUTPUT: 4000+300+20+1
+
+ RULES:
+ 1. Wajib menggunakan rekursif!
+ 2. Tidak boleh menambahkan parameter dan function baru
+*/
+
+function parseNumber(equation) {
+ //code here
+
+ // Convert the number to a string for easy manipulation
+ let numStr = equation.toString();
+
+ // Base case: if the string length is 1, return the string itself
+ if (numStr.length === 1) {
+ return numStr;
+ }
+
+ // Take the first digit and append the necessary number of zeros
+ let part = numStr[0] + "0".repeat(numStr.length - 1);
+
+ // Recursive call with the rest of the number, excluding the first digit
+ let rest = parseNumber(parseInt(numStr.substring(1)));
+
+ // If the rest part starts with '0', it means there are no more significant digits to add, so we don't include it in the result
+ if (rest.startsWith("0")) {
+ return part;
+ }
+
+ // Concatenate the current part with the result of the recursive call
+ return part + "+" + rest;
+}
+
+console.log(parseNumber(3333)); // 3000+300+30+3 // 3000 + 300 + 30 + 3
+console.log(parseNumber(90)); // 90
+console.log(parseNumber(2333)); // 2000+300+30+3
diff --git a/Part 16 - Web Development/Rekursif Harus Menjadi Temanmu Juga/soal_8.js b/Part 16 - Web Development/Rekursif Harus Menjadi Temanmu Juga/soal_8.js
new file mode 100644
index 0000000..a00ae35
--- /dev/null
+++ b/Part 16 - Web Development/Rekursif Harus Menjadi Temanmu Juga/soal_8.js
@@ -0,0 +1,50 @@
+/*
+Budi ingin menyusun batu bata dengan ukuran yang sama sampai membentuk piramid 2 dimensi
+Jika piramid bertingkat 1, Budi hanya memerlukan 1 batu bata
+ B
+Jika piramid bertingkat 2, Budi memerlukan 3 batu bata
+ B
+ B B
+Jika piramid bertingkat 3, Budi memerlukan 6 batu bata
+ B
+ B B
+B B B
+Jika piramid bertingkat 4, Budi memerlukan 10 batu bata
+ B
+ B B
+ B B B
+B B B B
+
+Di setiap tingkat bertambah 1 batu bata dibanding tingkatan diatasnya
+
+Buatlah function piramid (n) yang memberitahu berapa jumlah batu bata yang diperlukan untuk membuat piramid bertingkat n.
+
+[RULES]
+ 1. Wajib menggunakan RECURSIVE.
+ 2. Dilarang membuat function tambahan selain function piramid.
+ 3. Dilarang menambah parameter function.
+*/
+
+function piramid(n) {
+ //code here
+
+ // Base case: if n is 0, no bricks are needed
+ if (n === 0) {
+ return 0;
+ }
+
+ // Recursive case: the number of bricks needed for a pyramid of height n
+ // is n (for the current level) plus the number of bricks needed for a pyramid of height n-1
+ return n + piramid(n - 1);
+}
+
+// console.log(piramid()) // 0
+console.log(piramid(0)); // 0
+console.log(piramid(1)); // 1
+console.log(piramid(2)); // 3
+console.log(piramid(3)); // 6
+console.log(piramid(4)); // 10
+console.log(piramid(5)); // 15
+console.log(piramid(6)); // 21
+console.log(piramid(100)); // 5050
+console.log(piramid(888)); // 394716
diff --git a/Part 16 - Web Development/Rekursif Harus Menjadi Temanmu Juga/soal_9.js b/Part 16 - Web Development/Rekursif Harus Menjadi Temanmu Juga/soal_9.js
new file mode 100644
index 0000000..8b8ce91
--- /dev/null
+++ b/Part 16 - Web Development/Rekursif Harus Menjadi Temanmu Juga/soal_9.js
@@ -0,0 +1,66 @@
+/**
+Virus Check Recursive
+---------------------
+Implementasikan function `virusCheckRecursive` untuk menghitung ada berapa virus yang
+terdapat di dalam `str` berdasarkan `virus` yang dicari.
+
+Contoh 1:
+input:
+ str: 'qlD4MZax0raQqew'
+ virus: 'x|0|q' ==> berarti mencari x, 0 dan q
+
+output: 4
+
+Contoh 2:
+input:
+ str: 'HH0NBP1zRa'
+ virus: 'h|r' ==> berarti mencari h dan r
+
+outuput: 3
+
+
+RULES:
+ - Wajib menggunakan metode rekursif
+ - Dilarang menambahkan parameter baru
+ - Dilarang membuat variable di luar function virusCheckRecursive
+ - Dilarang mengubah tipe data parameter
+ - proses looping (while, for, do-while, dan lain-lain) HANYA BOLEH ADA SATU
+ - Dilarang menambahkan function di luar maupun di dalam function virusCheckRecursive
+
+*/
+
+function virusCheckRecursive(str, viruses) {
+ //code here
+
+ // Base case: if str is empty, return 0; if viruses is undefined or empty, return 'There is no virus'
+ if (viruses === undefined || viruses.length === 0 || str.length === 0) {
+ return "There is no virus";
+ }
+
+ // Remove '|' from viruses to create a list of virus characters
+ const cleanedViruses = viruses.replace(/\|/g, "");
+
+ // Initialize count for this level of recursion
+ let count = 0;
+
+ // Check if the current character in str matches any character in cleanedViruses
+ if (cleanedViruses.includes(str[0].toLowerCase())) {
+ count = 1; // Found a match, increment count
+ }
+
+ // Base case for recursion: if str has only one character, return the count for this level
+ if (str.length === 1) {
+ return count;
+ }
+
+ // Recursive call: check the rest of the string and add to count
+ return count + virusCheckRecursive(str.substring(1), cleanedViruses);
+}
+
+console.log(virusCheckRecursive("qlD4MZax0raQqew", "x|0|q")); // 5
+console.log(virusCheckRecursive("HH0NBP1zRa", "h|r")); // 3
+console.log(virusCheckRecursive("4O4TmIF6ONaiMlzpXxPqwy", "4|X|p")); // 6
+console.log(virusCheckRecursive("mjBgPlzks", "m")); // 1
+console.log(virusCheckRecursive("AIn4Ks05bBaa", "x")); // 0
+console.log(virusCheckRecursive("RsMFjBUjvIaP")); // There is no virus
+console.log(virusCheckRecursive("")); // There is no virus
diff --git a/Part 16 - Web Development/Todo List/index.html b/Part 16 - Web Development/Todo List/index.html
new file mode 100644
index 0000000..b85275e
--- /dev/null
+++ b/Part 16 - Web Development/Todo List/index.html
@@ -0,0 +1,30 @@
+
+
+
+
+
+ To-Do List
+
+
+
+
+
My To Do List
+
+ Search
+
+
+ Add
+
+
+
+
Hit the gym
+
Pay bills
+
Meet George
+
Buy eggs
+
Read a book
+
Organize office
+
+
+
+
+
\ No newline at end of file
diff --git a/Part 16 - Web Development/Todo List/script.js b/Part 16 - Web Development/Todo List/script.js
new file mode 100644
index 0000000..70a1679
--- /dev/null
+++ b/Part 16 - Web Development/Todo List/script.js
@@ -0,0 +1,83 @@
+// Membuat tanda "X" pada setiap list
+let myNodeList = document.getElementsByTagName("LI");
+for (let i = 0; i < myNodeList.length; i++) {
+ const span = document.createElement("SPAN");
+ const txt = document.createTextNode("\u00D7");
+ span.className = "close";
+ span.appendChild(txt);
+ myNodeList[i].appendChild(span);
+}
+
+// Membuat list menghilang ketika tanda "X" click
+let close = document.getElementsByClassName("close");
+
+for (let i = 0; i < close.length; i++) {
+ // console.log('close',close[i]);
+ close[i].onclick = function () {
+ let div = this.parentElement;
+ div.style.display = "none";
+ };
+}
+
+// Membuat simbol "checked" pada setiap list ketika diclick
+const list = document.querySelector("ul");
+function checked(event) {
+ if (event.target.tagName === "LI") {
+ event.target.classList.toggle("checked");
+ }
+}
+list.addEventListener("click", checked);
+
+// Menambahkan list baru ketika "add" diclick
+function newElement() {
+ let li = document.createElement("li");
+ let inputValue = document.getElementById("myInput").value;
+
+ if (inputValue === "") {
+ alert("You must write something!");
+ } else {
+ let a = document.createElement("a");
+ a.href = "#";
+ a.appendChild(document.createTextNode(inputValue));
+
+ li.appendChild(a);
+ document.getElementById("myUL").appendChild(li);
+ }
+ document.getElementById("myInput").value = "";
+
+ // Untuk menambah "X"
+ let span = document.createElement("SPAN");
+ let txt = document.createTextNode("\u00D7");
+ span.className = "close";
+ span.appendChild(txt);
+ li.appendChild(span);
+
+ for (let i = 0; i < close.length; i++) {
+ close[i].onclick = function () {
+ let div = this.parentElement;
+ div.style.display = "none";
+ };
+ }
+}
+
+function searchElement() {
+ let searchValue = document.getElementById("mySearch");
+ let filter = searchValue.value.toUpperCase();
+ let ul = document.getElementById("myUL");
+ let li = ul.getElementsByTagName("li");
+
+ if (searchValue.value === "") {
+ alert("You must write something!");
+ }
+
+ for (let i = 0; i < li.length; i++) {
+ let a = li[i].getElementsByTagName("a")[0];
+ if (a && a.innerHTML.toUpperCase().indexOf(filter) > -1) {
+ li[i].style.display = "";
+ } else {
+ li[i].style.display = "none";
+ }
+ }
+
+ document.getElementById("mySearch").value = "";
+}
\ No newline at end of file
diff --git a/Part 16 - Web Development/Todo List/style.css b/Part 16 - Web Development/Todo List/style.css
new file mode 100644
index 0000000..af214a8
--- /dev/null
+++ b/Part 16 - Web Development/Todo List/style.css
@@ -0,0 +1,131 @@
+/* Include the padding and border in an element's total width and height */
+* {
+ box-sizing: border-box;
+}
+
+/* Remove margins and padding from the list */
+ul {
+ margin: 0;
+ padding: 0;
+}
+
+/* Style the list items */
+ul li {
+ cursor: pointer;
+ position: relative;
+ padding: 12px 8px 12px 40px;
+ background: #eee;
+ font-size: 18px;
+ transition: 0.2s;
+
+ /* make the list items unselectable */
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+/* Set all odd list items to a different color (zebra-stripes) */
+ul li:nth-child(odd) {
+ background: #f9f9f9;
+}
+
+/* Darker background-color on hover */
+ul li:hover {
+ background: #ddd;
+}
+
+/* When clicked on, add a background color and strike out text */
+ul li.checked {
+ background: #888;
+ color: #fff;
+ text-decoration: line-through;
+}
+
+/* Add a "checked" mark when clicked on */
+ul li.checked::before {
+ content: "";
+ position: absolute;
+ border-color: #fff;
+ border-style: solid;
+ border-width: 0 2px 2px 0;
+ top: 10px;
+ left: 16px;
+ transform: rotate(45deg);
+ height: 15px;
+ width: 7px;
+}
+
+/* Style the close button */
+.close {
+ position: absolute;
+ right: 0;
+ top: 0;
+ padding: 12px 16px 12px 16px;
+}
+
+.close:hover {
+ background-color: #f44336;
+ color: white;
+}
+
+/* Style the header */
+.header {
+ background-color: #f44336;
+ padding: 30px 40px;
+ color: white;
+ text-align: center;
+}
+
+/* Clear floats after the header */
+.header:after {
+ content: "";
+ display: table;
+ clear: both;
+}
+
+/* Style the input */
+input {
+ margin: 0;
+ border: none;
+ border-radius: 0;
+ width: 75%;
+ padding: 10px;
+ float: left;
+ font-size: 16px;
+}
+
+/* Style the "Add" button */
+.addBtn {
+ padding: 10px;
+ width: 25%;
+ background: #d9d9d9;
+ color: #555;
+ float: left;
+ text-align: center;
+ font-size: 16px;
+ cursor: pointer;
+ transition: 0.3s;
+ border-radius: 0;
+}
+
+.addBtn:hover {
+ background-color: #bbb;
+}
+
+.searchBtn {
+ padding: 10px;
+ width: 25%;
+ background: #d9d9d9;
+ color: #555;
+ float: left;
+ text-align: center;
+ font-size: 16px;
+ cursor: pointer;
+ transition: 0.3s;
+ border-radius: 0;
+}
+
+.searchBtn:hover {
+ background-color: #bbb;
+}
diff --git a/Part 16 - Web Development/You Need to Like Object/soal_1.js b/Part 16 - Web Development/You Need to Like Object/soal_1.js
new file mode 100644
index 0000000..aa193c8
--- /dev/null
+++ b/Part 16 - Web Development/You Need to Like Object/soal_1.js
@@ -0,0 +1,151 @@
+/*
+ ================
+ ASIAN GAMES GANJIL GENAP
+ ================
+
+ description: Sebuah fungsi yang akan mengembalikan berapa banyak jumlah pelanggaran lalu lintas
+ yang terjadi saat asian games berlangsung. Pelanggaran akan terhitung apabila
+ ada plat mobil yang melintas pada tanggal tertentu dengan nomor plat yang tidak
+ sama dengan aturan ganjil genap
+
+ rules:
+ 1. tidak boleh menggunakan built in function .filter(), .map(), .reduce()
+ 2. Function menerima parameter berupa tanggal dan data kendaraan yang melintas
+ 3. Function hanya akan bisa membaca dari tanggal 1 sampai 31 ( asumsi setiap bulan memiliki range
+ tanggal tersebut )
+ 4. Contoh membaca nomor plat kendaraan adalah misal B 1234 HAHA, berarti yang dilihat cukup
+ angka paling belakang dari 1234 berarti 4, berati nomor plat mobil ini termasuk genap
+
+
+ examples:
+ JIKA INPUT DATA KENDARAAN = [{
+ plat: 'B 1234 ABC',
+ type: 'Mobil'
+ }, {
+ plat: 'A 2457 HE',
+ type: 'Motor'
+ }, {
+ plat: 'Z 999 ERT',
+ type: 'Mobil'
+ }]
+ DAN INPUT TANGGAL ADALAH = 18
+ MAKA OUTPUTNYA ADALAH 1, yaitu hanya plat mobil Z 999 ERT karena merupakan jenis kendaraan
+ mobil dan memiliki plat 'ganjil'
+*/
+
+function ganjilGenapAsianGames(date, data) {
+ //code here
+ // Check for valid date (1 to 31)
+ if (date < 1 || date > 31) {
+ return "invalid dates";
+ }
+
+ // Count of violations
+ let violationCount = 0;
+
+ // Iterate through data
+ for (let i = 0; i < data.length; i++) {
+ const platNumber = parseInt(data[i].plat.match(/\d+/)[0]); // Extract numeric part of the plate
+ const isEven = platNumber % 2 === 0; // Check if it's even
+
+ // Check if the date is within range and the type is 'Mobil' (Car)
+ if (date >= 1 && date <= 31 && data[i].type === "Mobil") {
+ if ((date % 2 === 0 && isEven) || (date % 2 !== 0 && !isEven)) {
+ // If date is even and plat is even, or date is odd and plat is odd, it's a violation
+ violationCount++;
+ }
+ }
+ }
+
+ return violationCount;
+}
+
+console.log(
+ ganjilGenapAsianGames(30, [
+ {
+ plat: "B 1234 ABC",
+ type: "Mobil",
+ },
+ {
+ plat: "A 2457 HE",
+ type: "Motor",
+ },
+ {
+ plat: "AB 87 RFS",
+ type: "Motor",
+ },
+ {
+ plat: "Z 999 ERT",
+ type: "Mobil",
+ },
+ ])
+); // 1
+
+console.log(
+ ganjilGenapAsianGames(26, [
+ {
+ plat: "A 24 HE",
+ type: "Mobil",
+ },
+ {
+ plat: "AB 871 RFS",
+ type: "Mobil",
+ },
+ {
+ plat: "Z 9992 ERT",
+ type: "Mobil",
+ },
+ ])
+); // 1
+
+console.log(
+ ganjilGenapAsianGames(1, [
+ {
+ plat: "A 24 WE",
+ type: "Mobil",
+ },
+ {
+ plat: "AB 871 RFS",
+ type: "Mobil",
+ },
+ {
+ plat: "Z 9992 XOXO",
+ type: "Mobil",
+ },
+ ])
+); // 2
+
+console.log(
+ ganjilGenapAsianGames(1, [
+ {
+ plat: "A 2431 HE",
+ type: "Motor",
+ },
+ {
+ plat: "AB 8711 RFS",
+ type: "Motor",
+ },
+ {
+ plat: "Z 999 ERT",
+ type: "Motor",
+ },
+ ])
+); // 0
+
+console.log(
+ ganjilGenapAsianGames(32, [
+ {
+ plat: "X 123 HAHA",
+ type: "Mobil",
+ },
+ ])
+); // invalid dates
+
+console.log(
+ ganjilGenapAsianGames(0, [
+ {
+ plat: "X 123 HAHA",
+ type: "Mobil",
+ },
+ ])
+); // invalid dates
diff --git a/Part 16 - Web Development/You Need to Like Object/soal_2.js b/Part 16 - Web Development/You Need to Like Object/soal_2.js
new file mode 100644
index 0000000..8270abd
--- /dev/null
+++ b/Part 16 - Web Development/You Need to Like Object/soal_2.js
@@ -0,0 +1,100 @@
+/*
+=========
+HACKATHON
+=========
+
+[INSTRUCTION]
+Buatlah suatu aplikasi untuk membuat catatan ekonomi.
+
+[EXAMPLE]
+"bank account sudah disediakan"
+
+input: [['Jeff Bezos+5%', 'Larry Page+10%', 'Jeff Bezos-3%'], ['Larry Page+2%', 'Larry Page-1%']]
+process:
+ bank account => deposit atas nama Jeff Bezos ditambah 5%, menjadi 105000
+ bank account => deposit atas nama Larry Page ditambah 10%, mejadi 104500
+ bank account => deposit atas nama Jeff Bezos dikurangi 3%, mejadi 101850
+ ...dst
+output:
+ [
+ { name: 'Jeff Bezos', deposit: 105000, owner: 'Amazon' },
+ { name: 'Larry Page', deposit: 104500, owner: 'Google' },
+ { name: 'Jeff Bezos', deposit: 101850, owner: 'Amazon' },
+ { name: 'Larry Page', deposit: 106590, owner: 'Google' },
+ { name: 'Larry Page', deposit: 105524.1, owner: 'Google' }
+ ]
+
+[RULES]
+- Dilarang menggunakan .indexOf(), .split(), .filter(), .map(), dan .slice()
+*/
+
+function economyChangeSummary(tradeActivity) {
+ let duitJeff = 100000;
+ let duitLarry = 95000;
+ let duitJack = 90000;
+
+ // Temporary variables to track current deposits
+ let currentDuitJeff = duitJeff;
+ let currentDuitLarry = duitLarry;
+ let currentDuitJack = duitJack;
+
+ let result = [];
+
+ // Function to parse and apply percentage changes
+ function applyChange(name, change) {
+ let percentageChange = parseFloat(change) / 100;
+ if (name === "Jeff Bezos") {
+ currentDuitJeff += currentDuitJeff * percentageChange;
+ return { name, deposit: currentDuitJeff, owner: "Amazon" };
+ } else if (name === "Larry Page") {
+ currentDuitLarry += currentDuitLarry * percentageChange;
+ return { name, deposit: currentDuitLarry, owner: "Google" };
+ } else if (name === "Jack Ma") {
+ currentDuitJack += currentDuitJack * percentageChange;
+ return { name, deposit: currentDuitJack, owner: "Alibaba" };
+ }
+ }
+
+ // Iterate through trade activities
+ for (let dayActivities of tradeActivity) {
+ for (let activity of dayActivities) {
+ let [name, change] = activity.split("+");
+ if (!change) {
+ [name, change] = activity.split("-");
+ change = "-" + change;
+ }
+ result.push(applyChange(name, change));
+ }
+ }
+
+ return result;
+}
+
+console.log(
+ economyChangeSummary([
+ ["Jeff Bezos+5%", "Larry Page+10%", "Jeff Bezos-3%"],
+ ["Larry Page+2%", "Larry Page-1%"],
+ ["Jack Ma+4%"],
+ ["Larry Page-8%", "Jack Ma+20%", "Jeff Bezos-3%", "Jeff Bezos+8%"],
+ ])
+);
+/*
+ [ { name: 'Jeff Bezos', deposit: 105000, owner: 'Amazon' },
+ { name: 'Larry Page', deposit: 104500, owner: 'Google' },
+ { name: 'Jeff Bezos', deposit: 101850, owner: 'Amazon' },
+ { name: 'Larry Page', deposit: 106590, owner: 'Google' },
+ { name: 'Larry Page', deposit: 105524.1, owner: 'Google' },
+ { name: 'Jack Ma', deposit: 93600, owner: 'Alibaba' },
+ { name: 'Larry Page', deposit: 97082.172, owner: 'Google' },
+ { name: 'Jack Ma', deposit: 112320, owner: 'Alibaba' },
+ { name: 'Jeff Bezos', deposit: 98794.5, owner: 'Amazon' },
+ { name: 'Jeff Bezos', deposit: 106698.06, owner: 'Amazon' } ]
+ */
+console.log(
+ "=============================================================================="
+);
+
+console.log(economyChangeSummary([["Jeff Bezos-10%"]]));
+/*
+ [ { name: 'Jeff Bezos', deposit: 90000, owner: 'Amazon' } ]
+ */
diff --git a/Part 16 - Web Development/You Need to Like Object/soal_3.js b/Part 16 - Web Development/You Need to Like Object/soal_3.js
new file mode 100644
index 0000000..564fe07
--- /dev/null
+++ b/Part 16 - Web Development/You Need to Like Object/soal_3.js
@@ -0,0 +1,65 @@
+/*
+=======================
+Initial Object Grouping
+=======================
+
+[INSTRUCTION]
+
+Disediakan sebuah function initialObjectGrouping yang bertugas untuk menerima sebuah parameter
+berupa array satu dimensi berisikan nama-nama. Function initialObjectGrouping akan
+mengelompokkan nama-nama tersebut berdasarkan huruf depannya dan dipisahkan ke dalam
+sebuah object.
+[EXAMPLE]
+Input: ['Budi', 'Badu', 'Joni', 'Jono']
+Proses:
+Huruf depan yang ditemukan: B dan J
+Pisahkan nama yang depannya B, dan nama yang depannya J. Masukkan ke object berdasarkan huruf Awal nama
+{
+ B: ['Budi', 'Badu'],
+ J: ['Joni', 'Jono']
+}
+[CONSTRAINTS]
+Dilarang menggunakan sintaks Set atau Regex
+*/
+function initialObjectGrouping(studentsArr) {
+ //CODE HERE
+ var result = {}; // Initialize an empty object to hold the result
+ for (var i = 0; i < studentsArr.length; i++) {
+ var initial = studentsArr[i][0]; // Get the first letter of the current name
+ if (!result[initial]) {
+ result[initial] = [studentsArr[i]]; // If this initial is not yet a key in the result, add it with the current name as the first element of an array
+ } else {
+ result[initial].push(studentsArr[i]); // If this initial is already a key, push the current name to the corresponding array
+ }
+ }
+ return result; // Return the grouped object
+}
+console.log(initialObjectGrouping(["Budi", "Badu", "Joni", "Jono"]));
+/*
+ {
+ B: [ 'Budi', 'Badu' ],
+ J: [ 'Joni', 'Jono' ]
+ }
+ */
+console.log(
+ initialObjectGrouping(["Mickey", "Yusuf", "Donald", "Ali", "Gong"])
+);
+/*
+ {
+ M: [ 'Mickey' ],
+ Y: [ 'Yusuf' ],
+ D: [ 'Donald' ],
+ A: [ 'Ali' ],
+ G: [ 'Gong' ]
+ }
+ */
+console.log(
+ initialObjectGrouping(["Rock", "Stone", "Brick", "Rocker", "Sticker"])
+);
+/*
+ {
+ R: [ 'Rock', 'Rocker' ],
+ S: [ 'Stone', 'Sticker' ],
+ B: [ 'Brick' ]
+ }
+ */
diff --git a/Part 16 - Web Development/You Need to Like Object/soal_4.js b/Part 16 - Web Development/You Need to Like Object/soal_4.js
new file mode 100644
index 0000000..9e9cdeb
--- /dev/null
+++ b/Part 16 - Web Development/You Need to Like Object/soal_4.js
@@ -0,0 +1,166 @@
+/*
+Function travelingIndonesia akan mengembalikan nilai sebuah string suatu perjalanan seseorang
+di kota-kota besar yang ada di Indonesia.
+
+Secara berturut-turut rute akan berlangsung ;
+Yogyakarta > Semarang > Surabaya > Denpasar
+
+Rute tersebut berlaku arah sebaliknya.
+Traveller dapat menggunakan transportasi yang disediakan oleh
+Pemerintah yaitu berupa :
+
+- Pesawat, biayanya 275000
+- Kereta, biayanya 250000
+- Bis, biayanya 225000
+
+Biaya tersebut berlaku untuk jarak 1 kota saja.
+
+Dikarenakan traveller berkeliling Indonesia bertepatan dengan digalakkannya visit Indonesia
+Maka traveller akan mendapatkan diskon menggunakan metode pembayaran tertentu;
+
+- OVO > akan mendapatkan diskon 15% setiap kota
+- Dana > akan mendapatkan diskon 10% setiap kota
+- Gopay > akan mendapatkan diskon 5% setiap kota
+- Cash > normal;
+
+Function tersebut akan mengembalikan siapa yang mengeluarkan biaya paling besar (sudah termasuk diskon);
+
+Note:
+1. Hanya boleh menggunakan built in function .push();
+*/
+
+function calculateCost(distance, transportType, paymentType) {
+ const transportCosts = {
+ Pesawat: 275000,
+ Kereta: 250000,
+ Bis: 225000,
+ };
+ const paymentDiscounts = {
+ OVO: 0.15,
+ Dana: 0.1,
+ Gopay: 0.05,
+ Cash: 0,
+ };
+
+ let cost = distance * transportCosts[transportType];
+ let discount = cost * paymentDiscounts[paymentType];
+ return cost - discount;
+}
+
+function travelingIndonesia(arr, emoney) {
+ //code here
+ if (arr.length === 0) {
+ return [];
+ }
+
+ const destinations = ["Yogyakarta", "Semarang", "Surabaya", "Denpasar"];
+ let results = arr.map((trip) => {
+ let [name, departure, destination, transport] = trip.split("-");
+ let departureIndex = destinations.indexOf(departure);
+ let destinationIndex = destinations.indexOf(destination);
+ let distance = Math.abs(destinationIndex - departureIndex);
+
+ return {
+ name: name,
+ departureCity: departure,
+ destinationCity: destination,
+ transport: transport,
+ totalCost: calculateCost(distance, transport, emoney),
+ };
+ });
+
+ // Sort by totalCost in descending order
+ results.sort((a, b) => b.totalCost - a.totalCost);
+ return results;
+}
+
+console.log(
+ travelingIndonesia(
+ [
+ "Danang-Yogyakarta-Semarang-Bis",
+ "Alif-Denpasar-Surabaya-Kereta",
+ "Bahari-Semarang-Denpasar-Pesawat",
+ ],
+ "OVO"
+ )
+);
+/*
+ [ { name: 'Bahari',
+ departureCity: 'Semarang',
+ destinationCity: 'Denpasar',
+ transport: 'Pesawat',
+ totalCost: 467500 },
+ { name: 'Alif',
+ departureCity: 'Denpasar',
+ destinationCity: 'Surabaya',
+ transport: 'Kereta',
+ totalCost: 212500 },
+ { name: 'Danang',
+ departureCity: 'Yogyakarta',
+ destinationCity: 'Semarang',
+ transport: 'Bis',
+ totalCost: 191250 } ]
+ */
+console.log(
+ "=================================================================================================="
+);
+console.log(
+ travelingIndonesia(
+ [
+ "Shafur-Surabaya-Yogyakarta-Kereta",
+ "Taufik-Semarang-Surabaya-Pesawat",
+ "Alex-Yogyakarta-Semarang-Kereta",
+ ],
+ "Dana"
+ )
+);
+// /*
+// [ { name: 'Shafur',
+// departureCity: 'Surabaya',
+// destinationCity: 'Yogyakarta',
+// transport: 'Kereta',
+// totalCost: 450000 },
+// { name: 'Taufik',
+// departureCity: 'Semarang',
+// destinationCity: 'Surabaya',
+// transport: 'Pesawat',
+// totalCost: 247500 },
+// { name: 'Alex',
+// departureCity: 'Yogyakarta',
+// destinationCity: 'Semarang',
+// transport: 'Kereta',
+// totalCost: 225000 } ]
+// */
+console.log(
+ "=================================================================================================="
+);
+console.log(
+ travelingIndonesia(
+ ["Andika-Denpasar-Surabaya-Bis", "Katy-Surabaya-Denpasar-Pesawat"],
+ "Gopay"
+ )
+);
+// /*
+// [ { name: 'Katy',
+// departureCity: 'Surabaya',
+// destinationCity: 'Denpasar',
+// transport: 'Pesawat',
+// totalCost: 261250 },
+// { name: 'Andika',
+// departureCity: 'Denpasar',
+// destinationCity: 'Surabaya',
+// transport: 'Bis',
+// totalCost: 213750 } ]
+// */
+console.log(
+ "=================================================================================================="
+);
+console.log(travelingIndonesia(["Putra-Denpasar-Yogyakarta-Pesawat"], "Cash"));
+// /*
+// [ { name: 'Putra',
+// departureCity: 'Denpasar',
+// destinationCity: 'Yogyakarta',
+// transport: 'Pesawat',
+// totalCost: 825000 } ]
+// */
+console.log(travelingIndonesia([], "Cash")); // [];
diff --git a/Part 16 - Web Development/You Need to Like Object/soal_5.js b/Part 16 - Web Development/You Need to Like Object/soal_5.js
new file mode 100644
index 0000000..b14e69b
--- /dev/null
+++ b/Part 16 - Web Development/You Need to Like Object/soal_5.js
@@ -0,0 +1,109 @@
+/**
+Delete Undefined Keys
+=====================
+Implementasikan function `deleteUndefinedKeys` untuk menghapus
+key di dalam object yang memiliki value undefined.
+
+Function ini akan menerima satu parameter yaitu `data`
+yang memiliki tipe data array.
+Di dalam array `data` terdapat beberapa object yang memiliki
+value undefined. Tugas kamu adalah untuk menghapus key tersebut
+
+# Contoh I/O
+Contoh input dan output bisa kamu lihat di test case
+
+# Kondisi khusus
+- Jika tidak ada elemen di dalam `data`, maka tampilkan 'No data'
+
+CONSTRAINTS
+============
+- DILARANG menggunakan built-in function .map, .filter
+
+*/
+
+function deleteUndefinedKeys(data) {
+ //code here
+ if (data.length === 0) {
+ return 'No data';
+ }
+
+ // Iterate through each object in the array
+ for (let i = 0; i < data.length; i++) {
+ const currentObject = data[i];
+
+ // Get all keys in the current object
+ const keys = Object.keys(currentObject);
+
+ // Iterate through each key and remove key-value pair if the value is undefined
+ for (let j = 0; j < keys.length; j++) {
+ const key = keys[j];
+ if (currentObject[key] === undefined) {
+ delete currentObject[key];
+ }
+ }
+ }
+
+ return data;
+}
+
+console.log(
+ deleteUndefinedKeys([
+ {
+ name: "Dimitri",
+ address: undefined,
+ email: "dimitri@mail.com",
+ age: undefined,
+ gender: "male",
+ },
+ {
+ name: "Alexei",
+ address: "Earth",
+ email: undefined,
+ age: 18,
+ gender: "male",
+ },
+ ])
+);
+/*
+ [ { name: 'Dimitri', email: 'dimitri@mail.com', gender: 'male' },
+ { name: 'Alexei', address: 'Earth', age: 18, gender: 'male' } ]
+ */
+
+console.log(
+ deleteUndefinedKeys([
+ {
+ band: "Ghost",
+ formed: 2006,
+ members: ["Papa Emeritus", "Alpha", "Omega", "Water", "Wind", "Earth"],
+ genre: "Heavy Metal",
+ rating: undefined,
+ },
+ {
+ band: "BABYMETAL",
+ formed: undefined,
+ members: ["SU-METAL", "MOAMETAL", "YUIMETAL"],
+ genre: "Kawaii Metal",
+ rating: undefined,
+ },
+ {
+ band: "Avatar",
+ formed: 2006,
+ members: undefined,
+ genre: undefined,
+ rating: 5,
+ },
+ ])
+);
+/*
+ [ { band: 'Ghost',
+ formed: 2006,
+ members: [ 'Papa Emeritus', 'Alpha', 'Omega', 'Water', 'Wind', 'Earth' ],
+ genre: 'Heavy Metal' },
+ { band: 'BABYMETAL',
+ members: [ 'SU-METAL', 'MOAMETAL', 'YUIMETAL' ],
+ genre: 'Kawaii Metal' },
+ { band: 'Avatar', formed: 2006, rating: 5 } ]
+ */
+
+console.log(deleteUndefinedKeys([]));
+// No data
diff --git a/Part 8 - Array/tentukanDeretAritmatika(arr).js b/Part 8 - Array/tentukanDeretAritmatika(arr).js
index 53dbbf0..29dbff1 100644
--- a/Part 8 - Array/tentukanDeretAritmatika(arr).js
+++ b/Part 8 - Array/tentukanDeretAritmatika(arr).js
@@ -1,13 +1,16 @@
//tentukan apakah ini deret aritmatika atau bukan
function tentukanDeretAritmatika(arr) {
// you can only write your code here!
- for (let i = 0; i <= arr.length - 1; i++) {
- if (arr[i + arr.length - 1] - arr[i + arr.length - 2] == arr[i + 0]) {
- return true;
- } else {
+ let selisih = arr[1] - arr[0];
+
+ for (let i = 1; i < arr.length - 1; i++) {
+ if (arr[i + 1] - arr[i] !== selisih) {
return false;
}
}
+
+ // Jika selisih konsisten untuk semua pasangan elemen
+ return true;
}
// TEST CASES
@@ -16,3 +19,4 @@ console.log(tentukanDeretAritmatika([2, 4, 6, 12, 24])); // false
console.log(tentukanDeretAritmatika([2, 4, 6, 8])); // true
console.log(tentukanDeretAritmatika([2, 6, 18, 54])); // false
console.log(tentukanDeretAritmatika([1, 2, 3, 4, 7, 9])); // false
+console.log(tentukanDeretAritmatika([1, 2, 5, 4, 5, 6, 7])); // false
\ No newline at end of file
diff --git a/README.md b/README.md
index 92bad59..a0124eb 100644
Binary files a/README.md and b/README.md differ
diff --git a/iseng/Binary_Addition.js b/iseng/Binary_Addition.js
new file mode 100644
index 0000000..05f9b9a
--- /dev/null
+++ b/iseng/Binary_Addition.js
@@ -0,0 +1,14 @@
+function addBinary(a, b) {
+ // Convert decimal numbers to binary
+ const binaryA = a.toString(2);
+ const binaryB = b.toString(2);
+
+ // Calculate the sum of binary numbers
+ const sumDecimal = a + b;
+ const sumBinary = sumDecimal.toString(2);
+
+ return sumBinary;
+}
+console.log(addBinary(1, 2));
+console.log(addBinary(2, 3));
+console.log(addBinary(3, 4));
diff --git a/iseng/Longest_Palindrome.js b/iseng/Longest_Palindrome.js
new file mode 100644
index 0000000..c89b48e
--- /dev/null
+++ b/iseng/Longest_Palindrome.js
@@ -0,0 +1,46 @@
+function longestPalindrome(str) {
+ //Good Luck
+ // Step 1: Create a frequency map
+ for (let i = 0; i < str.length; i++) {
+ const char = str[i].toLowerCase(); // Convert to lowercase for case-insensitivity
+ // Check if the character is alphanumeric
+ if (/[a-z0-9]/.test(char)) {
+ if (charCount[char] === undefined) {
+ charCount[char] = 1;
+ } else {
+ charCount[char]++;
+ }
+ }
+ }
+// const charCount = new Map();
+// for (const char of str.toLowerCase()) {
+// if (/[a-z0-9]/.test(char)) {
+// charCount.set(char, (charCount.get(char) || 0) + 1);
+// }
+// }
+
+ // Step 2-6: Calculate the length of the longest palindrome
+ let length = 0;
+ let hasOddCount = false;
+
+ for (const count of charCount.values()) {
+ if (count % 2 === 0) {
+ length += count;
+ } else {
+ length += count - 1; // Use even count for the pair
+ hasOddCount = true;
+ }
+ }
+
+ // Add 1 for a single character with odd count if present
+ if (hasOddCount) {
+ length += 1;
+ }
+
+ return length;
+}
+
+console.log(longestPalindrome("Hannah")); //6
+console.log(longestPalindrome("aabbcc_yYx_")); //9
+console.log(longestPalindrome("xyz__a_/b0110//a_zyx")); //13
+console.log(longestPalindrome("$aaabbbccddd_!jJpqlQx_.///yYabababhii_")); //25
diff --git a/iseng/Replace_With_Alphabet_Position.js b/iseng/Replace_With_Alphabet_Position.js
new file mode 100644
index 0000000..6776a7e
--- /dev/null
+++ b/iseng/Replace_With_Alphabet_Position.js
@@ -0,0 +1,32 @@
+function alphabetPosition(text) {
+ const alphabet = "abcdefghijklmnopqrstuvwxyz";
+ text = text.toLowerCase(); //Convert Text to Lowercase:
+ console.log("text_1", text);
+ text = text.replace(/[^a-z]/g, ""); //Remove Non-Alphabetic Characters:
+ console.log("text_2", text);
+
+ const positions = [];
+ for (let i = 0; i < text.length; i++) {
+ //Loop Through Each Character:
+ const char = text[i];
+ const charPosition = alphabet.indexOf(char) + 1; //Find Position of Each Letter:
+ positions.push(charPosition);
+ }
+ console.log("positions", positions);
+
+ const result = positions.join(" ");
+ console.log('result',result);
+ return result;
+
+ // return text
+ // .toLowerCase() // Convert to lowercase to handle both uppercase and lowercase letters
+ // .replace(/[^a-z]/g, "") // Remove non-alphabetic characters
+ // .split("")
+ // .map((char) => alphabet.indexOf(char) + 1)
+ // .join(" ");
+}
+
+console.log(alphabetPosition("The sunset sets at twelve o' clock."));
+// "20 8 5 19 21 14 19 5 20 19 5 20 19 1 20 20 23 5 12 22 5 15 3 12 15 3 11"
+console.log(alphabetPosition("The narwhal bacons at midnight."));
+// "20 8 5 14 1 18 23 8 1 12 2 1 3 15 14 19 1 20 13 9 4 14 9 7 8 20"
diff --git a/iseng/The_Latest_Clock.js b/iseng/The_Latest_Clock.js
new file mode 100644
index 0000000..612f7c8
--- /dev/null
+++ b/iseng/The_Latest_Clock.js
@@ -0,0 +1,53 @@
+function latestClock(a, b, c, d) {
+ let latestTime = -1;
+
+ // Helper function to check if a time is valid
+ const isValidTime = (hour, minute) =>
+ hour >= 0 && hour < 24 && minute >= 0 && minute < 60;
+
+ // Helper function to swap two elements in an array
+ const swap = (arr, i, j) => {
+ const temp = arr[i];
+ arr[i] = arr[j];
+ arr[j] = temp;
+ };
+
+ // Helper function to generate all permutations of the digits
+ const generatePermutations = (arr, start) => {
+ if (start === arr.length - 1) {
+ const [h1, h2, m1, m2] = arr;
+ const hour = h1 * 10 + h2;
+ const minute = m1 * 10 + m2;
+
+ if (
+ isValidTime(hour, minute) &&
+ (hour > latestTime ||
+ (hour === latestTime && minute > latestTime % 100))
+ ) {
+ latestTime = hour * 100 + minute;
+ }
+ } else {
+ for (let i = start; i < arr.length; i++) {
+ swap(arr, start, i);
+ generatePermutations(arr, start + 1);
+ swap(arr, start, i);
+ }
+ }
+ };
+ // Initial call to generate permutations
+ generatePermutations([a, b, c, d], 0);
+
+ // Format the result as HH:MM
+ const resultHour = Math.floor(latestTime / 100);
+ const resultMinute = latestTime % 100;
+
+ return `${resultHour.toString().padStart(2, "0")}:${resultMinute
+ .toString()
+ .padStart(2, "0")}`;
+}
+
+console.log(latestClock(1, 9, 8, 3)); //"19:38"
+console.log(latestClock(9, 1, 2, 5)); //"21:59"
+console.log(latestClock(1, 2, 8, 9)); //"19:28"
+console.log(latestClock(0, 0, 0, 0)); //"00:00"
+console.log(latestClock(0, 0, 0, 0)); //"20:40"
diff --git a/iseng/index.html b/iseng/index.html
new file mode 100644
index 0000000..a3170f2
--- /dev/null
+++ b/iseng/index.html
@@ -0,0 +1,100 @@
+
+
+
+
+
+
+ 5 Trick CSS Mudah
+
+
+
+
+
+
5 Trick CSS Mudah
+
+
+
+
+
+
+
1. Meletakan element dari kiri atas ke tengah - tengah
+
2. Button
+
3. Animasi Teks Bergerak
+
4. Mainin Gambar
+
5. Bar pada Gambar
+
+
+
+
+
\ No newline at end of file
diff --git a/nextjs-tutorial/.eslintrc.json b/nextjs-tutorial/.eslintrc.json
new file mode 100644
index 0000000..bffb357
--- /dev/null
+++ b/nextjs-tutorial/.eslintrc.json
@@ -0,0 +1,3 @@
+{
+ "extends": "next/core-web-vitals"
+}
diff --git a/nextjs-tutorial/.gitignore b/nextjs-tutorial/.gitignore
new file mode 100644
index 0000000..fd3dbb5
--- /dev/null
+++ b/nextjs-tutorial/.gitignore
@@ -0,0 +1,36 @@
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
+# dependencies
+/node_modules
+/.pnp
+.pnp.js
+.yarn/install-state.gz
+
+# testing
+/coverage
+
+# next.js
+/.next/
+/out/
+
+# production
+/build
+
+# misc
+.DS_Store
+*.pem
+
+# debug
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+# local env files
+.env*.local
+
+# vercel
+.vercel
+
+# typescript
+*.tsbuildinfo
+next-env.d.ts
diff --git a/nextjs-tutorial/README.md b/nextjs-tutorial/README.md
new file mode 100644
index 0000000..c403366
--- /dev/null
+++ b/nextjs-tutorial/README.md
@@ -0,0 +1,36 @@
+This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
+
+## Getting Started
+
+First, run the development server:
+
+```bash
+npm run dev
+# or
+yarn dev
+# or
+pnpm dev
+# or
+bun dev
+```
+
+Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
+
+You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
+
+This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
+
+## Learn More
+
+To learn more about Next.js, take a look at the following resources:
+
+- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
+- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
+
+You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
+
+## Deploy on Vercel
+
+The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
+
+Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
diff --git a/nextjs-tutorial/app/contacts/page.tsx b/nextjs-tutorial/app/contacts/page.tsx
new file mode 100644
index 0000000..c59b5ff
--- /dev/null
+++ b/nextjs-tutorial/app/contacts/page.tsx
@@ -0,0 +1,15 @@
+import ContactTable from "@/component/contact-table"
+import Search from "@/component/search"
+const Contact = () => {
+ return (
+
+
+
+
+
+
+
+ )
+}
+
+export default Contact
diff --git a/nextjs-tutorial/app/favicon.ico b/nextjs-tutorial/app/favicon.ico
new file mode 100644
index 0000000..718d6fe
Binary files /dev/null and b/nextjs-tutorial/app/favicon.ico differ
diff --git a/nextjs-tutorial/app/globals.css b/nextjs-tutorial/app/globals.css
new file mode 100644
index 0000000..bcf21eb
--- /dev/null
+++ b/nextjs-tutorial/app/globals.css
@@ -0,0 +1,5 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+
diff --git a/nextjs-tutorial/app/layout.tsx b/nextjs-tutorial/app/layout.tsx
new file mode 100644
index 0000000..3314e47
--- /dev/null
+++ b/nextjs-tutorial/app/layout.tsx
@@ -0,0 +1,22 @@
+import type { Metadata } from "next";
+import { Inter } from "next/font/google";
+import "./globals.css";
+
+const inter = Inter({ subsets: ["latin"] });
+
+export const metadata: Metadata = {
+ title: "Create Next App",
+ description: "Generated by create next app",
+};
+
+export default function RootLayout({
+ children,
+}: Readonly<{
+ children: React.ReactNode;
+}>) {
+ return (
+
+ {children}
+
+ );
+}
diff --git a/nextjs-tutorial/app/page.tsx b/nextjs-tutorial/app/page.tsx
new file mode 100644
index 0000000..fe411cc
--- /dev/null
+++ b/nextjs-tutorial/app/page.tsx
@@ -0,0 +1,6 @@
+
+export default function Home() {
+ return (
+