Merge branch 'master' into feat/thank-you-page

feat/thank-you-page
Kamran Ahmed 2 days ago committed by GitHub
commit 9d4ef8e938
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 1
      contributing.md
  2. 1375
      pnpm-lock.yaml
  3. 1944
      public/roadmap-content/ai-agents.json
  4. 5
      public/roadmap-content/ai-engineer.json
  5. 2
      public/roadmap-content/ai-red-teaming.json
  6. 5
      public/roadmap-content/angular.json
  7. 32
      public/roadmap-content/blockchain.json
  8. 341
      public/roadmap-content/computer-science.json
  9. 20
      public/roadmap-content/cpp.json
  10. 64
      public/roadmap-content/cyber-security.json
  11. 10
      public/roadmap-content/engineering-manager.json
  12. 2
      public/roadmap-content/frontend.json
  13. 2
      public/roadmap-content/java.json
  14. 5
      public/roadmap-content/react.json
  15. 2
      public/roadmap-content/software-architect.json
  16. 2
      public/roadmap-content/typescript.json
  17. 6
      public/roadmap-content/vue.json
  18. 4
      src/components/AITutor/AITutorLayout.tsx
  19. 1
      src/components/CustomRoadmap/CustomRoadmap.tsx
  20. 20
      src/components/Footer.astro
  21. 2
      src/components/GenerateCourse/AICourseLessonChat.tsx
  22. 22
      src/components/GenerateCourse/GenerateAICourse.tsx
  23. 32
      src/components/SQLCourse/CourseAnnouncement.tsx
  24. 60
      src/components/TopicDetail/CreateCourseModal.tsx
  25. 54
      src/components/TopicDetail/PredefinedActionGroup.tsx
  26. 144
      src/components/TopicDetail/PredefinedActions.tsx
  27. 2
      src/components/TopicDetail/ResourceListSeparator.tsx
  28. 484
      src/components/TopicDetail/TopicDetail.tsx
  29. 522
      src/components/TopicDetail/TopicDetailAI.tsx
  30. 48
      src/components/TopicDetail/TopicDetailLink.tsx
  31. 68
      src/components/TopicDetail/TopicDetailsTabs.tsx
  32. 177
      src/components/TopicDetail/TopicProgressButton.tsx
  33. 18
      src/data/changelogs/ai-agents-red-teaming-roadmaps.md
  34. 4
      src/data/changelogs/ai-tutor-cpp-java-roadmaps.md
  35. 195
      src/data/guides/frontend-vs-backend-ai.md
  36. 2
      src/data/roadmaps/ai-engineer/ai-engineer.md
  37. 1
      src/data/roadmaps/ai-engineer/content/ollama@rTT2UnvqFO3GH6ThPLEjO.md
  38. 1
      src/data/roadmaps/angular/content/event-binding@bKnpirSvex4oE4lAjiSSV.md
  39. 10
      src/data/roadmaps/backend/content/authentication@PY9G7KQy8bF6eIdr1ydHf.md
  40. 1
      src/data/roadmaps/blockchain/content/crypto-wallets@SM8Wt3iNM_nncLj69KCuy.md
  41. 1
      src/data/roadmaps/blockchain/content/cryptowallets@FSThY0R1OAZCIL98W3AMj.md
  42. 2
      src/data/roadmaps/blockchain/content/dapps---decentralized-applications@SXXvFtf_7Rx64cHSEWxMS.md
  43. 3
      src/data/roadmaps/blockchain/content/javascript@fF06XiQV4CPEJnt_ESOvv.md
  44. 2
      src/data/roadmaps/blockchain/content/security@PBTrg9ivOpw9uNTVisIpx.md
  45. 1
      src/data/roadmaps/blockchain/content/smart-contracts@BV6lEwCAKaYxSPWD0LV_d.md
  46. 1
      src/data/roadmaps/blockchain/content/zk-rollups--zero-knowledge-proof@PykoX4j5Q3eJWIpUoczjM.md
  47. 2
      src/data/roadmaps/computer-science/content/osi-model@pZ5x_zDYGzW9VxYycyXtN.md
  48. 2
      src/data/roadmaps/computer-science/content/tcpip-model@Fed5y1D95WPpqoVg7kmob.md
  49. 22
      src/data/roadmaps/cpp/content/unique_ptr@k9c5seRkhgm_yHPpiz2X0.md
  50. 3
      src/data/roadmaps/cyber-security/content/comptia-security@AxeDcKK3cUtEojtHQPBw7.md
  51. 6
      src/data/roadmaps/datastructures-and-algorithms/content/programming-fundamentals/oop-basics.md
  52. 6
      src/data/roadmaps/engineering-manager/content/emotional-intelligence@h7gEQNbGiabDA1q1Bk_IB.md
  53. 4
      src/data/roadmaps/frontend/content/how-does-the-internet-work@yCnn-NfSxIybUQ2iTuUGq.md
  54. 2
      src/data/roadmaps/frontend/content/internet@VlNNwIEDWqQXtqkHWJYzC.md
  55. 2
      src/data/roadmaps/graphql/content/mutations/what-are-mutations.md
  56. 2
      src/data/roadmaps/java/content/classes-and-objects@LenPrQwxFsE1UVbXO_dE7.md
  57. 4
      src/data/roadmaps/linux/content/package-management/index.md
  58. 2
      src/data/roadmaps/php/content/csrf-protection@J9yIXZTtwbFzH2u4dI1ep.md
  59. 2
      src/data/roadmaps/php/content/inheritance@c5q2e_jyMt8Pir5Od3lRi.md
  60. 2
      src/data/roadmaps/php/content/polymorphism@gtq5KrghF28f5G8nuDcYQ.md
  61. 1
      src/data/roadmaps/react/content/cli-tools@tU4Umtnfu01t9gLlnlK6b.md
  62. 1
      src/data/roadmaps/rust/content/introduction/what-is-rust.md
  63. 2
      src/data/roadmaps/software-architect/content/osi@Mt5W1IvuHevNXVRlh7z26.md
  64. 2
      src/data/roadmaps/typescript/content/as-any@afTNr36VqeXoJpHxm2IoS.md
  65. 2
      src/data/roadmaps/vue/content/api-styles@OpJ2NMKCGXQezpzURE45R.md
  66. 2
      src/data/roadmaps/vue/content/composition-api@a0qwdQTunxEjQ9A5wpF-q.md
  67. 2
      src/data/roadmaps/vue/content/options-api@PPUU3Rb73aCpT4zcyvlJE.md
  68. 16
      src/helper/generate-ai-course.ts
  69. 4
      src/hooks/use-keydown.ts
  70. 1
      src/icons/blusky.svg
  71. 2
      src/layouts/BaseLayout.astro
  72. 22
      src/lib/config.ts
  73. 3
      src/pages/[roadmapId]/index.astro
  74. 4
      src/pages/best-practices/[bestPracticeId]/index.astro
  75. 89
      src/pages/courses/sql.astro
  76. 30
      src/pages/frontend/vs-backend-ai.astro
  77. 26
      src/queries/roadmap-tree.ts

@ -79,6 +79,7 @@ Visit the following resources to learn more:
- `@course@`
- `@podcast@`
- `@video@`
- `@book@`
It's important to add a valid type, this will help us categorize the content and display it properly on the roadmap. The order of the links based on type is same as above.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -906,6 +906,11 @@
"title": "Ollama: Easily run LLMs locally",
"url": "https://klu.ai/glossary/ollama",
"type": "article"
},
{
"title": "What is Ollama? Running Local LLMs Made Simple",
"url": "https://www.youtube.com/watch?v=5RIOQuHOihY",
"type": "video"
}
]
},

@ -335,7 +335,7 @@
"description": "Jailbreaking is a specific category of prompt hacking where the AI Red Teamer aims to bypass the LLM's safety and alignment training. They use techniques like creating fictional scenarios, asking the model to simulate an unrestricted AI, or using complex instructions to trick the model into generating content that violates its own policies (e.g., generating harmful code, hate speech, or illegal instructions).\n\nLearn more from the following resources:",
"links": [
{
"title": "InjectPrompt (David Willis-Owen)",
"title": "InjectPrompt",
"url": "https://injectprompt.com",
"type": "article"
},

@ -658,11 +658,6 @@
"title": "Angular Official Docs - Event Binding",
"url": "https://angular.dev/guide/templates/event-binding",
"type": "article"
},
{
"title": "Event Binding in Angular",
"url": "https://www.knowledgehut.com/blog/web-development/event-binding-in-angular",
"type": "article"
}
]
},

@ -328,6 +328,11 @@
"title": "What is a Crypto Wallet? A Beginner’s Guide",
"url": "https://crypto.com/university/crypto-wallets",
"type": "article"
},
{
"title": "Choose your wallet - Ethereum",
"url": "https://ethereum.org/en/wallets/find-wallet/",
"type": "article"
}
]
},
@ -982,6 +987,11 @@
"url": "https://chain.link/education/smart-contracts",
"type": "article"
},
{
"title": "Introduction to smart contracts - Ethereum",
"url": "https://ethereum.org/en/smart-contracts/",
"type": "article"
},
{
"title": "Explore top posts about Smart Contracts",
"url": "https://app.daily.dev/tags/smart-contracts?ref=roadmapsh",
@ -1238,6 +1248,11 @@
"url": "https://www.coinbase.com/learn/crypto-basics/what-is-a-crypto-wallet",
"type": "article"
},
{
"title": "Choose your wallet - Ethereum",
"url": "https://ethereum.org/en/wallets/find-wallet/",
"type": "article"
},
{
"title": "Explore top posts about Crypto",
"url": "https://app.daily.dev/tags/crypto?ref=roadmapsh",
@ -1799,6 +1814,16 @@
"title": "What Is a Dapp? Decentralized Apps Explained",
"url": "https://www.coindesk.com/learn/what-is-a-dapp-decentralized-apps-explained/",
"type": "article"
},
{
"title": "Explore Top dApps on Ethereum and its Layer 2s",
"url": "https://www.ethereum-ecosystem.com/apps",
"type": "article"
},
{
"title": "Explore Top Ethereum dApps",
"url": "https://eth.blockscout.com/apps",
"type": "article"
}
]
},
@ -2355,7 +2380,7 @@
"type": "article"
},
{
"title": "dApp Security:All You Need to Know",
"title": "dApp Security: All You Need to Know",
"url": "https://www.immunebytes.com/blog/dapp-security/#Benefits_of_DApps_Security",
"type": "article"
},
@ -2572,6 +2597,11 @@
"url": "https://ethereum.org/en/developers/docs/scaling/zk-rollups",
"type": "article"
},
{
"title": "What are Zero-Knowledge proofs? - Ethereum",
"url": "https://ethereum.org/en/zero-knowledge-proofs/",
"type": "article"
},
{
"title": "Why and How zk-SNARK Works",
"url": "https://medium.com/@imolfar/why-and-how-zk-snark-works-1-introduction-the-medium-of-a-proof-d946e931160",

@ -3,6 +3,11 @@
"title": "Pick a Language",
"description": "You need to pick a programming language to learn the Computer Science concepts. My personal recommendation would be to pick C++ or C and the reason for that is:\n\n* They allow you to deal with pointers and memory allocation/deallocation, so you feel the data structures and algorithms in your bones. In higher level languages like Python or Java, these are hidden from you. In day to day work, that's terrific, but when you're learning how these low-level data structures are built, it's great to feel close to the metal.\n* You will be able to find a lot of resources for the topics listed in this roadmap using C or C++. You can find a lot of resources for Python and Java, but they are not as abundant as C++ and C.\n\nGiven below is the list of resources; pick ones relevant to the language of your choice.\n\nVisit the following resources to learn more:",
"links": [
{
"title": "Visit Dedicated C++ Roadmap",
"url": "https://roadmap.sh/cpp",
"type": "article"
},
{
"title": "Learn C++ - W3Schools",
"url": "https://www.w3schools.com/cpp/",
@ -126,7 +131,7 @@
"type": "article"
},
{
"title": "W3Schools Go Tutorial ",
"title": "W3Schools Go Tutorial",
"url": "https://www.w3schools.com/go/",
"type": "article"
},
@ -219,7 +224,7 @@
"description": "C++ is a powerful general-purpose programming language. It can be used to develop operating systems, browsers, games, and so on. C++ supports different ways of programming like procedural, object-oriented, functional, and so on. This makes C++ powerful as well as flexible.\n\nVisit the following resources to learn more:",
"links": [
{
"title": "C++ Roadmap",
"title": "Visit Dedicated C++ Roadmap",
"url": "https://roadmap.sh/cpp",
"type": "article"
},
@ -301,7 +306,7 @@
"type": "article"
},
{
"title": "Java Website",
"title": "Java",
"url": "https://www.java.com/",
"type": "article"
},
@ -455,6 +460,11 @@
"title": "Hash Table",
"description": "Hash Table, Map, HashMap, Dictionary or Associative are all the names of the same data structure. It is one of the most commonly used data structures.\n\nVisit the following resources to learn more:",
"links": [
{
"title": "Hash Tables - Princeton University",
"url": "https://algs4.cs.princeton.edu/34hash/",
"type": "article"
},
{
"title": "Hash Table | Illustrated Data Structures",
"url": "https://www.youtube.com/watch?v=jalSiaIi8j4",
@ -470,26 +480,6 @@
"url": "https://www.youtube.com/watch?v=0M_kIqhwbFo&list=PLUl4u3cNGP61Oq3tWYp6V_F-5jb5L2iHb&index=9",
"type": "video"
},
{
"title": "Table Doubling, Karp-Rabin",
"url": "https://www.youtube.com/watch?v=BRO7mVIFt08&list=PLUl4u3cNGP61Oq3tWYp6V_F-5jb5L2iHb&index=10",
"type": "video"
},
{
"title": "Open Addressing, Cryptographic Hashing",
"url": "https://www.youtube.com/watch?v=rvdJDijO2Ro&list=PLUl4u3cNGP61Oq3tWYp6V_F-5jb5L2iHb&index=11",
"type": "video"
},
{
"title": "PyCon 2010: The Mighty Dictionary",
"url": "https://www.youtube.com/watch?v=C4Kc8xzcA68",
"type": "video"
},
{
"title": "PyCon 2017: The Dictionary Even Mightier",
"url": "https://www.youtube.com/watch?v=66P5FMkWoVU",
"type": "video"
},
{
"title": "(Advanced) Randomization: Universal & Perfect Hashing",
"url": "https://www.youtube.com/watch?v=z0lJ2k0sl1g&list=PLUl4u3cNGP6317WaSNfmCvGym2ucw3oGp&index=11",
@ -512,9 +502,9 @@
"type": "course"
},
{
"title": "Dynamic Arrays - Coursera",
"url": "https://www.coursera.org/lecture/data-structures/dynamic-arrays-EwbnV",
"type": "course"
"title": "What is Array in Data Structure? Types & Syntax",
"url": "https://www.simplilearn.com/tutorials/data-structure-tutorial/arrays-in-data-structure",
"type": "article"
},
{
"title": "Array Data Structure | Illustrated Data Structures",
@ -522,8 +512,8 @@
"type": "video"
},
{
"title": "UC Berkeley CS61B - Linear and Multi-Dim Arrays (Start watching from 15m 32s)",
"url": "https://archive.org/details/ucberkeley_webcast_Wp8oiO_CZZE",
"title": "Jagged Arrays",
"url": "https://www.youtube.com/watch?v=1jtrQqYpt7g",
"type": "video"
},
{
@ -537,8 +527,8 @@
"type": "video"
},
{
"title": "Jagged Arrays",
"url": "https://www.youtube.com/watch?v=1jtrQqYpt7g",
"title": "UC Berkeley CS61B - Linear and Multi-Dim Arrays (Start watching from 15m 32s)",
"url": "https://archive.org/details/ucberkeley_webcast_Wp8oiO_CZZE",
"type": "video"
}
]
@ -547,6 +537,11 @@
"title": "Tree",
"description": "A tree is non-linear and a hierarchical data structure consisting of a collection of nodes such that each node of the tree stores a value and a list of references to other nodes (the “children”).\n\nVisit the following resources to learn more:",
"links": [
{
"title": "Tree Data Structure",
"url": "https://www.programiz.com/dsa/trees",
"type": "article"
},
{
"title": "Tree | Illustrated Data Structures",
"url": "https://www.youtube.com/watch?v=S2W3SXGPVyU",
@ -674,8 +669,13 @@
"description": "An unbalanced binary tree is one that is not balanced.\n\nVisit the following resources to learn more:",
"links": [
{
"title": "Balanced Binary Tree",
"url": "https://www.programiz.com/dsa/balanced-binary-tree",
"title": "Balanced vs Unbalanced Binary Tree",
"url": "https://stackoverflow.com/questions/59206128/balanced-vs-unbalanced-binary-tree-clarification-needed",
"type": "article"
},
{
"title": "Unbalanced Binary Tree",
"url": "https://eng.libretexts.org/Bookshelves/Computer_Science/Databases_and_Data_Structures/Open_Data_Structures_-_An_Introduction_(Morin)/06%3A_Binary_Trees/6.02%3A_BinarySearchTree_-_An_Unbalanced_Binary_Search_Treee",
"type": "article"
}
]
@ -815,6 +815,11 @@
"url": "https://www.coursera.org/lecture/data-structures/introduction-2OpTs",
"type": "course"
},
{
"title": "Heap Data Structure",
"url": "https://www.programiz.com/dsa/heap-data-structure",
"type": "article"
},
{
"title": "CS 61B Lecture 24: Priority Queues",
"url": "https://archive.org/details/ucberkeley_webcast_yIUFT6AKBGE",
@ -878,7 +883,12 @@
"description": "The Big O notation can be used to describe how the running time of an algorithm scales with the growth of the input size, ignoring implementation details such as programming language and computer speed. Specifically, it denotes the upper bound of the growth rate of a function that relates the running time of an algorithm to its input size. It can be used to compare algorithms and determine which one is better.\n\nVisit the following resources to learn more:",
"links": [
{
"title": "moviesCS 61B Lecture 19: Asymptotic Analysis",
"title": "Big-O Notation: A Simple Explanation with Examples",
"url": "https://medium.com/better-programming/big-o-notation-a-simple-explanation-with-examples-a56347d1daca",
"type": "article"
},
{
"title": "CS 61B Lecture 19: Asymptotic Analysis",
"url": "https://archive.org/details/ucberkeley_webcast_VIS4YDpuP98",
"type": "article"
},
@ -982,6 +992,11 @@
"title": "Linear",
"description": "Linear algorithms are algorithms that have a runtime that is directly proportional to the size of the input. This means that the runtime of the algorithm will increase linearly with the size of the input. For example, if the input size is 10, the runtime will be 10 times the runtime of the algorithm when the input size is 1. If the input size is 100, the runtime will be 100 times the runtime of the algorithm when the input size is 1.\n\nVisit the following resources to learn more:",
"links": [
{
"title": "Linear Search Algorithm",
"url": "https://www.geeksforgeeks.org/linear-search/",
"type": "article"
},
{
"title": "Big O Notation — Calculating Time Complexity",
"url": "https://www.youtube.com/watch?v=Z0bH0cMY0E8",
@ -1028,8 +1043,19 @@
},
"m0umGQNdvg95UiNpQZsQN": {
"title": "Factorial",
"description": "Factorial complexity algorithms have a runtime of `O(n!)`. This is the worst case scenario for an algorithm. Factorial complexity algorithms are very inefficient and should be avoided.\n\n def generate_permutations(s):\n # Base case: If the string length is 1, return a list containing the string\n if len(s) == 1:\n return [s]\n \n # Initialize the result list\n permutations = []\n \n # Recursively generate all permutations\n for i in range(len(s)):\n # Current character\n current_char = s[i]\n # Remaining characters\n remaining_chars = s[:i] + s[i + 1 :]\n # Generate all permutations of the remaining characters\n for perm in generate_permutations(remaining_chars):\n # Add the current character to the front of each generated permutation\n permutations.append(current_char + perm)\n \n return permutations",
"links": []
"description": "Factorial complexity algorithms have a runtime of `O(n!)`. This is the worst case scenario for an algorithm. Factorial complexity algorithms are very inefficient and should be avoided.\n\n def generate_permutations(s):\n # Base case: If the string length is 1, return a list containing the string\n if len(s) == 1:\n return [s]\n \n # Initialize the result list\n permutations = []\n \n # Recursively generate all permutations\n for i in range(len(s)):\n # Current character\n current_char = s[i]\n # Remaining characters\n remaining_chars = s[:i] + s[i + 1 :]\n # Generate all permutations of the remaining characters\n for perm in generate_permutations(remaining_chars):\n # Add the current character to the front of each generated permutation\n permutations.append(current_char + perm)\n \n return permutations\n \n\nVisit the following resources to learn more:",
"links": [
{
"title": "Big O Cheat Sheet - Time Complexity Chart",
"url": "https://www.freecodecamp.org/news/big-o-cheat-sheet-time-complexity-chart/",
"type": "article"
},
{
"title": "Factorial Explained",
"url": "https://www.youtube.com/watch?v=pxh__ugRKz8",
"type": "video"
}
]
},
"7a6-AnBI-3tAU1dkOvPkx": {
"title": "Common Algorithms",
@ -1203,6 +1229,11 @@
"url": "https://www.coursera.org/lecture/algorithms-part1/selection-UQxFT",
"type": "course"
},
{
"title": "Selection Sort",
"url": "https://en.wikipedia.org/wiki/Selection_sort",
"type": "article"
},
{
"title": "Selection Sort in 3 Minutes",
"url": "https://www.youtube.com/watch?v=g-PGLbMth_g",
@ -1215,7 +1246,7 @@
"description": "Insertion sort is a simple sorting algorithm that builds the final sorted array one item at a time by comparisons. It is much less efficient on large lists than more advanced algorithms such as quicksort, heapsort, or merge sort.\n\nVisit the following resources to learn more:",
"links": [
{
"title": "Insertion Sort Algorithm",
"title": "Insertion Sort",
"url": "https://www.programiz.com/dsa/insertion-sort",
"type": "article"
},
@ -1324,6 +1355,11 @@
"title": "In-Order Traversal",
"description": "In-order traversal is a tree traversal algorithm that visits the left subtree, the root, and then the right subtree. This is the most common way to traverse a binary search tree. It is also used to create a sorted list of nodes in a binary search tree.\n\nVisit the following resources to learn more:",
"links": [
{
"title": "Tree Traversal Techniques",
"url": "https://www.geeksforgeeks.org/tree-traversals-inorder-preorder-and-postorder/",
"type": "article"
},
{
"title": "Tree | Illustrated Data Structures",
"url": "https://www.youtube.com/watch?v=S2W3SXGPVyU",
@ -1335,6 +1371,11 @@
"title": "Post Order Traversal",
"description": "Post-order traversal is a type of tree traversal that visits the left subtree, then the right subtree, and finally the root node. This is the opposite of pre-order traversal, which visits the root node first, then the left subtree, and finally the right subtree.\n\nVisit the following resources to learn more:",
"links": [
{
"title": "Postorder Traversal of Binary Tree",
"url": "https://www.geeksforgeeks.org/postorder-traversal-of-binary-tree/",
"type": "article"
},
{
"title": "Tree | Illustrated Data Structures",
"url": "https://www.youtube.com/watch?v=S2W3SXGPVyU",
@ -1552,7 +1593,7 @@
"type": "article"
},
{
"title": "Knights Tour Proble",
"title": "Knights Tour Problem",
"url": "https://www.codesdope.com/course/algorithms-knights-tour-problem/",
"type": "article"
},
@ -1708,6 +1749,11 @@
"title": "LFU Cache",
"description": "LFU Cache is a data structure that stores key-value pairs. It has a fixed size and when it is full, it removes the least frequently used key-value pair. It is a variation of the LRU Cache and is used in many applications such as caching web pages, caching database queries, and caching images.\n\nVisit the following resources to learn more:",
"links": [
{
"title": "Least Frequently Used (LFU) Cache Implementation",
"url": "https://www.geeksforgeeks.org/least-frequently-used-lfu-cache-implementation/",
"type": "article"
},
{
"title": "1117. Data Structure - LFU Cache",
"url": "https://jojozhuang.github.io/algorithm/data-structure-lfu-cache/",
@ -1720,7 +1766,7 @@
"description": "String search and manipulation is a very important topic in computer science. It is used in many different applications, such as searching or replacing a specific pattern, word or character in a string.\n\nVisit the following resources to learn more:",
"links": [
{
"title": "String-searching algorithm",
"title": "String-searching Algorithm",
"url": "https://en.wikipedia.org/wiki/String-searching_algorithm",
"type": "article"
}
@ -1734,6 +1780,11 @@
"title": "Search Pattern in Text",
"url": "https://www.coursera.org/learn/data-structures/lecture/tAfHI/search-pattern-in-text",
"type": "course"
},
{
"title": "Pattern Searching",
"url": "https://www.geeksforgeeks.org/pattern-searching/",
"type": "article"
}
]
},
@ -1747,7 +1798,12 @@
"type": "course"
},
{
"title": "Suffix array introduction",
"title": "Suffix Arrays - Princeton University",
"url": "https://algs4.cs.princeton.edu/63suffix/",
"type": "article"
},
{
"title": "Suffix Array Introduction",
"url": "https://www.youtube.com/watch?v=zqKlL3ZpTqs",
"type": "video"
},
@ -1757,7 +1813,7 @@
"type": "video"
},
{
"title": "Suffix arrays: building",
"title": "Suffix Arrays: building",
"url": "https://www.youtube.com/watch?v=ZWlbhBjjwyA",
"type": "video"
}
@ -1773,7 +1829,7 @@
"type": "course"
},
{
"title": "A beginner guide to Brute Force Algorithm for substring search",
"title": "A Beginner Guide to Brute Force Algorithm for Substring Search",
"url": "https://nulpointerexception.com/2019/02/10/a-beginner-guide-to-brute-force-algorithm-for-substring-search/",
"type": "article"
},
@ -1808,6 +1864,11 @@
"title": "Boyer Moore Algorithm",
"url": "https://www.coursera.org/learn/algorithms-part2/lecture/CYxOT/boyer-moore",
"type": "course"
},
{
"title": "Boyer-Moore String-search Algorithm",
"url": "https://en.wikipedia.org/wiki/Boyer%E2%80%93Moore_string-search_algorithm",
"type": "article"
}
]
},
@ -1921,7 +1982,7 @@
"description": "Little Endian is a way of storing data in memory. It is the opposite of Big Endian. In Little Endian, the least significant byte is stored first. In Big Endian, the most significant byte is stored first.\n\nVisit the following resources to learn more:",
"links": [
{
"title": "Big Endian vs Little Endian.mp4",
"title": "Big Endian vs Little Endian",
"url": "https://www.youtube.com/watch?v=JrNF0KRAlyo",
"type": "video"
},
@ -1936,6 +1997,11 @@
"title": "Common UML Diagrams",
"description": "UML is a standard way of visualizing a software system. It is a general-purpose, developmental, modeling language in the field of software engineering that is intended to provide a standard way to visualize the design of a system.\n\nVisit the following resources to learn more:",
"links": [
{
"title": "Unified Modeling Language (UML) Description",
"url": "https://www.uml-diagrams.org/",
"type": "article"
},
{
"title": "UML Diagrams Full Course (Unified Modeling Language)",
"url": "https://www.youtube.com/watch?v=WnMQ8HlmeXc",
@ -2091,7 +2157,7 @@
"type": "opensource"
},
{
"title": "Design Patterns - Wikipedia",
"title": "Design Patterns",
"url": "https://en.wikipedia.org/wiki/Software_design_pattern",
"type": "article"
},
@ -2314,7 +2380,7 @@
"description": "Combinatorics is the study of counting. It is a branch of mathematics that is used to solve problems in a variety of fields, including computer science, statistics, and physics. In computer science, combinatorics is used to solve problems related to counting the number of possible outcomes of a given problem. For example, if you are given a set of 10 objects, how many different ways can you arrange them? Or, if you are given a set of 10 objects, how many different ways can you choose 3 objects from that set? These are examples of combinatorial problems.\n\nVisit the following resources to learn more:",
"links": [
{
"title": "Probability and Combinatorics Topic",
"title": "Probability and Combinatorics",
"url": "https://www.khanacademy.org/math/probability/probability-and-combinatorics-topic",
"type": "article"
},
@ -2368,21 +2434,6 @@
"title": "Greedy Algs. II & Intro to NP Completeness",
"url": "https://youtu.be/qcGnJ47Smlo?list=PLFDnELG9dpVxQCxuD-9BSy2E7BWY3t5Sm&t=2939",
"type": "video"
},
{
"title": "NP Completeness II & Reductions",
"url": "https://www.youtube.com/watch?v=e0tGC6ZQdQE&index=16&list=PLFDnELG9dpVxQCxuD-9BSy2E7BWY3t5Sm",
"type": "video"
},
{
"title": "NP Completeness III",
"url": "https://www.youtube.com/watch?v=fCX1BGT3wjE&index=17&list=PLFDnELG9dpVxQCxuD-9BSy2E7BWY3t5Sm",
"type": "video"
},
{
"title": "NP Completeness IV",
"url": "https://www.youtube.com/watch?v=NKLDp3Rch3M&list=PLFDnELG9dpVxQCxuD-9BSy2E7BWY3t5Sm&index=18",
"type": "video"
}
]
},
@ -2419,21 +2470,6 @@
"title": "Greedy Algs. II & Intro to NP Completeness",
"url": "https://youtu.be/qcGnJ47Smlo?list=PLFDnELG9dpVxQCxuD-9BSy2E7BWY3t5Sm&t=2939",
"type": "video"
},
{
"title": "NP Completeness II & Reductions",
"url": "https://www.youtube.com/watch?v=e0tGC6ZQdQE&index=16&list=PLFDnELG9dpVxQCxuD-9BSy2E7BWY3t5Sm",
"type": "video"
},
{
"title": "NP Completeness III",
"url": "https://www.youtube.com/watch?v=fCX1BGT3wjE&index=17&list=PLFDnELG9dpVxQCxuD-9BSy2E7BWY3t5Sm",
"type": "video"
},
{
"title": "NP Completeness IV",
"url": "https://www.youtube.com/watch?v=NKLDp3Rch3M&list=PLFDnELG9dpVxQCxuD-9BSy2E7BWY3t5Sm&index=18",
"type": "video"
}
]
},
@ -2558,21 +2594,6 @@
"url": "https://www.youtube.com/watch?v=YX40hbAHx3s",
"type": "video"
},
{
"title": "Complexity: Approximation Algorithms",
"url": "https://www.youtube.com/watch?v=MEz1J9wY2iM&list=PLUl4u3cNGP6317WaSNfmCvGym2ucw3oGp&index=24",
"type": "video"
},
{
"title": "Complexity: Fixed-Parameter Algorithms",
"url": "https://www.youtube.com/watch?v=4q-jmGrmxKs&index=25&list=PLUl4u3cNGP6317WaSNfmCvGym2ucw3oGp",
"type": "video"
},
{
"title": "Lecture 23: Computational Complexity",
"url": "https://www.youtube.com/watch?v=moPtwq_cVH8&list=PLUl4u3cNGP61Oq3tWYp6V_F-5jb5L2iHb&index=24",
"type": "video"
},
{
"title": "Greedy Algs. II & Intro to NP Completeness",
"url": "https://youtu.be/qcGnJ47Smlo?list=PLFDnELG9dpVxQCxuD-9BSy2E7BWY3t5Sm&t=2939",
@ -2610,6 +2631,11 @@
"title": "Travelling Salesman Problem",
"description": "The Travelling Salesman Problem (TSP) is a classic problem in computer science. It is a problem that is NP-complete, which means that it is a problem that is hard to solve. It is also a problem that is used to test the efficiency of algorithms.\n\nVisit the following resources to learn more:",
"links": [
{
"title": "Traveling Salesman Problem",
"url": "https://en.wikipedia.org/wiki/Travelling_salesman_problem",
"type": "article"
},
{
"title": "What is the Traveling Salesman Problem?",
"url": "https://www.youtube.com/watch?v=1pmBjIZ20pE",
@ -2715,7 +2741,7 @@
"description": "Balanced search trees are a type of data structure that allow for fast insertion, deletion, and lookup of data. They are a type of self-balancing binary search tree, which means that they are a binary tree that maintains the binary search tree property while also keeping the tree balanced. This means that the tree is always approximately balanced, which allows for fast insertion, deletion, and lookup of data.\n\nVisit the following resources to learn more:",
"links": [
{
"title": "Self-balancing binary search tree - Wikipedia",
"title": "Self-balancing Binary Search Tree - Wikipedia",
"url": "https://en.wikipedia.org/wiki/Self-balancing_binary_search_tree",
"type": "article"
},
@ -2750,6 +2776,11 @@
"url": "https://www.coursera.org/learn/data-structures/lecture/22BgE/split-and-merge",
"type": "course"
},
{
"title": "AVL Tree - Programiz",
"url": "https://www.programiz.com/dsa/avl-tree",
"type": "article"
},
{
"title": "MIT AVL Trees / AVL Sort",
"url": "https://www.youtube.com/watch?v=FNeL18KsWPc&list=PLUl4u3cNGP61Oq3tWYp6V_F-5jb5L2iHb&index=6",
@ -2871,7 +2902,7 @@
"type": "opensource"
},
{
"title": "System Design: The complete course",
"title": "System Design: The Complete Course",
"url": "https://dev.to/karanpratapsingh/system-design-the-complete-course-10fo",
"type": "article"
},
@ -2891,7 +2922,7 @@
"type": "video"
},
{
"title": "System design interview: Scale to 1 million users",
"title": "System Design interview: Scale to 1 million users",
"url": "https://www.youtube.com/watch?v=YkGHxOg9d3M",
"type": "video"
}
@ -2922,6 +2953,11 @@
"title": "Load Balancing",
"description": "Load balancing is the process of distributing network or application traffic across a cluster of servers. Load balancing is used to improve responsiveness and reliability of applications, maximize throughput, minimize response time, and avoid overload of any single server.\n\nVisit the following resources to learn more:",
"links": [
{
"title": "What is Load Balancing? | How load balancers work",
"url": "https://www.cloudflare.com/learning/performance/what-is-load-balancing/",
"type": "article"
},
{
"title": "Load Balancers 101",
"url": "https://www.youtube.com/watch?v=galcDRNd5Ow",
@ -2987,13 +3023,13 @@
"description": "A proxy server is an intermediary piece of hardware/software sitting between the client and the backend server. It receives requests from clients and relays them to the origin servers. Typically, proxies are used to filter requests, log requests, or sometimes transform requests (by adding/removing headers, encrypting/decrypting, or compression).\n\nVisit the following resources to learn more:",
"links": [
{
"title": "Proxy - System Design",
"url": "https://dev.to/karanpratapsingh/system-design-the-complete-course-10fo#proxy",
"title": "Proxy Servers",
"url": "https://roadmap.sh/guides/proxy-servers",
"type": "article"
},
{
"title": "Proxy Servers",
"url": "https://roadmap.sh/guides/proxy-servers",
"title": "Proxy - System Design",
"url": "https://dev.to/karanpratapsingh/system-design-the-complete-course-10fo#proxy",
"type": "article"
}
]
@ -3003,7 +3039,7 @@
"description": "The CAP theorem states that it is impossible for a distributed data store to simultaneously provide more than two out of Consistency, Availability and Partition Tolerance.\n\nVisit the following resources to learn more:",
"links": [
{
"title": "CAP Theorem - Wikipedia",
"title": "CAP Theorem",
"url": "https://en.wikipedia.org/wiki/CAP_theorem",
"type": "article"
},
@ -3040,7 +3076,7 @@
"description": "Architectural patterns are the fundamental organization of a system, defining how the system is composed and how its components interact. Architectural patterns are identified by their name, like client-server, peer-to-peer, and layered.\n\nVisit the following resources to learn more:",
"links": [
{
"title": "List of software architecture styles and patterns",
"title": "List of Software Architecture Styles and Patterns",
"url": "https://en.wikipedia.org/wiki/List_of_software_architecture_styles_and_patterns",
"type": "article"
}
@ -3081,6 +3117,16 @@
"url": "https://roadmap.sh/graphql",
"type": "article"
},
{
"title": "GraphQL",
"url": "https://graphql.org/",
"type": "article"
},
{
"title": "GraphQL Documentation",
"url": "https://graphql.org/learn/",
"type": "article"
},
{
"title": "Apollo GraphQL Tutorials",
"url": "https://www.apollographql.com/tutorials/",
@ -3381,8 +3427,19 @@
},
"q3nRhTYS5wg9tYnQe2sCF": {
"title": "BASE",
"description": "The rise in popularity of NoSQL databases provided a flexible and fluidity with ease to manipulate data and as a result, a new database model was designed, reflecting these properties. The acronym BASE is slightly more confusing than ACID but however, the words behind it suggest ways in which the BASE model is different and acronym BASE stands for:-\n\n* **B**asically **A**vailable\n* **S**oft state\n* **E**ventual consistency",
"links": []
"description": "The rise in popularity of NoSQL databases provided a flexible and fluidity with ease to manipulate data and as a result, a new database model was designed, reflecting these properties. The acronym BASE is slightly more confusing than ACID but however, the words behind it suggest ways in which the BASE model is different and acronym BASE stands for:-\n\n* **B**asically **A**vailable\n* **S**oft state\n* **E**ventual consistency\n\nVisit the following resources to learn more:",
"links": [
{
"title": "ACID vs. BASE Database Model",
"url": "https://phoenixnap.com/kb/acid-vs-base",
"type": "article"
},
{
"title": "What Is BASE in Database Engineering?",
"url": "https://www.lifewire.com/abandoning-acid-in-favor-of-base-1019674",
"type": "article"
}
]
},
"uqfeiQ9K--QkGNwks4kjk": {
"title": "CAP Theorem",
@ -3430,6 +3487,11 @@
"title": "Indexes",
"description": "An index is a data structure that you build and assign on top of an existing table that basically looks through your table and tries to analyze and summarize so that it can create shortcuts.\n\nVisit the following resources to learn more:",
"links": [
{
"title": "Database Indexes Explained",
"url": "https://www.essentialsql.com/what-is-a-database-index/",
"type": "article"
},
{
"title": "Database Indexing Explained",
"url": "https://www.youtube.com/watch?v=-qNSXK7s7_w",
@ -3461,6 +3523,11 @@
"title": "What are Transactions?",
"url": "https://fauna.com/blog/database-transaction",
"type": "article"
},
{
"title": "Database Transaction",
"url": "https://en.wikipedia.org/wiki/Database_transaction",
"type": "article"
}
]
},
@ -3566,7 +3633,7 @@
},
"pZ5x_zDYGzW9VxYycyXtN": {
"title": "OSI Model",
"description": "The OSI and TCP/IP model is used to help the developer to design their system for interoperability. The OSI model has 7 layers while the TCP/IP model has a more summarized form of the OSI model only consisting 4 layers. This is important if you're are trying to design a system to communicate with other systems.\n\nVisit the following resources to learn more:",
"description": "The OSI and TCP/IP model is used to help the developer to design their system for interoperability. The OSI model has 7 layers while the TCP/IP model has a more summarized form of the OSI model only consisting 4 layers. This is important if you're trying to design a system to communicate with other systems.\n\nVisit the following resources to learn more:",
"links": [
{
"title": "Cloudflare - What is the OSI model",
@ -3582,7 +3649,7 @@
},
"Fed5y1D95WPpqoVg7kmob": {
"title": "TCP/IP Model",
"description": "The OSI and TCP/IP model is used to help the developer to design their system for interoperability. The OSI model has 7 layers while the TCP/IP model has a more summarized form of the OSI model only consisting 4 layers. This is important if you're are trying to design a system to communicate with other systems.\n\nVisit the following resources to learn more:",
"description": "The OSI and TCP/IP model is used to help the developer to design their system for interoperability. The OSI model has 7 layers while the TCP/IP model has a more summarized form of the OSI model only consisting 4 layers. This is important if you're trying to design a system to communicate with other systems.\n\nVisit the following resources to learn more:",
"links": [
{
"title": "Cloudflare - What is the OSI model",
@ -3672,6 +3739,16 @@
"title": "TLS & HTTPS",
"description": "TLS (Transport Layer Security) is a cryptographic protocol that provides privacy and data integrity between two communicating applications. It is widely used to secure HTTP, although it can be used with any protocol. TLS is often used in combination with HTTPS, which is HTTP over TLS.\n\nVisit the following resources to learn more:",
"links": [
{
"title": "What is TLS & How Does it Work? - Internet Society",
"url": "https://www.internetsociety.org/deploy360/tls/basics/",
"type": "article"
},
{
"title": "What is TLS (Transport Layer Security)? - Cloudflare",
"url": "https://www.cloudflare.com/learning/ssl/transport-layer-security-tls/",
"type": "article"
},
{
"title": "SSL and HTTPS",
"url": "https://www.youtube.com/watch?v=S2iBR2ZlZf0",
@ -3792,6 +3869,11 @@
"title": "Hashing Algorithms",
"description": "Hashing algorithms are used to generate a unique value for a given input. This value is called a hash. Hashing algorithms are used to verify the integrity of data, to store passwords, and to generate unique identifiers for data.\n\nVisit the following resources to learn more:",
"links": [
{
"title": "Hashing Algorithm Overview:",
"url": "https://www.okta.com/identity-101/hashing-algorithms/",
"type": "article"
},
{
"title": "Explore top posts about Algorithms",
"url": "https://app.daily.dev/tags/algorithms?ref=roadmapsh",
@ -3850,12 +3932,12 @@
"description": "Computers are everywhere. They are in our phones, our cars, our homes, and even in our pockets. But how do they actually work? How do they take in information, and how do they output information?\n\nVisit the following resources to learn more:",
"links": [
{
"title": "How CPU executes a program",
"title": "How CPU Executes A Program",
"url": "https://www.youtube.com/watch?v=XM4lGflQFvA",
"type": "video"
},
{
"title": "How computers calculate - ALU",
"title": "How Computers Calculate - ALU",
"url": "https://youtu.be/1I5ZMmrOfnA",
"type": "video"
},
@ -3897,7 +3979,12 @@
"description": "Computers calculate using the binary system, where all data is represented as 0s and 1s. These binary states correspond to the ON/OFF positions of transistors, which are the building blocks of logic gates (AND, OR, NOT). Numbers, characters, and instructions are broken into binary sequences (bits), and grouped into bytes (8 bits). Arithmetic operations like addition are performed through logic gates, which combine binary values. The CPU executes these calculations by following a fetch-decode-execute cycle. Complex calculations, such as handling decimals, use floating-point representation. Programs written in high-level languages are compiled into machine code for the CPU to execute.\n\nVisit the following resources to learn more:",
"links": [
{
"title": "How computers calculate - ALU",
"title": "How Does A Computer Calculate Numbers?",
"url": "https://www.sciencing.com/computer-calculate-numbers-4705975/",
"type": "article"
},
{
"title": "How Computers Calculate - ALU",
"url": "https://youtu.be/1I5ZMmrOfnA",
"type": "video"
}
@ -3905,8 +3992,13 @@
},
"U3379F4AO1KSmGtVmPr27": {
"title": "Registers and RAM",
"description": "**_Registers_** are the smallest data-holding elements built into the processor itself. Registers are the memory locations that are directly accessible by the processor. The registers hold the instruction or operands currently accessed by the CPU.\n\nRegisters are the high-speed accessible storage elements. The processor accesses the registers within one CPU clock cycle. The processor can decode the instructions and perform operations on the register contents at more than one operation per CPU clock cycle.\n\n**_Memory_** is a hardware device that stores computer programs, instructions, and data. The memory that is internal to the processor is primary memory (RAM), and the memory that is external to the processor is secondary (**Hard Drive**). Primary memory or RAM is a volatile memory, meaning the primary memory data exist when the system's power is on, and the data vanishes as the system is switched off. The primary memory contains the data required by the currently executing program in the CPU. If the data required by the processor is not in primary memory, then the data is transferred from secondary storage to primary memory, and then it is fetched by the processor.\n\nVisit the following resources to learn more:",
"description": "**_Registers_** are the smallest data-holding elements built into the processor itself. Registers are the memory locations that are directly accessible by the processor. The registers hold the instruction or operands currently accessed by the CPU.\n\nRegisters are the high-speed accessible storage elements. The processor accesses the registers within one CPU clock cycle. The processor can decode the instructions and perform operations on the register contents at more than one operation per CPU clock cycle.\n\n**_Memory_** is a hardware device that stores computer programs, instructions, and data. The memory that is internal to the processor is primary memory (RAM), and the memory that is external to the processor is secondary (**Hard Drive**).\n\nVisit the following resources to learn more:",
"links": [
{
"title": "RAM vs. Registers - What's the Difference?",
"url": "https://thisvsthat.io/ram-vs-registers",
"type": "article"
},
{
"title": "Registers and RAM",
"url": "https://youtu.be/fpnE6UAfbtU",
@ -3981,6 +4073,11 @@
"title": "Process Forking",
"description": "Process forking is a way to create a new process from an existing process. The new process is a copy of the existing process. The new process is called a child process and the existing process is called a parent process.\n\nVisit the following resources to learn more:",
"links": [
{
"title": "Fork System Call in Operating System",
"url": "https://www.geeksforgeeks.org/fork-system-call-in-operating-system/",
"type": "article"
},
{
"title": "Understanding fork() system call for new process creation",
"url": "https://www.youtube.com/watch?v=PwxTbksJ2fo",
@ -4053,13 +4150,24 @@
},
"Ge2nagN86ofa2y-yYR1lv": {
"title": "Scheduling Algorithms",
"description": "CPU Scheduling is the process of selecting a process from the ready queue and allocating the CPU to it. The selection of a process is based on a particular scheduling algorithm. The scheduling algorithm is chosen depending on the type of system and the requirements of the processes.\n\nHere is the list of some of the most commonly used scheduling algorithms:\n\n* **First Come First Serve (FCFS):** The process that arrives first is allocated the CPU first. It is a non-preemptive algorithm.\n* **Shortest Job First (SJF):** The process with the smallest execution time is allocated the CPU first. It is a non-preemptive algorithm.\n* **Shortest Remaining Time First (SRTF):** The process with the smallest remaining execution time is allocated the CPU first. It is a preemptive algorithm.\n* **Round Robin (RR):** The process is allocated the CPU for a fixed time slice. The time slice is usually 10 milliseconds. It is a preemptive algorithm.\n* **Priority Scheduling:** The process with the highest priority is allocated the CPU first. It is a preemptive algorithm.\n* **Multi-level Queue Scheduling:** The processes are divided into different queues based on their priority. The process with the highest priority is allocated the CPU first. It is a preemptive algorithm.\n* **Multi-level Feedback Queue Scheduling:** The processes are divided into different queues based on their priority. The process with the highest priority is allocated the CPU first. If a process is preempted, it is moved to the next queue. It is a preemptive algorithm.\n* **Highest Response Ratio Next(HRRN):** CPU is allotted to the next process which has the highest response ratio and not to the process having less burst time. It is a Non-Preemptive algorithm.\n* **Lottery Scheduling:** The process is allocated the CPU based on a lottery system. It is a preemptive algorithm.",
"links": []
"description": "CPU Scheduling is the process of selecting a process from the ready queue and allocating the CPU to it. The selection of a process is based on a particular scheduling algorithm. The scheduling algorithm is chosen depending on the type of system and the requirements of the processes.\n\nHere is the list of some of the most commonly used scheduling algorithms:\n\n* **First Come First Serve (FCFS):** The process that arrives first is allocated the CPU first. It is a non-preemptive algorithm.\n* **Shortest Job First (SJF):** The process with the smallest execution time is allocated the CPU first. It is a non-preemptive algorithm.\n* **Shortest Remaining Time First (SRTF):** The process with the smallest remaining execution time is allocated the CPU first. It is a preemptive algorithm.\n* **Round Robin (RR):** The process is allocated the CPU for a fixed time slice. The time slice is usually 10 milliseconds. It is a preemptive algorithm.\n* **Priority Scheduling:** The process with the highest priority is allocated the CPU first. It is a preemptive algorithm.\n* **Multi-level Queue Scheduling:** The processes are divided into different queues based on their priority. The process with the highest priority is allocated the CPU first. It is a preemptive algorithm.\n* **Multi-level Feedback Queue Scheduling:** The processes are divided into different queues based on their priority. The process with the highest priority is allocated the CPU first. If a process is preempted, it is moved to the next queue. It is a preemptive algorithm.\n* **Highest Response Ratio Next(HRRN):** CPU is allotted to the next process which has the highest response ratio and not to the process having less burst time. It is a Non-Preemptive algorithm.\n* **Lottery Scheduling:** The process is allocated the CPU based on a lottery system. It is a preemptive algorithm.\n\nVisit the following resources to learn more:",
"links": [
{
"title": "CPU Scheduling in Operating System",
"url": "https://www.scaler.com/topics/operating-system/cpu-scheduling/",
"type": "article"
}
]
},
"cpQvB0qMDL3-NWret7oeA": {
"title": "CPU Interrupts",
"description": "CPU Interrupts are a way for the CPU to communicate with the rest of the computer. They are a way for the CPU to tell the rest of the computer that it needs to do something. For example, if the CPU is running a program and it needs to read from the keyboard, it will send an interrupt to the keyboard to tell it to send the data to the CPU. The CPU will then wait for the keyboard to send the data and then continue running the program.\n\nVisit the following resources to learn more:",
"links": [
{
"title": "System Interrupts 100% CPU",
"url": "https://www.wikihow.com/System-Interrupts-100-Cpu",
"type": "article"
},
{
"title": "Explore top posts about Computing",
"url": "https://app.daily.dev/tags/computing?ref=roadmapsh",
@ -4109,7 +4217,7 @@
"description": "Skip lists are a data structure that allows you to perform operations on a sorted list in O(log n) time. Skip lists are a probabilistic data structure, which means that the probability of a certain operation taking a certain amount of time is a certain value. In the case of skip lists, the probability of an operation taking O(log n) time is 1.\n\nVisit the following resources to learn more:",
"links": [
{
"title": "Skip Lists - Wikipedia",
"title": "Skip Lists",
"url": "https://en.wikipedia.org/wiki/Skip_list",
"type": "article"
},
@ -4153,21 +4261,6 @@
"title": "Greedy Algs. II & Intro to NP Completeness",
"url": "https://youtu.be/qcGnJ47Smlo?list=PLFDnELG9dpVxQCxuD-9BSy2E7BWY3t5Sm&t=2939",
"type": "video"
},
{
"title": "NP Completeness II & Reductions",
"url": "https://www.youtube.com/watch?v=e0tGC6ZQdQE&index=16&list=PLFDnELG9dpVxQCxuD-9BSy2E7BWY3t5Sm",
"type": "video"
},
{
"title": "NP Completeness III",
"url": "https://www.youtube.com/watch?v=fCX1BGT3wjE&index=17&list=PLFDnELG9dpVxQCxuD-9BSy2E7BWY3t5Sm",
"type": "video"
},
{
"title": "NP Completeness IV",
"url": "https://www.youtube.com/watch?v=NKLDp3Rch3M&list=PLFDnELG9dpVxQCxuD-9BSy2E7BWY3t5Sm&index=18",
"type": "video"
}
]
},

@ -281,8 +281,24 @@
},
"k9c5seRkhgm_yHPpiz2X0": {
"title": "unique_ptr",
"description": "",
"links": []
"description": "One of C++'s main features includes variants of the normal _raw_ C pointers. One of these is the `unique_ptr`, which is a type of smart pointer that claims exclusive ownership over a value.\n\nThese types of pointers **can be moved** (`std::move`), but not **copied** and are automatically deleted when out of scope. The recommended way to create a `unique_ptr` is using `std::make_unique`.\n\n #include <memory>\n #include <iostream>\n \n int main() {\n std::unique_ptr<int> uptr = std::make_unique<int>(10);\n std::cout << *uptr << std::endl;\n \n std::unique_ptr<int> uptr2 = uptr; // compile error\n std::unique_ptr<int> uptr2 = std::move(uptr); // transferring ownership\n }",
"links": [
{
"title": "std::unique_ptr - Detailed Reference",
"url": "https://en.cppreference.com/w/cpp/memory/unique_ptr",
"type": "article"
},
{
"title": "Smart Pointers – unique_ptr",
"url": "https://www.learncpp.com/cpp-tutorial/unique-ptr/",
"type": "article"
},
{
"title": "When should you use std::unique_ptr? - StackOverflow Discussion",
"url": "https://stackoverflow.com/questions/13782051/when-should-you-use-stdunique-ptr",
"type": "video"
}
]
},
"uEGEmbxegATIrvGfobJb9": {
"title": "Raw Pointers",

@ -199,7 +199,7 @@
"description": "iCloud is a cloud storage and cloud computing service provided by Apple Inc. It allows users to store data, such as documents, photos, and music, on remote servers and synchronize them across their Apple devices, including iPhones, iPads, and MacBooks.\n\nLearn more from the following resources:",
"links": [
{
"title": "iCloud Website",
"title": "iCloud",
"url": "https://www.icloud.com/",
"type": "article"
}
@ -237,7 +237,7 @@
"description": "Hack The Box (HTB) is a popular online platform designed for security enthusiasts, penetration testers, and ethical hackers to develop and enhance their skills by engaging in real-world cybersecurity challenges. The platform provides a wide array of virtual machines (VMs), known as \"boxes,\" each with a unique set of security vulnerabilities to exploit.\n\nLearn more from the following resources:",
"links": [
{
"title": "Hack The Box Website",
"title": "Hack The Box",
"url": "https://www.hackthebox.com/",
"type": "article"
},
@ -380,6 +380,11 @@
"title": "CompTIA Security+",
"description": "CompTIA Security+ is a highly recognized and respected certification for individuals seeking to start their careers in the field of cybersecurity. This certification is vendor-neutral, meaning it doesn't focus on any specific technology or platform, and provides a solid foundation in cybersecurity principles, concepts, and best practices.\n\nLearn more from the following resources:",
"links": [
{
"title": "CompTIA SY0-701 Security+ Exam Course Playlist",
"url": "https://www.youtube.com/playlist?list=PLG49S3nxzAnl4QDVqK-hOnoqcSKEIDDuv",
"type": "course"
},
{
"title": "CompTIA Security+ Course",
"url": "https://www.youtube.com/watch?v=yLf2jRY39Rc&list=PLIhvC56v63IIyU0aBUed4qwP0nSCORAdB",
@ -1075,7 +1080,12 @@
"description": "IP, or Internet Protocol, is a fundamental concept in cybersecurity that refers to the way data is transferred across networks, specifically the internet. It is a core component of the internet's architecture and serves as the primary building block for communication between devices connected to the network. An IP address is a unique identifier assigned to each device connected to a network, like a computer or smartphone. It comprises a series of numbers separated by dots (e.g., 192.168.1.1). IP addresses can be either IPv4 (32-bit) or the newer IPv6 (128-bit) format, which provides more available addresses. They allow devices to send and receive data packets to and from other devices on the internet.\n\nLearn more from the following resources:",
"links": [
{
"title": "What is an IP address and what does it mean?",
"title": "Check Your IP Address",
"url": "https://ipleak.net",
"type": "website"
},
{
"title": "What is an IP Address and What does it mean?",
"url": "https://www.kaspersky.com/resource-center/definitions/what-is-an-ip-address",
"type": "article"
},
@ -1430,7 +1440,7 @@
"description": "HTTP (Hypertext Transfer Protocol) and HTTPS (HTTP Secure) are fundamental protocols for web communication. HTTP is the foundation for data exchange on the World Wide Web, allowing browsers to request resources from web servers. However, HTTP transmits data in plain text, making it vulnerable to eavesdropping and man-in-the-middle attacks. HTTPS addresses these security concerns by adding a layer of encryption using SSL/TLS (Secure Sockets Layer/Transport Layer Security). This encryption protects the confidentiality and integrity of data in transit, securing sensitive information such as login credentials and financial transactions. HTTPS also provides authentication, ensuring that users are communicating with the intended website. In recent years, there has been a significant push towards HTTPS adoption across the web, with major browsers marking HTTP sites as \"not secure.\" This shift has greatly enhanced overall web security, though it's important to note that HTTPS secures the connection, not necessarily the content of the website itself.\n\nLearn more from the following resources:",
"links": [
{
"title": "An overview of HTTP",
"title": "An Overview of HTTP",
"url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Overview",
"type": "article"
},
@ -1538,7 +1548,7 @@
},
"CIoLaRv5I3sCr9tBnZHEi": {
"title": "Hypervisor",
"description": "A hypervisor, also known as a virtual machine monitor (VMM), is software or firmware that enables the creation and management of virtual machines (VMs) by abstracting the underlying hardware. It allows multiple VMs to run on a single physical machine, each operating independently with its own operating system and applications. Hypervisors facilitate better resource utilization by allowing a physical server to host several virtual environments, optimizing hardware efficiency.\n\nThere are two types of hypervisors:\n\n* **Type 1 hypervisor**, or bare-metal hypervisor, runs directly on the physical hardware without a host operating system. It provides better performance and is commonly used in enterprise environments. Examples include VMware ESXi and Microsoft Hyper-V.\n* **Type 2 hypervisor** runs on top of an existing operating system, relying on the host OS for resource management. These are typically used for personal or development purposes, with examples like VMware Workstation and Oracle VirtualBox.\n\nHypervisors are fundamental in cloud computing, virtualization, and server consolidation, allowing for flexible and efficient resource management and isolation between virtual environments.\n\nLearn more from the following resources:",
"description": "A hypervisor, also known as a virtual machine monitor (VMM), is software or firmware that enables the creation and management of virtual machines (VMs) by abstracting the underlying hardware. It allows multiple VMs to run on a single physical machine, each operating independently with its own operating system and applications. Hypervisors facilitate better resource utilization by allowing a physical server to host several virtual environments, optimizing hardware efficiency.\n\nLearn more from the following resources:",
"links": [
{
"title": "What is a hypervisor?",
@ -2548,7 +2558,7 @@
"description": "hping is a versatile and powerful command-line based packet crafting tool that allows network administrators, security professionals, and system auditors to manipulate and analyze network packets at a granular level. hping can be used to perform stress testing, firewall testing, scanning, and packet generation, among other functionalities.\n\nLearn more from the following resources:",
"links": [
{
"title": "hping source code",
"title": "hping",
"url": "https://salsa.debian.org/debian/hping3",
"type": "article"
},
@ -2823,6 +2833,16 @@
"url": "https://www.techtarget.com/searchdatamanagement/definition/hashing",
"type": "article"
},
{
"title": "Hashing Algorithm Overview: Types, Methodologies & Usage",
"url": "https://www.okta.com/identity-101/hashing-algorithms/",
"type": "article"
},
{
"title": "Understanding Cryptography Types:",
"url": "https://geekflare.com/cybersecurity/cryptography-types/",
"type": "article"
},
{
"title": "Hashing Explained",
"url": "https://www.youtube.com/watch?v=EOe1XUykdP4",
@ -2952,7 +2972,7 @@
"description": "The International Organization for Standardization (ISO) is an international standard-setting body composed of representatives from various national standards organizations. It promotes worldwide proprietary, industrial, and commercial standards. In the domain of cyber security, there are several important ISO standards that help organizations to protect their sensitive data and to be resilient against cyber threats.\n\nLearn more from the following resources:",
"links": [
{
"title": "ISO Website",
"title": "International Organization for Standardization",
"url": "https://www.iso.org/home.html",
"type": "article"
},
@ -3103,6 +3123,16 @@
"title": "Kali Linux",
"url": "https://www.kali.org/",
"type": "article"
},
{
"title": "Kali Tools",
"url": "https://www.kali.org/tools",
"type": "article"
},
{
"title": "Kali Docs",
"url": "https://www.kali.org/docs/",
"type": "article"
}
]
},
@ -3319,12 +3349,12 @@
"description": "A **jump server**, also known as a **bastion host** or **jump host**, is a critical security component in many network architectures. It is a dedicated, locked-down, and secure server that sits within a protected network, and provides a controlled access point for users and administrators to access specific components within the system. This intermediate server acts as a bridge between untrusted networks and the internal privileged systems, thereby reducing the attack surface and securing the environment.\n\nLearn more from the following resources:",
"links": [
{
"title": "What is a jump server?",
"title": "What is a Jump Server?",
"url": "https://www.ssh.com/academy/iam/jump-server",
"type": "article"
},
{
"title": "What is a bastion host and why is it so important?",
"title": "What is a Bastion Host and Why is it so important?",
"url": "https://www.youtube.com/watch?v=pI6glWVEkcY",
"type": "video"
}
@ -3792,6 +3822,16 @@
"title": "Known vs Unknown",
"description": "\"known\" and \"unknown\" refer to the classification of threats based on the visibility and familiarity of the attack or vulnerability.\n\n* **Known Threats** are those that have been previously identified and documented, such as malware signatures, vulnerabilities, or attack patterns. Security solutions like antivirus software and intrusion detection systems typically rely on databases of known threats to recognize and block them. These threats are easier to defend against because security teams have the tools and knowledge to detect and mitigate them.\n \n* **Unknown Threats**, on the other hand, refer to new, emerging, or sophisticated threats that have not been previously encountered or documented. These can include zero-day vulnerabilities, which are software flaws not yet known to the vendor or the public, or advanced malware designed to evade traditional defenses. Unknown threats require more advanced detection techniques, such as behavioral analysis, machine learning, or heuristic-based detection, to identify anomalies and suspicious activities that don't match known patterns.\n \n\nLearn more from the following resources:",
"links": [
{
"title": "From Known to Unknown",
"url": "https://securitysandman.com/2025/01/06/from-known-to-unknown-shifting-cybersecurity-to-proactive-ai-detection/",
"type": "article"
},
{
"title": "Catching all Threats - Known, Unknown, and Unknown Unknown",
"url": "https://www.scworld.com/perspective/catching-all-threats-known-unknown-and-unknown-unknown-before-they-can-harm-you",
"type": "article"
},
{
"title": "Detecting known threats",
"url": "https://www.youtube.com/watch?v=hOaHDVMQ9_s",
@ -3851,7 +3891,7 @@
"description": "Joe Sandbox is an advanced malware analysis platform that allows security professionals to analyze suspicious files, URLs, and documents in a controlled and isolated environment known as a sandbox. This platform provides in-depth behavioral analysis by executing the potentially malicious code in a virtualized environment to observe its actions, such as file modifications, network communications, and registry changes, without risking the integrity of the actual network or systems. Joe Sandbox supports a wide range of file types and can detect and analyze complex, evasive malware that may attempt to avoid detection in less sophisticated environments. The insights generated from Joe Sandbox are crucial for understanding the nature of the threat, aiding in the development of countermeasures, and enhancing overall cybersecurity defenses.\n\nLearn more from the following resources:",
"links": [
{
"title": "Joe Sandbox Website",
"title": "Joe Sandbox",
"url": "https://www.joesandbox.com/#windows",
"type": "article"
},
@ -4933,7 +4973,7 @@
"description": "iCloud is a cloud storage and cloud computing service provided by Apple Inc. It allows users to store data, such as documents, photos, and music, on remote servers and synchronize them across their Apple devices, including iPhones, iPads, and MacBooks.\n\nLearn more from the following resources:",
"links": [
{
"title": "iCloud Website",
"title": "iCloud",
"url": "https://www.icloud.com/",
"type": "article"
}
@ -5022,7 +5062,7 @@
"description": "JavaScript (often abbreviated as JS) is a widely-used, high-level programming language. It is predominantly used for creating and enhancing the interactive elements of web pages, making it an integral part of the web development space. JavaScript was initially known as LiveScript and was created by Brendan Eich in 1995, but it later got renamed to JavaScript.\n\nLearn more from the following resources:",
"links": [
{
"title": "JavaScript Roadmap",
"title": "Visit Dedicated JavaScript Roadmap",
"url": "https://roadmap.sh/javascript",
"type": "article"
},

@ -354,8 +354,14 @@
},
"h7gEQNbGiabDA1q1Bk_IB": {
"title": "Emotional Intelligence",
"description": "Emotional intelligence is crucial for an Engineering Manager. It helps them understand team dynamics, enhances communication, and strengthens relationships. Their main responsibilities include recognizing team members' emotions, gauging their reactions appropriately, and managing their responses effectively.\n\nEngineering Managers often face challenges in dealing with various personalities within a team. By applying emotional intelligence, they can navigate these difficulties, resolve conflicts, and maintain a positive working environment. Their challenge is to balance their own emotions while addressing those of their team.\n\nSuccess in this aspect requires strong listening skills, empathy, and patience. Engineering Managers also need to continuously improve their emotional intelligence through self-reflection and seeking feedback. This helps them foster a team environment where everyone is understood and valued.",
"links": []
"description": "Emotional intelligence is crucial for an Engineering Manager. It helps them understand team dynamics, enhances communication, and strengthens relationships. Their main responsibilities include recognizing team members' emotions, gauging their reactions appropriately, and managing their responses effectively.\n\nEngineering Managers often face challenges in dealing with various personalities within a team. By applying emotional intelligence, they can navigate these difficulties, resolve conflicts, and maintain a positive working environment. Their challenge is to balance their own emotions while addressing those of their team.\n\nSuccess in this aspect requires strong listening skills, empathy, and patience. Engineering Managers also need to continuously improve their emotional intelligence through self-reflection and seeking feedback. This helps them foster a team environment where everyone is understood and valued.\n\nVisit the following resources to learn more:",
"links": [
{
"title": "Daniel Goleman on the different kinds of empathy",
"url": "https://www.youtube.com/watch?v=WdDVvLEKoc8",
"type": "video"
}
]
},
"ZuZuzwy-Frsn_PFJZVuAQ": {
"title": "Defining and Enforcing Values",

@ -17,7 +17,7 @@
},
"yCnn-NfSxIybUQ2iTuUGq": {
"title": "How does the internet work?",
"description": "The Internet works through a global network of interconnected computers and servers, communicating via standardized protocols. Data is broken into packets and routed through various network nodes using the Internet Protocol (IP). These packets travel across different physical infrastructures, including fiber optic cables, satellites, and wireless networks. The Transmission Control Protocol (TCP) ensures reliable delivery and reassembly of packets at their destination. Domain Name System (DNS) servers translate human-readable website names into IP addresses. When you access a website, your device sends a request to the appropriate server, which responds with the requested data. This process, facilitated by routers, switches, and other networking equipment, enables the seamless exchange of information across vast distances, forming the backbone of our digital communications.\n\nVisit the following resources to learn more:",
"description": "The internet is a global network that connects computers and devices so they can share information with each other. It’s how you browse websites, send emails, watch videos, and use apps. Think of it like a giant web that links everything together.\n\nVisit the following resources to learn more:",
"links": [
{
"title": "Introduction to Internet",

@ -222,7 +222,7 @@
{
"title": "Java Classes and Objects",
"url": "https://www.youtube.com/watch?v=IUqKuGNasdM",
"type": "article"
"type": "video"
}
]
},

@ -3,11 +3,6 @@
"title": "CLI Tools",
"description": "Here is the list of most common CLI tools for React development:",
"links": [
{
"title": "create-react-app",
"url": "https://create-react-app.dev",
"type": "article"
},
{
"title": "vite",
"url": "https://vitejs.dev",

@ -1820,7 +1820,7 @@
},
"Mt5W1IvuHevNXVRlh7z26": {
"title": "OSI",
"description": "The OSI and TCP/IP model is used to help the developer to design their system for interoperability. The OSI model has 7 layers while the TCP/IP model has a more summarized form of the OSI model only consisting 4 layers. This is important if you're are trying to design a system to communicate with other systems.\n\nVisit the following resources to learn more:",
"description": "The OSI and TCP/IP model is used to help the developer to design their system for interoperability. The OSI model has 7 layers while the TCP/IP model has a more summarized form of the OSI model only consisting 4 layers. This is important if you're trying to design a system to communicate with other systems.\n\nVisit the following resources to learn more:",
"links": [
{
"title": "Cloudflare - What is the OSI model",

@ -382,7 +382,7 @@
"description": "`any` is a special type in TypeScript that represents a value of any type. When a value is declared with the any type, the compiler will not perform any type checks or type inference on that value.\n\nFor example:\n\n let anyValue: any = 42;\n \n // we can assign any value to anyValue, regardless of its type\n anyValue = 'Hello, world!';\n anyValue = true;\n \n\nLearn more from the following links:",
"links": [
{
"title": "Arrays",
"title": "any",
"url": "https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#any",
"type": "article"
}

@ -141,7 +141,7 @@
},
"OpJ2NMKCGXQezpzURE45R": {
"title": "API Styles",
"description": "Up until Vue 2, there was one way to create components in Vue. With Vue 3, a new methodology was introduced called the Composition API. Now, if we want to make a component in Vue, we have two ways to do it. You might be wondering what the difference is, exactly, so let’s take a look at how the newer Composition API differs from the Vue 2 methodology, which is now known as the Options API\n\nVisit the following resources to learn more:",
"description": "Though Vue 2 supported many approaches to writing components, only one approach, the \"Options API\", was built in and accessible without plugins. Vue 3, retains the Options API (OAPI), and adds in the Composition API (CAPI). Composition API itself is actually a part of the Options API, but moves most of the component logic into a setup function. This led to a 3rd approach to writing components being built in called \"script/setup\", which removes much of the boilerplate from Composition API. These approaches are not mutually exclusive. Each component in your project can use any of these approaches, however for consistency it is recommended to stick primarily to one, and only deviate to one of the others when you have a good reason.\n\nVisit the following resources to learn more:",
"links": [
{
"title": "The Difference Between the Composition API and Options API in Vue",
@ -152,7 +152,7 @@
},
"PPUU3Rb73aCpT4zcyvlJE": {
"title": "Options API",
"description": "We use Options API in a Vue application to write and define different components. With this API, we can use options such as data, methods, and mounted. To state it simply, Options API is an old way to structure a Vue.JS application. Due to some limitations in this API, Composition API was introduced in Vue 3.\n\nVisit the following resources to learn more:",
"description": "Vue offers many approaches for how to write components, including the Options API. It is the only API that is available in all versions of Vue. Its primary focus is on providing a consistent, clean, and organized aproach to writing component logic. Each part of a component's logic is given a dedicated section (data, methods, computed, props, life-cycle hooks, etc). By putting the logic in the correct section it has access to the features of the framework automatically. With the official Vue ESLint plugin the order of these sections can be enforced across all components allowing developers to predicatably locate any part of the component, even if they've never looked at the file before.\n\nVisit the following resources to learn more:",
"links": [
{
"title": "TypeScript with Options API",
@ -168,7 +168,7 @@
},
"a0qwdQTunxEjQ9A5wpF-q": {
"title": "Composition API",
"description": "With the release of Vue 3, developers now have access to the Composition API, a new way to write Vue components. This API allows features to be grouped together logically, rather than having to organize your single-file components by function. Using the Composition API can lead to more readable code, and gives the developer more flexibility when developing their applications.\n\nVisit the following resources to learn more:",
"description": "Vue offers many approaches for how to write components, including the \"Composition API\", which is most commonly used via \"Script Setup\". This approach is based around pulling in low level atomic functions used by Vue's reactivity engine. By composing these low level functions together, you can craft your own system for writing components. One feature this allows for is extending reactivity outside of components. This means you can extract your custom functions for reuse in multiple components. When reusing reactive logic, your functions are called \"composables\".\n\nVisit the following resources to learn more:",
"links": [
{
"title": "TypeScript with Composition API",

@ -15,7 +15,7 @@ export function AITutorLayout(props: AITutorLayoutProps) {
return (
<>
<div className="flex flex-row items-center justify-between border-b border-slate-200 px-4 py-3 lg:hidden">
<div className="flex flex-row items-center justify-between border-b border-slate-200 px-4 py-3 lg:hidden sticky top-0 bg-white z-10">
<a href="/" className="flex flex-row items-center gap-1.5">
<RoadmapLogoIcon className="size-6 text-gray-500" color="black" />
</a>
@ -27,7 +27,7 @@ export function AITutorLayout(props: AITutorLayoutProps) {
</button>
</div>
<div className="flex flex-grow flex-row">
<div className="flex flex-grow lg:h-screen flex-row">
<AITutorSidebar
onClose={() => setIsSidebarFloating(false)}
isFloating={isSidebarFloating}

@ -118,6 +118,7 @@ export function CustomRoadmap(props: CustomRoadmapProps) {
resourceId={roadmap!._id}
resourceTitle={roadmap!.title}
resourceType="roadmap"
renderer='editor'
isEmbed={isEmbed}
canSubmitContribution={false}
/>

@ -67,14 +67,13 @@ import Icon from './AstroIcon.astro';
<span class='mx-1.5'>&middot;</span>
<a href='/privacy' class='hover:text-white'>Privacy</a>
<span class='mx-1.5'>&middot;</span>
<a href='/advertise' class='hover:text-white'>Advertise</a>
<span class='mx-1.5'>&middot;</span>
<a
aria-label='Write us an email'
href='mailto:info@roadmap.sh'
aria-label='Follow on LinkedIn'
href='https://www.linkedin.com/company/roadmapsh'
class='hover:text-white'
target='_blank'
>
<AstroIcon icon='letter' class='inline-block h-5 w-5' />
<AstroIcon icon='linkedin-2' class='inline-block h-5 w-5 fill-current' />
</a>
<a
aria-label='Subscribe to YouTube channel'
@ -95,6 +94,17 @@ import Icon from './AstroIcon.astro';
class='inline-block h-5 w-5 fill-current'
/>
</a>
<a
aria-label='Follow on Blusky'
href='http://roadmapsh.bsky.social/'
target='_blank'
class='ml-2 hover:text-white'
>
<AstroIcon
icon='blusky'
class='inline-block h-5 w-5 fill-current'
/>
</a>
</p>
</div>
</div>

@ -399,7 +399,7 @@ type AIChatCardProps = {
html?: string;
};
function AIChatCard(props: AIChatCardProps) {
export function AIChatCard(props: AIChatCardProps) {
const { role, content, html: defaultHtml } = props;
const html = useMemo(() => {

@ -7,7 +7,6 @@ import { generateCourse } from '../../helper/generate-ai-course';
import { useQuery } from '@tanstack/react-query';
import { getAiCourseOptions } from '../../queries/ai-course';
import { queryClient } from '../../stores/query-client';
import { useAuth } from '../../hooks/use-auth';
type GenerateAICourseProps = {};
@ -21,8 +20,8 @@ export function GenerateAICourse(props: GenerateAICourseProps) {
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState('');
const currentUser = useAuth();
const [creatorId, setCreatorId] = useState('');
const [courseId, setCourseId] = useState('');
const [courseSlug, setCourseSlug] = useState('');
const [course, setCourse] = useState<AiCourse>({
@ -54,6 +53,7 @@ export function GenerateAICourse(props: GenerateAICourseProps) {
const params = getUrlParams();
const paramsTerm = params?.term;
const paramsDifficulty = params?.difficulty;
const paramsSrc = params?.src || 'search';
if (!paramsTerm || !paramsDifficulty) {
return;
}
@ -87,6 +87,7 @@ export function GenerateAICourse(props: GenerateAICourseProps) {
instructions: paramsCustomInstructions,
goal: paramsGoal,
about: paramsAbout,
src: paramsSrc,
});
}, [term, difficulty]);
@ -98,9 +99,18 @@ export function GenerateAICourse(props: GenerateAICourseProps) {
about?: string;
isForce?: boolean;
prompt?: string;
src?: string;
}) => {
const { term, difficulty, isForce, prompt, instructions, goal, about } =
options;
const {
term,
difficulty,
isForce,
prompt,
instructions,
goal,
about,
src,
} = options;
if (!isLoggedIn()) {
window.location.href = '/ai';
@ -113,6 +123,7 @@ export function GenerateAICourse(props: GenerateAICourseProps) {
slug: courseSlug,
onCourseIdChange: setCourseId,
onCourseSlugChange: setCourseSlug,
onCreatorIdChange: setCreatorId,
onCourseChange: setCourse,
onLoadingChange: setIsLoading,
onError: setError,
@ -121,6 +132,7 @@ export function GenerateAICourse(props: GenerateAICourseProps) {
about,
isForce,
prompt,
src,
});
};
@ -152,7 +164,7 @@ export function GenerateAICourse(props: GenerateAICourseProps) {
return (
<AICourseContent
courseSlug={courseSlug}
creatorId={currentUser?.id}
creatorId={creatorId}
course={course}
isLoading={isLoading}
error={error}

@ -2,10 +2,22 @@ import { Database, X } from 'lucide-react';
import { useState, useEffect } from 'react';
import { cn } from '../../lib/classname';
const COURSE_ANNOUNCEMENT_STORAGE_KEY = '__course_announcement_closed_at__';
export function CourseAnnouncement() {
const [isVisible, setIsVisible] = useState(false);
useEffect(() => {
const closedAt = Number(
localStorage.getItem(COURSE_ANNOUNCEMENT_STORAGE_KEY) || '0',
);
// only show if the closed at passed 3 days ago
const shouldShow = closedAt < Date.now();
if (!shouldShow) {
return;
}
const timer = setTimeout(() => setIsVisible(true), 5000);
return () => clearTimeout(timer);
}, []);
@ -14,7 +26,7 @@ export function CourseAnnouncement() {
<div
className={cn(
'sticky top-0 z-91 h-0 overflow-hidden transition-[height] duration-300',
isVisible ? 'sm:h-[36px] h-[30px]' : 'h-0',
isVisible ? 'h-[30px] sm:h-[36px]' : 'h-0',
)}
>
<a href="/courses/sql" className="flex items-center bg-yellow-400 py-1.5">
@ -26,10 +38,12 @@ export function CourseAnnouncement() {
</span>
<span className="block sm:hidden">Announcing our SQL course</span>
</span>
<span className={cn(
"items-center gap-1.5 rounded-full bg-black px-2 py-0.5 text-xs font-medium uppercase tracking-wide text-white hover:bg-zinc-800 sm:px-3 sm:py-1",
isVisible && "animate-wiggle [animation-delay:0.25s]"
)}>
<span
className={cn(
'items-center gap-1.5 rounded-full bg-black px-2 py-0.5 text-xs font-medium tracking-wide text-white uppercase hover:bg-zinc-800 sm:px-3 sm:py-1',
isVisible && 'animate-wiggle [animation-delay:0.25s]',
)}
>
<span className="mr-1.5 hidden sm:inline">Start Learning</span>
<span className="mr-1.5 inline sm:hidden">Visit</span>
<span className=""></span>
@ -38,9 +52,15 @@ export function CourseAnnouncement() {
</a>
<button
type="button"
className="absolute right-3.5 top-1/2 -translate-y-1/2 rounded-lg px-1.5 py-1.5 text-gray-500 hover:bg-yellow-500 hover:text-gray-700"
className="absolute top-1/2 right-3.5 -translate-y-1/2 rounded-lg px-1.5 py-1.5 text-gray-500 hover:bg-yellow-500 hover:text-gray-700"
onClick={(e) => {
setIsVisible(false);
const threeDaysFromNow = Date.now() + 1000 * 60 * 60 * 24 * 3;
localStorage.setItem(
COURSE_ANNOUNCEMENT_STORAGE_KEY,
String(threeDaysFromNow),
);
}}
>
<X className="h-4 w-4" />

@ -0,0 +1,60 @@
import { WandSparkles } from 'lucide-react';
import { Modal } from '../Modal';
import { useState } from 'react';
type CreateCourseModalProps = {
onClose: () => void;
};
export function CreateCourseModal(props: CreateCourseModalProps) {
const { onClose } = props;
const [subject, setSubject] = useState('');
return (
<Modal
onClose={onClose}
wrapperClassName="h-auto mt-20"
overlayClassName="items-start"
bodyClassName="p-1.5"
>
<form
onSubmit={(e) => {
e.preventDefault();
const formData = new FormData(e.target as HTMLFormElement);
const subject = formData.get('subject');
window.location.href = `/ai/search?term=${subject}&difficulty=beginner&src=topic`;
onClose();
}}
>
<label
className="mb-2.5 ml-1 inline-block text-sm leading-none"
htmlFor="subject"
>
Ask AI to Teach You
</label>
<div className="relative flex items-center gap-2 overflow-hidden">
<input
id="subject"
type="text"
className="w-full bg-white p-2.5 pr-8 text-sm focus:outline-hidden"
placeholder="Enter a topic to learn"
name="subject"
autoFocus={true}
value={subject}
onChange={(e) => setSubject(e.target.value)}
/>
<button
disabled={!subject.trim()}
className="flex h-full disabled:opacity-40 items-center justify-center gap-2 rounded-md bg-black px-3 py-1 text-sm text-white hover:opacity-80"
>
Generate
<WandSparkles className="size-4" />
</button>
</div>
</form>
</Modal>
);
}

@ -0,0 +1,54 @@
import type { LucideIcon } from 'lucide-react';
import { useState, useRef } from 'react';
import { useOutsideClick } from '../../hooks/use-outside-click';
import {
type PredefinedActionType,
PredefinedActionButton,
} from './PredefinedActions';
type PredefinedActionGroupProps = {
label: string;
icon: LucideIcon;
actions: PredefinedActionType[];
onSelect: (action: PredefinedActionType) => void;
};
export function PredefinedActionGroup(props: PredefinedActionGroupProps) {
const { label, icon: Icon, actions, onSelect } = props;
const [isOpen, setIsOpen] = useState(false);
const containerRef = useRef<HTMLDivElement>(null);
useOutsideClick(containerRef, () => {
setIsOpen(false);
});
return (
<div className="relative" ref={containerRef}>
<PredefinedActionButton
label={label}
icon={Icon}
onClick={() => setIsOpen(!isOpen)}
isGroup={true}
/>
{isOpen && (
<div className="absolute top-full left-0 z-20 mt-1 divide-y overflow-hidden rounded-md border border-gray-200 bg-white p-0">
{actions.map((action) => {
return (
<PredefinedActionButton
key={action.label}
{...action}
className="py-2 pl-2.5 pr-5 w-full rounded-none bg-transparent hover:bg-gray-200"
onClick={() => {
onSelect(action);
setIsOpen(false);
}}
/>
);
})}
</div>
)}
</div>
);
}

@ -0,0 +1,144 @@
import {
BabyIcon,
BookOpenTextIcon,
BrainIcon,
ChevronDownIcon,
ListIcon,
NotebookPenIcon,
PencilLine,
Star,
type LucideIcon
} from 'lucide-react';
import { cn } from '../../lib/classname';
import { PredefinedActionGroup } from './PredefinedActionGroup';
export type PredefinedActionType = {
icon: LucideIcon;
label: string;
prompt?: string;
children?: PredefinedActionType[];
};
export const actions: PredefinedActionType[] = [
{
icon: BookOpenTextIcon,
label: 'Explain',
children: [
{
icon: NotebookPenIcon,
label: 'Explain the topic',
prompt: 'Explain this topic in detail and include examples',
},
{
icon: ListIcon,
label: 'List the key points',
prompt: 'List the key points to remember from this topic',
},
{
icon: PencilLine,
label: 'Summarize the topic',
prompt:
'Briefly explain the topic in a few sentences. Treat it as a brief answer to an interview question. Your response should just be the answer to the question, nothing else.',
},
{
icon: BabyIcon,
label: 'Explain like I am five',
prompt: 'Explain this topic like I am a 5 years old',
},
{
icon: Star,
label: 'Why is it important?',
prompt:
'Why is this topic important? What are the real world applications (only add if appropriate)?',
},
],
},
{
icon: BrainIcon,
label: 'Test my Knowledge',
prompt:
"Act as an interviewer and test my understanding of this topic. Ask me a single question at a time and evaluate my answer. Question number should be bold. After evaluating my answer, immediately proceed to the next question without asking if I'm ready or want another question. Continue asking questions until I explicitly tell you to stop.",
},
];
export const promptLabelMapping = actions.reduce(
(acc, action) => {
if (action.prompt) {
acc[action.prompt] = action.label;
}
if (action.children) {
action.children.forEach((child) => {
if (child.prompt) {
acc[child.prompt] = child.label;
}
});
}
return acc;
},
{} as Record<string, string>,
);
type PredefinedActionsProps = {
onSelect: (action: PredefinedActionType) => void;
};
export function PredefinedActions(props: PredefinedActionsProps) {
const { onSelect } = props;
return (
<div className="flex items-center gap-2 border-gray-200 px-3 py-1 text-sm">
{actions.map((action) => {
if (!action.children) {
return (
<PredefinedActionButton
key={action.label}
icon={action.icon}
label={action.label}
onClick={() => {
onSelect(action);
}}
/>
);
}
return (
<PredefinedActionGroup
key={action.label}
label={action.label}
icon={action.icon}
actions={action.children}
onSelect={onSelect}
/>
);
})}
</div>
);
}
type PredefinedActionButtonProps = {
label: string;
icon?: LucideIcon;
onClick: () => void;
isGroup?: boolean;
className?: string;
};
export function PredefinedActionButton(props: PredefinedActionButtonProps) {
const { label, icon: Icon, onClick, isGroup = false, className } = props;
return (
<button
className={cn(
'flex shrink-0 items-center gap-1.5 rounded-md bg-gray-200 px-2 py-1 text-sm whitespace-nowrap hover:bg-gray-300',
className,
)}
onClick={onClick}
>
{Icon && <Icon className="mr-1 size-3.5" />}
{label}
{isGroup && <ChevronDownIcon className="size-3.5" />}
</button>
);
}

@ -27,7 +27,7 @@ export function ResourceListSeparator(props: ResourceSeparatorProps) {
{Icon && <Icon className="inline-block h-3 w-3 fill-current" />}
{text}
</span>
<hr className="absolute inset-x-0 grow border-current" />
<span className="absolute inset-x-0 h-px w-full grow bg-current" />
</p>
);
}

@ -14,7 +14,6 @@ import {
updateResourceProgress as updateResourceProgressApi,
} from '../../lib/resource-progress';
import { pageProgressMessage } from '../../stores/page';
import { TopicProgressButton } from './TopicProgressButton';
import { showLoginPopup } from '../../lib/popup';
import { useToast } from '../../hooks/use-toast';
import type {
@ -22,20 +21,34 @@ import type {
RoadmapContentDocument,
} from '../CustomRoadmap/CustomRoadmap';
import { markdownToHtml, sanitizeMarkdown } from '../../lib/markdown';
import { Ban, Coins, FileText, HeartHandshake, Star, X } from 'lucide-react';
import { Ban, FileText, HeartHandshake, Star, X } from 'lucide-react';
import { getUrlParams, parseUrl } from '../../lib/browser';
import { Spinner } from '../ReactIcons/Spinner';
import { GitHubIcon } from '../ReactIcons/GitHubIcon.tsx';
import { resourceTitleFromId } from '../../lib/roadmap.ts';
import {
resourceTitleFromId,
type AllowedRoadmapRenderer,
} from '../../lib/roadmap.ts';
import { lockBodyScroll } from '../../lib/dom.ts';
import { TopicDetailLink } from './TopicDetailLink.tsx';
import { ResourceListSeparator } from './ResourceListSeparator.tsx';
import { PaidResourceDisclaimer } from './PaidResourceDisclaimer.tsx';
import {
TopicDetailsTabs,
type AllowedTopicDetailsTabs,
} from './TopicDetailsTabs.tsx';
import { TopicDetailAI } from './TopicDetailAI.tsx';
import { cn } from '../../lib/classname.ts';
import type { AIChatHistoryType } from '../GenerateCourse/AICourseLessonChat.tsx';
import { UpgradeAccountModal } from '../Billing/UpgradeAccountModal.tsx';
import { TopicProgressButton } from './TopicProgressButton.tsx';
import { CreateCourseModal } from './CreateCourseModal.tsx';
type TopicDetailProps = {
resourceId?: string;
resourceTitle?: string;
resourceType?: ResourceType;
renderer?: AllowedRoadmapRenderer;
isEmbed?: boolean;
canSubmitContribution: boolean;
@ -51,6 +64,14 @@ type PaidResourceType = {
const paidResourcesCache: Record<string, PaidResourceType[]> = {};
export const defaultChatHistory: AIChatHistoryType[] = [
{
role: 'assistant',
content: 'Hey, I am your AI instructor. How can I help you today? 🤖',
isDefault: true,
},
];
async function fetchRoadmapPaidResources(roadmapId: string) {
if (paidResourcesCache[roadmapId]) {
return paidResourcesCache[roadmapId];
@ -77,6 +98,7 @@ export function TopicDetail(props: TopicDetailProps) {
canSubmitContribution,
resourceId: defaultResourceId,
isEmbed = false,
renderer = 'balsamiq',
resourceTitle,
} = props;
@ -91,6 +113,15 @@ export function TopicDetail(props: TopicDetailProps) {
const [topicTitle, setTopicTitle] = useState('');
const [topicHtmlTitle, setTopicHtmlTitle] = useState('');
const [links, setLinks] = useState<RoadmapContentDocument['links']>([]);
const [activeTab, setActiveTab] =
useState<AllowedTopicDetailsTabs>('content');
const [aiChatHistory, setAiChatHistory] =
useState<AIChatHistoryType[]>(defaultChatHistory);
const [showUpgradeModal, setShowUpgradeModal] = useState(false);
const [isCustomResource, setIsCustomResource] = useState(false);
const [showSubjectSearchModal, setShowSubjectSearchModal] = useState(false);
const toast = useToast();
const [showPaidResourceDisclaimer, setShowPaidResourceDisclaimer] =
@ -106,14 +137,17 @@ export function TopicDetail(props: TopicDetailProps) {
const [resourceType, setResourceType] = useState<ResourceType>('roadmap');
const [paidResources, setPaidResources] = useState<PaidResourceType[]>([]);
// Close the topic detail when user clicks outside the topic detail
useOutsideClick(topicRef, () => {
const handleClose = () => {
setIsActive(false);
});
setShowUpgradeModal(false);
setAiChatHistory(defaultChatHistory);
setActiveTab('content');
setShowSubjectSearchModal(false);
};
useKeydown('Escape', () => {
setIsActive(false);
});
// Close the topic detail when user clicks outside the topic detail
useOutsideClick(topicRef, handleClose);
useKeydown('Escape', handleClose);
useEffect(() => {
if (resourceType !== 'roadmap' || !defaultResourceId) {
@ -177,6 +211,7 @@ export function TopicDetail(props: TopicDetailProps) {
setTopicId(topicId);
setResourceType(resourceType);
setResourceId(resourceId);
setIsCustomResource(isCustomResource);
const topicPartial = topicId.replaceAll(':', '/');
let topicUrl =
@ -318,10 +353,6 @@ export function TopicDetail(props: TopicDetailProps) {
return null;
}
const resourceTitleForSearch = resourceTitle
?.toLowerCase()
?.replace(/\s+?roadmap/gi, '');
const tnsLink =
'https://thenewstack.io/devops/?utm_source=roadmap.sh&utm_medium=Referral&utm_campaign=Topic';
@ -331,19 +362,25 @@ export function TopicDetail(props: TopicDetailProps) {
return resource.topicIds.includes(normalizedTopicId);
});
const hasPaidScrimbaLinks = paidResourcesForTopic.some(
(resource) => resource?.url?.toLowerCase().indexOf('scrimba') !== -1,
);
const shouldShowAiTab = !isCustomResource && resourceType === 'roadmap';
return (
<div className={'relative z-92'}>
<div
ref={topicRef}
tabIndex={0}
className="fixed right-0 top-0 z-40 flex h-screen w-full flex-col overflow-y-auto bg-white p-4 focus:outline-0 sm:max-w-[600px] sm:p-6"
className="fixed top-0 right-0 z-40 flex h-screen w-full flex-col overflow-y-auto bg-white p-4 focus:outline-0 sm:max-w-[600px] sm:p-6"
>
{showUpgradeModal && (
<UpgradeAccountModal onClose={() => setShowUpgradeModal(false)} />
)}
{showSubjectSearchModal && (
<CreateCourseModal onClose={() => setShowSubjectSearchModal(false)} />
)}
{isLoading && (
<div className="flex h-full w-full items-center justify-center">
<div className="flex h-full w-full justify-center">
<Spinner
outerFill="#d1d5db"
className="h-6 w-6 sm:h-8 sm:w-8"
@ -355,234 +392,237 @@ export function TopicDetail(props: TopicDetailProps) {
{!isContributing && !isLoading && !error && (
<>
<div className="flex-1">
{/* Actions for the topic */}
<div className="mb-2">
{!isEmbed && (
<TopicProgressButton
topicId={
topicId.indexOf('@') !== -1
? topicId.split('@')[1]
: topicId
}
resourceId={resourceId}
resourceType={resourceType}
onClose={() => {
setIsActive(false);
}}
<div
className={cn('flex-1', {
'flex flex-col': activeTab === 'ai',
})}
>
<div className="flex justify-between">
{shouldShowAiTab && (
<TopicDetailsTabs
activeTab={activeTab}
setActiveTab={setActiveTab}
hasAITutor={renderer === 'editor'}
/>
)}
<button
type="button"
id="close-topic"
className="absolute right-2.5 top-2.5 inline-flex items-center rounded-lg bg-transparent p-1.5 text-sm text-gray-400 hover:bg-gray-200 hover:text-gray-900"
onClick={() => {
setIsActive(false);
}}
<div
className={cn('flex flex-grow justify-end gap-1', {
'justify-between': !shouldShowAiTab,
})}
>
<X className="h-5 w-5" />
</button>
</div>
{/* Topic Content */}
{hasContent ? (
<>
<div className="prose prose-quoteless prose-h1:mb-2.5 prose-h1:mt-7 prose-h1:text-balance prose-h2:mb-3 prose-h2:mt-0 prose-h3:mb-[5px] prose-h3:mt-[10px] prose-p:mb-2 prose-p:mt-0 prose-blockquote:font-normal prose-blockquote:not-italic prose-blockquote:text-gray-700 prose-li:m-0 prose-li:mb-0.5">
{topicTitle && <h1>{topicTitle}</h1>}
<div
id="topic-content"
dangerouslySetInnerHTML={{ __html: topicHtml }}
{!isEmbed && (
<TopicProgressButton
topicId={
topicId.indexOf('@') !== -1
? topicId.split('@')[1]
: topicId
}
dropdownClassName={
!shouldShowAiTab ? 'left-0' : 'right-0'
}
resourceId={resourceId}
resourceType={resourceType}
onClose={handleClose}
/>
</div>
</>
) : (
<>
{!canSubmitContribution && (
<div className="flex h-[calc(100%-38px)] flex-col items-center justify-center">
<FileText className="h-16 w-16 text-gray-300" />
<p className="mt-2 text-lg font-medium text-gray-500">
Empty Content
</p>
</div>
)}
{canSubmitContribution && (
<div className="mx-auto flex h-[calc(100%-38px)] max-w-[400px] flex-col items-center justify-center text-center">
<HeartHandshake className="mb-2 h-16 w-16 text-gray-300" />
<p className="text-lg font-semibold text-gray-900">
Help us write this content
</p>
<p className="mb-3 mt-2 text-sm text-gray-500">
Write a brief introduction to this topic and submit a
link to a good article, podcast, video, or any other
self-vetted resource that helped you understand this
topic better.
</p>
<a
href={contributionUrl}
target={'_blank'}
className="flex w-full items-center justify-center rounded-md bg-gray-800 p-2 text-sm text-white transition-colors hover:bg-black hover:text-white disabled:bg-green-200 disabled:text-black"
>
<GitHubIcon className="mr-2 inline-block h-4 w-4 text-white" />
Help us Write this Content
</a>
</div>
)}
</>
)}
<button
type="button"
id="close-topic"
className="flex items-center gap-1.5 rounded-lg bg-gray-200 px-1.5 py-1 text-xs text-black hover:bg-gray-300 hover:text-gray-900"
onClick={handleClose}
>
<X className="size-4" />
</button>
</div>
</div>
{links.length > 0 && (
<>
<ResourceListSeparator
text="Free Resources"
className="text-green-600"
icon={HeartHandshake}
/>
<ul className="ml-3 mt-4 space-y-1">
{links.map((link) => {
return (
<li key={link.id}>
<TopicDetailLink
url={link.url}
type={link.type}
title={link.title}
onClick={() => {
// if it is one of our roadmaps, we want to track the click
if (canSubmitContribution) {
const parsedUrl = parseUrl(link.url);
window.fireEvent({
category: 'TopicResourceClick',
action: `Click: ${parsedUrl.hostname}`,
label: `${resourceType} / ${resourceId} / ${topicId} / ${link.url}`,
});
}
}}
/>
</li>
);
})}
</ul>
</>
{activeTab === 'ai' && shouldShowAiTab && (
<TopicDetailAI
resourceId={resourceId}
resourceType={resourceType}
topicId={topicId}
aiChatHistory={aiChatHistory}
setAiChatHistory={setAiChatHistory}
onUpgrade={() => setShowUpgradeModal(true)}
onLogin={() => {
handleClose();
showLoginPopup();
}}
onShowSubjectSearchModal={() => {
if (!isLoggedIn()) {
showLoginPopup();
return;
}
setShowSubjectSearchModal(true);
}}
/>
)}
{paidResourcesForTopic.length > 0 && (
{activeTab === 'content' && (
<>
<ResourceListSeparator text="Premium Resources" icon={Star} />
<ul className="ml-3 mt-3 space-y-1">
{paidResourcesForTopic.map((resource) => {
return (
<li key={resource._id}>
<TopicDetailLink
url={resource.url}
type={resource.type as any}
title={resource.title}
isPaid={true}
/>
</li>
);
})}
</ul>
{hasPaidScrimbaLinks && (
<div className="relative -mb-1 ml-3 mt-4 rounded-md border border-yellow-300 bg-yellow-100 px-2.5 py-2 text-sm text-yellow-800">
<div className="flex items-center gap-2">
<Coins className="h-4 w-4 text-yellow-700" />
<span>
Scrimba is offering{' '}
<span className={'font-semibold'}>20% off</span> on
all courses for roadmap.sh users.
</span>
{hasContent ? (
<>
<div className="prose prose-quoteless prose-h1:mb-2.5 prose-h1:mt-7 prose-h1:text-balance prose-h2:mb-3 prose-h2:mt-0 prose-h3:mb-[5px] prose-h3:mt-[10px] prose-p:mb-2 prose-p:mt-0 prose-blockquote:font-normal prose-blockquote:not-italic prose-blockquote:text-gray-700 prose-li:m-0 prose-li:mb-0.5">
{topicTitle && <h1>{topicTitle}</h1>}
<div
id="topic-content"
dangerouslySetInnerHTML={{ __html: topicHtml }}
/>
</div>
</div>
</>
) : (
<>
{!canSubmitContribution && (
<div className="flex h-[calc(100%-38px)] flex-col items-center justify-center">
<FileText className="h-16 w-16 text-gray-300" />
<p className="mt-2 text-lg font-medium text-gray-500">
Empty Content
</p>
</div>
)}
{canSubmitContribution && (
<div className="mx-auto flex h-[calc(100%-38px)] max-w-[400px] flex-col items-center justify-center text-center">
<HeartHandshake className="mb-2 h-16 w-16 text-gray-300" />
<p className="text-lg font-semibold text-gray-900">
Help us write this content
</p>
<p className="mt-2 mb-3 text-sm text-gray-500">
Write a brief introduction to this topic and submit
a link to a good article, podcast, video, or any
other self-vetted resource that helped you
understand this topic better.
</p>
<a
href={contributionUrl}
target={'_blank'}
className="flex w-full items-center justify-center rounded-md bg-gray-800 p-2 text-sm text-white transition-colors hover:bg-black hover:text-white disabled:bg-green-200 disabled:text-black"
>
<GitHubIcon className="mr-2 inline-block h-4 w-4 text-white" />
Help us Write this Content
</a>
</div>
)}
</>
)}
{showPaidResourceDisclaimer && (
<PaidResourceDisclaimer
onClose={() => {
localStorage.setItem(
PAID_RESOURCE_DISCLAIMER_HIDDEN,
'true',
);
setShowPaidResourceDisclaimer(false);
}}
/>
{links.length > 0 && (
<>
<ResourceListSeparator
text="Free Resources"
className="text-green-600"
icon={HeartHandshake}
/>
<ul className="mt-4 ml-3 space-y-1">
{links.map((link) => {
return (
<li key={link.id}>
<TopicDetailLink
url={link.url}
type={link.type}
title={link.title}
onClick={() => {
// if it is one of our roadmaps, we want to track the click
if (canSubmitContribution) {
const parsedUrl = parseUrl(link.url);
window.fireEvent({
category: 'TopicResourceClick',
action: `Click: ${parsedUrl.hostname}`,
label: `${resourceType} / ${resourceId} / ${topicId} / ${link.url}`,
});
}
}}
/>
</li>
);
})}
</ul>
</>
)}
{paidResourcesForTopic.length > 0 && (
<>
<ResourceListSeparator
text="Premium Resources"
icon={Star}
/>
<ul className="mt-3 ml-3 space-y-1">
{paidResourcesForTopic.map((resource) => {
return (
<li key={resource._id}>
<TopicDetailLink
url={resource.url}
type={resource.type as any}
title={resource.title}
isPaid={true}
/>
</li>
);
})}
</ul>
{showPaidResourceDisclaimer && (
<PaidResourceDisclaimer
onClose={() => {
localStorage.setItem(
PAID_RESOURCE_DISCLAIMER_HIDDEN,
'true',
);
setShowPaidResourceDisclaimer(false);
}}
/>
)}
</>
)}
</>
)}
{/* Contribution */}
{canSubmitContribution &&
!hasEnoughLinks &&
contributionUrl &&
hasContent && (
<div className="mb-12 mt-3 border-t text-sm text-gray-400 sm:mt-12">
<h2 className="mb-1 mt-4 text-base text-black font-medium">
Help us add learning resources
</h2>
<p className="mb-4 leading-relaxed">
This popup should be a brief introductory paragraph for
the topic and a few links to good articles, videos, or any
other self-vetted learning resources. Please consider submitting a
PR to improve this content.
</p>
<a
href={contributionUrl}
target={'_blank'}
className="flex w-full items-center justify-center rounded-md bg-gray-800 p-2 text-sm text-white transition-colors hover:bg-black hover:text-white disabled:bg-green-200 disabled:text-black"
>
<GitHubIcon className="mr-2 inline-block h-4 w-4 text-white" />
Help us Improve this Content
</a>
</div>
)}
</div>
{resourceId === 'devops' && (
<div className="mt-4">
<a
href={tnsLink}
target="_blank"
className="hidden rounded-md border bg-gray-200 px-2 py-2 text-sm hover:bg-gray-300 sm:block"
>
<span className="badge mr-1.5">Partner</span>
Get the latest {resourceTitleFromId(resourceId)} news from our
sister site{' '}
<span className="font-medium underline underline-offset-1">
TheNewStack.io
</span>
</a>
<a
href={tnsLink}
className="hidden rounded-md border bg-gray-200 px-2 py-1.5 text-sm hover:bg-gray-300 min-[390px]:block sm:hidden"
onClick={() => {
window.fireEvent({
category: 'PartnerClick',
action: 'TNS Redirect',
label: 'Roadmap Topic / TNS Link',
});
}}
>
<span className="badge mr-1.5">Partner</span>
Visit{' '}
<span className="font-medium underline underline-offset-1">
TheNewStack.io
</span>{' '}
for {resourceTitleFromId(resourceId)} news
</a>
</div>
)}
{canSubmitContribution &&
contributionUrl &&
activeTab === 'content' &&
hasContent && (
<div className="mt-4">
<a
href={contributionUrl}
target="_blank"
className="hidden items-center justify-center rounded-md border bg-gray-200 px-2 py-2 text-sm hover:bg-gray-300 sm:flex"
>
<GitHubIcon className="mr-2 inline-block h-4 w-4 text-current" />
Help us Improve this Content
</a>
<a
href={tnsLink}
className="hidden rounded-md border bg-gray-200 px-2 py-1.5 text-sm hover:bg-gray-300 min-[390px]:block sm:hidden"
onClick={() => {
window.fireEvent({
category: 'PartnerClick',
action: 'TNS Redirect',
label: 'Roadmap Topic / TNS Link',
});
}}
>
<span className="badge mr-1.5">Partner</span>
Visit{' '}
<span className="font-medium underline underline-offset-1">
TheNewStack.io
</span>{' '}
for {resourceTitleFromId(resourceId)} news
</a>
</div>
)}
</>
)}
{/* Error */}
{!isContributing && !isLoading && error && (
<>
<button
type="button"
id="close-topic"
className="absolute right-2.5 top-2.5 inline-flex items-center rounded-lg bg-transparent p-1.5 text-sm text-gray-400 hover:bg-gray-200 hover:text-gray-900"
className="absolute top-2.5 right-2.5 inline-flex items-center rounded-lg bg-transparent p-1.5 text-sm text-gray-400 hover:bg-gray-200 hover:text-gray-900"
onClick={() => {
setIsActive(false);
setIsContributing(false);

@ -0,0 +1,522 @@
import '../GenerateCourse/AICourseLessonChat.css';
import { useQuery } from '@tanstack/react-query';
import { useState, useRef, Fragment, useCallback, useEffect } from 'react';
import { billingDetailsOptions } from '../../queries/billing';
import { getAiCourseLimitOptions } from '../../queries/ai-course';
import { queryClient } from '../../stores/query-client';
import { isLoggedIn, removeAuthToken } from '../../lib/jwt';
import {
BotIcon,
ChevronRightIcon,
Gift,
Loader2Icon,
LockIcon, SendIcon, Trash2,
WandSparkles
} from 'lucide-react';
import { showLoginPopup } from '../../lib/popup';
import { cn } from '../../lib/classname';
import TextareaAutosize from 'react-textarea-autosize';
import { flushSync } from 'react-dom';
import {
AIChatCard,
type AIChatHistoryType,
} from '../GenerateCourse/AICourseLessonChat';
import { useToast } from '../../hooks/use-toast';
import { readStream } from '../../lib/ai';
import { markdownToHtmlWithHighlighting } from '../../lib/markdown';
import type { ResourceType } from '../../lib/resource-progress';
import { getPercentage } from '../../lib/number';
import { roadmapTreeMappingOptions } from '../../queries/roadmap-tree';
import { defaultChatHistory } from './TopicDetail';
import { AILimitsPopup } from '../GenerateCourse/AILimitsPopup';
import { PredefinedActions, promptLabelMapping } from './PredefinedActions';
type TopicDetailAIProps = {
resourceId: string;
resourceType: ResourceType;
topicId: string;
aiChatHistory: AIChatHistoryType[];
setAiChatHistory: (history: AIChatHistoryType[]) => void;
onUpgrade: () => void;
onLogin: () => void;
onShowSubjectSearchModal: () => void;
};
export function TopicDetailAI(props: TopicDetailAIProps) {
const {
aiChatHistory,
setAiChatHistory,
resourceId,
resourceType,
topicId,
onUpgrade,
onLogin,
onShowSubjectSearchModal,
} = props;
const textareaRef = useRef<HTMLTextAreaElement>(null);
const scrollareaRef = useRef<HTMLDivElement>(null);
const formRef = useRef<HTMLFormElement>(null);
const sanitizedTopicId = topicId?.includes('@')
? topicId?.split('@')?.[1]
: topicId;
const toast = useToast();
const [message, setMessage] = useState('');
const [isStreamingMessage, setIsStreamingMessage] = useState(false);
const [streamedMessage, setStreamedMessage] = useState('');
const [showAILimitsPopup, setShowAILimitsPopup] = useState(false);
const { data: tokenUsage, isLoading } = useQuery(
getAiCourseLimitOptions(),
queryClient,
);
const { data: userBillingDetails, isLoading: isBillingDetailsLoading } =
useQuery(billingDetailsOptions(), queryClient);
const { data: roadmapTreeMapping, isLoading: isRoadmapTreeMappingLoading } =
useQuery(
{
...roadmapTreeMappingOptions(resourceId),
select: (data) => {
const node = data.find(
(mapping) => mapping.nodeId === sanitizedTopicId,
);
return node;
},
},
queryClient,
);
const isLimitExceeded = (tokenUsage?.used || 0) >= (tokenUsage?.limit || 0);
const isPaidUser = userBillingDetails?.status === 'active';
const handleChatSubmit = (overrideMessage?: string) => {
const trimmedMessage = (overrideMessage ?? message).trim();
if (
!trimmedMessage ||
isStreamingMessage ||
!isLoggedIn() ||
isLimitExceeded ||
isLoading
) {
return;
}
const newMessages: AIChatHistoryType[] = [
...aiChatHistory,
{
role: 'user',
content: trimmedMessage,
},
];
flushSync(() => {
setAiChatHistory(newMessages);
setMessage('');
});
scrollToBottom();
completeAITutorChat(newMessages);
};
const scrollToBottom = useCallback(() => {
scrollareaRef.current?.scrollTo({
top: scrollareaRef.current.scrollHeight,
behavior: 'smooth',
});
}, [scrollareaRef]);
const completeAITutorChat = async (messages: AIChatHistoryType[]) => {
try {
setIsStreamingMessage(true);
const response = await fetch(
`${import.meta.env.PUBLIC_API_URL}/v1-topic-detail-chat`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
credentials: 'include',
body: JSON.stringify({
resourceId,
resourceType,
topicId: sanitizedTopicId,
messages: messages.slice(-10),
}),
},
);
if (!response.ok) {
const data = await response.json();
toast.error(data?.message || 'Something went wrong');
setAiChatHistory([...messages].slice(0, messages.length - 1));
setIsStreamingMessage(false);
if (data.status === 401) {
removeAuthToken();
window.location.reload();
}
queryClient.invalidateQueries(getAiCourseLimitOptions());
return;
}
const reader = response.body?.getReader();
if (!reader) {
setIsStreamingMessage(false);
toast.error('Something went wrong');
return;
}
await readStream(reader, {
onStream: async (content) => {
flushSync(() => {
setStreamedMessage(content);
});
scrollToBottom();
},
onStreamEnd: async (content) => {
const newMessages: AIChatHistoryType[] = [
...messages,
{
role: 'assistant',
content,
html: await markdownToHtmlWithHighlighting(content),
},
];
flushSync(() => {
setStreamedMessage('');
setIsStreamingMessage(false);
setAiChatHistory(newMessages);
});
queryClient.invalidateQueries(getAiCourseLimitOptions());
scrollToBottom();
},
});
setIsStreamingMessage(false);
} catch (error) {
toast.error('Something went wrong');
setIsStreamingMessage(false);
}
};
useEffect(() => {
scrollToBottom();
}, []);
const isDataLoading =
isLoading || isBillingDetailsLoading || isRoadmapTreeMappingLoading;
const usagePercentage = getPercentage(
tokenUsage?.used || 0,
tokenUsage?.limit || 0,
);
const hasChatHistory = aiChatHistory.length > 1;
const nodeTextParts = roadmapTreeMapping?.text?.split('>') || [];
const hasSubjects =
(roadmapTreeMapping?.subjects &&
roadmapTreeMapping?.subjects?.length > 0) ||
nodeTextParts.length > 1;
return (
<div className="relative mt-4 flex grow flex-col overflow-hidden rounded-lg border border-gray-200">
{isDataLoading && (
<div className="absolute inset-0 z-20 flex items-center justify-center gap-2 bg-white text-black">
<Loader2Icon className="size-8 animate-spin stroke-3 text-gray-500" />
</div>
)}
{showAILimitsPopup && (
<AILimitsPopup
onClose={() => setShowAILimitsPopup(false)}
onUpgrade={() => {
setShowAILimitsPopup(false);
onUpgrade();
}}
/>
)}
{hasSubjects && (
<div className="border-b border-gray-200 p-3">
<h4 className="flex items-center gap-2 text-sm">
Complete the following AI Tutor courses
</h4>
<div className="mt-2.5 flex flex-wrap gap-1 text-sm">
{roadmapTreeMapping?.subjects?.map((subject) => {
return (
<a
key={subject}
target="_blank"
onClick={(e) => {
if (!isLoggedIn()) {
e.preventDefault();
onLogin();
return;
}
if (isLimitExceeded) {
e.preventDefault();
onUpgrade();
return;
}
}}
href={`/ai/search?term=${subject}&difficulty=beginner&src=topic`}
className="flex items-center gap-1 gap-2 rounded-md border border-gray-300 bg-gray-100 px-2 py-1 hover:bg-gray-200 hover:text-black"
>
{subject}
</a>
);
})}
{roadmapTreeMapping?.subjects?.length === 0 && (
<a
target="_blank"
href={`/ai/search?term=${roadmapTreeMapping?.text}&difficulty=beginner&src=topic`}
className="flex items-center gap-1 rounded-md border border-gray-300 bg-gray-100 px-2 py-1 hover:bg-gray-200 hover:text-black"
>
{nodeTextParts.map((text, index) => (
<>
<span key={text} className="flex items-center">
{text}
</span>
{index !== nodeTextParts.length - 1 && (
<ChevronRightIcon className="h-3 w-3 text-gray-400" />
)}
</>
))}
</a>
)}
<button
onClick={onShowSubjectSearchModal}
className="flex text-gray-400 items-center gap-1.5 rounded-md border border-dashed hover:border-solid border-gray-300 bg-transparent px-2 py-1 hover:bg-gray-200 hover:text-black"
>
<WandSparkles className="h-3 w-3" />
Learn another topic
</button>
</div>
</div>
)}
<div
className={cn(
'flex min-h-[46px] items-center justify-between gap-2 border-gray-200 px-3 py-2 text-sm',
)}
>
{hasSubjects && (
<span className="flex items-center gap-2 text-sm">
<BotIcon
className="relative -top-[1px] size-4 shrink-0 text-black"
strokeWidth={2.5}
/>
<span className="hidden sm:block">Chat with AI</span>
<span className="block sm:hidden">AI Tutor</span>
</span>
)}
{!hasSubjects && (
<h4 className="flex items-center gap-2 text-base font-medium">
<BotIcon
className="relative -top-[1px] size-5 shrink-0 text-black"
strokeWidth={2.5}
/>
AI Tutor
</h4>
)}
{!isDataLoading && (
<div className="flex gap-1.5">
{hasChatHistory && (
<button
className="rounded-md bg-white px-2 py-2 text-xs font-medium text-black hover:bg-gray-200"
onClick={() => {
setAiChatHistory(defaultChatHistory);
}}
>
<Trash2 className="size-3.5" />
</button>
)}
{!isPaidUser && (
<>
<button
className="hidden rounded-md bg-gray-200 px-2 py-1 text-sm hover:bg-gray-300 sm:block"
onClick={() => {
if (!isLoggedIn()) {
onLogin();
return;
}
setShowAILimitsPopup(true);
}}
>
<span className="font-medium">{usagePercentage}%</span>{' '}
credits used
</button>
<button
className="flex items-center gap-1 rounded-md bg-yellow-400 px-2 py-1 text-sm text-black hover:bg-yellow-500"
onClick={() => {
if (!isLoggedIn()) {
onLogin();
return;
}
onUpgrade();
}}
>
<Gift className="size-4" />
Upgrade
</button>
</>
)}
</div>
)}
</div>
<PredefinedActions
onSelect={(action) => {
if (!isLoggedIn()) {
onLogin();
return;
}
if (isLimitExceeded) {
onUpgrade();
return;
}
if (!action?.prompt) {
toast.error('Something went wrong');
return;
}
setMessage(action.prompt);
handleChatSubmit(action.prompt);
}}
/>
<div
className="scrollbar-thumb-gray-300 scrollbar-track-transparent scrollbar-thin relative grow overflow-y-auto"
ref={scrollareaRef}
>
<div className="absolute inset-0 flex flex-col">
<div className="relative flex grow flex-col justify-end">
<div className="flex flex-col justify-end gap-2 px-3 py-2">
{aiChatHistory.map((chat, index) => {
let content = chat.content;
if (chat.role === 'user' && promptLabelMapping[chat.content]) {
content = promptLabelMapping[chat.content];
}
return (
<Fragment key={`chat-${index}`}>
<AIChatCard
role={chat.role}
content={content}
html={chat.html}
/>
</Fragment>
);
})}
{isStreamingMessage && !streamedMessage && (
<AIChatCard role="assistant" content="Thinking..." />
)}
{streamedMessage && (
<AIChatCard role="assistant" content={streamedMessage} />
)}
</div>
</div>
</div>
</div>
<form
ref={formRef}
className="relative flex items-start border-t border-gray-200 text-sm"
onSubmit={(e) => {
e.preventDefault();
handleChatSubmit();
}}
>
{isLimitExceeded && isLoggedIn() && (
<div className="absolute inset-0 z-10 flex items-center justify-center gap-2 bg-black text-white">
<LockIcon className="size-4 cursor-not-allowed" strokeWidth={2.5} />
<p className="cursor-not-allowed">
Limit reached for today
{isPaidUser ? '. Please wait until tomorrow.' : ''}
</p>
{!isPaidUser && (
<button
onClick={onUpgrade}
className="rounded-md bg-white px-2 py-1 text-xs font-medium text-black hover:bg-gray-300"
>
Upgrade for more
</button>
)}
</div>
)}
{!isLoggedIn() && (
<div className="absolute inset-0 z-10 flex items-center justify-center gap-2 bg-black text-white">
<LockIcon className="size-4 cursor-not-allowed" strokeWidth={2.5} />
<p className="cursor-not-allowed">Please login to continue</p>
<button
onClick={() => {
showLoginPopup();
}}
className="rounded-md bg-white px-2 py-1 text-xs font-medium text-black hover:bg-gray-300"
>
Login / Register
</button>
</div>
)}
{isDataLoading && (
<div className="absolute inset-0 z-10 flex items-center justify-center gap-2 bg-black text-white">
<Loader2Icon className="size-4 animate-spin" />
<p>Loading...</p>
</div>
)}
<TextareaAutosize
className={cn(
'h-full min-h-[41px] grow resize-none bg-transparent px-4 py-2 focus:outline-hidden',
)}
placeholder="Ask AI anything about the lesson..."
value={message}
onChange={(e) => setMessage(e.target.value)}
autoFocus={true}
onKeyDown={(e) => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
handleChatSubmit();
}
}}
ref={textareaRef}
/>
<button
type="submit"
disabled={isStreamingMessage || isLimitExceeded}
className="flex aspect-square size-[41px] items-center justify-center text-zinc-500 hover:text-black disabled:cursor-not-allowed disabled:opacity-50"
>
<SendIcon className="size-4 stroke-[2.5]" />
</button>
</form>
</div>
);
}

@ -1,7 +1,7 @@
import { cn } from '../../lib/classname.ts';
import type { AllowedLinkTypes } from '../CustomRoadmap/CustomRoadmap.tsx';
const linkTypes: Record<AllowedLinkTypes, string> = {
const linkTypes: Record<AllowedLinkTypes | string, string> = {
article: 'bg-yellow-300',
course: 'bg-green-400',
opensource: 'bg-black text-white',
@ -18,6 +18,34 @@ const paidLinkTypes: Record<string, string> = {
course: 'bg-yellow-300',
};
type TopicLinkBadgeProps = {
isPaid: boolean;
discountText?: string;
type: AllowedLinkTypes | string;
className?: string;
};
function TopicLinkBadge(props: TopicLinkBadgeProps) {
const { isPaid, type, className } = props;
const linkType = type === 'opensource' ? 'OpenSource' : type;
const isDiscount = type.includes('% off');
return (
<span className={cn('mr-2', className)}>
<span
className={cn(
'inline-block rounded-sm px-1.5 py-0.5 text-xs capitalize no-underline',
(isPaid ? paidLinkTypes[type] : linkTypes[type]) || 'bg-gray-200',
isDiscount && 'bg-green-300',
)}
>
{linkType}
</span>
</span>
);
}
type TopicDetailLinkProps = {
url: string;
onClick?: () => void;
@ -29,7 +57,7 @@ type TopicDetailLinkProps = {
export function TopicDetailLink(props: TopicDetailLinkProps) {
const { url, onClick, type, title, isPaid = false } = props;
const linkType = type === 'opensource' ? 'OpenSource' : type;
const isScrimbaLink = url.toLowerCase().includes('scrimba.com');
return (
<a
@ -38,14 +66,14 @@ export function TopicDetailLink(props: TopicDetailLinkProps) {
className="group font-medium text-gray-800 underline underline-offset-1 hover:text-black"
onClick={onClick}
>
<span
className={cn(
'mr-2 inline-block rounded-sm px-1.5 py-0.5 text-xs capitalize no-underline',
(isPaid ? paidLinkTypes[type] : linkTypes[type]) || 'bg-gray-200',
)}
>
{linkType}
</span>
<TopicLinkBadge
isPaid={isPaid}
type={type}
discountText={isScrimbaLink ? '20% off' : undefined}
className={isScrimbaLink ? 'mr-1' : 'mr-2'}
/>
{isScrimbaLink && <TopicLinkBadge isPaid={isPaid} type="20% off" />}
{title}
</a>
);

@ -0,0 +1,68 @@
import { Earth, WandSparkles, type LucideIcon } from 'lucide-react';
export type AllowedTopicDetailsTabs = 'content' | 'ai';
type TopicDetailsTabsProps = {
activeTab: AllowedTopicDetailsTabs;
setActiveTab: (tab: AllowedTopicDetailsTabs) => void;
hasAITutor?: boolean;
};
export function TopicDetailsTabs(props: TopicDetailsTabsProps) {
const { activeTab, setActiveTab, hasAITutor = true } = props;
return (
<div className="flex w-max gap-1.5">
<TopicDetailsTab
isActive={activeTab === 'content'}
icon={Earth}
label="Resources"
onClick={() => setActiveTab('content')}
/>
<TopicDetailsTab
isActive={activeTab === 'ai'}
icon={WandSparkles}
label="AI Tutor"
isNew={true}
isDisabled={!hasAITutor}
onClick={() => setActiveTab('ai')}
/>
</div>
);
}
type TopicDetailsTabProps = {
isActive: boolean;
icon: LucideIcon;
label: string;
isNew?: boolean;
isDisabled?: boolean;
onClick: () => void;
};
function TopicDetailsTab(props: TopicDetailsTabProps) {
const { isActive, icon: Icon, label, isNew, isDisabled, onClick } = props;
return (
<button
className="flex select-none disabled:pointer-events-none items-center gap-2 rounded-md border border-gray-300 px-2 py-1 text-sm text-gray-500 hover:border-gray-400 data-[state=active]:border-black data-[state=active]:bg-black data-[state=active]:text-white"
data-state={isActive ? 'active' : 'inactive'}
onClick={onClick}
disabled={isDisabled}
type="button"
>
<Icon className="h-4 w-4" />
<span className="hidden sm:block">{label}</span>
{isNew && !isDisabled && (
<span className="hidden rounded-sm bg-yellow-400 px-1 text-xs text-black sm:block">
New
</span>
)}
{isDisabled && (
<span className="hidden rounded-sm bg-gray-400 px-1 text-xs text-white sm:block">
Soon
</span>
)}
</button>
);
}

@ -16,25 +16,54 @@ import { showLoginPopup } from '../../lib/popup';
import { useToast } from '../../hooks/use-toast';
import { Spinner } from '../ReactIcons/Spinner';
import { ChevronDown } from 'lucide-react';
import { cn } from '../../lib/classname';
const statusColors: Record<ResourceProgressType, string> = {
done: 'bg-green-500',
learning: 'bg-yellow-500',
pending: 'bg-gray-300',
skipped: 'bg-black',
removed: '',
};
type TopicProgressButtonProps = {
topicId: string;
resourceId: string;
resourceType: ResourceType;
dropdownClassName?: string;
onClose: () => void;
};
const statusColors: Record<ResourceProgressType, string> = {
done: 'bg-green-500',
learning: 'bg-yellow-500',
pending: 'bg-gray-300',
skipped: 'bg-black',
removed: '',
type ProgressDropdownItemProps = {
status: ResourceProgressType;
shortcutKey: string;
label: string;
onClick: () => void;
};
function ProgressDropdownItem(props: ProgressDropdownItemProps) {
const { status, shortcutKey, label, onClick } = props;
return (
<button
className="inline-flex justify-between px-3 py-1.5 text-left text-sm text-gray-800 hover:bg-gray-100"
onClick={onClick}
>
<span>
<span
className={`mr-2 inline-block h-2 w-2 rounded-full ${statusColors[status]}`}
></span>
{label}
</span>
<span className="text-xs text-gray-500">{shortcutKey}</span>
</button>
);
}
export function TopicProgressButton(props: TopicProgressButtonProps) {
const { topicId, resourceId, resourceType, onClose } = props;
const { topicId, resourceId, resourceType, onClose, dropdownClassName } =
props;
const toast = useToast();
const [isUpdatingProgress, setIsUpdatingProgress] = useState(true);
@ -66,7 +95,15 @@ export function TopicProgressButton(props: TopicProgressButtonProps) {
// Mark as done
useKeydown(
'd',
() => {
(e: KeyboardEvent) => {
if (
e.target instanceof HTMLTextAreaElement ||
e.target instanceof HTMLInputElement ||
e.target instanceof HTMLSelectElement
) {
return;
}
if (progress === 'done') {
onClose();
return;
@ -80,7 +117,15 @@ export function TopicProgressButton(props: TopicProgressButtonProps) {
// Mark as learning
useKeydown(
'l',
() => {
(e: KeyboardEvent) => {
if (
e.target instanceof HTMLTextAreaElement ||
e.target instanceof HTMLInputElement ||
e.target instanceof HTMLSelectElement
) {
return;
}
if (progress === 'learning') {
return;
}
@ -93,7 +138,15 @@ export function TopicProgressButton(props: TopicProgressButtonProps) {
// Mark as learning
useKeydown(
's',
() => {
(e: KeyboardEvent) => {
if (
e.target instanceof HTMLTextAreaElement ||
e.target instanceof HTMLInputElement ||
e.target instanceof HTMLSelectElement
) {
return;
}
if (progress === 'skipped') {
onClose();
return;
@ -107,9 +160,16 @@ export function TopicProgressButton(props: TopicProgressButtonProps) {
// Mark as pending
useKeydown(
'r',
() => {
(e: KeyboardEvent) => {
if (
e.target instanceof HTMLTextAreaElement ||
e.target instanceof HTMLInputElement ||
e.target instanceof HTMLSelectElement
) {
return;
}
if (progress === 'pending') {
onClose();
return;
}
@ -147,6 +207,7 @@ export function TopicProgressButton(props: TopicProgressButtonProps) {
console.error(err);
})
.finally(() => {
setShowChangeStatus(false);
setIsUpdatingProgress(false);
});
};
@ -167,15 +228,20 @@ export function TopicProgressButton(props: TopicProgressButtonProps) {
if (isUpdatingProgress) {
return (
<button className="inline-flex cursor-default items-center rounded-md border border-gray-300 bg-white p-1 px-2 text-sm text-black">
<Spinner className="h-4 w-4" />
<span className="ml-2">Updating Status..</span>
<Spinner isDualRing={false} className="h-4 w-4" />
<span className="ml-2">Please wait..</span>
</button>
);
}
return (
<div className="relative inline-flex rounded-md border border-gray-300">
<span className="inline-flex cursor-default items-center p-1 px-2 text-sm text-black">
<div className="relative inline-flex">
<button
className={cn(
'flex cursor-default cursor-pointer items-center rounded-md border border-gray-300 p-1 px-2 text-sm text-black hover:border-gray-400',
)}
onClick={() => setShowChangeStatus(true)}
>
<span className="flex h-2 w-2">
<span
className={`relative inline-flex h-2 w-2 rounded-full ${statusColors[progress]}`}
@ -184,77 +250,48 @@ export function TopicProgressButton(props: TopicProgressButtonProps) {
<span className="ml-2 capitalize">
{progress === 'learning' ? 'In Progress' : progress}
</span>
</span>
<button
className="inline-flex cursor-pointer items-center rounded-br-md rounded-tr-md border-l border-l-gray-300 bg-gray-100 p-1 px-2 text-sm text-black hover:bg-gray-200"
onClick={() => setShowChangeStatus(true)}
>
<span className="mr-0.5">Update Status</span>
<ChevronDown className="h-4 w-4" />
<ChevronDown className="ml-2 h-4 w-4" />
</button>
{showChangeStatus && (
<div
className="absolute right-0 top-full mt-1 flex min-w-[160px] flex-col divide-y rounded-md border border-gray-200 bg-white shadow-md [&>button:first-child]:rounded-t-md [&>button:last-child]:rounded-b-md"
className={cn(
'absolute top-full right-0 z-50 mt-1 flex min-w-[160px] flex-col divide-y rounded-md border border-gray-200 bg-white shadow-md [&>button:first-child]:rounded-t-md [&>button:last-child]:rounded-b-md',
dropdownClassName,
)}
ref={changeStatusRef!}
>
{allowMarkingDone && (
<button
className="inline-flex justify-between px-3 py-1.5 text-left text-sm text-gray-800 hover:bg-gray-100"
<ProgressDropdownItem
status="done"
shortcutKey="D"
label="Done"
onClick={() => handleUpdateResourceProgress('done')}
>
<span>
<span
className={`mr-2 inline-block h-2 w-2 rounded-full ${statusColors['done']}`}
></span>
Done
</span>
<span className="text-xs text-gray-500">D</span>
</button>
/>
)}
{allowMarkingLearning && (
<button
className="inline-flex justify-between px-3 py-1.5 text-left text-sm text-gray-800 hover:bg-gray-100"
<ProgressDropdownItem
status="learning"
shortcutKey="L"
label="In Progress"
onClick={() => handleUpdateResourceProgress('learning')}
>
<span>
<span
className={`mr-2 inline-block h-2 w-2 rounded-full ${statusColors['learning']}`}
></span>
In Progress
</span>
<span className="text-xs text-gray-500">L</span>
</button>
/>
)}
{allowMarkingPending && (
<button
className="inline-flex justify-between px-3 py-1.5 text-left text-sm text-gray-800 hover:bg-gray-100"
<ProgressDropdownItem
status="pending"
shortcutKey="R"
label="Reset"
onClick={() => handleUpdateResourceProgress('pending')}
>
<span>
<span
className={`mr-2 inline-block h-2 w-2 rounded-full ${statusColors['pending']}`}
></span>
Reset
</span>
<span className="text-xs text-gray-500">R</span>
</button>
/>
)}
{allowMarkingSkipped && (
<button
className="inline-flex justify-between px-3 py-1.5 text-left text-sm text-gray-800 hover:bg-gray-100"
<ProgressDropdownItem
status="skipped"
shortcutKey="S"
label="Skip"
onClick={() => handleUpdateResourceProgress('skipped')}
>
<span>
<span
className={`mr-2 inline-block h-2 w-2 rounded-full ${statusColors['skipped']}`}
></span>
Skip
</span>
<span className="text-xs text-gray-500">S</span>
</button>
/>
)}
</div>
)}

@ -0,0 +1,18 @@
---
title: 'AI Agents, Red Teaming Roadmaps and Community Courses'
description: 'New roadmaps for AI Agents and Red Teaming plus access to community-generated AI courses'
images:
'AI Agents': 'https://assets.roadmap.sh/guest/ai-agents-roadmap-min-poii3.png'
'Red Teaming': 'https://assets.roadmap.sh/guest/ai-red-teaming-omyvx.png'
'AI Community Courses': 'https://assets.roadmap.sh/guest/ai-community-courses.png'
seo:
title: 'AI Agents, Red Teaming Roadmaps and Community Courses'
description: ''
date: 2025-05-12
---
We added new AI roadmaps for AI Agents and Red Teaming and made our AI Tutor better with courses created by the community.
- We just released a new [AI Agents Roadmap](https://roadmap.sh/ai-agents) that covers how to build, design, and run smart autonomous systems.
- There's also a new [Red Teaming Roadmap](https://roadmap.sh/ai-red-teaming) for people who want to learn about testing AI systems for weaknesses and security flaws.
- Our [AI Tutor](https://roadmap.sh/ai) now lets you use courses made by other users. You can learn from their content or share your own learning plans.

@ -15,6 +15,4 @@ We have revised the C++ and Java roadmaps and introduced an AI tutor to help you
- We just launched an [AI Tutor](https://roadmap.sh/ai), just give it a topic, pick a difficulty level and it will generate a personalized study plan for you. There is a map view, quizzes an embedded chat to help you along the way.
- [C++ roadmap](https://roadmap.sh/cpp) has been revised with improved content
- We have also redrawn the [Java roadmap](https://roadmap.sh/java) from scratch, replacing the deprecated items, adding new content and improving the overall structure.
- We have also redrawn the [Java roadmap](https://roadmap.sh/java) from scratch, replacing the deprecated items, adding new content and improving the overall structure.

@ -1,195 +0,0 @@
---
title: 'Frontend vs. Backend in AI Development'
description: 'Learn the key differences between frontend and backend in AI development, from roles to tools, and how they impact project success.'
authorId: william
excludedBySlug: '/frontend/vs-backend-ai'
seo:
title: 'Frontend vs. Backend in AI Development'
description: 'Learn the key differences between frontend and backend in AI development, from roles to tools, and how they impact project success.'
ogImageUrl: 'https://assets.roadmap.sh/guest/frontend-vs-backend-in-ai-43wtm.jpg'
relatedTitle: "Other Guides"
relatedGuidesId: frontend
isNew: false
type: 'textual'
date: 2024-10-17
sitemap:
priority: 0.7
changefreq: 'weekly'
tags:
- 'guide'
- 'textual-guide'
- 'guide-sitemap'
---
![The best frontend developer skills to learn.](https://assets.roadmap.sh/guest/frontend-vs-backend-in-ai-43wtm.jpg)
Many software developers begin their careers by choosing an area of focus: backend or front end development. If you're an aspiring software developer, understanding the differences between frontend and backend can help you choose a focus for your career path. This guide focuses on the [front-end](https://roadmap.sh/frontend) and [back-end](https://roadmap.sh/backend) development for AI.
Frontend vs Backend is a common topic in software engineering and understanding both frontend and backend development is crucial for creating effective and efficient websites. Both are essential for a well-rounded web development process. Both career paths are in high demand.
Front-end development refers to the visual elements that users can directly interact with. It is the user facing side of an application also known as the client side of an application. Back-end development includes everything the user cannot see. It focuses on the application’s overall functionality and business logic.
Despite frontend and backend developers in AI having specific roles in the overall software development life cycle, they work together to design, program, test, and deploy AI applications. They collaborate to ensure AI applications meet quality and security standards. In addition to front-end and back-end developers, there are also full stack developers. Full stack developers work and specialize in both frontend and backend of web development.
![Frontend vs Backend AI developers](https://assets.roadmap.sh/guest/frontend-backend-jk2nh.jpeg)
The table below presents a comparison of frontend vs backend development AI specializations.
| Frontend AI development | Backend AI development |
| ---------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| Focuses on the visual aspects of an AI application which is the UI and users directly interact with. | Focuses on the server-side development of an application which has data storage and the user does not directly interact with. |
| Specializes in the client side of the application. | Not concerned with the client side of web applications. |
| The front end is about user interface (UI) and user experience (UX). | Focuses on the application’s functionality and business logic. |
| Uses HTML, CSS and JavaScript as part of the toolbox. | Uses back-end programming languages like Java, C#, Python and so on. |
Let’s look at frontend vs backend in detail.
## What is frontend development for AI?
Frontend development for AI involves the design and implementation of the visual elements of an AI application. Several AI applications are being used on a daily basis, such as Chatbots, Virtual assistants, face recognition systems, etc. A user interface (UI) enables you to interact with these applications.
An AI frontend developer designs and builds the parts of an AI application that users can directly interact with. For larger projects, front-end developers will work with a digital and web designer who is responsible for creating a graphic design for the web page of the application. Frontend developers are also referred to as web developers.
Frontends are also built on other platforms asides the web, such as mobile apps for Android and iOS, or desktop apps.
The next section presents who a front-end developer is and the tools they use for building applications for the web.
## Who is a frontend developer?
A [frontend developer](https://roadmap.sh/frontend) builds the visual part of an application, which includes the parts users see and directly interact with, such as the graphical user interface (GUI) and the command line, including the design, navigation menus, texts, images, videos, etc. A page or screen a user sees with several UI components is called a document object model (DOM).
![Frontend development AI tools](https://assets.roadmap.sh/guest/frontend-ai-developer-tools-q8xnv.png)
Frontend developers build these visual parts using front end programming languages such as:
- HTML (Hypertext Markup Language)
- CSS
- JavaScript
### HTML (Hypertext Markup Language):
The basic building block of an application. It defines the markup of the language.
### CSS (Cascading Style Sheets)
Builds upon HTML and defines the layout and style of an application.
### JavaScript
The front-end programming language that adds logic to an application. It can be used for both the frontend and backend (NodeJs, ExpressJs, NestJS).
HTML, CSS, and [JavaScript](https://roadmap.sh/javascript) are fundamental tools in a frontend developer’s toolkit and are used to determine the look and functionality of the client side of an application.
In addition to these languages, there are frontend frameworks, libraries, and CSS preprocessors that help to create websites and applications efficiently. Some of the popular ones are [React](https://roadmap.sh/react), [Vue](https://roadmap.sh/vue), [Angular](https://roadmap.sh/angular), and SASS.
## Front end developers responsibilities for AI
The core responsibilities of AI front end developers include:
- Designing and developing dashboards
- Developing graphs and charts for data visualization
- Integrating with AI services
- Testing and validating the integrated AI services
- Optimizing the user experience of AI applications
### Designing and developing dashboards
A dashboard conveys different but related information in an understandable format. Frontend developers are responsible for designing and developing dashboards that convey different AI data and metrics. They use design programs to lay out a dashboard prototype and ensure that the dashboards are implemented according to specifications.
### Developing graphs and charts for data visualization
Data visualization is an important process in AI that presents data in visual formats such as graphs and charts. Frontend AI developers use libraries such as Chart.js, Plotly, and D3.js to create graphs and charts to visualize and interpret data.
### Integrating with AI services
AI front end developers connect frontend applications to AI services via Application Programming Interfaces (APIs) to fetch data and predict or perform certain actions. For example, a weather application’s frontend connects to weather prediction services through API endpoints or other means of communication and displays the information users interact with.
### Testing and validating integrated AI services
After integrating AI services into an application, frontend AI developers also test and validate that these services function properly and provide accurate and efficient data. Testing and validation are important for identifying and resolving technical issues that might come up and for addressing optimization requirements.
### Optimizing the user experience of AI applications
Frontend AI developers focus on improving the user experience of software and other mobile applications by optimizing UI elements and adding features like hovering effects or tooltips, navigation flows, and application interactions. They also iterate on designs and features with UI/UX experts based on user feedback to enhance user satisfaction and produce a responsive web design.
## Frontend developer skills for AI
To be a frontend AI developer, you need a combination of soft and technical skills. Some of the skills you require to be a frontend AI developer include:
- Deep understanding of HTML, CSS, and JavaScript/TypeScript.
- Knowledge of at least one web application framework or library, e.g., React, Vue, and Angular.
- Knowledge of data visualization libraries. e.g., Chart.js, Plotly.
- Basic understanding of machine learning and machine learning models. e.g., linear regression, random forest, etc.
- Collaboration and communication skills.
- Problem-solving skills.
## What is back end development for AI?
Back end development for AI is the design and implementation of the server side of an AI application. As opposed to frontend development, which involves the visual and interactive elements of an application, backend development involves the part of an application a user cannot directly interact with. The next section goes into detail about who a back-end developer is and their role in the software development process and lifecycle.
## Who is a back-end developer?
A [back-end developer](https://roadmap.sh/backend) specializes in the server-side development of an AI application that users cannot see and directly interact with. A back-end developer manages the behind-the-scenes part of an application, such as the servers, databases, and machine learning models that power AI applications.
![backend developer tools](https://assets.roadmap.sh/guest/ai-backend-developer-tools-nozax.png)
AI back end developers use server-side programming languages such as C#, [Java](https://roadmap.sh/java), [Python](https://roadmap.sh/python), and [Rust](https://roadmap.sh/rust) and frameworks such as [Spring Boot](https://roadmap.sh/spring-boot), [ASP.NET core](https://roadmap.sh/aspnet-core), Django, and Ruby on Rails to develop the backend of AI applications.
## Back end developers responsibilities for AI
The responsibilities of AI back end developers include:
- Database design and management
- AI model development
- Application Programming Interface design and development
- Performance optimization
### Database design and management
Data is stored and retrieved from databases. AI deals with a large amount of data, which can be structured or unstructured. Back end developers are responsible for setting up these databases to save AI data. Two common types of databases are:
- [Relational databases](https://roadmap.sh/sql) /Structured Query Language (SQL) e.g., PostgreSQL, Microsoft SQL Server
- NoSQL databases, e.g., [MongoDB](https://roadmap.sh/mongodb).
### AI model development
AI models are computer programs that recognize patterns in data and make predictions. They rely heavily on trained and untrained data, and each model is suitable for different cases. Examples of AI models include:
- Classification models, e.g., random forest, K-nearest neighbor, naive bayes
- Regression models, e.g., linear regression, decision trees
Backend AI developers use tools and frameworks such as Pandas, Numpy, Scikit-Learn, PyTorch, and so on to develop AI these AI models.
### API design and development
A backend AI developer designs and develops APIs that are consumed by the frontend of an AI application or other services. API development involves creating endpoints that provide data that users can visualize and interact with. Backend AI developers use different tools to design and document APIs; a common one is [Swagger](https://swagger.io/).
### Performance optimization
Backend AI developers are constantly optimizing the performance of AI applications. They do this by scaling applications to ensure the backend can handle large volumes of requests. The performance optimization involves code refactoring, optimizing database queries, adding caching, and load balancing.
## Backend developer skills for AI
Some of the job-ready skills needed to excel as a backend AI developer include:
- In-depth knowledge of at least one back-end programming language.
- Knowledge of database systems.
- Basic knowledge of web servers.
- Basic knowledge of how to deploy applications on cloud services or on-premise.
- Knowledge of machine learning models.
- Knowledge of data structures and algorithm
- Knowledge of web application frameworks
- Problem-solving and logical reasoning skills.
- Collaboration and communication skills.
## Which should I go for - frontend vs backend?
As you’ve seen in the frontend vs backend comparison, frontend and backend developers who specialize in AI perform different responsibilities and require various skill sets.
![Frontend vs Backend](https://assets.roadmap.sh/guest/frontend-vs-backend-development-1hox5.png)
If you like user interfaces, keen on sound design, and like the visual aspects of creating apps, then perhaps you would be most interested in becoming a front end software developer. If you are more interested in servers, databases, and how systems work behind the scenes, then you should consider backend development.
You can begin your frontend or backend engineering career by obtaining a bachelor’s degree in computer science degree from a college.
roadmap.sh provides you with step-by-step guidance on how to become a [frontend developer](https://roadmap.sh/frontend) and [backend developer](https://roadmap.sh/backend). You can also explore the [full stack developer roadmap](https://roadmap.sh/full-stack) if you are interested in learning full stack development, which is a combination of frontend and backend development. Signing up on roadmap.sh makes it easy to track your progress and also share it on your profile. You can also draw up your personalized roadmap or work with AI to [generate new roadmaps](https://roadmap.sh/ai).

@ -15,7 +15,7 @@ dimensions:
question:
title: 'What is an AI Engineer?'
description: |
An AI Engineer uses pre-trained models and existing AI tools to improve user experiences. They focus on applying AI in practical ways, without building models from scratch. This is different from AI Researchers and ML Engineers, who focus more on creating new models or developing AI theory. The [advantages and disadvantages of AI](https://towardsdatascience.com/advantages-and-disadvantages-of-artificial-intelligence-182a5ef6588c) are key considerations that AI Engineers must understand to effectively implement solutions.
An AI Engineer uses pre-trained models and existing AI tools to improve user experiences. They focus on applying AI in practical ways, without building models from scratch. This is different from AI Researchers and ML Engineers, who focus more on creating new models or developing AI theory.
schema:
headline: 'AI Engineer Roadmap'
description: 'Learn how to become an AI Engineer with this interactive step by step guide in 2023. We also have resources and short descriptions attached to the roadmap items so you can get everything you want to learn in one place.'

@ -6,3 +6,4 @@ Learn more from the following resources:
- [@official@Ollama](https://ollama.com/)
- [@article@Ollama: Easily run LLMs locally](https://klu.ai/glossary/ollama)
- [@video@What is Ollama? Running Local LLMs Made Simple](https://www.youtube.com/watch?v=5RIOQuHOihY)

@ -5,4 +5,3 @@ Event binding lets you listen for and respond to user actions such as keystrokes
Visit the following resources to learn more:
- [@official@Angular Official Docs - Event Binding](https://angular.dev/guide/templates/event-binding)
- [@article@Event Binding in Angular](https://www.knowledgehut.com/blog/web-development/event-binding-in-angular)

@ -4,10 +4,10 @@ API authentication is the process of verifying the identity of clients attemptin
Visit the following resources to learn more:
- [@roadmap.sh@SSO - Single Sign On](https://roadmap.sh/guides/sso)
- [@roadmap.sh@OAuth - Open Authorization](https://roadmap.sh/guides/oauth)
- [@roadmap.sh@JWT Authentication](https://roadmap.sh/guides/jwt-authentication)
- [@roadmap.sh@Token Based Authentication](https://roadmap.sh/guides/token-authentication)
- [@roadmap.sh@Session Based Authentication](https://roadmap.sh/guides/session-authentication)
- [@roadmap.sh@Basic Authentication](https://roadmap.sh/guides/basic-authentication)
- [@roadmap.sh@Session Based Authentication](https://roadmap.sh/guides/session-authentication)
- [@roadmap.sh@Token Based Authentication](https://roadmap.sh/guides/token-authentication)
- [@roadmap.sh@JWT Authentication](https://roadmap.sh/guides/jwt-authentication)
- [@roadmap.sh@OAuth - Open Authorization](https://roadmap.sh/guides/oauth)
- [@roadmap.sh@SSO - Single Sign On](https://roadmap.sh/guides/sso)
- [@feed@Explore top posts about Authentication](https://app.daily.dev/tags/authentication?ref=roadmapsh)

@ -6,4 +6,5 @@ Visit the following resources to learn more:
- [@article@What is a Crypto Wallet?: A Beginner’s Guide](https://crypto.com/university/crypto-wallets)
- [@article@Crypto Wallet? What is it?](https://www.coinbase.com/learn/crypto-basics/what-is-a-crypto-wallet)
- [@article@Choose your wallet - Ethereum](https://ethereum.org/en/wallets/find-wallet/)
- [@feed@Explore top posts about Crypto](https://app.daily.dev/tags/crypto?ref=roadmapsh)

@ -6,3 +6,4 @@ Visit the following resources to learn more:
- [@article@What is a Cryptocurrency Wallet?](https://www.investopedia.com/terms/b/bitcoin-wallet.asp)
- [@article@What is a Crypto Wallet? A Beginner’s Guide](https://crypto.com/university/crypto-wallets)
- [@article@Choose your wallet - Ethereum](https://ethereum.org/en/wallets/find-wallet/)

@ -6,3 +6,5 @@ Visit the following resources to learn more:
- [@article@Introduction to dApps](https://ethereum.org/en/developers/docs/dapps/)
- [@article@What Is a Dapp? Decentralized Apps Explained](https://www.coindesk.com/learn/what-is-a-dapp-decentralized-apps-explained/)
- [@feed@Explore Top dApps on Ethereum and its Layer 2s](https://www.ethereum-ecosystem.com/apps)
- [@feed@Explore Top Ethereum dApps](https://eth.blockscout.com/apps)

@ -8,5 +8,6 @@ Visit the following resources to learn more:
- [@article@The Modern JavaScript Tutorial](https://javascript.info/)
- [@article@Eloquent Javascript - Book](https://eloquentjavascript.net/)
- [@opensource@You Dont Know JS Yet](https://github.com/getify/You-Dont-Know-JS)
- [@video@JavaScript Crash Course for Beginners](https://youtu.be/hdI2bqOjy3c)- [@video@Node.js Tutorial for Beginners](https://www.youtube.com/watch?v=TlB_eWDSMt4)
- [@video@JavaScript Crash Course for Beginners](https://youtu.be/hdI2bqOjy3c)
- [@video@Node.js Tutorial for Beginners](https://www.youtube.com/watch?v=TlB_eWDSMt4)
- [@feed@Explore top posts about JavaScript](https://app.daily.dev/tags/javascript?ref=roadmapsh)

@ -6,5 +6,5 @@ Visit the following resources to learn more:
- [@opensource@DAPP Security Standards](https://github.com/Dexaran/DAPP-security-standards/blob/master/README.md)
- [@article@dApp Security Considerations](https://livebook.manning.com/book/building-ethereum-dapps/chapter-14/)
- [@article@dApp Security:All You Need to Know](https://www.immunebytes.com/blog/dapp-security/#Benefits_of_DApps_Security)
- [@article@dApp Security: All You Need to Know](https://www.immunebytes.com/blog/dapp-security/#Benefits_of_DApps_Security)
- [@feed@Explore top posts about Security](https://app.daily.dev/tags/security?ref=roadmapsh)

@ -6,5 +6,6 @@ Visit the following resources to learn more:
- [@article@Smart Contracts](https://www.ibm.com/topics/smart-contracts)
- [@article@What Are Smart Contracts and How Do They Work?](https://chain.link/education/smart-contracts)
- [@article@Introduction to smart contracts - Ethereum](https://ethereum.org/en/smart-contracts/)
- [@video@Smart Contracts - Simply Explained](https://youtu.be/ZE2HxTmxfrI)
- [@feed@Explore top posts about Smart Contracts](https://app.daily.dev/tags/smart-contracts?ref=roadmapsh)

@ -5,5 +5,6 @@ Zero-knowledge rollups (ZK-rollups) are layer 2 scaling solutions that increase
Visit the following resources to learn more:
- [@article@Zero-Knowledge Rollups - Ethereum](https://ethereum.org/en/developers/docs/scaling/zk-rollups)
- [@article@What are Zero-Knowledge proofs? - Ethereum](https://ethereum.org/en/zero-knowledge-proofs/)
- [@article@Why and How zk-SNARK Works](https://medium.com/@imolfar/why-and-how-zk-snark-works-1-introduction-the-medium-of-a-proof-d946e931160)
- [@article@Introduction to zk-SNARKs](https://vitalik.eth.limo/general/2021/01/26/snarks.html)

@ -1,6 +1,6 @@
# OSI and TCP/IP Models
The OSI and TCP/IP model is used to help the developer to design their system for interoperability. The OSI model has 7 layers while the TCP/IP model has a more summarized form of the OSI model only consisting 4 layers. This is important if you're are trying to design a system to communicate with other systems.
The OSI and TCP/IP model is used to help the developer to design their system for interoperability. The OSI model has 7 layers while the TCP/IP model has a more summarized form of the OSI model only consisting 4 layers. This is important if you're trying to design a system to communicate with other systems.
Visit the following resources to learn more:

@ -1,6 +1,6 @@
# OSI and TCP/IP Models
The OSI and TCP/IP model is used to help the developer to design their system for interoperability. The OSI model has 7 layers while the TCP/IP model has a more summarized form of the OSI model only consisting 4 layers. This is important if you're are trying to design a system to communicate with other systems.
The OSI and TCP/IP model is used to help the developer to design their system for interoperability. The OSI model has 7 layers while the TCP/IP model has a more summarized form of the OSI model only consisting 4 layers. This is important if you're trying to design a system to communicate with other systems.
Visit the following resources to learn more:

@ -0,0 +1,22 @@
# unique_ptr
One of C++'s main features includes variants of the normal *raw* C pointers. One of these is the `unique_ptr`, which is a type of smart pointer that claims exclusive ownership over a value.
These types of pointers **can be moved** (`std::move`), but not **copied** and are automatically deleted when out of scope. The recommended way to create a `unique_ptr` is using `std::make_unique`.
```cpp
#include <memory>
#include <iostream>
int main() {
std::unique_ptr<int> uptr = std::make_unique<int>(10);
std::cout << *uptr << std::endl;
std::unique_ptr<int> uptr2 = uptr; // compile error
std::unique_ptr<int> uptr2 = std::move(uptr); // transferring ownership
}
```
- [@official@std::unique_ptr - Detailed Reference](https://en.cppreference.com/w/cpp/memory/unique_ptr)
- [@article@Smart Pointers – unique_ptr](https://www.learncpp.com/cpp-tutorial/unique-ptr/)
- [@video@When should you use std::unique_ptr? - StackOverflow Discussion](https://stackoverflow.com/questions/13782051/when-should-you-use-stdunique-ptr)

@ -4,5 +4,6 @@ CompTIA Security+ is a highly recognized and respected certification for individ
Learn more from the following resources:
- [@course@CompTIA SY0-701 Security+ Exam Course Playlist](https://www.youtube.com/playlist?list=PLG49S3nxzAnl4QDVqK-hOnoqcSKEIDDuv)
- [@official@CompTIA Security+ Website](https://www.comptia.org/certifications/security)
- [@course@CompTIA Security+ Course](https://www.youtube.com/watch?v=yLf2jRY39Rc&list=PLIhvC56v63IIyU0aBUed4qwP0nSCORAdB)
- [@course@CompTIA Security+ Course](https://www.youtube.com/watch?v=yLf2jRY39Rc&list=PLIhvC56v63IIyU0aBUed4qwP0nSCORAdB)

@ -1,3 +1,7 @@
# OOP Basics
Object-oriented programming (OOP) is a programming paradigm that uses "objects" to design applications and software. In OOP, each object is an instance of a class. A class defines the properties (often known as attributes or fields) and methods (actions) that are common to all objects of a certain kind. A key principle of OOP is the ability to hide certain parts of the objects’ data from the outside, a concept known as encapsulation. Other key principles are inheritance, a way to form new classes using classes that have already been defined, and polymorphism, the concept of designing objects to share behaviors and being able to override shared behaviors with specifics.
Object-oriented programming (OOP) is a programming paradigm that uses "objects" to design applications and software. In OOP, each object is an instance of a class. A class defines the properties (often known as attributes or fields) and methods (actions) that are common to all objects of a certain kind. A key principle of OOP is the ability to hide certain parts of the objects’ data from the outside, a concept known as encapsulation. Other key principles are inheritance, a way to form new classes using classes that have already been defined, and polymorphism, the concept of designing objects to share behaviors and being able to override shared behaviors with specifics.
Visit the following resources to learn more:
- [@video@Object-Oriented Programming (Simplified)](https://youtu.be/pTB0EiLXUC8?si=I8rV2K5fhpoqmixX)

@ -4,4 +4,8 @@ Emotional intelligence is crucial for an Engineering Manager. It helps them unde
Engineering Managers often face challenges in dealing with various personalities within a team. By applying emotional intelligence, they can navigate these difficulties, resolve conflicts, and maintain a positive working environment. Their challenge is to balance their own emotions while addressing those of their team.
Success in this aspect requires strong listening skills, empathy, and patience. Engineering Managers also need to continuously improve their emotional intelligence through self-reflection and seeking feedback. This helps them foster a team environment where everyone is understood and valued.
Success in this aspect requires strong listening skills, empathy, and patience. Engineering Managers also need to continuously improve their emotional intelligence through self-reflection and seeking feedback. This helps them foster a team environment where everyone is understood and valued.
Visit the following resources to learn more:
- [@video@Daniel Goleman on the different kinds of empathy](https://www.youtube.com/watch?v=WdDVvLEKoc8)

@ -1,10 +1,10 @@
# How Does The Internet Work
The Internet works through a global network of interconnected computers and servers, communicating via standardized protocols. Data is broken into packets and routed through various network nodes using the Internet Protocol (IP). These packets travel across different physical infrastructures, including fiber optic cables, satellites, and wireless networks. The Transmission Control Protocol (TCP) ensures reliable delivery and reassembly of packets at their destination. Domain Name System (DNS) servers translate human-readable website names into IP addresses. When you access a website, your device sends a request to the appropriate server, which responds with the requested data. This process, facilitated by routers, switches, and other networking equipment, enables the seamless exchange of information across vast distances, forming the backbone of our digital communications.
The internet is a global network that connects computers and devices so they can share information with each other. It’s how you browse websites, send emails, watch videos, and use apps. Think of it like a giant web that links everything together.
Visit the following resources to learn more:
- [@roadmap@Introduction to Internet](https://roadmap.sh/guides/what-is-internet)
- [@article@Introduction to Internet](https://roadmap.sh/guides/what-is-internet)
- [@article@How does the Internet Work?](https://cs.fyi/guide/how-does-internet-work)
- [@article@How Does the Internet Work? MDN Docs](https://developer.mozilla.org/en-US/docs/Learn/Common_questions/How_does_the_Internet_work)
- [@video@How the Internet Works in 5 Minutes](https://www.youtube.com/watch?v=7_LPdttKXPc)

@ -4,5 +4,5 @@ The Internet is a global network of interconnected computer networks that use th
Visit the following resources to learn more:
- [@roadmap@Introduction to Internet](https://roadmap.sh/guides/what-is-internet)
- [@article@Introduction to Internet](https://roadmap.sh/guides/what-is-internet)
- [@article@The Internet](https://en.wikipedia.org/wiki/Internet)

@ -6,4 +6,4 @@ A mutation typically includes fields that specify the data to be changed and the
Learn more from the following resources:
- [@official@Get started with Mutations](https://graphql.org/learn/queries/#mutations)
- [@official@Get started with Mutations](https://graphql.org/learn/mutations/)

@ -5,4 +5,4 @@ Classes are blueprints for creating objects, which are instances of those classe
Visit the following resources to learn more:
- [@article@Java Class and Objects](https://www.programiz.com/java-programming/class-objects)
- [@article@Java Classes and Objects](https://www.youtube.com/watch?v=IUqKuGNasdM)
- [@video@Java Classes and Objects](https://www.youtube.com/watch?v=IUqKuGNasdM)

@ -7,11 +7,11 @@ Linux distributions use various package managers. Some of the commonly used are
For instance, to install a package in a Debian-based distribution, you would use the following command in apt:
```bash
sudo apt-get install <package-name>
sudo apt install <package-name>
```
Such vital features have made package management systems an integral part of Linux distributions, allowing users to handle applications efficiently.
Learn more from the following resources:
- [@article@Software Installation on Linux](https://labex.io/tutorials/linux-software-installation-on-linux-18005)
- [@article@Software Installation on Linux](https://labex.io/tutorials/linux-software-installation-on-linux-18005)

@ -18,4 +18,4 @@ if(isset($_POST['csrf']) && $_POST['csrf'] === $_SESSION['csrf']) {
Visit the following resources to learn more:
- [@article@PHP Tutorial CSRF] (https://www.phptutorial.net/php-tutorial/php-csrf/)
- [@article@PHP Tutorial CSRF](https://www.phptutorial.net/php-tutorial/php-csrf/)

@ -25,4 +25,4 @@ In the above example, the 'Car' class inherits the drive method from the 'Vehicl
Visit the following resources to learn more:
- [@official@Inheritance](https://www.php.net/manual/en/keyword.extends.php)
- [@official@Inheritance](https://www.php.net/manual/en/language.oop5.inheritance.php)

@ -35,4 +35,4 @@ This creates a scalable way to add more shapes, as you only need to follow the '
Visit the following resources to learn more:
- [@official@Polymorphism](https://www.php.net/manual/en/language.oop5.polymorphism.php)
- [@opensource@Polymorphism](https://www.phptutorial.net/php-oop/php-polymorphism/)

@ -2,6 +2,5 @@
Here is the list of most common CLI tools for React development:
- [@article@create-react-app](https://create-react-app.dev)
- [@article@vite](https://vitejs.dev)
- [@feed@Explore top posts about CLI](https://app.daily.dev/tags/cli?ref=roadmapsh)

@ -6,3 +6,4 @@ Visit the following resources to learn more:
- [@video@What is Rust?](https://www.youtube.com/watch?v=R33h77nrMqc)
- [@feed@Explore top posts about Rust](https://app.daily.dev/tags/rust?ref=roadmapsh)
- [@official@Rust by example](https://doc.rust-lang.org/stable/rust-by-example/index.html)

@ -1,6 +1,6 @@
# OSI and TCP/IP Models
The OSI and TCP/IP model is used to help the developer to design their system for interoperability. The OSI model has 7 layers while the TCP/IP model has a more summarized form of the OSI model only consisting 4 layers. This is important if you're are trying to design a system to communicate with other systems.
The OSI and TCP/IP model is used to help the developer to design their system for interoperability. The OSI model has 7 layers while the TCP/IP model has a more summarized form of the OSI model only consisting 4 layers. This is important if you're trying to design a system to communicate with other systems.
Visit the following resources to learn more:

@ -14,4 +14,4 @@ anyValue = true;
Learn more from the following links:
- [@official@Arrays](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#any)
- [@official@any](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#any)

@ -1,6 +1,6 @@
# API Styles
Up until Vue 2, there was one way to create components in Vue. With Vue 3, a new methodology was introduced called the Composition API. Now, if we want to make a component in Vue, we have two ways to do it. You might be wondering what the difference is, exactly, so let’s take a look at how the newer Composition API differs from the Vue 2 methodology, which is now known as the Options API
Though Vue 2 supported many approaches to writing components, only one approach, the "Options API", was built in and accessible without plugins. Vue 3, retains the Options API (OAPI), and adds in the Composition API (CAPI). Composition API itself is actually a part of the Options API, but moves most of the component logic into a setup function. This led to a 3rd approach to writing components being built in called "script/setup", which removes much of the boilerplate from Composition API. These approaches are not mutually exclusive. Each component in your project can use any of these approaches, however for consistency it is recommended to stick primarily to one, and only deviate to one of the others when you have a good reason.
Visit the following resources to learn more:

@ -1,6 +1,6 @@
# Composition API
With the release of Vue 3, developers now have access to the Composition API, a new way to write Vue components. This API allows features to be grouped together logically, rather than having to organize your single-file components by function. Using the Composition API can lead to more readable code, and gives the developer more flexibility when developing their applications.
Vue offers many approaches for how to write components, including the "Composition API", which is most commonly used via "Script Setup". This approach is based around pulling in low level atomic functions used by Vue's reactivity engine. By composing these low level functions together, you can craft your own system for writing components. One feature this allows for is extending reactivity outside of components. This means you can extract your custom functions for reuse in multiple components. When reusing reactive logic, your functions are called "composables".
Visit the following resources to learn more:

@ -1,6 +1,6 @@
# Options API
We use Options API in a Vue application to write and define different components. With this API, we can use options such as data, methods, and mounted. To state it simply, Options API is an old way to structure a Vue.JS application. Due to some limitations in this API, Composition API was introduced in Vue 3.
Vue offers many approaches for how to write components, including the Options API. It is the only API that is available in all versions of Vue. Its primary focus is on providing a consistent, clean, and organized aproach to writing component logic. Each part of a component's logic is given a dedicated section (data, methods, computed, props, life-cycle hooks, etc). By putting the logic in the correct section it has access to the features of the framework automatically. With the official Vue ESLint plugin the order of these sections can be enforced across all components allowing developers to predicatably locate any part of the component, even if they've never looked at the file before.
Visit the following resources to learn more:

@ -19,7 +19,9 @@ type GenerateCourseOptions = {
onCourseSlugChange?: (courseSlug: string) => void;
onCourseChange?: (course: AiCourse, rawData: string) => void;
onLoadingChange?: (isLoading: boolean) => void;
onCreatorIdChange?: (creatorId: string) => void;
onError?: (error: string) => void;
src?: string;
};
export async function generateCourse(options: GenerateCourseOptions) {
@ -32,11 +34,13 @@ export async function generateCourse(options: GenerateCourseOptions) {
onCourseChange,
onLoadingChange,
onError,
onCreatorIdChange,
isForce = false,
prompt,
instructions,
goal,
about,
src = 'search',
} = options;
onLoadingChange?.(true);
@ -85,6 +89,7 @@ export async function generateCourse(options: GenerateCourseOptions) {
instructions,
goal,
about,
src,
}),
credentials: 'include',
},
@ -113,14 +118,17 @@ export async function generateCourse(options: GenerateCourseOptions) {
const COURSE_ID_REGEX = new RegExp('@COURSEID:(\\w+)@');
const COURSE_SLUG_REGEX = new RegExp(/@COURSESLUG:([\w-]+)@/);
const CREATOR_ID_REGEX = new RegExp('@CREATORID:(\\w+)@');
await readStream(reader, {
onStream: (result) => {
if (result.includes('@COURSEID') || result.includes('@COURSESLUG')) {
const courseIdMatch = result.match(COURSE_ID_REGEX);
const courseSlugMatch = result.match(COURSE_SLUG_REGEX);
const creatorIdMatch = result.match(CREATOR_ID_REGEX);
const extractedCourseId = courseIdMatch?.[1] || '';
const extractedCourseSlug = courseSlugMatch?.[1] || '';
const extractedCreatorId = creatorIdMatch?.[1] || '';
if (extractedCourseSlug) {
window.history.replaceState(
@ -137,10 +145,12 @@ export async function generateCourse(options: GenerateCourseOptions) {
result = result
.replace(COURSE_ID_REGEX, '')
.replace(COURSE_SLUG_REGEX, '');
.replace(COURSE_SLUG_REGEX, '')
.replace(CREATOR_ID_REGEX, '');
onCourseIdChange?.(extractedCourseId);
onCourseSlugChange?.(extractedCourseSlug);
onCreatorIdChange?.(extractedCreatorId);
}
try {
@ -159,7 +169,9 @@ export async function generateCourse(options: GenerateCourseOptions) {
onStreamEnd: (result) => {
result = result
.replace(COURSE_ID_REGEX, '')
.replace(COURSE_SLUG_REGEX, '');
.replace(COURSE_SLUG_REGEX, '')
.replace(CREATOR_ID_REGEX, '');
onLoadingChange?.(false);
queryClient.invalidateQueries(getAiCourseLimitOptions());
},

@ -7,14 +7,14 @@ export function useKeydown(keyName: string, callback: any, deps: any[] = []) {
!keyName.startsWith('mod_') &&
event.key.toLowerCase() === keyName.toLowerCase()
) {
callback();
callback(event);
} else if (
keyName.startsWith('mod_') &&
event.metaKey &&
event.key.toLowerCase() === keyName.replace('mod_', '').toLowerCase()
) {
event.preventDefault();
callback();
callback(event);
}
};

@ -0,0 +1 @@
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" id="Bluesky--Streamline-Simple-Icons" height="24" width="24"><desc>Bluesky Streamline Icon: https://streamlinehq.com</desc><title>Bluesky</title><path d="M12 10.8c-1.087 -2.114 -4.046 -6.053 -6.798 -7.995C2.566 0.944 1.561 1.266 0.902 1.565 0.139 1.908 0 3.08 0 3.768c0 0.69 0.378 5.65 0.624 6.479 0.815 2.736 3.713 3.66 6.383 3.364 0.136 -0.02 0.275 -0.039 0.415 -0.056 -0.138 0.022 -0.276 0.04 -0.415 0.056 -3.912 0.58 -7.387 2.005 -2.83 7.078 5.013 5.19 6.87 -1.113 7.823 -4.308 0.953 3.195 2.05 9.271 7.733 4.308 4.267 -4.308 1.172 -6.498 -2.74 -7.078a8.741 8.741 0 0 1 -0.415 -0.056c0.14 0.017 0.279 0.036 0.415 0.056 2.67 0.297 5.568 -0.628 6.383 -3.364 0.246 -0.828 0.624 -5.79 0.624 -6.478 0 -0.69 -0.139 -1.861 -0.902 -2.206 -0.659 -0.298 -1.664 -0.62 -4.3 1.24C16.046 4.748 13.087 8.687 12 10.8Z" fill="currentColor" stroke-width="1"></path></svg>

After

Width:  |  Height:  |  Size: 928 B

@ -177,7 +177,7 @@ const gaPageIdentifier = Astro.url.pathname
jsonLd.length > 0 && (
<script
type='application/ld+json'
set:html={JSON.stringify(jsonLd.length === 1 ? jsonLd[0] : jsonLd)}
set:html={JSON.stringify(jsonLd)}
/>
)
}

@ -12,16 +12,19 @@ export const siteConfig = {
},
keywords: [
'roadmap',
'roadmap.sh',
'developer roadmaps',
'developer roadmap',
'how to become a developer',
...[
'frontend developer',
'backend developer',
'full stack developer',
'sre',
'devops',
'devops engineer',
'android developer',
'dba',
'database administrator',
'blockchain developer',
'qa',
'qa engineer',
@ -38,9 +41,24 @@ export const siteConfig = {
'design system',
'software design',
'graphql',
'ux design',
'terraform developer',
'sql developer',
'spring boot developer',
'php developer',
'ios developer',
'game developer',
'flutter developer',
'data analyst',
'aws developer',
'cyber security specialist',
'ai developer',
'ai engineer',
'ai data scientist'
].flatMap((roadmapKeyword) => [
`${roadmapKeyword} roadmap`,
`${roadmapKeyword} roadmap 2023`,
`${roadmapKeyword} roadmap 2024`,
`${roadmapKeyword} roadmap 2025`,
]),
],
};

@ -18,6 +18,7 @@ import RoadmapNote from '../../components/RoadmapNote.astro';
import { RoadmapTitleQuestion } from '../../components/RoadmapTitleQuestion';
import ResourceProgressStats from '../../components/ResourceProgressStats.astro';
import { getProjectsByRoadmapId } from '../../lib/project';
import { CheckSubscriptionVerification } from '../../components/Billing/CheckSubscriptionVerification';
export const prerender = true;
@ -101,6 +102,7 @@ const courses = roadmapData.courses || [];
resourceTitle={roadmapData.title}
resourceId={roadmapId}
resourceType='roadmap'
renderer={roadmapData.renderer}
client:idle
canSubmitContribution={true}
/>
@ -183,5 +185,6 @@ const courses = roadmapData.courses || [];
<RelatedRoadmaps roadmap={roadmapData} />
</div>
<CheckSubscriptionVerification client:load />
<div slot='changelog-banner'></div>
</BaseLayout>

@ -14,6 +14,7 @@ import {
type BestPracticeFrontmatter,
getAllBestPractices,
} from '../../../lib/best-practice';
import { CheckSubscriptionVerification } from '../../../components/Billing/CheckSubscriptionVerification';
export const prerender = true;
@ -107,6 +108,7 @@ const ogImageUrl = getOpenGraphImageUrl({
resourceId={bestPracticeId}
resourceTitle={bestPracticeData.title}
resourceType='best-practice'
renderer={'balsamiq'}
client:idle
canSubmitContribution={true}
/>
@ -136,6 +138,6 @@ const ogImageUrl = getOpenGraphImageUrl({
/>
{bestPracticeData.isUpcoming && <UpcomingForm />}
<CheckSubscriptionVerification client:load />
<div slot='changelog-banner'></div>
</BaseLayout>

@ -16,6 +16,95 @@ import SkeletonLayout from '../../layouts/SkeletonLayout.astro';
'database administration',
]}
canonicalUrl='/courses/sql'
jsonLd={[
{
"@context": "https://schema.org",
"@type": "Course",
"@id": "https://roadmap.sh/courses/sql",
"name": "Master SQL",
"description": "A comprehensive SQL course designed to take you from beginner to advanced levels, featuring 55+ lessons, 100+ challenges, an integrated IDE, and an AI tutor. Ideal for developers, data analysts, and anyone working with data.",
"provider": {
"@type": "Organization",
"name": "roadmap.sh",
"url": "https://roadmap.sh"
},
"publisher": {
"@type": "Organization",
"name": "roadmap.sh",
"url": "https://roadmap.sh"
},
"timeRequired": "PT60H",
"isAccessibleForFree": false,
"offers": {
"@type": "Offer",
"url": "https://roadmap.sh/courses/sql",
"price": "59.99",
"priceCurrency": "USD",
"availability": "https://schema.org/InStock",
"category": "paid"
},
"image": [
"https://assets.roadmap.sh/guest/sql-course-bjc53.png"
],
"coursePrerequisites": [],
"teaches": [
"SQL syntax and queries",
"Data filtering and sorting",
"Joins and subqueries",
"Aggregate functions",
"Stored procedures",
"Views and indexes",
"Transactions and ACID properties",
"Query optimization techniques"
],
"educationalLevel": "Beginner to Advanced",
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "4.8",
"ratingCount": 500
},
"inLanguage": "en",
"review": [
{
"@type": "Review",
"reviewBody": "This course was absolutely brilliant! The integrated database environment to practice what I learned was the best part.",
"author": {
"@type": "Person",
"name": "Gourav Khunger"
}
},
{
"@type": "Review",
"reviewBody": "Kamran has clearly put a lot of thought into this course. The content, structure and exercises were all great.",
"author": {
"@type": "Person",
"name": "Meabed"
}
},
{
"@type": "Review",
"reviewBody": "I already knew SQL but this course taught me a bunch of new things. Practical examples and challenges were great. Highly recommended!",
"author": {
"@type": "Person",
"name": "Mohsin Aheer"
}
}
],
"educationalCredentialAwarded": {
"@type": "EducationalOccupationalCredential",
"name": "Certificate of Completion",
"credentialCategory": "Certificate",
"url": "https://roadmap.sh/courses/sql"
},
"hasCourseInstance": [
{
"@type": "CourseInstance",
"courseMode": "Online",
"courseWorkload": "PT60H",
}
]
}
]}
>
<SQLCoursePage client:load />
</SkeletonLayout>

@ -1,30 +0,0 @@
---
import GuideContent from '../../components/Guide/GuideContent.astro';
import BaseLayout from '../../layouts/BaseLayout.astro';
import { getGuideById } from '../../lib/guide';
import { getOpenGraphImageUrl } from '../../lib/open-graph';
import { replaceVariables } from '../../lib/markdown';
const guideId = 'frontend-vs-backend-ai';
const guide = await getGuideById(guideId);
const { frontmatter: guideData } = guide!;
const ogImageUrl =
guideData.seo.ogImageUrl ||
getOpenGraphImageUrl({
group: 'guide',
resourceId: guideId,
});
---
<BaseLayout
title={guideData.seo.title}
description={guideData.seo.description}
permalink={guideData.excludedBySlug}
canonicalUrl={guideData.canonicalUrl}
ogImageUrl={ogImageUrl}
>
<GuideContent guide={guide!} />
<div slot="changelog-banner" />
</BaseLayout>

@ -0,0 +1,26 @@
import { queryOptions } from '@tanstack/react-query';
import { httpGet } from '../lib/query-http';
export interface RoadmapTreeDocument {
_id?: string;
roadmapId: string;
mapping: {
_id?: string;
nodeId: string;
text: string;
subjects: string[];
}[];
createdAt: Date;
updatedAt: Date;
}
export function roadmapTreeMappingOptions(roadmapId: string) {
return queryOptions({
queryKey: ['roadmap-tree-mapping', { roadmapId }],
queryFn: () => {
return httpGet<RoadmapTreeDocument['mapping']>(
`${import.meta.env.PUBLIC_API_URL}/v1-roadmap-tree-mapping/${roadmapId}`,
);
},
});
}
Loading…
Cancel
Save