<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>c0smos.dev</title><description>Blog posts, CTF writeups, and thoughts</description><link>https://c0smos.dev/</link><language>en-us</language><item><title>UoftCTF Writeup</title><link>https://c0smos.dev/writeups/uotfctf-2026/</link><guid isPermaLink="true">https://c0smos.dev/writeups/uotfctf-2026/</guid><description>Something random</description><pubDate>Sat, 31 Jan 2026 04:06:59 GMT</pubDate><content:encoded>&lt;p&gt;This is a simple challenge, but I&apos;ll talk a bit about angr and symbolic execution for newbies.&lt;/p&gt;&lt;h2&gt;Initial Look&lt;/h2&gt;&lt;p&gt;For the challenge handout we&apos;ve been given a simple flag checker binary named checker. When simply running it and testing it, its asks for user input and rejects/accepts it, pretty standard and nothing fancy so far. Running file on this reveals that it&apos;s a statically compiled binary but the section header is missing which is not a good sign.&lt;/p&gt;&lt;p&gt;After this I decided to open this in IDA to have a better look at what it&apos;s doing, but when I opened it in IDA I noticed something very strange. The binary only has 5-6 functions:&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/511x166/612f9f91fc/funcs.png&quot; /&gt;and there is a big blog of bytes possibly our code which has been laid out as bytes, but if we simply try to convert these bytes into code using IDA it gives us obscure instructions, so we&apos;re probably missing something.&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/806x341/ec196baff4/code_blob.png&quot; /&gt;But if we look at the Strings in this binary it gives away why this binary looks so weird. Looking at this string: &lt;code&gt;$Info: This file is packed with the UPX executable packer&lt;/code&gt; we know that the binary is packed with upx and this is why IDA only shows us a tiny stub while the rest of the actual code is compressed and unpacked at runtime.&lt;/p&gt;&lt;p&gt;Now we can simply unpack the file using upx and take a look at the actual file using: &lt;code&gt;upx -d checker&lt;/code&gt;&lt;/p&gt;&lt;h2&gt;Looking at the actual file&lt;/h2&gt;&lt;p&gt;Opening the actual binary in IDA,  we can see a whopping 4231 functions!&lt;/p&gt;&lt;p&gt;If we take a look at the decomp of the main function:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;int __fastcall main(int argc, const char **argv, const char **envp)
{
  unsigned __int64 i; // [rsp+0h] [rbp-80h]
  char v5[48]; // [rsp+10h] [rbp-70h] BYREF
  char s[56]; // [rsp+40h] [rbp-40h] BYREF
  unsigned __int64 v7; // [rsp+78h] [rbp-8h]

  v7 = __readfsqword(0x28u);
  if ( fgets(s, 46, _bss_start) &amp;amp;&amp;amp; strcspn(s, &quot;\r\n&quot;) == 42 )
  {
    for ( i = 0LL; i &amp;lt;= 41; ++i )
      v5[i] = s[i];
    f_0(v5);
    return 0;
  }
  else
  {
    puts(&quot;No&quot;);
    return 0;
  }
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We see that it takes our input and rejects it if the length is not 42. It then copies it into a buffer and passes it to &lt;code&gt;f_0&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;Now looking at function &lt;code&gt;f_0&lt;/code&gt;, it modifies the buffer and then passes it to function &lt;code&gt;f_1&lt;/code&gt; and so on until function &lt;code&gt;f_4200&lt;/code&gt;. Function &lt;code&gt;f_4200&lt;/code&gt; compares the modified input buffer to pre-existing bytes and if it matches then we&apos;re good.&lt;/p&gt;&lt;p&gt;But the problem at hand is that there are 4200 functions and it&apos;s really hard to look at each one manually let alone reverse them. So let&apos;s try to find a pattern within these functions.&lt;/p&gt;&lt;p&gt;If we take a look at some of these function we can see that all these functions perform byte assignment at some index of the input buffer. There are two important things to note here:&lt;/p&gt;&lt;p&gt;- The byte assignments are independent of each other meaning each function only modifies a single byte in the input buffer.&lt;/p&gt;&lt;p&gt;- These are very trivial operations so should be fairly easy to reverse.&lt;/p&gt;&lt;p&gt;So in theory, we can build a reverse map for each function and call it on the expected bytes to get to the actual flag. But doing that for 4200 is literal insanity.&lt;/p&gt;&lt;h2&gt;Enter: Symbolic Execution&lt;/h2&gt;&lt;p&gt;Since finding the correct input which gets us the flag is very hard with normal execution we should give symbolic execution a try. If you&apos;re new to the concept of symbolic execution I&apos;ll try my best to give you a fair gist of it.&lt;/p&gt;&lt;p&gt;Symbolic Execution is a great way to understand program execution and program behavior under different inputs, conversely it also helps us find that input given an execution path. In symbolic execution we don&apos;t work with fixed variable values, instead we define symbolic variables which do not have a defined value but rather accumulate constraints throughout the process execution. And at the end present it in the form of an equation which can be solved to get the desired value.&lt;/p&gt;&lt;p&gt;This way symbolic execution let&apos;s us explore multiple paths that a binary can take and then let&apos;s us choose which path are we interested in and how do we get there. &lt;/p&gt;&lt;h2&gt;Time to get angr-y&lt;/h2&gt;&lt;p&gt;angr is an excellent framework for symbolic execution on binaries and we&apos;ll use that to solve this problem.&lt;/p&gt;&lt;p&gt;First we&apos;ll load the binary in angr and create an angr project and define our flag length which we know is 42 bytes long (43 with a newline). &lt;/p&gt;&lt;pre&gt;&lt;code&gt;BIN_PATH = &quot;./checker&quot;
FLAG_LEN = 42            # maybe 43 if newline is included; adjust if needed

proj = angr.Project(BIN_PATH, auto_load_libs=False)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Next we&apos;ll create symbolic variables for each character of our flag string, for this we&apos;ll use claripy which is angr&apos;s abstraction layer on top of z3. For each character of the flag we&apos;ll create a symbolic variable using &lt;code&gt;claripy.BVS(name, size_in_bits)&lt;/code&gt;. We can name each character of the flag based on it&apos;s index for simplicity and since each character in C takes 1 byte, we&apos;ll define these symbolic vars. as 8 bits long.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;flag_chars = [claripy.BVS(f&apos;flag_{i}&apos;, 8) for i in range(FLAG_LEN)]
flag = claripy.Concat(*flag_chars)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now we&apos;ll create a state for our program in angr, a state let&apos;s us access the program&apos;s memory, registers and every object during the emulation of the program. If you&apos;re curious you might dump a register value in a particular state and find a symbolic variable instead of a concrete value inside it like this: &lt;code&gt;&amp;lt;BV64 reg_48_11_64{UNINITIALIZED}&amp;gt;&lt;/code&gt;. We&apos;ll choose the state as the entrypoint of the program with &lt;code&gt;.entry_state()&lt;/code&gt; and provide our flag (symbolic variable) as the input. &lt;/p&gt;&lt;pre&gt;&lt;code&gt;state = proj.factory.entry_state(stdin=flag)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Next we can define some custom constraints on the input flag other than the ones that the binary imposes, and that is to constrain every flag char. variable to be in the ASCII printable range, we can actually further modify them based on the regex of the flag format but this is more generalized. This step isn&apos;t necessary but is good practice to include and will tighten our constraints.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;for c in flag_chars:
    state.solver.add(c &amp;gt;= 0x20, c &amp;lt;= 0x7e)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Next and very important step is to declare a simulation manager, since symbolic execution goes over multiples states, we need a Simulation Manager to manage all these states so that we can explore and find the path that leads us to the success state. Speaking of which we also need to define a success state and optionally a fail state.&lt;/p&gt;&lt;p&gt;In function &lt;code&gt;f_4200&lt;/code&gt; we accept/reject the block based on a simple compare operation, which makes the binary take one of two paths (correct/incorrect flag). We can use the address of these blocks of code as our success/failure states. Since PIE is enabled we need to make sure add the base address of the binary along with the offset we get from IDA and then we simply tell the simulation manager to find a path which gets us to the success state and avoid all paths which get us to the failed state.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;BASE = proj.loader.main_object.mapped_base
print(&quot;BASE =&quot;, hex(BASE))

ADDR_YES = BASE + 0x40E6F
ADDR_NO  = BASE + 0x40E80

simgr.explore(find=ADDR_YES, avoid=ADDR_NO)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;At last if any such paths are found then we use the solver to print the input that was used to reach that path:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;if simgr.found:
    found = simgr.found[0]
    solve = found.solver.eval(flag, cast_to=bytes)
    print(&quot;FLAG:&quot;, solve)
else:
    print(&quot;No solution found&quot;)&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;Final solve script&lt;/h2&gt;&lt;pre&gt;&lt;code&gt;import angr
import claripy

BIN_PATH = &quot;./checker&quot;
FLAG_LEN = 42            # maybe 43 if newline is included; adjust if needed

proj = angr.Project(BIN_PATH, auto_load_libs=False)

BASE = proj.loader.main_object.mapped_base
print(&quot;BASE =&quot;, hex(BASE))

ADDR_YES = BASE + 0x40E6F
ADDR_NO  = BASE + 0x40E80

print(&quot;ADDR_YES =&quot;, hex(ADDR_YES))
print(&quot;ADDR_NO  =&quot;, hex(ADDR_NO))

# Create 42 symbolic bytes
flag_chars = [claripy.BVS(f&apos;flag_{i}&apos;, 8) for i in range(FLAG_LEN)]
flag = claripy.Concat(*flag_chars)

# Supply symbolic input on stdin
state = proj.factory.entry_state(stdin=flag)

# Constrain to printable bytes (typical CTF flags)
for c in flag_chars:
    state.solver.add(c &amp;gt;= 0x20, c &amp;lt;= 0x7e)

simgr = proj.factory.simulation_manager(state)

# Explore until we hit the &apos;Yes&apos; block, avoiding &apos;No&apos;
simgr.explore(find=ADDR_YES, avoid=ADDR_NO)

if simgr.found:
    found = simgr.found[0]
    solve = found.solver.eval(flag, cast_to=bytes)
    print(&quot;FLAG:&quot;, solve)
else:
    print(&quot;No solution found&quot;)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;/p&gt;</content:encoded></item><item><title>CorCTF 2025</title><link>https://c0smos.dev/writeups/corctf-2025/</link><guid isPermaLink="true">https://c0smos.dev/writeups/corctf-2025/</guid><description>Rev writeups for CorCTF 2025 as part of Team Shellphish </description><pubDate>Sun, 21 Sep 2025 02:28:07 GMT</pubDate><content:encoded>&lt;h1&gt;Challenge #1: yourock&lt;/h1&gt;&lt;h3&gt;Category: rev&lt;/h3&gt;&lt;h3&gt;Author: jazz&lt;/h3&gt;&lt;h3&gt;Challenge prompt: &lt;/h3&gt;&lt;p&gt;&lt;code&gt;Forget Enigma, forget Caesar. The only cipher you need is 2009&apos;s infamous password dump.&lt;/code&gt; &lt;/p&gt;&lt;p&gt;Challenge handout has two files inside, one of them is a target ELF named &lt;b&gt;encode&lt;/b&gt; and the other one is an encrypted file named &lt;b&gt;encoded.rj&lt;/b&gt;. Before we begin decompilation let&apos;s see what happens when we run the program:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;Usage: ./encode &quot;your message&quot;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So the program expects a string, let&apos;s try a random string for now:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;Failed to open ./rockyou.txt&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So the program needs &lt;b&gt;rockyou.txt&lt;/b&gt; to be in the same directory, I&apos;m guessing it uses it to encode the input string. This is also explains what the challenge prompt is referring to &quot;The only cipher you need is 2009&apos;s infamous password dump.&quot;&lt;/p&gt;&lt;p&gt;So after placing rockyou.txt in the same directory, we pass in a string &quot;random&quot;:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;cosmos@cosmos-VirtualBox:~/workspace/corctf/yourock$ ./encode random
Encoded output:
hellokitty 00000 qwerty lovely 12345678 12345678 1234567&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If we compare this with our &lt;b&gt;encoded.rj&lt;/b&gt; file, we can see that both of them have a similar format, where the encoded output has words separated by a space. I think it is safe to assume that the &lt;b&gt;encoded.rj&lt;/b&gt; file is encoded output of the flag when it was ran against the given program.&lt;/p&gt;&lt;p&gt;Another interesting thing to notice is that the number of words in the encoded output is always 1 more than the length of the input string, this suggests that the encode program could be doing some kind of byte-by-byte operation on the input string outputting an extra word with it.&lt;/p&gt;&lt;h2&gt;DECOMPILATION&lt;/h2&gt;&lt;p&gt;Let&apos;s look at the program decompilation in IDA:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;std::allocator&amp;lt;char&amp;gt;::allocator(&amp;amp;wordlist_map, argv, a3);
std::string::basic_string&amp;lt;std::allocator&amp;lt;char&amp;gt;&amp;gt;(&amp;amp;input, argv[1], &amp;amp;wordlist_map);
std::allocator&amp;lt;char&amp;gt;::~allocator(&amp;amp;wordlist_map);
std::vector&amp;lt;std::string&amp;gt;::vector(&amp;amp;wordlist_lines);
std::unordered_map&amp;lt;std::string,unsigned long&amp;gt;::unordered_map(&amp;amp;wordlist_map);
if ( (unsigned __int8)load_file(&amp;amp;wordlist_lines, &amp;amp;wordlist_map) != 1 )&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Looking at this we can safely say that this is a C++ binary and at first it can be hard to read, but let&apos;s try to dig in and see what the binary is trying to do. &lt;/p&gt;&lt;p&gt;So the binary allocates an empty string vector named &lt;b&gt;wordlist_lines&lt;/b&gt; and an unordered map named &lt;b&gt;wordlist_map&lt;/b&gt;. If you don&apos;t know what an unordered map is, you can think of it as a python dictionary which holds values in key-value pairs as they are both implementations of hash maps.&lt;/p&gt;&lt;h2&gt;Encoding&lt;/h2&gt;&lt;p&gt;Upon successfully opening &lt;b&gt;rockyou.txt&lt;/b&gt; it generates a key using &lt;b&gt;generate_key&lt;/b&gt; and encodes the given string using encode function which takes 4 args.:&lt;/p&gt;&lt;p&gt;- encoded_words (empty vector for now)&lt;/p&gt;&lt;p&gt;- input (input string)&lt;/p&gt;&lt;p&gt;- wordlist_lines (vector containing all passwords from rockyou.txt)&lt;/p&gt;&lt;p&gt;- key (generated from generate_key)&lt;/p&gt;&lt;p&gt;And after execution of this function the binary prints out the encoded_words buffer separated by a space.&lt;/p&gt;&lt;p&gt;Let&apos;s look inside the encode function first:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;  std::vector&amp;lt;std::string&amp;gt;::vector(encoded_words);
  word = std::vector&amp;lt;std::string&amp;gt;::operator[](wordlist_lines, key);
  std::vector&amp;lt;std::string&amp;gt;::push_back(encoded_words, word);
  for ( i = 0LL; i &amp;lt; std::string::size(input); ++i )
  {
    xored_byte = key ^ *(_BYTE *)std::string::operator[](input, i);
    if ( xored_byte &amp;gt;= (unsigned __int64)std::vector&amp;lt;std::string&amp;gt;::size(wordlist_lines) )
      exit(1);
    new_line = std::vector&amp;lt;std::string&amp;gt;::operator[](wordlist_lines, xored_byte);
    std::vector&amp;lt;std::string&amp;gt;::push_back(encoded_words, new_line);
    key ^= i ^ xored_byte;
  }
  return encoded_words;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;so the encode function boils down to this:&lt;/p&gt;&lt;p&gt;- It takes the key and uses it as an index in the &lt;b&gt;wordlist_lines&lt;/b&gt; array, grabs the word from that index and puts that &lt;b&gt;word&lt;/b&gt; into the encoded_words array. (This is the reason why we always have an extra word in the encoded output)&lt;/p&gt;&lt;p&gt;- After that it kicks off a loop based on the size of the input string, and XOR&apos;s every byte of the input string with the key. &lt;/p&gt;&lt;p&gt;- Then it uses the XOR&apos;ed value as an index into the wordlist array and puts that word into the encoded words array.&lt;/p&gt;&lt;p&gt;- Then it updates the key by XOR&apos;ing it with the index and the &lt;b&gt;xored_byte&lt;/b&gt; variable&lt;/p&gt;&lt;p&gt;Updating the key is a simple XOR operation which can be reversed if we know the index &lt;b&gt;i&lt;/b&gt; and the &lt;b&gt;xored_byte&lt;/b&gt;, we already know &lt;b&gt;i&lt;/b&gt; but the &lt;b&gt;xored_byte&lt;/b&gt; depends on the initial key. So all we need to break this encoding is the initial key, let&apos;s see how that is being generated.&lt;/p&gt;&lt;h2&gt;Key generation&lt;/h2&gt;&lt;p&gt;Key generation is pretty simple, we take a time-based seed and feed it to srand and then generate a random number from it. But we compute the modulus of it with 256 means that the returned value will be within the range &lt;b&gt;[0, 255]&lt;/b&gt;&lt;/p&gt;&lt;pre&gt;&lt;code&gt;__int64 __fastcall generate_key(__int64 *a1)
{
  unsigned int v1; // eax

  v1 = time(a1);
  srand(v1);
  return (unsigned int)(rand() % 256);
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Since our key is used as an index in the wordlist array, it means that our initial word will always be within the first 255 words of &lt;b&gt;rockyou.txt&lt;/b&gt;. So basically given an encoded output we just need to find the index of the first encoded word and that will be our key.&lt;/p&gt;&lt;p&gt;Looking at &lt;b&gt;encoded.rj&lt;/b&gt; the first word is &lt;b&gt;charlie&lt;/b&gt;, let&apos;s look for its index in &lt;b&gt;rockyou.txt&lt;/b&gt; &lt;/p&gt;&lt;pre&gt;&lt;code&gt;head -n255 rockyou.txt | cat -n | grep charlie&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;the output comes out to be &lt;b&gt;64 charlie&lt;/b&gt;, but since this is 1-indexed we can set our key as 63.&lt;/p&gt;&lt;h2&gt;Solution&lt;/h2&gt;&lt;p&gt;Now that we know our initial key we can reverse the XOR operation and get the actual string back, While encoding the input string we did:&lt;/p&gt;&lt;p&gt;&lt;b&gt;xored_byte = input[i] ^ key&lt;/b&gt;&lt;/p&gt;&lt;p&gt;so to reverse this we just need to do:&lt;/p&gt;&lt;p&gt;&lt;b&gt;input[i] = xored_byte ^ key&lt;/b&gt;&lt;/p&gt;&lt;p&gt;This is the final solve script:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;with open(&quot;encoded.rj&quot;) as fp:
    encoded = fp.read().strip()

encoded_words = encoded.split(&quot; &quot;)
print(encoded_words)

flag = &quot;&quot;

with open(&quot;rockyou.txt&quot;, encoding=&apos;utf-8&apos;, errors=&quot;ignore&quot;) as fp:
    pwds = [line.strip() for line in fp]

key = pwds.index(encoded_words[0])
encoded_words = encoded_words[1:]

for i in range(len(encoded_words)):
    xored_byte = pwds.index(encoded_words[i])
    flag += chr(key^xored_byte)
    key ^= i^xored_byte

print(flag)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And we get the flag: &lt;b&gt;corctf{r0cky0u_3nc0d1ng_r0cks}&lt;/b&gt; &lt;span&gt;🎉&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;h1&gt;Challenge #2: tagme&lt;/h1&gt;&lt;h3&gt;Category: rev&lt;/h3&gt;&lt;h3&gt;Author: maxster&lt;/h3&gt;&lt;p&gt;We are greeted with a dynamically linked, stripped binary. Classic crackme style challenge which takes in a input string and validates it, our input is also our flag.&lt;/p&gt;&lt;p&gt;Looking at the binary in IDA the binary isn&apos;t completely stripped, libc functions are there, but we still need to make sense of some functions and rename them:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;void __fastcall __noreturn main(int a1, char **a2, char **a3)
{
  char v3; // [rsp+3h] [rbp-3Dh]
  char *lineptr; // [rsp+8h] [rbp-38h] BYREF
  size_t n; // [rsp+10h] [rbp-30h] BYREF
  unsigned __int64 i; // [rsp+18h] [rbp-28h]
  __ssize_t v7; // [rsp+20h] [rbp-20h]
  char *v8; // [rsp+28h] [rbp-18h]
  unsigned __int64 v9; // [rsp+30h] [rbp-10h]
  unsigned __int64 v10; // [rsp+38h] [rbp-8h]

  v10 = __readfsqword(0x28u);
  puts(&quot;Enter flag:&quot;);
  lineptr = 0LL;
  n = 0LL;
  v7 = getline(&amp;amp;lineptr, &amp;amp;n, stdin);
  if ( v7 == -1 )
    sub_1209(&quot;Illiterate&quot;);
  if ( v7 &amp;lt;= 8 )
    sub_1209(&quot;Short&quot;);
  if ( v7 &amp;gt; 39 )
    sub_1209(&quot;Long&quot;);
  if ( strncmp(&quot;corctf{&quot;, lineptr, 7uLL) )
    sub_1209(&quot;Ineligible&quot;);
  if ( strncmp(&quot;}\n&quot;, &amp;amp;lineptr[v7 - 2], 2uLL) )
    sub_1209(&quot;Ineligible&quot;);
  sub_126D();
  v8 = lineptr + 7;
  v9 = v7 - 9;
  for ( i = 0LL; i &amp;lt; v9; ++i )
  {
    v3 = v8[i];
    if ( (i &amp;amp; 1) != 0 )
    {
      if ( i % 6 &amp;gt; 3 )
      {
        if ( v3 &amp;lt;= 112 )
          sub_1209(&quot;Forbidden&quot;);
      }
      else if ( v3 &amp;lt;= 107 || v3 == 115 )
      {
        sub_1209(&quot;Forbidden&quot;);
      }
    }
    else if ( v3 == 99 || v3 &amp;gt; 108 )
    {
      sub_1209(&quot;Forbidden&quot;);
    }
    sub_12A4((unsigned int)v3);
  }
  while ( !(unsigned int)sub_13F8() )
    ;
  sub_1209(&quot;Boring&quot;);
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We take input from stdin using getline, which returns the number of chars taken input. This means that v7 has the &lt;b&gt;flag_length&lt;/b&gt; and &lt;b&gt;lineptr&lt;/b&gt; is basically a pointer to the input string.&lt;/p&gt;&lt;p&gt;v8 is &lt;b&gt;flag_ptr&lt;/b&gt; &lt;b&gt;+ 7&lt;/b&gt;, since flag format starts with &lt;b&gt;corctf{&lt;/b&gt;, v8 basically points to the first character inside the brackets aka the &lt;b&gt;flag_bytes&lt;/b&gt;. v9 is &lt;b&gt;v7 - 9&lt;/b&gt; and since &lt;b&gt;v7&lt;/b&gt; was our flag_length, v9 is the length of our &lt;b&gt;flag_bytes&lt;/b&gt; which is the string inside the brackets. &lt;/p&gt;&lt;p&gt;By the looks of it &lt;b&gt;sub_1209()&lt;/b&gt; looks like some kind of fail condition function, since it prints &lt;b&gt;Rejected&lt;/b&gt; and exits the program.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;void __fastcall __noreturn sub_1209(const char *a1)
{
  printf(&quot;%s\nRejected\n&quot;, a1);
  exit(1);
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We&apos;ll rename &lt;b&gt;sub_1209&lt;/b&gt; to &lt;b&gt;fail&lt;/b&gt; for now.  We can also rename v8 and v9 to &lt;b&gt;flag_chars&lt;/b&gt; and &lt;b&gt;flag_len&lt;/b&gt; based on what we discussed above.&lt;/p&gt;&lt;p&gt;Looking at the for loop, we loop until the end of the input string and store the current byte in v3. We can rename v3 as &lt;b&gt;flag_byte&lt;/b&gt;. Now if we look inside the for loop it is laid out with traps which instantly trigger the fail condition, if we manage to avoid these we get to a function named &lt;b&gt;sub_12A4&lt;/b&gt;&lt;/p&gt;&lt;p&gt;Now let&apos;s look at this other function &lt;b&gt;sub_12A4:&lt;/b&gt; &lt;/p&gt;&lt;pre&gt;&lt;code&gt;__int64 __fastcall sub_12A4(char a1)
{
  __int64 result; // rax

  byte_4060[qword_4048] = a1;
  if ( ++qword_4048 == 4600 )
    qword_4048 = 0LL;
  result = qword_4040;
  if ( qword_4048 == qword_4040 )
    sub_123B(&quot;Interesting&quot;);
  return result;
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If we manage to avoid the traps, we pass the &lt;b&gt;flag_byte&lt;/b&gt; as input to this function which writes it to a global buffer &lt;b&gt;byte_4060&lt;/b&gt;. The index is decided by another value stored in the .bss &lt;b&gt;qword_4048&lt;/b&gt;. This global buffer is interesting because it writes upto size 4600 and then loops back around to the start of the buffer by setting the index pointer to 0.&lt;/p&gt;&lt;p&gt;This means that &lt;b&gt;byte_4060&lt;/b&gt; is some kind of circular buffer with length 4600. We also take another pointer &lt;b&gt;qword_4040&lt;/b&gt; and compare it with our index pointer. If these two pointers match then we take this other function &lt;b&gt;sub_123B&lt;/b&gt; and if we look inside it we can see that it prints &lt;b&gt;Accepted&lt;/b&gt; and exits. This clearly means that this is our success case and we have to somehow reach here to get the flag!&lt;/p&gt;&lt;p&gt;So based on all of this we can re-define:&lt;/p&gt;&lt;p&gt;- &lt;b&gt;byte_4060&lt;/b&gt; to &lt;b&gt;circular_buffer&lt;/b&gt;&lt;/p&gt;&lt;p&gt;- qword_4048 to &lt;b&gt;write_ptr&lt;/b&gt;&lt;/p&gt;&lt;p&gt;- qword_4040 to &lt;b&gt;read_ptr&lt;/b&gt;&lt;/p&gt;&lt;p&gt;- sub_123B to &lt;b&gt;success&lt;/b&gt;&lt;/p&gt;&lt;p&gt;There&apos;s another interesting function in a while loop at the end, let&apos;s uncover that:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;__int64 sub_13F8()
{
  size_t j; // rax
  char v2; // [rsp+Ah] [rbp-26h]
  char v3; // [rsp+Bh] [rbp-25h]
  int i; // [rsp+Ch] [rbp-24h]
  size_t v5; // [rsp+10h] [rbp-20h]
  __int64 v6; // [rsp+18h] [rbp-18h]
  char *s; // [rsp+28h] [rbp-8h]

  if ( (unsigned int)sub_138A() )
    return 1LL;
  v2 = sub_1318();
  v6 = sub_13AB((unsigned int)v2);
  if ( v6 == -1 )
    fail(&quot;Bizzare&quot;);
  for ( i = 1; i &amp;lt;= 1; ++i )
  {
    if ( (unsigned int)sub_138A() )
      return 1LL;
    v3 = sub_1318();
    if ( sub_13AB((unsigned int)v3) == -1 )
      fail(&quot;Bizzarre&quot;);
  }
  s = (char *)*((_QWORD *)&amp;amp;unk_3CE0 + 2 * v6 + 1);
  v5 = 0LL;
  for ( j = strlen(s); v5 &amp;lt; j; j = strlen(s) )
    sub_12A4(s[v5++]);
  return 0LL;
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If we look at &lt;b&gt;sub_1318&lt;/b&gt;, we check if our write_ptr is the same as &lt;b&gt;qword_4040&lt;/b&gt;. If not we use the &lt;b&gt;qword_4040&lt;/b&gt; to read values from the &lt;b&gt;circular_buffer&lt;/b&gt; and return it. From this we can rename &lt;b&gt;qword_4040&lt;/b&gt; to be our &lt;b&gt;read_ptr&lt;/b&gt;&lt;/p&gt;&lt;pre&gt;&lt;code&gt;__int64 sub_1318()
{
  unsigned __int8 v1; // [rsp+Fh] [rbp-1h]

  if ( qword_4040 == write_ptr )
    fail(&quot;Dry&quot;);
  v1 = circular_buffer[qword_4040];
  if ( ++qword_4040 == 4600 )
    qword_4040 = 0LL;
  return v1;
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This also makes sense because at the start of the function, we check if &lt;b&gt;read_ptr&lt;/b&gt; and &lt;b&gt;write_ptr&lt;/b&gt; are not same, otherwise it would mean that the buffer is empty. From this we can also rename &lt;b&gt;sub_138A&lt;/b&gt; to &lt;b&gt;is_buffer_empty&lt;/b&gt; as it does the same. We can also rename &lt;b&gt;sub_1318&lt;/b&gt; to &lt;b&gt;circular_buffer_read&lt;/b&gt;.&lt;/p&gt;&lt;p&gt;Now let&apos;s look at &lt;b&gt;sub_13AB&lt;/b&gt;:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;__int64 __fastcall sub_13AB(char a1)
{
  unsigned __int64 i; // [rsp+Ch] [rbp-8h]

  for ( i = 0LL; i &amp;lt;= 9; ++i )
  {
    if ( a1 == *((_BYTE *)&amp;amp;unk_3CE0 + 16 * i) )
      return i;
  }
  return -1LL;
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is comparing a1(char from circular_buffer_read) to a dereferenced value from the global buffer/struct. But it&apos;s hard to read like this:&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/779x476/c9d1398c99/corctf-ida.png&quot; /&gt;&lt;/p&gt;&lt;p&gt;But looking at this we can see a clear defined structure, so let&apos;s go ahead and make a custom struct for this so it is more readable. So every entry has:&lt;/p&gt;&lt;p&gt;- 1 byte char&lt;/p&gt;&lt;p&gt;- 7 null bytes&lt;/p&gt;&lt;p&gt;- pointer to a string in .rodata (double-click aNs or aJjj to check)&lt;/p&gt;&lt;p&gt;Let&apos;s go over to Local types and make this struct:&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/505x229/a125b7e99d/corctf-ida3.png&quot; /&gt;&lt;/p&gt;&lt;p&gt;we save this and we go over to our data in the global section and we hit &lt;b&gt;y&lt;/b&gt; on the &lt;b&gt;unk_3CE0&lt;/b&gt; to change it&apos;s type to &lt;b&gt;lookup_entry[10];&lt;/b&gt; since we have 10 entries in total. And BOOM! we get a much more readable version:&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/888x270/78ccb1c6cf/corctf-ida2.png&quot; /&gt;&lt;/p&gt;&lt;p&gt;From this we can get this mapping:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;a ---&amp;gt; &quot;ns&quot;
b ---&amp;gt; &quot;jjj&quot;
c ---&amp;gt; &quot;flag&quot;
d ---&amp;gt; &quot;q&quot;
e ---&amp;gt; &quot;tt&quot;
f ---&amp;gt; &quot;gg&quot;
j ---&amp;gt; &quot;gg&quot;
n ---&amp;gt; &quot;a&quot;
p ---&amp;gt; &quot;cor&quot;
s ---&amp;gt; &quot;aaa&quot;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So if we look closely, the code takes each byte of input and checks it against the keys in this struct, if they don&apos;t match, it immediately reverts to a fail case and exits the program. So using this we&apos;ve constrained our flag_bytes to only these 10 characters.&lt;/p&gt;&lt;p&gt;If we look further into the function it does &lt;b&gt;circular_buffer_read&lt;/b&gt; twice that means it gets the current and the next flag_byte, but it only uses the flag_byte at the current index to modify the input string. &lt;/p&gt;&lt;pre&gt;&lt;code&gt;s = char_lookup_table[char_index].value;
v5 = 0LL;
for ( j = strlen(s); v5 &amp;lt; j; j = strlen(s) )
	circular_buffer_write(s[v5++]);&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This piece of code just appends the value from the lookup_table to the end of the input string. So if our string was &lt;b&gt;anp&lt;/b&gt; (assuming we pass the checks in our main function), it would become:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;anp --------&amp;gt; npns
npns -------&amp;gt; pnsa
pnsa -------&amp;gt; nsacor
nsacor -----&amp;gt; sacora
sacora -----&amp;gt; acoraaaa
acoraaaa ---&amp;gt; coraaaans
coraaaans --&amp;gt; oraaaansflag
oraaaansflag --&amp;gt; Invalid ❌ &lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Thinking about this we can rule out some more characters from our &lt;b&gt;lookup_entry&lt;/b&gt; table as they&apos;ll lead to bad input characters i.e. characters which our not present in the lookup table after expansion. Therefore:&lt;/p&gt;&lt;p&gt;Bad input chars: &lt;b&gt;[&apos;b&apos;, &apos;c&apos;, &apos;d&apos;, &apos;e&apos;, &apos;f&apos;, &apos;j&apos;, &apos;p&apos;]&lt;/b&gt;&lt;/p&gt;&lt;p&gt;Good input chars: &lt;b&gt;[&apos;a&apos;, &apos;n&apos;, &apos;s&apos;]&lt;/b&gt;&lt;/p&gt;&lt;p&gt;Now if we go back and look at the constraints present in the main function, we can maybe shorten our search space even more. The constraints in the main function are for odd/even indices and can be summarized like this:&lt;/p&gt;&lt;p&gt;There are only 3 types of possible input chars, if we hold the above assumption of good chars. to be true:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;Odd1 indices ---&amp;gt; [1, 3, 7, 9, 13, 15...]  
these can only have char &quot;n&quot;  

Odd2 indices ---&amp;gt; [5, 11, 17...] 
these can only have char &quot;s&quot;

Even indices ---&amp;gt; [0, 2, 4, 6...] 
these can only have char &quot;a&quot;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now that we know which indices can have which chars. we still need to know the length of the flag, but we can just try every flag length upto 30 and one of them should be correct. So we just write a simple script which does that.&lt;/p&gt;&lt;h2&gt;Final solve script&lt;/h2&gt;&lt;pre&gt;&lt;code&gt;from pwn import *

PREFIX = &quot;corctf{&quot;
SUFFIX = &quot;}&quot;

def generate_flags(len):
    
    candidate = []

    for i in range(len):
        if i%2 == 0:
            candidate.append(&quot;a&quot;)
        elif i % 6 &amp;gt; 3:
            candidate.append(&quot;s&quot;)
        else:
            candidate.append(&quot;n&quot;)

    return f&quot;{PREFIX}{&apos;&apos;.join(candidate)}{SUFFIX}&quot;

for i in range(31):
    flag = generate_flags(i)
    
    with process(&quot;tagme&quot;, level=&quot;CRITICAL&quot;) as p:
        p.sendline(flag)
        
        out = p.recvall()
        if b&apos;Accepted&apos; in out:
            print(out)
            print(flag)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Flag: &lt;b&gt;corctf{ananasananasananasananasana}&lt;/b&gt; &lt;span&gt;🎉&lt;/span&gt;&lt;/p&gt;</content:encoded></item><item><title>Stepping down into the Ocaml Mines  -  UIUCTF 2025 Writeup</title><link>https://c0smos.dev/writeups/uiuctf-2025/</link><guid isPermaLink="true">https://c0smos.dev/writeups/uiuctf-2025/</guid><description>Writeup for UIUCTF 2025 as part of CTF Academy</description><pubDate>Tue, 05 Aug 2025 23:57:09 GMT</pubDate><content:encoded>&lt;p&gt;This writeup and solution is a combined effort from me and &lt;b&gt;my teammate “e-” (Elemental) as part of &lt;/b&gt;&lt;a href=&quot;https://ctftime.org/team/384247/&quot; target=&quot;_blank&quot;&gt;&lt;b&gt;&lt;u&gt;CTF Academy&lt;/u&gt;&lt;/b&gt;&lt;/a&gt;&lt;b&gt;.&lt;/b&gt; I decided to keep this writeup a bit comprehensive because it took us embarrassingly long to solve this challenge, but it allowed me to learn a lot about how Ocaml works.&lt;/p&gt;&lt;p&gt;This rev challenge is based around a pretty old functional programming language known as “Ocaml” which I was completely unaware of before this CTF. Personally I found this challenge pretty interesting which helped me discover a niche language, understand it and then reverse the logic to get the flag!&lt;/p&gt;&lt;h1&gt;&lt;b&gt;Challenge #1: WeirdCaml&lt;/b&gt;&lt;/h1&gt;&lt;h3&gt;&lt;b&gt;Category: rev&lt;/b&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;b&gt;Author: n8&lt;/b&gt;&lt;/h3&gt;&lt;h2&gt;&lt;b&gt;Brief info about the challenge and Ocaml&lt;/b&gt;&lt;/h2&gt;&lt;p&gt;The challenge gives us a file with a long list of type definitions, which to be honest were a bit hard to understand for me.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;type b_true
type b_false
type &apos;a val_t =
 | T : b_true val_t
 | F : b_false val_t&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This snippet represents the first part of the problem, let’s break it down to understand what’s going on. The challenge file declares two empty types called &lt;b&gt;b_true &lt;/b&gt;and &lt;b&gt;b_false&lt;/b&gt;, at no point in the file are these types used for any variables, these are purely used as empty type markers or boolean flags. You can think of them as undefined macros in C:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;#DEFINE b_true
#DEFINE b_false&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then there’s another type definition, &lt;b&gt;’a val_t&lt;/b&gt;. This is interesting because the type definition here is ambiguous and is dependent on type of &lt;b&gt;a&lt;/b&gt; hence the apostrophe before it: &lt;b&gt;’a&lt;/b&gt;. This is known as a &lt;b&gt;GADT (Generalized algebraic datatypes)&lt;/b&gt; in Ocaml. This pattern allows us to create polymorphic types by passing a ambiguous type parameter.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;type &apos;a val_t =
 | T : b_true val_t
 | F : b_false val_t&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;b&gt;T &lt;/b&gt;and &lt;b&gt;F&lt;/b&gt; are called constructors for this GADT, this means that we can only invoke constructor T when &lt;b&gt;’a &lt;/b&gt;is set to &lt;b&gt;b_true&lt;/b&gt; and constructor &lt;b&gt;F&lt;/b&gt; only when &lt;b&gt;’a&lt;/b&gt; is set to &lt;b&gt;b_false&lt;/b&gt;.&lt;/p&gt;&lt;p&gt;Now let’s look at the next part of the challenge:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;type (&apos;a, &apos;b, &apos;c, &apos;d) p1_t =
 | P1_1 : b_true val_t -&amp;gt; (&apos;a, b_true, &apos;c, &apos;d) p1_t
 | P1_2 : b_true val_t -&amp;gt; (&apos;a, &apos;b, b_true, &apos;d) p1_t
 | P1_3 : b_true val_t -&amp;gt; (&apos;a, &apos;b, &apos;c, b_true) p1_t
 | P1_4 : b_true val_t -&amp;gt; (b_false, &apos;b, &apos;c, &apos;d) p1_t&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;now that we understand how GADT’s work, the challenge defines a ton of GADT’s in the form of &lt;b&gt;px_t &lt;/b&gt;where x ranges from 1 to 1435 to be precise, but this time these GADT’s define 4 type parameters, and 4 constructors which determines different constraints on these type parameters.&lt;/p&gt;&lt;p&gt;&lt;b&gt;For example:&lt;/b&gt; calling &lt;b&gt;p1_t &lt;/b&gt;with constructor &lt;b&gt;P1_1&lt;/b&gt; with value &lt;b&gt;T&lt;/b&gt; (&lt;b&gt;b_true val_t&lt;/b&gt;) means that among the returned type parameters &lt;b&gt;’b&lt;/b&gt; has to be of the type &lt;b&gt;b_true&lt;/b&gt; while &lt;b&gt;’a&lt;/b&gt;, &lt;b&gt;’c&lt;/b&gt;, &lt;b&gt;’d&lt;/b&gt; can be ambiguous types. In the given problem every constructor restricts one output type while the other 3 type parameters can be ambiguous types.&lt;/p&gt;&lt;h2&gt;&lt;b&gt;Taking a look at type puzzle&lt;/b&gt;&lt;/h2&gt;&lt;p&gt;Finally we have one last type definition called puzzle, this defines the core problem in our CTF so let’s have a look at first part of puzzle:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;type puzzle =
 Puzzle :
 &apos;flag_000 val_t * 
 &apos;flag_001 val_t * 
 &apos;flag_002 val_t *
 …
 &apos;flag_103 val_t *
 &apos;a val_t * 
 &apos;b val_t * 
 &apos;c val_t *
 …
 &apos;z val_t *
 &apos;a1 val_t * 
 &apos;a2 val_t * 
 &apos;a3 val_t *
 …
 &apos;a147 val_t *&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;type puzzle is another GADT, and a massive one which starts by defining a single constructor called &lt;b&gt;Puzzle&lt;/b&gt; which binds a bunch of type variables divided in 3 parts:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;b&gt;&apos;flag_000&lt;/b&gt; to &lt;b&gt;‘flag_103&lt;/b&gt; (flag bits encoded in the form of T/F)&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;b&gt;‘a &lt;/b&gt;to &lt;b&gt;‘z&lt;/b&gt; (idk why there are types from a to z)&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;b&gt;‘a1 &lt;/b&gt;to &lt;b&gt;‘a147 &lt;/b&gt;(more supporting variable types)&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Since there are 104 type variables of the format &lt;b&gt;flag_XXX&lt;/b&gt;, &lt;b&gt;we can assume that these constitute individual flag bits, so 104/8 = 13 flag bytes.&lt;/b&gt; The other type variables are just supporting variables which help us set constraints for the flag type variables.&lt;br /&gt;&lt;b&gt;PS:&lt;/b&gt; Something which bugged me for a long time in this problem was why are there type variables ranging from &lt;b&gt;’a&lt;/b&gt; to &lt;b&gt;’z&lt;/b&gt; when they have nothing to do with the flag directly, before solving the problem I kept thinking they have some connection to the flag which kept putting me off-track.&lt;/p&gt;&lt;p&gt;Now let’s look at next part of type puzzle:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;(&apos;a, &apos;flag_016, &apos;flag_038, &apos;flag_040) p1_t *
(&apos;a, &apos;flag_016, &apos;flag_038, &apos;flag_040) p2_t *
(&apos;a, &apos;flag_016, &apos;flag_038, &apos;flag_040) p3_t *&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We find a bunch of type annotations, which take some type parameters and match it against the allowed type definitions for that type. &lt;b&gt;For example:&lt;/b&gt; if we look at the passed type parameters for this annotation: &lt;b&gt;(‘a, ‘flag_016, ‘flag_038, ‘flag_040) p1_t *&lt;/b&gt; this means that for this expression to be valid it has to returned by invoking of the constructors from &lt;b&gt;p1_t&lt;/b&gt;’s GADT.&lt;/p&gt;&lt;p&gt;&lt;b&gt;That means this condition has to match against one of these 4 constraints for it to be a valid type:&lt;/b&gt;&lt;/p&gt;&lt;pre&gt;&lt;code&gt;type (&apos;a, &apos;b, &apos;c, &apos;d) p1_t =
 | P1_1 : b_true val_t -&amp;gt; (&apos;a, b_true, &apos;c, &apos;d) p1_t
 | P1_2 : b_true val_t -&amp;gt; (&apos;a, &apos;b, b_true, &apos;d) p1_t
 | P1_3 : b_true val_t -&amp;gt; (&apos;a, &apos;b, &apos;c, b_true) p1_t
 | P1_4 : b_true val_t -&amp;gt; (b_false, &apos;b, &apos;c, &apos;d) p1_t&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now we have a whole overview of what constructor Puzzle in type puzzle is, by definition it defines a humungous tuple where each type is concatenated by an asterisk &lt;b&gt;*&lt;/b&gt; which is like an &lt;b&gt;AND&lt;/b&gt; condition.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;b&gt;&lt;i&gt;So for the whole type puzzle to be valid, every single type inside the tuple should be a valid type.&lt;/i&gt;&lt;/b&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Now this statement has some interesting implications, since all the type variables are defined with &lt;b&gt;val_t&lt;/b&gt; they can only be of constructor type &lt;b&gt;T&lt;/b&gt; or type F from &lt;b&gt;val_t&lt;/b&gt;’s GADT. Now we can resolve this problem by using a constraint solver and putting in all our constraints and try to find a solution which satisfies them.&lt;/p&gt;&lt;h1&gt;&lt;b&gt;Solution&lt;/b&gt;&lt;/h1&gt;&lt;p&gt;For our solve script we’ll use Z3 as our constraint solver, but first we need to set variables and build constraints for Z3 to work.&lt;/p&gt;&lt;h2&gt;&lt;b&gt;Making variables&lt;/b&gt;&lt;/h2&gt;&lt;p&gt;As we saw earlier we have 3 types of type variables, even though we only care about the &lt;b&gt;flag_XXX&lt;/b&gt; variables we need to give Z3 all of them as the flag types depend on the other supporting type variables. Since all these types are of type &lt;b&gt;val_t&lt;/b&gt; which can only be defined with type &lt;b&gt;T&lt;/b&gt; or type &lt;b&gt;F&lt;/b&gt;, &lt;b&gt;we can treat them as booleans or more conveniently in Z3 as BitVectors of size 1.&lt;/b&gt;&lt;/p&gt;&lt;pre&gt;&lt;code&gt;def make_vars():
    flag = {}

    for i in range(104):
    var_name = &apos;flag_&apos; + str(i).rjust(3, &apos;0&apos;)
    flag[var_name] = BitVec(var_name, 1)

    for i in range(1, 148):
    var_name = &apos;a&apos; + str(i)
    flag[var_name] = BitVec(var_name, 1)

    for i in range(97, 123):
    var_name = chr(i)
    flag[var_name] = BitVec(var_name, 1)

    return flag

flag = make_vars()&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;For convenience we just bundled them up and put them in a dictionary.&lt;/p&gt;&lt;h3&gt;Parsing conditions from constructors&lt;/h3&gt;&lt;p&gt;Let’s look at a sample constraint for this type definition: &lt;b&gt;(‘a, ‘flag_016, ‘flag_038, ‘flag_040) p1_t *&lt;/b&gt;&lt;/p&gt;&lt;p&gt;Looking at this above constraint for type &lt;b&gt;p1_t&lt;/b&gt; we can’t really say much because we don’t know which constructor resulted in this type declaration. But what we do know that for it to be a valid type declaration it has to come from one of the 4 constructors of &lt;b&gt;p1_t&lt;/b&gt; i.e. &lt;b&gt;P1_1&lt;/b&gt; to &lt;b&gt;P1_4&lt;/b&gt;. Which means we can combine these 4 conditions with a single &lt;b&gt;OR&lt;/b&gt; operation.&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/1406x396/acc57acda3/or_condition.png&quot; /&gt;&lt;/p&gt;&lt;p&gt;Since all other type variables are ambiguous &lt;b&gt;we can condense all 4 possible constructors into a single condition by just OR-ing them.&lt;/b&gt; Similarly we can do the same for all of the type variables of the form &lt;code&gt;px_t&lt;/code&gt; and store them in a dictionary.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;def make_constraints(raw_string):
    chunks = raw_string.split(&quot;type &quot;)
    chunks = chunks[1:]
    filtered = []
    p_dict = {}
    for i in range(len(chunks)):
        data = chunks[i].lstrip().rstrip().split(&apos;\n&apos;)
        data[0] = data[0].replace(&apos;=&apos;, &quot;&quot;).lstrip().rstrip()
        temp = data[0].split(&quot; &quot;)
        data[0] = temp[-1]
        key = data[0]
        value = [0] * (len(data)-1)
        for j in range(1, len(data)):
            rules = data[j].split(&quot; &quot;)
            rules = rules[8:12]
 
        for k in range(len(rules)):
            if &apos;b_true&apos; in rules[k]:
              value[k] = 1
            if &apos;b_false&apos; in rules[k]:
              value[k] = 0
        
        p_dict[key] = value

    return p_dict

p_dict = make_constraints(raw_px_t)&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;Building constraints for Z3&lt;/h3&gt;&lt;p&gt;After we are done dealing with our polymorphic constructors we can now move on to looking at constraints for our type variables. &lt;b&gt;This part was mostly done by my teammate “e-”&lt;/b&gt; so I’ll just try to summarize his approach. Before building the constraints I want to point out something very important he mentioned which will help us later on.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;(&apos;a, &apos;flag_016, &apos;flag_038, &apos;flag_040) p1_t *
 (&apos;a, &apos;flag_016, &apos;flag_038, &apos;flag_040) p2_t *
 (&apos;a, &apos;flag_016, &apos;flag_038, &apos;flag_040) p3_t *
 (&apos;a, &apos;flag_016, &apos;flag_038, &apos;flag_040) p4_t *
 (&apos;a, &apos;flag_016, &apos;flag_038, &apos;flag_040) p5_t *
 (&apos;a, &apos;flag_016, &apos;flag_038, &apos;flag_040) p6_t *
 (&apos;a, &apos;flag_016, &apos;flag_038, &apos;flag_040) p7_t *
 (&apos;a, &apos;flag_016, &apos;flag_038, &apos;flag_040) p8_t *
 (&apos;a, &apos;b, &apos;flag_068, &apos;flag_071) p9_t *
 (&apos;a, &apos;b, &apos;flag_068, &apos;flag_071) p10_t *
 (&apos;a, &apos;b, &apos;flag_068, &apos;flag_071) p11_t *
 (&apos;a, &apos;b, &apos;flag_068, &apos;flag_071) p12_t *
 (&apos;a, &apos;b, &apos;flag_068, &apos;flag_071) p13_t *
 (&apos;a, &apos;b, &apos;flag_068, &apos;flag_071) p14_t *
 (&apos;a, &apos;b, &apos;flag_068, &apos;flag_071) p15_t *
 (&apos;a, &apos;b, &apos;flag_068, &apos;flag_071) p16_t *
 (&apos;b, &apos;a60, &apos;flag_101, &apos;flag_091) p17_t *
 (&apos;b, &apos;a60, &apos;flag_101, &apos;flag_091) p18_t *
 (&apos;b, &apos;a60, &apos;flag_101, &apos;flag_091) p19_t *
 (&apos;b, &apos;a60, &apos;flag_101, &apos;flag_091) p20_t *
 (&apos;b, &apos;a60, &apos;flag_101, &apos;flag_091) p21_t *
 (&apos;b, &apos;a60, &apos;flag_101, &apos;flag_091) p22_t *
 (&apos;b, &apos;a60, &apos;flag_101, &apos;flag_091) p23_t *
 (&apos;b, &apos;a60, &apos;flag_101, &apos;flag_091) p24_t *
 (&apos;a60) p25_t *&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Look at this small snippet which defines constraints on types from &lt;b&gt;p1_t&lt;/b&gt; to &lt;b&gt;p25_t&lt;/b&gt;, we can definitely see a pattern here where every 8 consecutive types use the same variable but all of them have a type parameter in common, but after this these variables don’t appear. &lt;b&gt;My teammate’s idea was to classify this as a single group since all these type variables are dependent on each other and are bound by a single type variable which we know for sure is &lt;/b&gt;T&lt;b&gt; or &lt;/b&gt;F&lt;b&gt; i.e. &lt;/b&gt;a60&lt;b&gt; in this case.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;PS:&lt;/b&gt; I think it’s not necessary to make groups for this challenge, it’s just easier to feed it to Z3 if we do it this way.&lt;/p&gt;&lt;h3&gt;Feeding constraints to Z3&lt;/h3&gt;&lt;p&gt;Now that we know how to segregate our constraints into groups, we need to parse it and let Z3 know about the constraints. As discussed earlier every line of constraint can be resolved with an &lt;b&gt;Or&lt;/b&gt; operator in Z3 since any one constructor needs to be valid. Now we need to chain all these constraints together with an And operator in Z3,&lt;b&gt; &lt;/b&gt;since all these type variables need to be valid at the same time. To better visualize it this is how the first 4 constraints would look like without grouping:&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/1377x735/d7d17d0c8c/and_condition.png&quot; /&gt;&lt;/p&gt;&lt;p&gt;Code for parsing groups and feeding constraints to Z3:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;def parse_group(input):
    group = []
    
    lines = input.split(&apos;*&apos;)
    for i in range(len(lines)):
        lines[i] = lines[i].lstrip()
        lines[i] = lines[i].rstrip()
    
    if lines[-1] == &quot;&quot;:
        lines = lines[:-1]
 
    for i in range(len(lines)):
        data = lines[i].split(&quot; &quot;)
        for j in range(len(data)):
            data[j] = data[j].replace(&quot;(&quot;, &quot;&quot;).replace(&quot;)&quot;, &quot;&quot;).replace(&quot;,&quot;, &quot;&quot;).replace(&quot;&apos;&quot;, &quot;&quot;)
 
        # px_t member
        px_t = data[-1]
        px_t = p_dict[px_t]
        members = data[:-1]
        for j in range(len(members)):
            members[j] = flag[members[j]]
        group.append(check_px_t(px_t, members))
  
    #print(And(*group))
    return And(*group)

def check_px_t(px_t, nominee): # p1_t = F T T T
    equality = [px_t[i] == nominee[i] for i in range(len(px_t))]
 
    res = Or(*equality)
 
    return res

s = Solver()
s.add(parse_group(raw_input) == True)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now that we’re done adding our constraints time to let it rip and see if it is even satisfiable!&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/1061x97/7614bf3c0c/flag_ocaml.png&quot; /&gt;&lt;/p&gt;&lt;h3&gt;Final solution:&lt;/h3&gt;&lt;pre&gt;&lt;code&gt;raw_input = &quot;&quot;&quot;
 (&apos;a, &apos;flag_016, &apos;flag_038, &apos;flag_040) p1_t *
 (&apos;a, &apos;flag_016, &apos;flag_038, &apos;flag_040) p2_t *
 (&apos;a, &apos;flag_016, &apos;flag_038, &apos;flag_040) p3_t *
 (&apos;a, &apos;flag_016, &apos;flag_038, &apos;flag_040) p4_t *
…
 (&apos;a57) p1435_t
&quot;&quot;&quot;
raw_px_t = &quot;&quot;&quot;
type (&apos;a, &apos;b, &apos;c, &apos;d) p1_t =
 | P1_1 : b_true val_t -&amp;gt; (&apos;a, b_true, &apos;c, &apos;d) p1_t
 | P1_2 : b_true val_t -&amp;gt; (&apos;a, &apos;b, b_true, &apos;d) p1_t
 | P1_3 : b_true val_t -&amp;gt; (&apos;a, &apos;b, &apos;c, b_true) p1_t
 | P1_4 : b_true val_t -&amp;gt; (b_false, &apos;b, &apos;c, &apos;d) p1_t
…
type (&apos;a) p1435_t =
 | P1435_1 : b_true val_t -&amp;gt; (b_false) p1435_t
&quot;&quot;&quot;

def make_vars():
    flag = {}

    for i in range(104):
    var_name = &apos;flag_&apos; + str(i).rjust(3, &apos;0&apos;)
    flag[var_name] = BitVec(var_name, 1)

    for i in range(1, 148):
    var_name = &apos;a&apos; + str(i)
    flag[var_name] = BitVec(var_name, 1)

    for i in range(97, 123):
    var_name = chr(i)
    flag[var_name] = BitVec(var_name, 1)

    return flag

flag = make_vars()

def make_constraints(raw_string):
    chunks = raw_string.split(&quot;type &quot;)
    chunks = chunks[1:]
    filtered = []
    p_dict = {}
    for i in range(len(chunks)):
        data = chunks[i].lstrip().rstrip().split(&apos;\n&apos;)
        data[0] = data[0].replace(&apos;=&apos;, &quot;&quot;).lstrip().rstrip()
        temp = data[0].split(&quot; &quot;)
        data[0] = temp[-1]
        key = data[0]
        value = [0] * (len(data)-1)
        for j in range(1, len(data)):
            rules = data[j].split(&quot; &quot;)
            rules = rules[8:12]
 
        for k in range(len(rules)):
            if &apos;b_true&apos; in rules[k]:
              value[k] = 1
            if &apos;b_false&apos; in rules[k]:
              value[k] = 0
        
        p_dict[key] = value

    return p_dict

p_dict = make_constraints(raw_px_t)
# pprint(p_dict)

def parse_group(input):
    group = []
    
    lines = input.split(&apos;*&apos;)
    for i in range(len(lines)):
        lines[i] = lines[i].lstrip()
        lines[i] = lines[i].rstrip()
    
    if lines[-1] == &quot;&quot;:
        lines = lines[:-1]
 
    for i in range(len(lines)):
        data = lines[i].split(&quot; &quot;)
        for j in range(len(data)):
            data[j] = data[j].replace(&quot;(&quot;, &quot;&quot;).replace(&quot;)&quot;, &quot;&quot;).replace(&quot;,&quot;, &quot;&quot;).replace(&quot;&apos;&quot;, &quot;&quot;)
 
        # px_t member
        px_t = data[-1]
        px_t = p_dict[px_t]
        members = data[:-1]
        for j in range(len(members)):
            members[j] = flag[members[j]]
        group.append(check_px_t(px_t, members))
  
    #print(And(*group))
    return And(*group)

def check_px_t(px_t, nominee): # p1_t = F T T T
    equality = [px_t[i] == nominee[i] for i in range(len(px_t))]
 
    res = Or(*equality)
 
    return res

s = Solver()
s.add(parse_group(raw_input) == True)

def bits_to_ascii(bit_string):
    flag = &quot;&quot;
    for i in range(0, 104, 8):
        val = int(bit_string[i:i+8], 2)
        flag+=chr(val)
    return flag
  
bit_string = &quot;&quot;
if s.check() == sat:
    m = s.model()
    for i in range(104):
        bit = m[flag[&apos;flag_%.3d&apos; % i]].as_long()
        print(bit, end=&quot;&quot;)
        bit_string+=str(bit)
    print()
    print(f&quot;Decoded bit string: {bits_to_ascii(bit_string)}&quot;)
else:
  print(&quot;unsat&quot;)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;b&gt;Final flag:&lt;/b&gt; &lt;code&gt;uiuctf{sat_on_a_caml}&lt;/code&gt;&lt;/p&gt;&lt;h3&gt;Something to think about: Why does challenge say flag will be printed to stderr?&lt;/h3&gt;&lt;p&gt;This is like a bonus section, but very important to understand how this challenge works under the hood and more importantly why it takes so long to compile.&lt;/p&gt;&lt;p&gt;After our first failed attempt to get the flag, I started wandering in different rabbit holes &lt;b&gt;and one question that prompted in my head was &lt;/b&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;b&gt;&lt;i&gt;“Why does the challenge say that the flag will be printed out in stderr?”&lt;/i&gt;&lt;/b&gt;&lt;/p&gt;&lt;p&gt;Even if the script takes too long why &lt;b&gt;stderr&lt;/b&gt; and not &lt;b&gt;stdout&lt;/b&gt;. So I decided to explore a bit and using some of the conditions from the original ocaml file &lt;b&gt;I decided to build another toy ocaml file to play around the code a little bit.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;Since there were a lot of type definitions and constraints in the original file, I decided to put only a handful to test out how things play out, here’s the toy file:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;type b_true
type b_false
type _ val_t =
 | T : b_true val_t
 | F : b_false val_t

type (&apos;a, &apos;b, &apos;c, &apos;d) p1_t =
 | P1_1 : b_true val_t -&amp;gt; (&apos;a, b_true, &apos;c, &apos;d) p1_t
 | P1_2 : b_true val_t -&amp;gt; (&apos;a, &apos;b, b_true, &apos;d) p1_t
 | P1_3 : b_true val_t -&amp;gt; (&apos;a, &apos;b, &apos;c, b_true) p1_t
 | P1_4 : b_true val_t -&amp;gt; (b_false, &apos;b, &apos;c, &apos;d) p1_t
type (&apos;a, &apos;b, &apos;c, &apos;d) p2_t =
 | P2_1 : b_true val_t -&amp;gt; (&apos;a, b_true, &apos;c, &apos;d) p2_t
 | P2_2 : b_true val_t -&amp;gt; (b_false, &apos;b, &apos;c, &apos;d) p2_t
 | P2_3 : b_true val_t -&amp;gt; (&apos;a, &apos;b, b_false, &apos;d) p2_t
 | P2_4 : b_false val_t -&amp;gt; (&apos;a, &apos;b, &apos;c, b_false) p2_t
type (&apos;a, &apos;b, &apos;c, &apos;d) p3_t =
 | P3_1 : b_true val_t -&amp;gt; (&apos;a, &apos;b, b_true, &apos;d) p3_t
 | P3_2 : b_false val_t -&amp;gt; (b_false, &apos;b, &apos;c, &apos;d) p3_t
 | P3_3 : b_true val_t -&amp;gt; (&apos;a, b_false, &apos;c, &apos;d) p3_t
 | P3_4 : b_true val_t -&amp;gt; (&apos;a, &apos;b, &apos;c, b_false) p3_t

type puzzle =
 Puzzle :
 &apos;flag_000 val_t *
 &apos;flag_001 val_t *
 (&apos;a, &apos;flag_000, &apos;flag_001, &apos;flag_002) p1_t *
 (&apos;a, &apos;flag_000, &apos;flag_001, &apos;flag_002) p2_t *
 (&apos;a, &apos;flag_000, &apos;flag_001, &apos;flag_002) p3_t
 -&amp;gt; puzzle

let check1 (f: puzzle) = function
 | Puzzle _ -&amp;gt; .
 | _ -&amp;gt; ()&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If we focus on the last 3 lines where we define a function check which takes an argument &lt;b&gt;f&lt;/b&gt; of type puzzle, and it returns a function which tries to pattern match constructor Puzzle with &lt;b&gt;_&lt;/b&gt;. The &lt;b&gt;.&lt;/b&gt; in Ocaml is very interesting because it represents a refutation case in Ocaml, &lt;b&gt;it’s a way of telling the Ocaml compiler that &lt;/b&gt;&lt;b&gt;&lt;i&gt;“Prove that this branch is impossible to reach if a type puzzle is passed as an argument”&lt;/i&gt;&lt;/b&gt;&lt;b&gt;.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;Since the value we passed is indeed of type puzzle, the only way to prove it is impossible to reach is to prove that the constructor Puzzle is invalid or that there is no combination of type variables which satisfy this type. &lt;b&gt;The way the Ocaml compiler deals with this is by trying to find a solution to determine if it is actually unreachable and if there is a solution it prints out the combination in stderr.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;And since the challenge is designed in a way that it has a solution, this is what we get when we try to compile our toy ocaml file:&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/692x188/d4d16f745d/pattern_match.png&quot; /&gt;&lt;/p&gt;&lt;p&gt;This represents a valid combination of types, which in our case would be the bit representation of all the flag type variables. But since, in our original problem we have a massive tuple with a ton of conditions, the Ocaml compiler tries every possible combination to refute that this branch is impossible which takes forever, &lt;b&gt;therefore the goal is to optimize this using Z3 and get the flag!&lt;/b&gt;&lt;/p&gt;&lt;h1&gt;Challenge #2: Nocaml&lt;/h1&gt;&lt;h3&gt;Category: misc&lt;br /&gt;Author: n8&lt;/h3&gt;&lt;p&gt;This was another Ocaml challenge in the miscellanous category in the CTF, but sadly I could only solve this after the CTF ended. Nevertheless this was another cool challenge which made me dig around Ocaml a bit more to finally get the flag.&lt;/p&gt;&lt;p&gt;The challenge prompt is simple “just cat the flag” using your Ocaml script but there’s a small problem in doing that since &lt;b&gt;the given challenge file starts by setting everything to null, making all the standard library functions impossible to use.&lt;/b&gt; Functions such as &lt;code&gt;open_in&lt;/code&gt; (Open file), &lt;code&gt;print_endline&lt;/code&gt; (write) are basically useless now. The challenge script also sets a lot of core modules like &lt;b&gt;Stdlib, Printf&lt;/b&gt; to empty structs which makes them unusable and since most of the I/O functions are defined in Stdlib we’re pretty much cooked without it.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;let stdin = ()
let stdout = ()
let stderr = ()
let print_char = ()
let print_string = ()
let print_bytes = ()
let print_int = ()
let print_float = ()
let print_endline = ()
let print_newline = ()&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code&gt;module Stack = struct end
module StdLabels = struct end
module Stdlib = struct end
module String = struct end
module StringLabels = struct end
module Sys = struct e&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;But since most of these library functions rely on some sort of lower-level C functions to execute, we can still craft our exploit by directly calling into those lower-level functions. During the CTF I had a hard time finding documentation for these functions and gave up on this challenge, &lt;b&gt;but after peeking at the source code I realized this challenge is not that hard.&lt;/b&gt;&lt;/p&gt;&lt;h2&gt;Solution&lt;/h2&gt;&lt;p&gt;As I said earlier, &lt;b&gt;instead of relying on the library functions we need to make our own custom functions which mimic their functionality and call into the lower-level C functions.&lt;/b&gt; Let’s look at how the library functions are defined in the first place in Ocaml source code: &lt;a href=&quot;https://github.com/ocaml/ocaml/blob/trunk/stdlib/stdlib.ml&quot; target=&quot;_blank&quot;&gt;https://github.com/ocaml/ocaml/blob/trunk/stdlib/stdlib.ml&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Let’s dissect how a stdlib function is defined:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;external output_char : out_channel -&amp;gt; char -&amp;gt; unit = &quot;caml_ml_output_char&quot;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If you’re unfamiliar with the Ocaml syntax, let me break it down for you. In Ocaml the function definition starts with the &lt;b&gt;function_name&lt;/b&gt; and then the type of the parameters it takes separated by a &lt;b&gt;colon&lt;/b&gt; and &lt;b&gt;-&amp;gt;&lt;/b&gt;, and the last type parameter is for the &lt;b&gt;function output&lt;/b&gt;. So this essentially defines a function called &lt;b&gt;output_char&lt;/b&gt; which takes 2 args.: first one of type &lt;b&gt;out_channel&lt;/b&gt; &lt;b&gt;(similar to a file_descriptor)&lt;/b&gt; and second one a &lt;b&gt;character&lt;/b&gt; &lt;b&gt;(char to print)&lt;/b&gt; and it returns a value of type unit which similar to &lt;b&gt;return void&lt;/b&gt; in C.&lt;/p&gt;&lt;p&gt;The external keyword helps Ocaml interface with C functions and I think in this case it uses a lower-level C function called &lt;b&gt;caml_ml_output_char&lt;/b&gt;.&lt;/p&gt;&lt;p&gt;Now that we know how it works let’s try to replicate the same logic using our custom functions. Before making our custom functions &lt;b&gt;let’s see how to open/read/write files in Ocaml if these restrictions were not in place to know what things we need to replace.&lt;/b&gt;&lt;/p&gt;&lt;pre&gt;&lt;code&gt;let file = &quot;flag.txt&quot;
let () =
let ic = open_in file in
while true do
 let char = input_char ic in
 output_char stdout char;
 done&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;From this we know we at least need custom definitions for &lt;b&gt;open_in&lt;/b&gt;, &lt;b&gt;input_char&lt;/b&gt;, &lt;b&gt;output_char&lt;/b&gt;, and &lt;b&gt;stdout&lt;/b&gt;.&lt;/p&gt;&lt;h4&gt;Making our custom functions&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;We can easily replace &lt;code&gt;input_char&lt;/code&gt; and &lt;code&gt;output_char&lt;/code&gt; with &lt;b&gt;custom_input_char&lt;/b&gt; and &lt;b&gt;custom_output_char&lt;/b&gt; respectively as a like-to-like replacement.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Looking at the source code &lt;code&gt;open_in&lt;/code&gt; recursively keeps using other library functions which are also disabled, so we need to define all of them again. &lt;code&gt;open_in&lt;/code&gt; uses &lt;code&gt;open_in_gen&lt;/code&gt; which uses &lt;code&gt;open_descriptor_in&lt;/code&gt;, &lt;code&gt;open_desc&lt;/code&gt; and &lt;code&gt;set_in_channel_name&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Finally those smelly nerds didn’t even leave &lt;code&gt;stdout&lt;/code&gt;, so we need to re-define a &lt;b&gt;custom_stdout&lt;/b&gt; which uses a &lt;b&gt;custom_open_descriptor_out&lt;/b&gt;.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;Final solution&lt;/h2&gt;&lt;pre&gt;&lt;code&gt;let file = &quot;flag.txt&quot;

external custom_input_char : in_channel -&amp;gt; char = &quot;caml_ml_input_char&quot;
external custom_output_char : out_channel -&amp;gt; char -&amp;gt; unit = &quot;caml_ml_output_char&quot;

type open_flag =
 Open_rdonly | Open_wronly | Open_append
 | Open_creat | Open_trunc | Open_excl
 | Open_binary | Open_text | Open_nonblock

external custom_open_desc : string -&amp;gt; open_flag list -&amp;gt; int -&amp;gt; int = &quot;caml_sys_open&quot;
external custom_open_descriptor_in : int -&amp;gt; in_channel = &quot;caml_ml_open_descriptor_in&quot;
external custom_open_descriptor_out : int -&amp;gt; out_channel = &quot;caml_ml_open_descriptor_out&quot;
external custom_set_in_channel_name: in_channel -&amp;gt; string -&amp;gt; unit = &quot;caml_ml_set_channel_name&quot;

let custom_open_in_gen mode perm name =
 let c = custom_open_descriptor_in(custom_open_desc name mode perm) in
 custom_set_in_channel_name c name;
 c

let custom_open_in name =
 custom_open_in_gen [Open_rdonly; Open_text] 0 name

let custom_stdout = custom_open_descriptor_out 1

let () =

  let ic = custom_open_in file in

  try
    while true do
      let char = custom_input_char ic in
      custom_output_char custom_stdout char;
    done
  with End_of_file -&amp;gt; ()&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Thank you for reading it, if you made it this far and have a great day! &lt;span&gt;😅&lt;/span&gt;&lt;/p&gt;&lt;h1&gt;References&lt;/h1&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Static Typing in Ocaml: &lt;a href=&quot;https://www2.lib.uchicago.edu/keith/ocaml-class/static.html&quot; target=&quot;_blank&quot;&gt;https://www2.lib.uchicago.edu/keith/ocaml-class/static.html&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Detailed info on GADT’s: &lt;a href=&quot;https://dev.realworldocaml.org/gadts.html&quot; target=&quot;_blank&quot;&gt;https://dev.realworldocaml.org/gadts.html&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Some discussion on Ocaml pattern matching:&lt;b&gt; &lt;/b&gt;&lt;a href=&quot;https://discuss.ocaml.org/t/in-pattern-matching/2676&quot; target=&quot;_blank&quot;&gt;https://discuss.ocaml.org/t/in-pattern-matching/2676&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Ocaml stdlib source code: &lt;a href=&quot;https://github.com/ocaml/ocaml/blob/trunk/stdlib/stdlib.ml&quot; target=&quot;_blank&quot;&gt;https://github.com/ocaml/ocaml/blob/trunk/stdlib/stdlib.ml&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;A bit about CTF Academy:&lt;b&gt; &lt;/b&gt;&lt;a href=&quot;https://ctf.asu.edu/education/ace-ctf-academy/&quot; target=&quot;_blank&quot;&gt;https://ctf.asu.edu/education/ace-ctf-academy/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;</content:encoded></item><item><title>Pedri&apos;s resurgence under Luis de la Fuente</title><link>https://c0smos.dev/blog/pedri-resurgence-with-spain/</link><guid isPermaLink="true">https://c0smos.dev/blog/pedri-resurgence-with-spain/</guid><description>Pedri is back to his best for La Roja after a long hiatus, but something has changed in his game. Time to take a closer look at it </description><pubDate>Sun, 30 Jun 2024 15:06:03 GMT</pubDate><content:encoded>&lt;p&gt;This is going to be a succinct post about something that recently caught my eye and that is Pedri’s role in the national team in the Euros which hasn’t been talked about enough.&lt;/p&gt;&lt;p&gt;Pedri who has been a key player for the La Roja since his breakthrough at Barcelona at a tender age of just 18 years, has often been compared to the likes of Xavi &amp;amp; Iniesta due to the immense talent that he has on display. Despite being pretty young he has been an undisputed starter for club &amp;amp; country when fit and after getting rid of his injuries he is finally back to his best, but something has changed and that is how Luis de La Fuente is using him differently on the pitch as opposed to Luis Enrique. Let’s take a closer look:&lt;/p&gt;&lt;p&gt;&lt;b&gt;&lt;i&gt;According to statistics from Sofascore Pedri averaged around 120 touches per game in the 2022 World Cup, meanwhile in the Euros he has only averaged 39 touches per game so far. So what has changed?&lt;/i&gt;&lt;/b&gt;&lt;/p&gt;&lt;p&gt;Mainly two things:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;First of all Spain’s style of play in the tournament has been very different from their usual self. Usually you would find Spain being patient in their build-up trying to play out from the back and moving the ball through lines of pressure to arrive in the final third. But this time round &lt;b&gt;Spain have played a lot more direct &lt;/b&gt;especially to their wingers as they want them to generate more 1v1 chances on the flanks due to their sheer quality. There is a lot more to talk about Spain’s setup and I’ll write a detailed blog if they make it into the final stages of the tournament but for now I’ll limit this blog to Pedri’s role in the team.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Second and the more significant change is Pedri’s role under Luis de la Fuente, from the recent matches one can easily concur that Pedri is no longer involved in the build-up phases instead he operates between the lines as a &lt;b&gt;hole player&lt;/b&gt;. Playing further up the pitch means that he is always looking to crash the box looking for a cutback from the wingers, and providing an additional goal threat. This also means that he is no longer looking to progress the ball in the midfield instead he is always looking to receive the ball on a half-turn and pinging through balls to their forwards.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/828x465/f9673bbac9/pedri_bw_the_lines.webp&quot; /&gt;&lt;span&gt;Pedri playing between the lines vs Italy&lt;/span&gt;&lt;/p&gt;&lt;h2&gt;&lt;b&gt;Heatmaps&lt;/b&gt;&lt;/h2&gt;&lt;p&gt;The best way to display the difference is by using heatmaps where the darker regions indicate more touches on the left side, while you can easily see that Pedri has played a lot closer to the box in this tournament.&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/1485x745/edda7a9d5f/pedri_heatmap.jpg&quot; /&gt;&lt;span&gt;Pedri’s heavy involvement in the build-up phase in 2022 WC vs more box presence in Euro 2024&lt;/span&gt;&lt;/p&gt;&lt;h1&gt;&lt;b&gt;The Upsides&lt;/b&gt;&lt;/h1&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;The obvious upsides of playing Pedri higher up the pitch is that he arrives a lot more than before in the box and plays decisive combinations in the final third. He is not just a great shooter he also has an eye for a killer final pass to set up his teammates in clear goal scoring scenarios. In fact he has &lt;b&gt;averaged more key passes and chance creation with his new role than he did under Luis Enrique&lt;/b&gt; despite seeing the ball way less than before.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Apart from this Pedri is known for his great football IQ and positioning to find pockets of space to exasperate the opponents. He has good tight space control and dribbling ability to weave through the final defensive line and take a shot. If needed he can come out of the structure and drop into midfield as he is also excellent at beating the press and technically adept to find an outlet to improve build-up against high pressing teams.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h1&gt;&lt;b&gt;Downsides&lt;/b&gt;&lt;/h1&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Pedri has an exquisite passing range, &lt;b&gt;one of his best skills is to play accurate long balls into the box&lt;/b&gt; from the deep to create chances. Also playing long diagonal balls to a winger to switch flanks after creating overload on one side of the pitch in attempt to try and break down a low-block. Since the departure of Busquets he fills that void perfectly by unlocking defenses from the deep with a single pass, but playing upfront means he can’t do it anymore.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;br /&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/600x338/3d421ef54f/pedri-ezgif-com-video-to-gif-converter.gif&quot; /&gt;&lt;span&gt;Pedri’s one of many accurate long balls vs Costa Rica (2022 WC)&lt;/span&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Not really a downside this one, but playing between the lines means that there may be games where Pedri has little to no influence over the midfield and he has to rely on Rodri and Fabian Ruiz to find him between the lines. So far Fabian Ruiz has been excellent for Spain and if he keeps up these performances this will rarely be a problem for Spain.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h1&gt;Luis de la Fuente’s comments on Pedri&lt;/h1&gt;&lt;blockquote&gt;&lt;p&gt;&lt;i&gt;“We have been very happy and because he is a very good player and he knows that I have confidence in him and he is going to give us very good things in this competition,”&lt;/i&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;i&gt;“I have always talked about it from the point of view of the confidence he has to have. I said that ‘Pedri has to meet Pedri’, in the figurative sense of gaining confidence. The best version of Pedri we don’t know where he is, because he’s so good. We expect so much from him that it’s infinite.”&lt;/i&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;i&gt;“It has to be the player who takes that step forward, as he has done, to be sure and confident to do the things that only he can do.”&lt;/i&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Though Pedri is a very dynamic player who is immaculate in every phase of the game, it will be very interesting to see how far Spain can progress in the Euros with his brilliance.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;</content:encoded><category>Football</category><category>Spain</category></item><item><title>It&apos;s the Hope that kills you</title><link>https://c0smos.dev/thoughts/hope-is-dead/</link><guid isPermaLink="true">https://c0smos.dev/thoughts/hope-is-dead/</guid><description>Another farewell ruined for Marco Reus as Dortmund somehow lose the 2024 Champions League final to Real Madrid</description><pubDate>Mon, 17 Jun 2024 22:12:22 GMT</pubDate><content:encoded>&lt;p&gt;Last night was a reminder why football can be so cruel at times, no matter how hard you try some things are just inevitable as Dortmund fell short once again at the final hurdle. I can&apos;t imagine how heartbreaking it must be for the passionate fans of Borussia Dortmund to see their team crumble in the second half after dominating Madrid in the first half. Contrary to what people thought Dortmund started the game valiantly looking to press higher up the pitch and played so much better all over the pitch in the initial stages of the game. The backline looked solid, midfielders were winning ground duels and the frontline looked energetic by offering runs in behind. &lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/535x342/7b7e0c533e/screenshot-2024-06-02-152331.jpg&quot; /&gt;&lt;span&gt;First half overview from Sofascore (Green: Dortmund, Purple: Real Madrid)&lt;/span&gt;&lt;/p&gt;&lt;p&gt;But even after a dominant first half display from Dortmund they had nothing to show for it, as missed chances from Karim Adeyemi and Fullkrug proved to be a thorn in their side. Those two missed chances from Adeyemi will definitely haunt him for some time as in a high profile fixture like this it is imperative to be clinical in front of the goal.&lt;/p&gt;&lt;p&gt;But props to Real Madrid as they showed once again why they&apos;re the most fearsome team in Europe as even though they looked below par in the first half, after re-emerging from the tunnel they looked like a different team altogether. And when that first goal went in from the corner I honestly turned off the stream because I knew it was already game over, as teams like Madrid feed on momentum and after that there was no way Dortmund could get back in the game.&lt;/p&gt;&lt;h2&gt;An Emotional Farewell for Reus&lt;/h2&gt;&lt;p&gt;Look up Loyalty in any dictionary/thesaurus and you will definitely see his name, Marco Reus is a name that has been engraved in the hearts and history of Borussia Dortmund where he almost spent his entire youth and professional career. But despite doing &lt;i&gt;&quot;everything right&quot;&lt;/i&gt; as he said himself, the dream of walking away with a major trophy eluded him even in his final season. &lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/1920x1080/7bb0ce31d2/reus_final.webp&quot; /&gt;&lt;span&gt;Reus&apos; final game at the Signal Iduna Park&lt;/span&gt; &lt;/p&gt;&lt;p&gt;If you look at his profile you would expect a player who was a regular starter for the German NT, who won the German POTY twice and the Bundesliga POTY thrice to have a stunning trophy cabinet, but you would be totally surprised to know that &lt;b&gt;he does not have single League Title, UCL trophy or even an International trophy!&lt;/b&gt; This is because he was probably the unluckiest footballer I&apos;ve seen in my time as he narrowly missed out on a lot major tournaments, important fixtures just because he was &lt;b&gt;injury-prone&lt;/b&gt;, the worst happened when he was at his peak but injured his foot in the last friendly before the 2014 World Cup which Germany eventually won. Nevertheless, as I mentioned earlier football can be a bit cruel sometimes but all in all Reus has enjoyed a stellar career at Borussia Dortmund and is signing off as a Club Legend and has immortalized his name in the history books as a loyal club icon.&lt;/p&gt;&lt;p&gt;But at times like what really begs a question is that &lt;b&gt;&lt;i&gt;&quot;Is it really worth hoping for especially after it kills you time and again?&quot; &lt;/i&gt;&lt;/b&gt;&lt;i&gt;   &lt;/i&gt;&lt;/p&gt;</content:encoded></item><item><title>Dread it, Run from it, Man City arrive all the same</title><link>https://c0smos.dev/thoughts/man-city-champions-23-24/</link><guid isPermaLink="true">https://c0smos.dev/thoughts/man-city-champions-23-24/</guid><description>Man City can&apos;t catch a break in the Premier League, as they are the Champions of England once again for a fourth consecutive time.</description><pubDate>Wed, 22 May 2024 20:31:09 GMT</pubDate><content:encoded>&lt;p&gt;How obsessed can one man be to chase absolute perfection is what I think whenever I see Pep Guardiola. Man came to England, as a decorated manager and people still told him that he won&apos;t be able to replicate the same kind of success that he had elsewhere, that Premier League is not a &quot;Farmers League&quot;, pretty funny when you think about them now. He just came in and obliterated every doubt around him and I&apos;ve never seen someone who is unanimously hated by all their rival fans.&lt;/p&gt;&lt;p&gt;Though most of the hate does not directly go to Guardiola, most of it is because people don&apos;t like Man City as a club. They can&apos;t digest the fact that despite having no history they are successful only because of the &quot;Oil Money&quot; put into the club.&lt;/p&gt;&lt;h2&gt;Discrediting Man City&apos;s Success&lt;/h2&gt;&lt;p&gt;Nobody, literally nobody credits Man City for their success, majority of football fans  carry the baton of 115 FFP charges while the other part simply doesn&apos;t want to accept Guardiola&apos;s dominance.  &lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/500x545/8143d68506/8qxx8p.jpg&quot; /&gt;&lt;/p&gt;&lt;p&gt;Honestly, I believe that you cannot deny the fact that Man City would be nowhere near good enough without the Oil Money that was put in, but even then you have to acknowledge the fact that they took great sporting decisions all round. Not just around buying star players, they made every signing work barring a couple of them, nurtured players from their academy and created a positive healthy environment to inspire younger ones.&lt;/p&gt;&lt;p&gt;And as opposed to what anyone says, Premier League is still NOT a Farmer&apos;s League despite City&apos;s unstoppable domination in recent years. The reason I still give Pep the respect he deserves is because even with all the money, resources in the world managers still find a way to fuck it up. At the end of the day you can&apos;t disregard Pep&apos;s genius, the way he manages tough fixtures throughout and keeps his players motivated every season even after winning so much is astounding. The fact that he manages to win every season by the skin of his teeth also shows that the Premier League is still competitive af, the only difference is being consistent and performing well throughout the season.  &lt;/p&gt;</content:encoded></item><item><title>Taking a step back to reflect on life</title><link>https://c0smos.dev/thoughts/taking-a-step-back-in-life/</link><guid isPermaLink="true">https://c0smos.dev/thoughts/taking-a-step-back-in-life/</guid><description>Feeling lost in life, overcoming insecurities and growing ever so calm.</description><pubDate>Wed, 22 May 2024 20:10:41 GMT</pubDate><content:encoded>&lt;p&gt;Life can be pretty overwhelming at times, especially with no sense of certainty or stability it can feel quite challenging. Sometimes there is so much going on, I feel like my brain goes into autopilot at times where I just persistently chase a goal without questioning anything about it. But every now and then, it is good to stop by, take a moment and reflect on life. Reflect on how far you&apos;ve come and recount the mistakes you made along the way. Don&apos;t get me wrong though, &lt;b&gt;I don&apos;t mean to get stuck in the past&lt;/b&gt; or repent over how I could&apos;ve done things differently, it is just a way of questioning your decisions to keep yourself in check.  &lt;/p&gt;&lt;p&gt;For the last 4 or 5 years I&apos;ve been pretty disconnected with the outside world, there are times when I&apos;ve absolutely no idea what is going on. But living solitary also gives you a lot of time to review yourself and makes you less prone to making bad decisions in my opinion. &lt;/p&gt;&lt;h2&gt;Finding your own Moral Compass &lt;/h2&gt;&lt;p&gt;For me upholding my integrity is imperative and above everything else I do, I can&apos;t sleep properly knowing I wronged someone intentionally, &lt;b&gt;mistakes are allowed though because mistakes are genuine.&lt;/b&gt; But having a faulty moral compass doesn&apos;t work with me at all, and this is why even though I&apos;ve changed a lot over the years there are some things that remain constant, some core values that I never want to get rid of. &lt;/p&gt;&lt;p&gt;Though every now and then some event will test your morality in unexpected ways and will make you doubt your integrity. And unlike a regular compass &lt;b&gt;a moral one does not deal in absolutes, &lt;/b&gt;it is subjective pertaining to what you believe in what you think is right. At times like these the best solution for me has always been listening to what people close to me have to say, not seeking validation from people on the outside, rather than from someone close to you who can give you unbiased advice no matter how harsh it might sound. And I&apos;ve been blessed with good people all my life that is probably the only thing I&apos;ve earned, I don&apos;t make a lot of friends but I fully intend to hold on to them and keep them close. Apart from all this the realization of knowing that no matter how hard you try there are some things you can never control/change has helped me grow pretty calm over time and at the end of the day it is all that matters.&lt;/p&gt;</content:encoded></item><item><title>Intro to Thoughts</title><link>https://c0smos.dev/thoughts/intro/</link><guid isPermaLink="true">https://c0smos.dev/thoughts/intro/</guid><description>Welcome to thoughts, a separate place to dump all those thoughts that bug me, share personal experiences, critique on Cinema and much more!</description><pubDate>Wed, 22 May 2024 20:10:30 GMT</pubDate><content:encoded>&lt;p&gt;This is Doge&lt;/p&gt;&lt;p&gt;Doge is not happy, anyways welcome to Thoughts a totally different space where I can write about random things. This is a personal space where I can express my unhinged self and talk about my personal observations and experiences so far. The main reason for separating this from my main blog is mostly because the blogs that I write are focused more on quality, I invest a lot of time reading, scouring the internet and watching related content to make them impeccable and easy to read at the same time. This means I may not be able to consistently write blogs when I&apos;m busy. Whereas &lt;b&gt;this space, is mostly about unfiltered, raw thoughts,&lt;/b&gt; things that bug me at night or when I&apos;m alone. These posts are supposed are to be succinct and quick so that I can write them from anywhere, anytime so don&apos;t expect much quality.&lt;/p&gt;&lt;p&gt;I feel like writing is the second best way to get something off your chest and helps you improve. I used to love writing when I was young but I lost my touch in high school, but now I want to take this opportunity and write about what I learned in life, my opinions, interests and much more. So watch me share my &lt;b&gt;unbiased takes on society, discuss football opinions, critique on cinema, gaming&lt;/b&gt; and everything else. Also I know the current UI doesn&apos;t really suit the type of content and I&apos;m still working on it (I&apos;m horrible at UI designing &lt;span&gt;😪&lt;/span&gt;) so stay tuned!&lt;/p&gt;</content:encoded></item><item><title>End of an Era: Jurgen Klopp</title><link>https://c0smos.dev/blog/end-of-an-era-klopp/</link><guid isPermaLink="true">https://c0smos.dev/blog/end-of-an-era-klopp/</guid><description>Jurgen Klopp&apos;s 9-year stint at Liverpool is coming to an end... Time to look back and reminisce some of the most iconic moments in his Liverpool journey.</description><pubDate>Tue, 21 May 2024 16:55:23 GMT</pubDate><content:encoded>&lt;p&gt;Before getting on with the blog I just want to mention that writing this piece took a long, long time, it was on my mind since Klopp announced his retirement so please even if you’re someone who isn’t really interested in Football try to stick around till the end and maybe you’ll learn something new. For the uninitiated Jurgen Klopp one of world football’s greatest ever manager has announced his retirement after a &lt;b&gt;9-year stint at Liverpool&lt;/b&gt; and this article is basically a short tribute to honor his Liverpool journey, &lt;b&gt;so strap in and enjoy my version of this beautiful story!&lt;/b&gt;&lt;/p&gt;&lt;h1&gt;Intro&lt;/h1&gt;&lt;p&gt;The title of this blog was supposed to be &lt;b&gt;“This is Anfield!”&lt;/b&gt; as if I’m slamming my desk being proven right with Darwin Nunez in the banner image celebrating after scoring a banger against Wolves in their final home game along with Klopp lifting the coveted Premier League trophy and the home fans serenading him by singing &lt;b&gt;“One Kiss” by Dua Lipa.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;What a sight that would have been… but sigh I’m too old to daydream now and certainly don’t believe in fairytales any more. I’ve been watching football for a decent amount of time now and as an Indian it can be hard to keep up with the European leagues especially with the time constraints. I’ve sunk in ungodly amount of hours watching late-night fixtures, managers explain their dogma, players talking shit and much more, but if someone were to ask me what was the favorite moment that I witnessed this would definitely be up there:&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=b5hjqSnliKk&quot; target=&quot;_self&quot;&gt;YT Embed&lt;/a&gt;&lt;/p&gt;&lt;p&gt;This is what legacy looks like, this is what victory sounds like, what passion feels like, the ambience, the aura of this resounding stadium is why we watch football, moments like these transcend the game itself and form perpetual memories for any supporter and this is exactly what Jurgen Klopp has earned &lt;b&gt;Eternal Respect.&lt;/b&gt;&lt;/p&gt;&lt;h1&gt;Inception&lt;/h1&gt;&lt;p&gt;Time to roll back the years and begin this article by going back to where it all started, &lt;b&gt;Klopp’s arrival at Anfield in 2015/16.&lt;/b&gt; I honestly don’t remember this time, as I was not into football back then and I guess it would take a couple more years before I even started taking interest in football. After a horrid start to Borussia Dortmund’s 14/15 season which even saw them lurking around the drop zone at a point, &lt;b&gt;Klopp announced in April that he’ll be leaving the club in the summer.&lt;/b&gt; On the other hand Liverpool also faced a disappointing start to their 15/16 season and had to sack Brendan Rodgers midseason, and just like that action met opportunity and the Liverpool management were somehow able to sign Klopp on a 3-year deal as he was officially announced a few days later.&lt;/p&gt;&lt;h2&gt;Introducing the “Normal One”&lt;/h2&gt;&lt;p&gt;Klopp’s first press conference was &lt;b&gt;imbued with energy and hope,&lt;/b&gt; both of which were nowhere to be found in the Liverpool dressing room in the past one year. Where successful managers came in with inflated egos (Mourinho I’m looking at you &lt;span&gt;&lt;img /&gt;&lt;/span&gt;) with the promise that they will take their team to the apex, Klopp came in as a &lt;b&gt;normal, humble guy&lt;/b&gt; with the hope that he’ll enjoy his work in England as much as he did in Germany and described himself as the &lt;b&gt;“Normal One”&lt;/b&gt;. He said something which stuck by every Liverpool supporter and made them believe once again:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;It’s not so important what people think when you come in, it’s much more important what people think when you leave… and please give us the time to work on it.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;I don’t wanna say we have to wait for the next 20 years… I know when I sit here in 4 years I think we would’ve won 1 title in that time, I’m pretty sure. &lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=J-Re0BihMy4&quot;&gt;https://www.youtube.com/watch?v=J-Re0BihMy4&lt;/a&gt;&lt;span&gt;Klopp’s first press conference in England&lt;/span&gt;&lt;/p&gt;&lt;h2&gt;Building from scraps&lt;/h2&gt;&lt;p&gt;Even though Liverpool miraculously finished second in the league a couple of years ago, they were still lacking star players and &lt;b&gt;a sense of belief that they can achieve something as a team.&lt;/b&gt; A lot of fans had lost hope in the team, the manager and the staff, and there was &lt;b&gt;no sense of identity within the club&lt;/b&gt;, their public perception deteriorated over time and no rival club really saw them as a threat. A slight simmer of hope which fans clung on to also died after the departure of Suarez and Sterling in the coming seasons, which meant another awful start to the season before Klopp arrived and &lt;b&gt;the bottom line was simply that &quot;this squad is nowhere near good enough&quot;&lt;/b&gt; to challenge for titles. The challenge here wasn’t just to manage a below-average side, it was also to induce a psychological shift among the players and fans that they can challenge for titles, this change in mentality as he described was to transform everyone around him from &lt;b&gt;“Doubters to Believers”.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/480x600/914df9e20a/first_xi.png&quot; /&gt;&lt;span&gt;Klopp’s first playing XI at Liverpool&lt;/span&gt;&lt;/p&gt;&lt;p&gt;At this point it was simply a question of &lt;b&gt;Pragmatism over his Footballing Philosophy or the other way around,&lt;/b&gt; and with Klopp’s first game in-charge he made sure his message was loud and clear, that there is only one way and that is his way. And even though he drew his first game away to Tottenham 0-0 he introduced his style of &lt;b&gt;high intensity football&lt;/b&gt; as they covered more ground than they did before in the whole season.&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/624x373/42fbb756e7/bbc_report.jpg&quot; /&gt;&lt;/p&gt;&lt;h1&gt;Klopp’s Footballing Philosophy &amp;amp; Style of Play&lt;/h1&gt;&lt;p&gt;I’ll just start with a quote from Ralf Rangnick about the importance of a coherent Footballing philosophy:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;What is the job of a Football Head Coach or Manager?…&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;To have a clear idea of how my team should play, this can be a bit of Pep Guardiola style or the Diego Simeone style, these are all variations where some coaches like more technical players while some prefer more intense, hardworking players. But what they all have in common is that they exactly know how this kind of football that they want to play, how it looks like… they have in their brains the video of the perfect game and &lt;b&gt;the job of a football coach is to transform this idea into the heads, hearts, brains, veins of your players.&lt;/b&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;For Jurgen Klopp his style of play is in a way a reflection of his own personality as he himself defined as &lt;b&gt;“lively”&lt;/b&gt; and &lt;b&gt;“entertaining”.&lt;/b&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Having memorable games in a row, that people really wanna see the next game, you leave the stadium and you can’t wait to see the next game and for me that is what football should be. And when you can do this very often you will be successful 100 percent.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;- Jurgen Klopp&lt;/p&gt;&lt;/blockquote&gt;&lt;h2&gt;Style of Play: Orchestra vs The Heavy Metal&lt;/h2&gt;&lt;p&gt;This is one of the finest interviews from Jurgen Klopp from when he was in-charge at Borussia Dortmund, where he was asked to draw an analogy between his style of play and Arsene Wenger’s brand of football. This single most iconic line where he contrasts between the two by saying &lt;b&gt;“His style of play is more like an orchestra, passing the ball, organized football… but I like the Heavy Metal more.”&lt;/b&gt; &lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=Qpv0QXZmq5A&quot;&gt;https://www.youtube.com/watch?v=Qpv0QXZmq5A&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;“Heavy Metal Football”&lt;/b&gt; is a term that vividly captures his distinctive style of play, emphasizing &lt;b&gt;intensity, energy, and relentless pressure.&lt;/b&gt; The goal is to create as many chances as possible through persistent counter-pressing to get hold of the ball as soon as you lose it.&lt;/p&gt;&lt;h2&gt;Gegenpressing &amp;amp; Quick transitions&lt;/h2&gt;&lt;p&gt;&lt;b&gt;Gegenpressing&lt;/b&gt; is a German term which loosely translates to &lt;b&gt;Counter-Pressing &lt;/b&gt;which is an imperative part of Klopp’s philosophy. The idea is to press the opponent in numbers higher up the pitch and win the ball back in advanced areas to quickly create quality chances by catching the opposition off guard. But counter-pressing has been a staple part of the game since a very long time, so what makes Klopp’s Gegenpress so distinctive? The key idea of Klopp’s play style here is to disrupt the opponent build-up, force unnecessary errors from the opponent on the ball by quickly closing down on him in numbers so that he can’t find an outlet and &lt;b&gt;eventually lose the ball.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;This quote from Pep Lijnders (Liverpool’s Assistant Coach) really sums it up:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;i&gt;Our idea of pressing is not to force them one way, not to force bad passes our idea of pressing is to &lt;/i&gt;&lt;b&gt;&lt;i&gt;steal the ball,&lt;/i&gt;&lt;/b&gt;&lt;i&gt; to attack and to create chances.&lt;/i&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;In this short clip below Jurgen Klopp himself articulates why he thinks &lt;b&gt;“Gegenpressing is the best playmaker”&lt;/b&gt; and how winning the ball back in advanced positions means creating a good chance is just a matter of one key pass with his approach. &lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=XvHT3BJu7g4&quot;&gt;https://www.youtube.com/watch?v=XvHT3BJu7g4&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Transitions are also a key part of Klopp’s philosophy which explains the various trade-off’s that are involved in this &lt;b&gt;high risk, high reward approach.&lt;/b&gt; Every time you commit numbers forward trying to suffocate the opposition in their own half you run the risk of getting exposed by open spaces in your own half, so what player profiles fit Klopp’s system to minimize this risk and gain maximum reward? This question brings me to my next point…&lt;/p&gt;&lt;h2&gt;Klopp’s Player Profiles&lt;/h2&gt;&lt;p&gt;When thinking about the greatest teams of all times who were triumphant over long spells in football, we often picture World-class technical players who have the ability, the natural gift to be prolific consistently, to influence the game with their silky touches and play near-perfect passes with their immaculate vision. When thinking about midfield trios we often think of &lt;b&gt;Xavi-Iniesta-Busquets&lt;/b&gt; or &lt;b&gt;Modric-Kroos-Casemiro&lt;/b&gt; or even &lt;b&gt;Pirlo-Seedorf-Gattuso&lt;/b&gt;(if you’re a boomer) but what if I tell you a midfield of Jordan Henderson, Gini Wijnaldum, Fabinho, James Milner, Alex-Oxalade Chamberlain and Naby Keita is enough to dominate football at its zenith by winning the Champions League and the Premier League, if someone told me this today I wouldn’t believe them either.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;This might seem odd at first because respectfully none of these players are really creative in the final third but all of them have something in common and that is their &lt;b&gt;work rate,&lt;/b&gt; &lt;b&gt;their aggression&lt;/b&gt; on the pitch, the intent to close down on opponents to win the ball back and that is exactly what Klopp prefers: &lt;b&gt;Highly athletic and hardworking players over technical players &lt;/b&gt;who know how to execute his instructions, players who wear their hearts on their sleeves, players who are persistent pressing machines.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;This is the reason why &lt;b&gt;Energy and Intensity&lt;/b&gt; are the main mantras of a Klopp team and this is what makes them so interesting to watch.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;blockquote&gt;&lt;p&gt;&lt;i&gt;We ran through walls for him… and that was his very least demand, that you work, that you run for him, for the team. And there’s something about that makes you feel at ease as a player… if you give your best the rest kind of takes care of itself.&lt;/i&gt;&lt;/p&gt;&lt;p&gt;&lt;i&gt;- Adam Lallana about Klopp&lt;/i&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;h2&gt;Embracing Chaos over Control&lt;/h2&gt;&lt;p&gt;Just like all the other top teams, the goal is to create an ample amount of chances in every game, but unlike other top teams Jurgen Klopp wasn’t very dogmatic with his approach, where others chose to play with control in high profile games &lt;b&gt;Klopp embraced the unpredictability of football&lt;/b&gt; to disrupt their natural game plan.&lt;/p&gt;&lt;p&gt;In possession phases and in between transitions the unwavering game plan was to quickly get the ball higher up the pitch as fast as possible, which made them &lt;b&gt;one of the most vertical teams in all of Europe.&lt;/b&gt; Even though the idea is pretty single-minded, there are a multitude of ways in which they achieve this: channel balls, through balls, long balls into the box, crosses from wide areas and even balls over the backline, the players were adept at providing service from every part of the field. And when you combine this with prolific forwards you get an everlasting supply of goals.&lt;/p&gt;&lt;h2&gt;Developing World Class Fullbacks&lt;/h2&gt;&lt;p&gt;Another key ingredient of Liverpool’s success comes from developing their world class fullbacks, where other teams rely on their creative players to play more centrally Klopp uses their &lt;b&gt;fullbacks higher up the pitch as wide playmakers&lt;/b&gt; in the form of Trent-Alexander Arnold and Andrew Robertson. This is because the front-three in Klopp’s system is usually very narrow which enables the fullbacks to be brave and work the flanks higher up the pitch. And when these two are at their best, nobody can stop Liverpool from dominating games.&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/1000x530/ba61459706/tactics1.png&quot; /&gt;&lt;span&gt;Robertson and Trent pushing forward in possession whereas the front three is narrow&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/578x813/b097b023d4/robbo_trent.png&quot; /&gt;&lt;span&gt;Andy Robertson and TAA at top in the All Time PL Assists List by defenders.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;If you look at both of their career trajectories none of them were world class players before, Andy Robertson came from Hull City who were relegated into the Championship the year prior to his signing and Trent was just an academy prospect from Liverpool, but both of them flourished under Klopp and formed the &lt;b&gt;best fullback partnership in the modern era.&lt;/b&gt; In fact, Robbo wasn’t even signed as a first choice fullback for Liverpool, he was considered backup for Alberto Moreno who was their regular starter, but after being injured midway through the season, Robertson got his chance and he proved his mettle. From literally nothing he earned his spot in Liverpool’s first team with his &lt;b&gt;work ethic and pressing intensity&lt;/b&gt; and in no time he became a menace on the left flank offensively, constantly swinging in crosses for the frontline, but was also smart and athletic enough to contribute defensively. &lt;/p&gt;&lt;p&gt;This is the reason why I always credit Klopp and his coaching staff on how they adapted their game to get the best out of these players.&lt;/p&gt;&lt;h1&gt;Incredible Man Manager&lt;/h1&gt;&lt;p&gt;We talked about intensity and work rate as the core principles of Klopp’s philosophy, but these things are so easy to talk about for someone watching from the sidelines, it is when you realize that some of the Liverpool players have to play around &lt;b&gt;40–50 club games a season&lt;/b&gt; as well as tend to their international duties. With fixtures coming in thick and fast every week it is hard to give your best and to maintain the same energy levels in each game. So how does Klopp manage that?&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;i&gt;I try everything to be as successful as possible, I live 100% for the boys, with the boys and what we do for the club and all that stuff.&lt;/i&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Jurgen Klopp has time and again emphasized on building a healthy culture within the clubs he has managed, for him football is not just about tactics on a board, he has a much more &lt;b&gt;emotional connect with the players&lt;/b&gt;, his coaching staff and even the people who work at the club. Forming strong interpersonal relationships with the players and giving them the tactical freedom on the pitch means the players wanted to work hard for him, he made them believe in a cause and wanted everyone to express themselves on the pitch.&lt;/p&gt;&lt;h1&gt;Welcome to Anfield, &quot;It’s not over yet&quot;&lt;/h1&gt;&lt;p&gt;Anfield has been the home of Liverpool FC for more than a century now and holds a lot of significance for any Scouser, it is way more than a football stadium, it is a &lt;b&gt;cultural landmark&lt;/b&gt; in Liverpool and for Liverpool FC fans it is their identity. Anfield has also proven to be one of the most hostile atmospheres for any away team and produced a number of historical matches, players and coaches alike have always found it difficult to produce the same kind of performance at Anfield as the ambience is so &lt;b&gt;“electric”&lt;/b&gt;, so &lt;b&gt;“intimidating”&lt;/b&gt; it almost feels as if Liverpool have a twelfth player on the pitch and that is their fans.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=czrH5jfQSO4&quot;&gt;https://www.youtube.com/watch?v=czrH5jfQSO4&lt;/a&gt;&lt;/p&gt;&lt;p&gt;I remember watching this episode and couldn’t help but think how frightening it looks from the perspective of the away players in and out of the stadium, the sight of &lt;b&gt;60,000 fans singing to “You’ll Never Walk Alone”&lt;/b&gt; and chanting for their team in unison regardless of how they are performing, I guess this is why people always say “At Anfield nothing is impossible”. And for Jurgen Klopp this is all he needed as he said: &lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;i&gt;The only reason I’m able to do my job is because the people show so much passion… I know I’m responsible for the performance, but the people are responsible for the atmosphere.&lt;/i&gt;&lt;/p&gt;&lt;p&gt;&lt;i&gt;- Jurgen Klopp&lt;/i&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;An absolute bonkers statistic about the influence of fans can be judged by the fact that since the start of the 2017/18 season, they’ve only lost two (Premier League) games at Anfield in front of fans (Leeds in October 22/23 &amp;amp; Crystal Palace this season)&lt;/p&gt;&lt;p&gt;And without fans, they lost six consecutive league games at Anfield between January and March of 2021 (Burnley, Brighton, City, Everton, Chelsea and Fulham)! This is the biggest proof that fans have had a huge say alongside Klopp in making &lt;b&gt;Anfield an impenetrable fortress&lt;/b&gt;.&lt;/p&gt;&lt;h2&gt;Unleashing Anfield’s true power&lt;/h2&gt;&lt;p&gt;Liverpool’s Champions League run of 2018/19 was one of the most miraculous campaigns I’ve ever witnessed in my time, the whole tournament in fact was marked with memorable moments from start to finish but as the dust settled there is that one match that stands tall and made every Scouser explode with joy, it is that &lt;b&gt;Champions League semi-final night at Anfield against FC Barcelona which was one for the history books.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;As a Barca fan myself even thinking about this match evokes traumatic memories (no cap &lt;span&gt;&lt;img /&gt;&lt;/span&gt;), whenever someone mentions the phrase “Corner taken quickly!” I’m reminded of that dreadful night at Anfield where Barca lost 4–0 despite having the upper hand in the first leg. I remember sleeping early that day thinking that we have a 3–0 lead and there’s no way we lose this game. And when I woke up I was greeted by the most insane comeback possible (moments like these made me question my loyalty as a Barca fan honestly &lt;span&gt;&lt;img /&gt;&lt;/span&gt;).&lt;/p&gt;&lt;p&gt;Barcelona who were firing on all cylinders having the likes of former Liverpool stars Coutinho and Suarez along with an equally star studded roster were looking threatening beyond compare. Though Liverpool were no slouch, it’s just that Barca had the world’s best player as Lionel Messi on their side who was also in red hot form and this matchup was hyped to the moon, and trust me it lived up to it.&lt;/p&gt;&lt;p&gt;I really don’t want to talk about this matchup though because it’s 4:30 A.M. as I’m writing this and I don’t want to cry &lt;span&gt;&lt;img /&gt;&lt;/span&gt;, but you can watch this video where Pep Lijnders breaks down how they made the impossible possible at Anfield:&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=zlwVZTtR0zQ&quot;&gt;https://www.youtube.com/watch?v=zlwVZTtR0zQ&lt;/a&gt;&lt;/p&gt;&lt;h1&gt;Transfer Strategy&lt;/h1&gt;&lt;p&gt;One of the most overlooked aspects of Liverpool’s resurgence under Klopp has been their transfer strategy throughout the years, it is when you know the context you understand why people love teams like Liverpool so much. Since his arrival in midway through 15/16&lt;b&gt; he did not get the liberty to choose his own transfers or have a proper pre-season&lt;/b&gt;, the next year was going to be very crucial. But where rival teams like Man City and Man Utd. were splurging money on marquee signings from top European clubs, Liverpool &lt;b&gt;relied on&lt;/b&gt; &lt;b&gt;signings from mid-table/relegated teams&lt;/b&gt; and even free transfers, but even though these transfers were not met with a lot of hype they were needed to play Klopp’s heavy metal football. And not just that season it was a common theme for the Liverpool management that they weren’t really concerned with signing the best talent, but the emphasis was more on &lt;b&gt;“nurturing talent”&lt;/b&gt;.&lt;/p&gt;&lt;p&gt;Sure they also made some high profile signings along the way, but they were better known for taking players from clubs who didn’t rate them very well, players like Andy Robertson, Alex-Oxalade Chamberlain and Mo Salah all of which were rejected at one point in their career were now thriving under Klopp’s main team. And Klopp once again proved that his decision-making is as astute as ever with Liverpool securing a &lt;b&gt;Champions League spot in their second proper season&lt;/b&gt;, where a new front three announced themselves and Andy Robertson came to light as a world-class left back.&lt;/p&gt;&lt;h2&gt;Building a World Class Front Three&lt;/h2&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/1000x563/0a47081aab/front_three.jpg&quot; /&gt;&lt;/p&gt;&lt;p&gt;We already talked about how Liverpool’s midfield worked hard throughout the game to regain possession and counter-attack quickly, but with any world-class team you need a lethal frontline to finish your chances as at the end of the day the aim of the game is to put the ball in the back of the net. And Liverpool built just that, with &lt;b&gt;Mane, Salah and Firmino&lt;/b&gt; they probably had the most exciting front-three in the world. The fact that these three players took almost no time to adapt to each other’s game is living proof of why some things are just meant to be, having different attributes they complemented each other on their pitch really well and scored a plethora of goals under Klopp.&lt;/p&gt;&lt;p&gt;Bobby Firmino was the first one to arrive at Anfield in 2015 under Brendan Rodgers as an attacking midfielder and was instrumental for Liverpool in their 4–1 victory over Man City in Klopp’s first season, this match highlighted his &lt;b&gt;ability to play upfront instead of Benteke as a false 9&lt;/b&gt; because of his linking ability and since then he’s only gone on to improve his game.&lt;/p&gt;&lt;p&gt;Sadio Mane was the next one to arrive a year later in 2016, he was signed from Southampton as the most expensive African player of his time and even though there were some doubts people knew he would fit right in Klopp’s system. Even though he was signed as a right winger he quickly found his place on the left side of the pitch and in coming years he also played as an &lt;b&gt;inside forward which favors his stronger right foot&lt;/b&gt;, this ability to adapt over the years and still produce massive numbers made him an all-round player. His world class performances have also contributed to one of the best fan memes &lt;span&gt;&lt;img /&gt;&lt;/span&gt; of all time linked below: &lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=2_O5YHX4urE&quot;&gt;https://www.youtube.com/watch?v=2_O5YHX4urE&lt;/a&gt;&lt;/p&gt;&lt;p&gt;I saved the best for the last, as the next one to arrive in 2017 was Liverpool’s club record signing at that time, it was the &lt;b&gt;Egyptian King Mo Salah&lt;/b&gt; and in his opening season he took the whole world by storm. His first season saw him obliterating doubters if there were any, as he scored 44 goals and registered 15 assists across all competitions, won the PL golden boot and broke so many records with every game he played that season that I can’t even write it here, so I’ll just link it down. &lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://www.espn.in/football/story/_/id/37493125/mohamed-salah-record-breaking-first-season-liverpool&quot;&gt;https://www.espn.in/football/story/_/id/37493125/mohamed-salah-record-breaking-first-season-liverpool&lt;/a&gt;&lt;/p&gt;&lt;p&gt;His amazing performances enabled Liverpool to reach the CL final where they eventually lost to Real Madrid, but his effort didn’t go unnoticed as he registered himself as one of the best wingers to grace the Premier league.&lt;/p&gt;&lt;p&gt;The most amazing revelation about this front three was from Ralf Rangnick who had this to say:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;i&gt;Let’s just have a close look at the their(Liverpool) three strikers, they have Salah, Firmino and Mane… three of them from three different countries and all three of them… two of them I had myself (Firmino and Mane), I can tell you all three of them including Mo Salah were &lt;/i&gt;&lt;b&gt;&lt;i&gt;not natural born ball winners when they came to Liverpool.&lt;/i&gt;&lt;/b&gt;&lt;i&gt; They were not the kind of players that people think are “Wow! they pressing machines” no.&lt;/i&gt;&lt;/p&gt;&lt;p&gt;&lt;i&gt;So all that things that happened at Liverpool was the job of the coach and their staff, they way they played in the last 3–4 years on that high level, this intense kind of football shows you what is possible and what can happen if a coach with a mindset and a clear idea of how his team should play.&lt;/i&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;h1&gt;Fan Favourite&lt;/h1&gt;&lt;blockquote&gt;&lt;p&gt;&lt;i&gt;Being a Liverpool manager, it’s a hard gig isn’t it because you have to be the best manager in the most competitive league possible and then the &lt;/i&gt;&lt;b&gt;&lt;i&gt;extra bit in Liverpool is that you have to be a man of the people.&lt;/i&gt;&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;i&gt;- A Liverpool fan (The Anfield Wrap)&lt;/i&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Apart from his managerial ideas Klopp made a name for himself mostly due to his &lt;b&gt;character and personality&lt;/b&gt;, everywhere he worked people were in awe of his &lt;b&gt;infectious positivity&lt;/b&gt; and his boundless passion for the game. He single-handedly won over every fan and turned the atmosphere from nervy to optimistic with his congenial smile regardless of the game’s outcome which makes me think he actually has the best set of teeth I’ve ever seen &lt;span&gt;&lt;img /&gt;&lt;/span&gt;.&lt;/p&gt;&lt;p&gt;I’ve been watching football for a decent amount of time now and even though I’ve seen more triumphant teams like Man City &amp;amp; Real Madrid, I know that Liverpool is the most entertaining football team I’ve witnessed without a shadow of a doubt. In victory and defeat alike they’ve been known to have the most riveting players who give 100% for the manager and for the club. After every game at Anfield he was either seen doing fist pumps when they won or clapping the fans for their unconditional support when they lost.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=XayT2yw7dtY&quot;&gt;https://www.youtube.com/watch?v=XayT2yw7dtY&lt;/a&gt;&lt;/p&gt;&lt;p&gt;As I mentioned Klopp’s presence does not end on the field or after the match, he was very emotionally invested in the culture of each club and it’s people around the city. This is evident by the fact that &lt;b&gt;he received huge farewells&lt;/b&gt; from all the clubs he managed including &lt;b&gt;Mainz, Dortmund and now Liverpool.&lt;/b&gt; All of them were very emotional and heartbreaking for the fans which shows that the work he did will never be forgotten. Also on the the 3rd of November 2022 Klopp was officially awarded the Freedom of the City of Liverpool! which is the highest civic honor bestowed by Liverpool’s mayor and this is what he had to say:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;I think he means more than a football manager to the city because one of my jobs is to try to attract people to come here and invest and many people who I’ve met in the office next door they wanna talk about Jurgen Klopp. &lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;I think &lt;b&gt;he epitomizes the best qualities of this place&lt;/b&gt;, even though he’s not from here… he’s an honorary scouser by the way. The same values and principles that are very much part of the Liverpudlian identity are also Jurgen Klopp’s bedrock.&lt;/p&gt;&lt;/blockquote&gt;&lt;h1&gt;Greatest Modern Day Rivalry&lt;/h1&gt;&lt;p&gt;Like every other great tale, the protagonist needs a proficient villain(metaphorically) someone who can match you for every blow and pushes you to become the best version of yourself. In football many people like to equate this analogy with &lt;b&gt;Messi and Ronaldo&lt;/b&gt;, but in managerial terms this analogy also fits perfectly between &lt;b&gt;Jurgen Klopp and Pep Guardiola&lt;/b&gt; who have been fierce rivals for as long as I can remember.&lt;/p&gt;&lt;h2&gt;Control vs Chaos&lt;/h2&gt;&lt;p&gt;Locked in an intense rivalry since their Bundesliga days, this battle was again rejuvenated as &lt;b&gt;Liverpool and Man City were always the top contenders in the Premier League.&lt;/b&gt; What fascinates me the most is how contrasting their footballing ideologies are, on one hand Guardiola prefers to control games through high possession, organized football using &lt;b&gt;technical players&lt;/b&gt; and on the other hand Klopp favors a more direct approach with more vertical passes, constant pressure to steal the ball back using &lt;b&gt;highly athletic players&lt;/b&gt;. Even though the core idea is to create as many chances as possible, the way they implement it using different player profiles is amazing to watch, regardless of what kind of football you prefer to watch you can’t deny they are definitely the greatest modern day managers to exist.&lt;/p&gt;&lt;p&gt;In terms of H2H record Pep &amp;amp; Klopp have met 30 times in all competitions and Klopp edges past him with &lt;b&gt;12 wins, 11 defeats and 7 draws in total.&lt;/b&gt; Regardless of statistics both of them share a great rapport and praise each other every now and then. In fact, when Klopp announced his retirement Pep told the media that he’ll sleep a bit easier knowing that isn’t there anymore.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=fO4sFBZvhuY&quot;&gt;https://www.youtube.com/watch?v=fO4sFBZvhuY&lt;/a&gt;&lt;/p&gt;&lt;h1&gt;The Grand Finale&lt;/h1&gt;&lt;h2&gt;Running out of Energy?&lt;/h2&gt;&lt;p&gt;Fast forward to recent times, the day is 26th of January 2024, after 21 match weeks Liverpool are sitting comfortably at the top of the Premier League with a lead of 5 points and suddenly Liverpool drop an official statement along with a video of &lt;b&gt;Jurgen Klopp saying that he will be leaving the club at the end of the season.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;I swear to god I was shook to the core just like every other football fan who just heard this news, why on Earth would an elite manager announce his retirement out of nowhere? In the video however he explains that:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;I love absolutely everything about this club, I love everything about the city, I love everything about our supporters, I love the team, I love the staff. I love everything. But that I still take this decision shows you that I am convinced it is the one I have to take.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;It is that I am, how can I say it, &lt;b&gt;running out of energy&lt;/b&gt;. I have no problem now, obviously, I knew it already for longer that I will have to announce it at one point, but I am absolutely fine now. I know that I cannot do the job again and again and again and again.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=mHYsAgAx5I4&quot;&gt;https://www.youtube.com/watch?v=mHYsAgAx5I4&lt;/a&gt;&lt;/p&gt;&lt;p&gt;After listening to what he said in the video it was pretty understandable why he made this decision, you see being a football manager at a top club is certainly of the hardest jobs in the world, considering the amount of press conferences, team meetings, training sessions, personal interviews you have to attend is no joke. Klopp is the kind of manager who wants to &lt;b&gt;give&lt;/b&gt; &lt;b&gt;his 100% every single day&lt;/b&gt; and if he can’t do it anymore then he certainly doesn’t want to feel like a passenger or prove to be a hindrance to Liverpool’s journey ahead.&lt;/p&gt;&lt;h2&gt;The quadruple dream&lt;/h2&gt;&lt;p&gt;Since the day he announced his retirement people especially Liverpool fans were very emotional, for some players he was like a father figure for the club, but if the decision has been made that means players would want to give their all in his final season and what better way to send off your manager with a &lt;b&gt;quadruple in his last season.&lt;/b&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;First up was the &lt;b&gt;Carabao Cup&lt;/b&gt;, most of the heavyweights were knocked out early leaving only Chelsea in the Cup final in February. Even though Chelsea having were having a rough season where they found it hard to be consistent, they were still the favorites to win because of Liverpool’s &lt;b&gt;injury crisis where half of their first team players were unavailable&lt;/b&gt; and young players had to fill in. What happened in this match was nothing short of a spectacle as the game was locked into a stalemate in normal time and was heading into extra time. &lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Right before the 90 minute mark Klopp took an &lt;b&gt;audacious decision&lt;/b&gt; and took out 4 first team players and subbed on 3 players right from the academy to inject some energy into the game. I remember watching this and thinking there’s no way they win now, but the young lads held on to the game and &lt;b&gt;Klopp’s faith in this youngsters was rewarded &lt;/b&gt;as an 118th minute header from their captain Virgil van Dijk was enough to seal the deal. The narrative was insane as Gary Neville described &lt;b&gt;“Liverpool’s kids beat the blue billion pound bottle jobs”&lt;/b&gt; as eight academy graduates walked out with a winner’s medal that night.&lt;br /&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;Falling short in the end&lt;/h2&gt;&lt;p&gt;With the Carabao Cup in hand the quadruple dream was looking feasible with each day passing, &lt;b&gt;until Liverpool hit a block which shattered their dreams altogether.&lt;/b&gt; In close succession they lost the FA Cup quarter final to Man Utd. (should’ve won this one) despite being the better team then went on to lose against Atalanta in Europa league and if that wasn’t enough lost two league games Crystal Palace and most notably their local rivals Everton. After the loss to Everton away from home fans knew that the PL title has slipped from their grasp and Everton fans put salt to their wounds by taunting them with &lt;b&gt;“You lost the league, at Goodison Park”.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;As I said in the beginning I don’t really believe in fairytales or happy endings, but I really wanted Liverpool to win some silverware in Klopp’s final season which they did in the form of a Carabao Cup. In the end though, it wouldn’t matter if he won something or not as he has given priceless memories for fans to cherish about and at the end of the day &lt;b&gt;football is much more about winning and losing&lt;/b&gt; it is about the difference one man made, the impact he had on people all around the world including me, the narrative he set that &lt;b&gt;“Believe and you will achieve”.&lt;/b&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;I didn’t make them believe. I reminded them that it helps when you believe. That’s what I think. Everybody was ready to push the train and that’s what we did for eight-and-a-half years.&lt;/p&gt;&lt;/blockquote&gt;&lt;h1&gt;Final Words&lt;/h1&gt;&lt;p&gt;I feel like I must stop here, honestly I have so much more to say, so many more iconic moments to talk about that I can keep writing for hours. I’ve already spent weeks working on this blog and I really hope you enjoyed reading this piece because editing this whole damn thing was an utter nightmare. If you managed to read till the end, I don’t know how to express my gratitude just know that you’re a real one and I hope you have a great day ahead &lt;span&gt;&lt;img /&gt;&lt;/span&gt;. Ending this blog with one final thing to say:&lt;/p&gt;&lt;p&gt;Danke Jürgen, Danke schön (I hope I wrote that right) and whatever happens &lt;b&gt;You’ll Never Walk Alone.&lt;/b&gt;&lt;/p&gt;&lt;h2&gt;References &amp;amp; Additional Content&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Pep Lijnders book named Intensity (must read): &lt;a href=&quot;https://www.amazon.in/Intensity-Our-Story-Pep-Lijnders/dp/1914197488&quot;&gt;https://www.amazon.in/Intensity-Our-Story-Pep-Lijnders/dp/1914197488&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;James Lawrence Scott video essay (must watch): &lt;a href=&quot;https://www.amazon.in/Intensity-Our-Story-Pep-Lijnders/dp/1914197488&quot;&gt;https://www.youtube.com/watch?v=gQ0oLupAbe0&amp;amp;t=325s&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Liverpool fan documentaries (insanely high production): &lt;a href=&quot;https://www.amazon.in/Intensity-Our-Story-Pep-Lijnders/dp/1914197488&quot;&gt;https://www.youtube.com/watch?v=t2o_41EGckE&amp;amp;list=PLUJS5vI4B14QZ_foMJK_8lhJtYxWK_fKJ&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Jurgen Klopp on his footballing philosophy: &lt;a href=&quot;https://www.amazon.in/Intensity-Our-Story-Pep-Lijnders/dp/1914197488&quot;&gt;https://www.youtube.com/watch?v=MwiULKG7KKg&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The evolution of Klopp’s tactics at Liverpool: &lt;a href=&quot;https://www.amazon.in/Intensity-Our-Story-Pep-Lijnders/dp/1914197488&quot;&gt;https://www.coachesvoice.com/cv/jurgen-klopp-tactics-liverpool/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Liverpool’s official tribute to Klopp: &lt;a href=&quot;https://www.amazon.in/Intensity-Our-Story-Pep-Lijnders/dp/1914197488&quot;&gt;https://www.youtube.com/watch?v=vBnC6hl8WR4&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Players and Coaches on Klopp: &lt;a href=&quot;https://www.amazon.in/Intensity-Our-Story-Pep-Lijnders/dp/1914197488&quot;&gt;https://www.planetfootball.com/quick-reads/13-quotes-to-explain-jurgen-klopps-philosophy-i-always-want-it-loud&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;</content:encoded><category>Football</category><category>Liverpool</category></item><item><title>How I set up my Blogsite quickly with AstroJS &amp; Storyblok</title><link>https://c0smos.dev/blog/how-i-set-up-this-blog-with-astrojs-storyblok/</link><guid isPermaLink="true">https://c0smos.dev/blog/how-i-set-up-this-blog-with-astrojs-storyblok/</guid><description>Setting up your own blog with Astro &amp; Storyblok is easy, let me show you how.</description><pubDate>Tue, 21 May 2024 16:55:13 GMT</pubDate><content:encoded>&lt;p&gt;Been a while since I wrote my last blog, well I was mostly procrastinating thinking what to work on next and finally decided to build my own portfolio website. The only problem you ask... is that we are in 2024 and there are a hell lot of tech stacks available to achieve this, my first thought was to use my new Swiss Army Knife (Next JS) and quickly build a portfolio using a template but then, I read about Astro JS and it completely won me over.&lt;/p&gt;&lt;p&gt;Don&apos;t get me wrong though I still think Next JS is an insanely good framework to work with it&apos;s just sometimes you are better off wielding a fucking lightsaber (Astro JS) than a Swiss Knife. And in this case using Astro JS is more preferable because Astro JS is specifically made for quickly prototyping static sites.&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/672x693/9875ddbd1c/drawing-2024-05-15-00-08-16-excalidraw.png&quot; /&gt;  &lt;/p&gt;&lt;h1&gt;Why Astro JS?&lt;/h1&gt;&lt;p&gt;Before getting into development let us try to understand what is Astro and when exactly should you choose Astro.&lt;/p&gt;&lt;p&gt;From the official docs: &lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;b&gt;&lt;i&gt;Astro&lt;/i&gt;&lt;/b&gt;&lt;i&gt;&lt;span&gt; &lt;/span&gt;&lt;/i&gt;&lt;i&gt;is the web framework for building&lt;/i&gt;&lt;i&gt;&lt;span&gt; &lt;/span&gt;&lt;/i&gt;&lt;b&gt;&lt;i&gt;content-driven websites&lt;/i&gt;&lt;/b&gt;&lt;i&gt;&lt;span&gt; l&lt;/span&gt;&lt;/i&gt;&lt;i&gt;ike blogs, marketing, and e-commerce. Astro is best-known for pioneering a new &lt;/i&gt;&lt;a href=&quot;https://docs.astro.build/en/concepts/islands/&quot;&gt;&lt;i&gt;frontend architecture&lt;/i&gt;&lt;/a&gt;&lt;i&gt;&lt;span&gt; &lt;/span&gt;&lt;/i&gt;&lt;i&gt;to reduce JavaScript overhead and complexity compared to other frameworks. If you need a website that loads fast and has great SEO, then Astro is for you.&lt;/i&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;h2&gt;The tradeoff between Performance &amp;amp; Complexity&lt;/h2&gt;&lt;p&gt;In general most modern web frameworks excel at building applications with complex functionalities such as admin dashboards, role management, HR portals etc. However, this complexity comes at a great cost of performance and requires a whole lot of optimization to deliver content.&lt;/p&gt;&lt;p&gt;But, not every site needs to be complex in order to fulfill your needs, sites which serve to deliver static content such as Blogs, Portfolios, Attractive Landing pages require little to no interactivity with the user to showcase content and this is where Astro JS shines.&lt;/p&gt;&lt;p&gt;Astro JS delivers fast websites by default as mentioned on their docs:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;i&gt;It should be nearly impossible to build a slow website with Astro.&lt;/i&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;This is purely because Astro ships websites with &lt;b&gt;ZERO Javascript by default&lt;/b&gt; to the browser! You heard me right ZERO Javascript meaning everything is pre-rendered on the server-side so it just aims to ship plain HTML to improve performance. As stated in the docs:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;JavaScript is often the culprit, since many phones and lower-powered devices rarely match the speed of a developer’s laptop. &lt;/p&gt;&lt;/blockquote&gt;&lt;h3&gt;But if everything is HTML what about my Interactive components as they rely on Javascript?&lt;/h3&gt;&lt;p&gt;This is where Astro&apos;s magic really kicks in because even though Astro components are rendered on the sever by default, you can really opt in and decide which components are to be rendered on the client side. This helps to ship minimal JavaScript to the browser while maintaining performance and interactivity on your website. The ability to enable different components to use static and dynamic rendering on demand is Astro&apos;s biggest strength &lt;span&gt;&lt;img /&gt;&lt;/span&gt; and this architecture is known as Islands.&lt;/p&gt;&lt;h2&gt;Astro Islands&lt;/h2&gt;&lt;blockquote&gt;&lt;p&gt;&lt;i&gt;The general idea of an “Islands” architecture is deceptively simple: render HTML pages on the server, and inject placeholders or slots around highly dynamic regions […] that can then be “hydrated” on the client into small self-contained widgets, reusing their server-rendered initial HTML.&lt;/i&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;— &lt;i&gt;Jason Miller, Creator of Preact&lt;/i&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;  &lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/903x853/9b1d722d85/astro_islands.jpg&quot; /&gt;&lt;/p&gt;&lt;p&gt;Simply put, think of your website as an &lt;b&gt;archipelago&lt;/b&gt; (a group of islands) where the &lt;b&gt;islands&lt;/b&gt; are your set of different interactive Components floating around in a &lt;b&gt;sea of lightweight, pre-rendered static HTML&lt;/b&gt;. This design pattern allows a developer to use different UI frameworks with Astro, which brings me to my next point... &lt;/p&gt;&lt;h3&gt;Astro does NOT compete with other Frontend-Frameworks instead it works in tandem with them&lt;/h3&gt;&lt;p&gt;The Island architecture allows Astro to support multiple UI frameworks like &lt;a href=&quot;https://react.dev/&quot;&gt;React&lt;/a&gt;,&lt;span&gt; &lt;/span&gt;&lt;a href=&quot;https://preactjs.com/&quot;&gt;Preact&lt;/a&gt;,&lt;span&gt; &lt;/span&gt;&lt;a href=&quot;https://svelte.dev/&quot;&gt;Svelte&lt;/a&gt;,&lt;span&gt; &lt;/span&gt;&lt;a href=&quot;https://vuejs.org/&quot;&gt;Vue&lt;/a&gt;,&lt;span&gt; &lt;/span&gt;and&lt;span&gt; &lt;/span&gt;&lt;a href=&quot;https://www.solidjs.com/&quot;&gt;SolidJS&lt;/a&gt;. Even though developers mostly stick to a particular framework this flexibility allows developers to use all of these at once in the same project!&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/500x756/1e1f8ce381/react_n_svelte.jpg&quot; /&gt;&lt;/p&gt;&lt;pre&gt;&lt;code&gt;---
// Example: Mixing multiple framework components on the same page.
import MyReactComponent from &apos;../components/MyReactComponent.jsx&apos;;
import MySvelteComponent from &apos;../components/MySvelteComponent.svelte&apos;;
import MyVueComponent from &apos;../components/MyVueComponent.vue&apos;;
---
&amp;lt;div&amp;gt;
  &amp;lt;MySvelteComponent /&amp;gt;
  &amp;lt;MyReactComponent /&amp;gt;
  &amp;lt;MyVueComponent /&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;&lt;/h2&gt;&lt;h1&gt;Setting up our Website&lt;/h1&gt;&lt;h2&gt;Portfolio/Landing Page&lt;/h2&gt;&lt;p&gt;Now that we know what Astro Js is:&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/450x295/0e45bbf662/hands-dirty.gif&quot; /&gt;&lt;/p&gt;&lt;p&gt;Right off the bat, we&apos;ll head on to &lt;a href=&quot;https://astro.build/themes/&quot; target=&quot;_self&quot;&gt;Astro Themes&lt;/a&gt; and pick a template to kickstart our project so that we don&apos;t have to build from scratch. Create a new repo for this project and clone it in your local machine then run &lt;span&gt;npm install&lt;/span&gt; to install all the required dependencies from &lt;b&gt;package.json&lt;/b&gt;. Run &lt;span&gt;npm run dev&lt;/span&gt; to start and you&apos;re good to go!&lt;/p&gt;&lt;p&gt;You can simply edit content on the Portfolio/Landing Page to quickly display your personal information and that is all, or you can ditch all or some of the components and add your own custom components to style your website.&lt;/p&gt;&lt;h2&gt;Setting up our Blog Page&lt;/h2&gt;&lt;p&gt;Now this is the more interesting part, before we start designing our Blog Page we first need to choose and set up a CMS. What is a CMS you might ask... don&apos;t worry I gotchu &lt;span&gt;🙃&lt;/span&gt; &lt;/p&gt;&lt;h2&gt;CMS (Content Management System)&lt;/h2&gt;&lt;p&gt;Let&apos;s take a small example to simplify why we need a CMS in the first place, imagine the company you&apos;re working at (with the ongoing recession, we can only imagine &lt;span&gt;😅&lt;/span&gt;) wants to start a blog page, so your boss assembles a team with 3-4 people including you as the sole tech guy. Unfortunately, the rest of your team does not know how to code and have no idea how to write a blog along with HTML for a website, but they are there as creative writers and UI designers. &lt;/p&gt;&lt;p&gt;Now you’re in a state of deadlock where your writers can’t write content on a webpage since they don’t know how to code and even if they did it is hard to write content in plain HTML.&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/1232x588/9532560a0c/drawing-2024-05-12-16-50-36-excalidraw.png&quot; /&gt;&lt;span&gt;Example Scenario&lt;/span&gt;&lt;/p&gt;&lt;p&gt;This is where a CMS comes in, A content management system (CMS) is an application that is used to manage content, allowing multiple contributors to create, edit and publish. It is divided into two main components: &lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;b&gt;CMA (Content Management Application): &lt;/b&gt;This is basically is a media storage cum editor where the author can write content in a user-friendly interface, think of it as Microsoft Word on Steroids.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;b&gt;CDA (Content Delivery Application): &lt;/b&gt;This on the other hand deals with all the behind the scenes stuff that processes all the static content and displays as a webpage.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/838x854/d31f033d5f/drawing-2024-05-12-16-50-36-excalidraw.png&quot; /&gt;&lt;span&gt;Segregating work using a CMS&lt;/span&gt;&lt;/p&gt;&lt;h2&gt;Choosing the Right CMS &lt;/h2&gt;&lt;p&gt;As for picking a CMS, there are a plethora of options available in the market which you can choose from, but for the sake of this blog I&apos;ll be talking about Storyblok which is an excellent Headless CMS option I used for my website. &lt;a href=&quot;https://www.storyblok.com/&quot;&gt;Storyblok&lt;/a&gt;&lt;span&gt; &lt;/span&gt;is a component-based headless CMS that allows you to manage your content using reusable components called &lt;b&gt;Bloks&lt;/b&gt;. Though Astro provides guides for a lot CMS options, it announced Storyblok as its official CMS integration and trust me when I say this, it really is worth it. &lt;/p&gt;&lt;h1&gt;Integrating Astro with Storyblok&lt;/h1&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;First up, we need to sign up for a Storyblok account and set up our own space, I just went with the free plan and it works well. Copy the Preview token from the settings and paste it into your &lt;b&gt;.env&lt;/b&gt; file for further use.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Now we need to install the official Storyblok Integration package using npm&lt;/p&gt;&lt;pre&gt;&lt;code&gt;npm install @storyblok/astro vite&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;Connecting Astro to your Storyblok Space&lt;/h2&gt;&lt;p&gt;To connect our Astro project to our Storyblok space we just need to modify our &lt;b&gt;astro.config.mjs&lt;/b&gt; file as shown below and add the preview token from our &lt;b&gt;.env&lt;/b&gt; file.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;import { defineConfig } from &apos;astro/config&apos;;
import storyblok from &apos;@storyblok/astro&apos;;
import { loadEnv } from &apos;vite&apos;;

const env = loadEnv(&quot;&quot;, process.cwd(), &apos;STORYBLOK&apos;);

export default defineConfig({
  integrations: [
    storyblok({
      accessToken: env.STORYBLOK_TOKEN,
      components: {
        // Add your components here
      },
      apiOptions: {
        // Choose your Storyblok space region
        region: &apos;us&apos;, // optional,  or &apos;eu&apos; (default)
      },
    })
  ],
});&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;Making Bloks in Storyblok&lt;/h2&gt;&lt;p&gt;&lt;b&gt;Bloks&lt;/b&gt; are literally the &quot;building blocks&quot; of our webpage when we incorporate Storyblok and are stored in the &lt;b&gt;Block Library&lt;/b&gt; in your Space. Think of your content on your webpage split into different chunks (Blocks) which you can move around, modify at will and even inject in other blocks.&lt;/p&gt;&lt;p&gt;Right now, we just need three blocks to write content namely &lt;b&gt;BlogPost&lt;/b&gt;, &lt;b&gt;BlogPostList &lt;/b&gt;and the other one being &lt;b&gt;Page. &lt;/b&gt;For every block that we create we need to create its equivalent Astro component, so we create a directory named &lt;b&gt;storyblok &lt;/b&gt;inside pages to store all these components. &lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;b&gt;BlogPost: &lt;/b&gt;This is a Content Type block which basically acts as a layout for our blogs where we can define some fixed fields and even add other nestable blocks such as Banner Images, Tables etc. The fixed fields being &lt;b&gt;title&lt;/b&gt;, &lt;b&gt;description, image&lt;/b&gt; and &lt;b&gt;content.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;pre&gt;&lt;code&gt;src/pages/storyblok/BlogPost.astro

---
import { storyblokEditable, renderRichText } from &apos;@storyblok/astro&apos;
const { blok } = Astro.props
const content = renderRichText(blok.content)
---

&amp;lt;article {...storyblokEditable(blok)}&amp;gt;
  &amp;lt;h1&amp;gt;{blok.title}&amp;lt;/h1&amp;gt;
  &amp;lt;p&amp;gt;{blok.description}&amp;lt;/p&amp;gt;
  &amp;lt;img
      class=&quot;w-full h-[360px] lg:h- [450px] object-cover&quot;
      src={`${blok.image.filename}/m/1600x0`}
   /&amp;gt;
  &amp;lt;Fragment set:html={content} /&amp;gt; 
&amp;lt;/article&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;Note:&lt;/b&gt; Since our content field is of type Richtext, we need to convert it into HTML first therefore we use &lt;span&gt;&amp;lt;Fragment set:html={content} /&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;b&gt;BlogPostList: &lt;/b&gt;This will be a nestable block which will contain all the blocks of the type &lt;b&gt;BlogPost&lt;/b&gt; and will be displayed as cards. It uses the &lt;span&gt;useStoryblokApi&lt;/span&gt; hook to fetch all the stories with the content type of &lt;span&gt;blogPost&lt;/span&gt; and then filter as draft/published as required.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;pre&gt;&lt;code&gt;src/pages/storyblok/BlogPostList.astro

---
import { storyblokEditable } from &apos;@storyblok/astro&apos;
import { useStoryblokApi } from &apos;@storyblok/astro&apos;

const storyblokApi = useStoryblokApi();

const { data } = await storyblokApi.get(&apos;cdn/stories&apos;, {
  version: import.meta.env.DEV ? &quot;draft&quot; : &quot;published&quot;,
  content_type: &apos;blogPost&apos;,
})

const posts = data.stories.map(story =&amp;gt; {
  return {
    title: story.content.title,
    date: new Date(story.published_at).toLocaleDateString(&quot;en-US&quot;, {dateStyle: &quot;full&quot;}),
    description: story.content.description,
    slug: story.full_slug,
  }
})

const { blok } = Astro.props
---

&amp;lt;ul {...storyblokEditable(blok)}&amp;gt;
  {posts.map(post =&amp;gt; (
    &amp;lt;li&amp;gt;
      &amp;lt;time&amp;gt;{post.date}&amp;lt;/time&amp;gt;
      &amp;lt;a href={post.slug}&amp;gt;{post.title}&amp;lt;/a&amp;gt;
      &amp;lt;p&amp;gt;{post.description}&amp;lt;/p&amp;gt;
    &amp;lt;/li&amp;gt;
  ))}
&amp;lt;/ul&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;b&gt;Page: &lt;/b&gt;This is also a nestable type block which will render all the components/blocks inside its &lt;b&gt;body&lt;/b&gt; field. It also adds the &lt;span&gt;storyblokEditable&lt;/span&gt; attributes to the parent element which will allow us to edit the page in Storyblok.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;pre&gt;&lt;code&gt;src/pages/storyblok/Page.astro

---
import { storyblokEditable } from &apos;@storyblok/astro&apos;
import StoryblokComponent from &quot;@storyblok/astro/StoryblokComponent.astro&quot;;
const { blok } = Astro.props
---

&amp;lt;main {...storyblokEditable(blok)}&amp;gt;
  {
    blok.body?.map((blok) =&amp;gt; {
      return &amp;lt;StoryblokComponent blok={blok} /&amp;gt;
    })
  }
&amp;lt;/main&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Now, that we have created our bloks, we just need to handle dynamic routes for each webpage that we create for our blogs. Creating dyamic routes with Astro is fairly simple, we just need to create a new directory named blog inside our pages directory and inside it create a new file called &lt;span&gt;[...slug].astro&lt;/span&gt; with the code below:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;src/pages/blog/[...slug].astro

---
import { useStoryblokApi } from &apos;@storyblok/astro&apos;
import StoryblokComponent from &apos;@storyblok/astro/StoryblokComponent.astro&apos;

export async function getStaticPaths() {
  const sbApi = useStoryblokApi();

  const { data } = await sbApi.get(&quot;cdn/stories&quot;, {
    content_type: &quot;blogPost&quot;,
    version: import.meta.env.DEV ? &quot;draft&quot; : &quot;published&quot;,
  });

  const stories = Object.values(data.stories);

  return stories.map((story) =&amp;gt; {
    return {
      params: { slug: story.slug },
    };
  });
}

const sbApi = useStoryblokApi();
const { slug } = Astro.params;
const { data } = await sbApi.get(`cdn/stories/blog/${slug}`, {
  version: import.meta.env.DEV ? &quot;draft&quot; : &quot;published&quot;,
});

const story = data.story;

---

&amp;lt;html lang=&quot;en&quot;&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;meta charset=&quot;UTF-8&quot; /&amp;gt;
    &amp;lt;title&amp;gt;Storyblok &amp;amp; Astro&amp;lt;/title&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;StoryblokComponent blok={story.content} tags={story.tag_list}/&amp;gt;    {/* Pass on Story taglist along with its content for each Story */}
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This way every request starting with &lt;code&gt;blog/&lt;/code&gt; will be handled by this file, as it maps the request URL to the slug generated by each Story that we have in our Library. We can test this out by making a Test Blog in our Storyblok Content Tab, head over to New Story and select Content type as &lt;b&gt;BlogPost&lt;/b&gt;. You’ll be greeted with a split screen where on the left side you’ll see what is called the &lt;b&gt;Visual Editor&lt;/b&gt; and on the right side a normal editor to write and manage content/media.&lt;/p&gt;&lt;h2&gt;Getting the hang of Storyblok’s Visual Editor &lt;/h2&gt;&lt;p&gt;I feel Visual Editor from Storyblok is their game changing feature, which makes writing content and visualizing it on the fly an enjoyable experience for any writer/developer. &lt;/p&gt;&lt;p&gt;But to set it up you need to change the preview URL from the default one to your localhost with port number where your dev server is running, in my case it is &lt;span&gt;https://localhost:4321/&lt;/span&gt; &lt;/p&gt;&lt;p&gt;&lt;b&gt;Note: &lt;/b&gt;By default the dev server runs on HTTP, however Storyblok requires apps to be served via HTTPS so to bypass this install &lt;span&gt;basicSsl&lt;/span&gt; and run your app in HTTPS. For more details refer this link: &lt;a href=&quot;https://www.storyblok.com/faq/setting-up-https-on-localhost-in-astro&quot; target=&quot;_blank&quot;&gt;https://www.storyblok.com/faq/setting-up-https-on-localhost-in-astro&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/582x429/5b74d9490d/dog_coding.jpg&quot; /&gt;&lt;/p&gt;&lt;p&gt;And just like that we’re done, now we have our own Content Editor platform that we can use to write content, visualize changes in real-time, manage media using Storyblok’s Asset Library and customize every component using custom Bloks.&lt;/p&gt;&lt;h2&gt;Source Code:&lt;/h2&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/NikhilC2209/portfolio&quot;&gt;https://github.com/NikhilC2209/portfolio&lt;/a&gt;&lt;/p&gt;&lt;h2&gt;References:&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Astro Docs:&lt;b&gt; &lt;/b&gt;&lt;a href=&quot;https://github.com/NikhilC2209/portfolio&quot;&gt;https://docs.astro.build/en/getting-started/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Storyblok Integration Guide: &lt;a href=&quot;https://github.com/NikhilC2209/portfolio&quot;&gt;https://docs.astro.build/en/guides/cms/storyblok/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Astro Syntax:&lt;b&gt; &lt;/b&gt;&lt;a href=&quot;https://github.com/NikhilC2209/portfolio&quot;&gt;https://docs.astro.build/en/basics/astro-syntax/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Astro Community Guides: &lt;a href=&quot;https://github.com/NikhilC2209/portfolio&quot;&gt;https://docs.astro.build/en/community-resources/talks/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;RichText vs Markdown: &lt;a href=&quot;https://github.com/NikhilC2209/portfolio&quot;&gt;https://www.ssp.sh/brain/markdown-vs-rich-text/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;</content:encoded><category>Astro</category><category>Javascript</category></item><item><title>Complete Authentication Guide Using Next-Auth v5 in Next.js 14</title><link>https://c0smos.dev/blog/nextjs-14-complete-auth-guide/</link><guid isPermaLink="true">https://c0smos.dev/blog/nextjs-14-complete-auth-guide/</guid><description>Authentication in websites can feel overwhelming, but with Next-Authv5 &amp; Next JS 14 it is that easy.</description><pubDate>Tue, 21 May 2024 16:55:03 GMT</pubDate><content:encoded>&lt;p&gt;So this is part two of a two-part blog I’m writing about implementing Complete Authentication in Next.js 14 using Next-Auth v5. If you haven’t read the first blog I would highly recommend checking it out first: &lt;a href=&quot;https://medium.com/@nikhilc2209/client-side-form-validation-with-zod-useformstate-in-next-js-14-dc011a9c44fb&quot;&gt;&lt;u&gt;https://medium.com/@nikhilc2209/client-side-form-validation-with-zod-useformstate-in-next-js-14-dc011a9c44fb&lt;/u&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;In this blog, I’m going to talk about how easy it is to implement Authentication &amp;amp; OAuth in your Next.js projects using Next-Auth v5.&lt;/p&gt;&lt;h1&gt;&lt;b&gt;Setting up Next-Auth&lt;/b&gt;&lt;/h1&gt;&lt;p&gt;NextAuth.js is an open-source authentication library for Next.js applications which tries to simplify the process of implementing authentication in your Next.js projects by providing a set of utilities, middleware, and strategies for various authentication providers making Authentication hassle-free for developers.&lt;/p&gt;&lt;h2&gt;&lt;b&gt;Installing Next-Auth&lt;/b&gt;&lt;/h2&gt;&lt;p&gt;To include Next-Auth v5 in your Next.js project simply run:&lt;/p&gt;&lt;p&gt;&lt;span&gt;npm install next-auth@beta&lt;/span&gt;&lt;/p&gt;&lt;p&gt;since this version is still in beta and not included in the main release.&lt;/p&gt;&lt;h1&gt;&lt;b&gt;Changes from Next-Auth v4&lt;/b&gt;&lt;/h1&gt;&lt;p&gt;The Next-Auth library has been around for a while now and has undergone major changes recently since the introduction of Next-Auth v5, though these changes introduce a lot of new features the publishers have tried their best to minimize the number of breaking changes.&lt;/p&gt;&lt;p&gt;Here is a summary of most of these changes from the official docs:&lt;/p&gt;&lt;p&gt;&amp;lt;Github Gist goes here&amp;gt;&lt;/p&gt;&lt;p&gt;The most notable change here is that most session related calls are now replaced by a universal &lt;span&gt;auth()&lt;/span&gt; call which can be imported in any Server component and makes the code more readable.&lt;/p&gt;&lt;h1&gt;&lt;b&gt;Adding Auth handler&lt;/b&gt;&lt;/h1&gt;&lt;p&gt;First we’ll set up a auth file which will handle all of our authentication based requests, create this file in the src directory so this way we can easily import it anywhere in our application using absolute imports starting with &lt;span&gt;@&lt;/span&gt; . Below is an example of how our auth.js file should look like. Starting off we have two options either login through Credentials(username/password) or login through an OAuth provider, in our case Google.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;auth.js

import NextAuth from &quot;next-auth&quot;
import GoogleProvider from &quot;next-auth/providers/google&quot;
import CredentialsProvider from &quot;next-auth/providers/credentials&quot;;

export const {
  handlers: { GET, POST },
  auth,
} = NextAuth({
  session: { strategy: &apos;jwt&apos; },

  providers: [

    CredentialsProvider({

      credentials: {
        username: { label: &quot;Username&quot;, type: &quot;text&quot; },
        password: { label: &quot;Password&quot;, type: &quot;password&quot; }
      },

      async authorize(credentials) {
        // authorization logic here
      }

    GoogleProvider({
      clientId: process.env.GOOGLE_CLIENT_ID,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET,
    }),
   ]
})&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;Now we’ll make a folder named&lt;span&gt; &lt;/span&gt;&lt;span&gt;api/auth&lt;/span&gt; inside the app directory which will contain all our logic for authentication. Inside this folder we create a subdirectory named&lt;span&gt; &lt;/span&gt;&lt;span&gt;[...nextauth]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;with a file named route.js.&lt;span&gt; &lt;/span&gt;&lt;b&gt;Interestingly, this naming convention is really important&lt;/b&gt;&lt;span&gt; &lt;/span&gt;because this way every API request beginning with &lt;span&gt;/api/auth/*&lt;/span&gt;&lt;span&gt; &lt;/span&gt;will be handled by the code written in the&lt;span&gt; &lt;/span&gt;&lt;span&gt;[...nextauth]/route.js&lt;/span&gt;&lt;span&gt; &lt;/span&gt;file.&lt;/p&gt;&lt;p&gt;&lt;b&gt;Note:&lt;/b&gt;&lt;span&gt; &lt;/span&gt;In Next-Auth v4 all the authorization logic was handled by the&lt;span&gt; &lt;/span&gt;&lt;span&gt;[...nextauth].js&lt;/span&gt; file, but since the v5 upgrade we have moved our authorization logic to the root of our repository so that it can be easily imported everywhere.&lt;/p&gt;&lt;p&gt;And now this file becomes a 1-line handler for&lt;span&gt; &lt;/span&gt;&lt;span&gt;GET&lt;/span&gt;&lt;span&gt; &lt;/span&gt;and&lt;span&gt; &lt;/span&gt;&lt;span&gt;POST&lt;/span&gt;&lt;span&gt; &lt;/span&gt;requests for those paths.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;app/api/auth/[...nextauth]/route.js

export { GET, POST } from &quot;@/auth&quot;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;/p&gt;&lt;h1&gt;Setting up Credentials Provider&lt;/h1&gt;&lt;p&gt;Setting up Credentials Provider is fairly simple, remember that login form we created in the previous blog, we just need to pass the form data using the &lt;span&gt;signIn&lt;/span&gt; function provided by the &lt;span&gt;next-auth&lt;/span&gt; library and await for a response.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;const response = await signIn(&quot;credentials&quot;, { 
   username: formData.get(&quot;username&quot;),
   password: formData.get(&quot;password&quot;),
   redirect: false, 
  });&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now we can handle this request in the &lt;span&gt;authorize&lt;/span&gt; function in the Credentials Provider we just created. For the purpose of this blog I’m not going to connect to a database, I’ll just use a &lt;span&gt;dummy.json&lt;/span&gt; file to store username &amp;amp; passwords for easier demonstration. So in our &lt;span&gt;authorize&lt;/span&gt; function we’ll just loop through the json file and try to find matching credentials for our username and password.&lt;/p&gt;&lt;p&gt;If we manage to find it we return a user object with &lt;span&gt;user.id&lt;/span&gt; &amp;amp; &lt;span&gt;user.username&lt;/span&gt; and next-auth will create a session using the strategy defined in &lt;span&gt;auth.js&lt;/span&gt; else we just return null indicating that the credentials are incorrect.&lt;/p&gt;&lt;p&gt;Similar to &lt;span&gt;signIn&lt;/span&gt; function Next-Auth also provides a &lt;span&gt;signOut&lt;/span&gt; function which deletes the current session and just like that we can easily login and logout using Next-Auth.&lt;/p&gt;&lt;p&gt;Also, to get our jwt tokens working we need to define a secret key named as &lt;span&gt;NEXTAUTH_SECRET&lt;/span&gt; in our &lt;span&gt;.env&lt;/span&gt; file, this is important because every jwt token has to be signed by a private key which is not meant to be shared. To generate this simply go to your terminal and run &lt;span&gt;openssl rand -base64 32&lt;/span&gt; to create a random 32-bit base64 string which we’ll use as our private key.&lt;/p&gt;&lt;h2&gt;Defining public, protected &amp;amp; auth routes&lt;/h2&gt;&lt;p&gt;Now that we have our login page working we can define our public, private and protected routes, the idea is pretty simple:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;b&gt;Public routes&lt;/b&gt; should always be accessible by everyone, therefore no sensitive data should be kept here and hence no checks are required if user wants to visit this url. For example: home page.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;b&gt;Protected routes&lt;/b&gt; should only be accessible to authenticated users as they might contain user-specific or some other kind of sensitive data, user needs to login to be able to view this and we can verify if the user is logged in by checking if the session token is valid or not. For example: user dashboard page.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;b&gt;Auth routes&lt;/b&gt; refer to login/register pages where the user is supposed to login credentials to verify his identity, these pages should only be visible to the user if the user is not logged in. If the user is logged in we redirect him back to the dashboard page, if the user wants to login using a different ID he needs to logout first to access an auth route. For example: login page.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h1&gt;Adding Middleware config&lt;/h1&gt;&lt;p&gt;Adding a middleware using Next-Auth is recommended and makes our job much easier, when configured the middleware acts as a filter through which all the requests go through. Here we can check which request belongs to which type of route and can handle them accordingly, below is an overview of how Middleware works.&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/828x599/0b169e87cf/middleware_diagram.webp&quot; /&gt;&lt;span&gt;Condensed view of the Middleware module&lt;/span&gt;&lt;/p&gt;&lt;pre&gt;&lt;code&gt;import { auth } from &quot;@/auth&quot;;
import { privateRoutes, 
         authRoutes, 
         DEFAULT_REDIRECT_LOGIN_URL, 
         DEFAULT_REDIRECT_HOME_URL } from &apos;./routes&apos;;

export const config = {
  matcher: [&quot;/((?!.+\\.[\\w]+$|_next).*)&quot;, &quot;/&quot;, &quot;/(api|trpc)(.*)&quot;],
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We also define a routes.js file along with middleware which contains all our private, public and protected routes.&lt;/p&gt;&lt;p&gt;&lt;b&gt;Note:&lt;/b&gt; This crazy looking regex basically matches every single request made to the server, meaning that every request has to go through the middleware checks. You can however define only private routes here, but the former gives you more control and is strongly advisable.&lt;/p&gt;&lt;h2&gt;&lt;b&gt;Using Sessions to render data&lt;/b&gt;&lt;/h2&gt;&lt;p&gt;We can also use the session we created to pass user-specific information such as the username/email of the authenticated user. If we &lt;span&gt;console.log()&lt;/span&gt; the session we just created we see:&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/790x27/6d8231a2a6/session_img.webp&quot; /&gt;&lt;/p&gt;&lt;p&gt;We get the username that we passed on successful login and the expiry time of the current token, we can also add additional information if we want from the &lt;span&gt;authorize&lt;/span&gt; function in &lt;span&gt;auth.js&lt;/span&gt; . We can use this information to display which user is logged in on the dashboard page or any other public/protected route.&lt;/p&gt;&lt;h2&gt;Adding redirects for protected and Auth routes&lt;/h2&gt;&lt;p&gt;The last thing to complete our Credentials Authentication is to set up redirect urls, these will be triggered in &lt;span&gt;middleware.js&lt;/span&gt; based on the type of route and if the user session exists or not.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;// When user is not logged in and tries to access protected routes redirect to login page
export const DEFAULT_REDIRECT_LOGIN_URL = &apos;/login&apos;

// When user is logged in and tries to access login page redirect to dashboard
export const DEFAULT_REDIRECT_HOME_URL = &apos;/dashboard&apos;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And now, we have successfully configured our Credentials Authentication using Next-Auth v5.&lt;/p&gt;&lt;h1&gt;Adding OAuth provider&lt;/h1&gt;&lt;p&gt;For our last act we just need to configure the OAuth providers we talked about so the user has the option of logging in via Credentials or through providers like Google, Github etc. With Next-Auth by our side adding OAuth is really a child’s play, Next-Auth provides a ton of OAuth options, but to keep this blog concise I’ll only demonstrate how to set up GoogleProvider.&lt;/p&gt;&lt;p&gt;From the Next-Auth official docs, we need a &lt;span&gt;GOOGLE_CLIENT_ID&lt;/span&gt; and a &lt;span&gt;GOOGLE_CLIENT_SECRET&lt;/span&gt; to set up our GoogleProvider, we can easily generate these by going to &lt;a href=&quot;https://console.developers.google.com/apis/credentials&quot; target=&quot;_blank&quot;&gt;&lt;u&gt;https://console.developers.google.com/apis/credentials&lt;/u&gt;&lt;/a&gt; and making a new project. From this project we can generate OAuth 2.0 credentials, generate them and paste them in a &lt;span&gt;.env&lt;/span&gt; file and don’t expose them anywhere.&lt;/p&gt;&lt;p&gt;While in development use localhost as your URI and &lt;span&gt;http://localhost:3000/api/auth/callback/google&lt;/span&gt; as your redirect URI, this way every OAuth request is handled by &lt;span&gt;auth.js&lt;/span&gt; file.&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/671x564/71620e87d0/google_oauth.webp&quot; /&gt;&lt;span&gt;Google Console settings for GoogleProvider&lt;/span&gt;&lt;/p&gt;&lt;p&gt;To trigger this we define a button for Google OAuth on our login page and when triggered this again invokes the &lt;span&gt;signIn&lt;/span&gt;&lt;span&gt; &lt;/span&gt;function we used earlier, we pass in the name of our provider along with a &lt;span&gt;callbackUrl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;to redirect the user on successful login.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;signIn(&quot;google&quot;, { callbackUrl: &apos;http://localhost:3000/dashboard&apos;});&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And with that, we have successfully configured our Login through Credentials &amp;amp; setup OAuth in just minutes Congrats! &lt;span&gt;&lt;img /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/360x243/4ac240efe5/great_success.gif&quot; /&gt;&lt;/p&gt;&lt;p&gt;As usual, for all those bums who skipped through the blog and are just interested in the code, I’ve attached the source code below.&lt;/p&gt;&lt;p&gt;&lt;i&gt;I hope you enjoyed reading this and I hope you have a great day! &lt;/i&gt;&lt;span&gt;&lt;img /&gt;&lt;/span&gt;&lt;/p&gt;&lt;h1&gt;&lt;b&gt;Source Code:&lt;/b&gt;&lt;/h1&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/884x500/5c1b62106e/where_code.jpg&quot; /&gt;&lt;a href=&quot;https://github.com/NikhilC2209/Next-Auth-v5&quot;&gt;https://github.com/NikhilC2209/Next-Auth-v5&lt;/a&gt;&lt;/p&gt;&lt;h2&gt;&lt;b&gt;References:&lt;/b&gt;&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;b&gt;Next.js docs:&lt;/b&gt; &lt;a href=&quot;https://nextjs.org/docs&quot;&gt;&lt;u&gt;https://nextjs.org/docs&lt;/u&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;b&gt;Next-Auth v5: &lt;/b&gt;&lt;a href=&quot;https://nextjs.org/docs&quot;&gt;&lt;u&gt;https://authjs.dev/guides/upgrade-to-v5&lt;/u&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;b&gt;Learn about jwt: &lt;/b&gt;&lt;a href=&quot;https://nextjs.org/docs&quot;&gt;&lt;u&gt;https://jwt.io/&lt;/u&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;</content:encoded><category>Javascript</category><category>Next JS</category></item><item><title>Client Side Form Validation with Zod &amp; useFormState() in Next.js 14</title><link>https://c0smos.dev/blog/client-side-form-validation-zod/</link><guid isPermaLink="true">https://c0smos.dev/blog/client-side-form-validation-zod/</guid><description>A small but useful guide to adding Zod in your NextJS projects for Client Side form validation.</description><pubDate>Tue, 21 May 2024 16:54:48 GMT</pubDate><content:encoded>&lt;p&gt;Authentication in Web Apps is a crucial aspect for securing any Web Application and is a must-know for every Full-Stack developer out there. Though implementing Authentication for the first time can be an annoying experience for people(including me!) as there are so many libraries and strategies out there. So this is part one of a two-part blog I’m writing about implementing Complete Authentication in Next.js 14 using Next-Auth v5.&lt;/p&gt;&lt;p&gt;In this blog I’m going to talk about the easiest way in which you can handle form data in react and perform Client-side Validation in minutes using Zod.&lt;/p&gt;&lt;h2&gt;&lt;b&gt;Creating Next app&lt;/b&gt;&lt;/h2&gt;&lt;p&gt;We’ll start by creating a Next-app from the terminal using the below command:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;npx create-next-app@latest&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;b&gt;Note: Make sure you have Node.js 18.17(or higher) installed before running this.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;Similarly if you have Bun pre-installed instead of Node.js run this command:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;bunx create-next-app&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;/p&gt;&lt;h1&gt;&lt;b&gt;Next.js Project Structure&lt;/b&gt;&lt;/h1&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/561x421/ba183e8195/next_dir_structure.jpg&quot; /&gt;&lt;/p&gt;&lt;p&gt;After creating our next app this is what our folder structure looks like for the project, this may seem overwhelming if you’re new to Next.js, but I’ll walk you through how simple this really is:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;b&gt;node-modules:&lt;/b&gt; if you’ve worked with Node.js before then this folder is self-explanatory, but if this is your first rodeo then this is where all the dependencies for our project are stored. Any external dependency we install using npm is imported from here.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;b&gt;public:&lt;/b&gt; this folder is where we store all our static assets including images, videos, gifs or any other kind of documents such as pdf’s etc. &lt;b&gt;which are not subject to change&lt;/b&gt;, since these files are cached to offer better performance.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;b&gt;src:&lt;/b&gt; this folder is the heart of our application as this contains our frontend &amp;amp; backend code in the form of .jsx or .tsx files. The app folder inside this contains all our routes for the application in the form of folders while the components folder contains all the custom reusable UI components such as buttons, cards etc.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Each folder in the app directory denotes a route which can be accessed by going to &lt;span&gt;/folder_name&lt;/span&gt;. The content of this page will be rendered from the file named as &lt;span&gt;page.js&lt;/span&gt; , the file named &lt;span&gt;layout.js&lt;/span&gt; defines a set of styles and UI components which will be rendered in every sub-route.&lt;/p&gt;&lt;p&gt;To know more about other files allowed by the App Router take a look at this from the official docs: &lt;a href=&quot;https://nextjs.org/docs/getting-started/project-structure#routing-files&quot;&gt;&lt;u&gt;https://nextjs.org/docs/getting-started/project-structure#routing-files&lt;/u&gt;&lt;/a&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;b&gt;.env:&lt;/b&gt; this file contains all the secret environment variables such as secret ID’s &amp;amp; keys that are required to confirm your identity. Split this into &lt;span&gt;.env.development.local&lt;/span&gt; and &lt;span&gt;.env.production&lt;/span&gt; and &lt;b&gt;never share this anywhere!&lt;/b&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;b&gt;package.json &amp;amp; package-lock.json:&lt;/b&gt; these files keep track of all the packages installed along their versions along with pre-defined scripts to run our project.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;b&gt;tailwind.config.js: &lt;/b&gt;this file contains all the configurations which tailwind will look for to define any customizations.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Now that we have this out of our way let’s fire up our server in development mode using &lt;span&gt;npm run dev&lt;/span&gt;&lt;/p&gt;&lt;p&gt;PS: this command is a script alias defined in the package.json to run the next server in development mode.&lt;/p&gt;&lt;h1&gt;&lt;b&gt;Adding Form page&lt;/b&gt;&lt;/h1&gt;&lt;p&gt;As discussed above, to create a new route we’ll create a new folder in the app directory named as login containing a file named &lt;span&gt;page.js&lt;/span&gt; . Any code that we write here is rendered on &lt;span&gt;/login&lt;/span&gt; .&lt;/p&gt;&lt;p&gt;We’ll look to create a simple form with Username &amp;amp; Password to login as Credentials or the user can use Google, Github, Reddit &amp;amp; Twitter as OAuth providers.&lt;/p&gt;&lt;p&gt;To quickly build our form page I’m using Tailwind components from Flowbite linked here: &lt;a href=&quot;https://flowbite.com/docs/components/forms/&quot;&gt;&lt;u&gt;https://flowbite.com/docs/components/forms/&lt;/u&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;But you can use any component library you want, it really doesn’t matter.&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/828x224/227d076d18/form.webp&quot; /&gt;&lt;/p&gt;&lt;p&gt;Finally, our page looks like this and now we can start working on it.&lt;/p&gt;&lt;h1&gt;&lt;b&gt;Client side Form Validation&lt;/b&gt;&lt;/h1&gt;&lt;p&gt;This is the first step of validating our form data, this step ensures we perform primitive data validation before sending our data to the server. The easiest way to do this would be by using a third-party library like &lt;b&gt;Zod.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/498x202/1774885aab/zod.gif&quot; /&gt;&lt;/p&gt;&lt;p&gt;Nope, not my Kryptonian friend over here &lt;span&gt;&lt;span&gt;😅&lt;/span&gt;&lt;/span&gt; &lt;/p&gt;&lt;p&gt;Zod is a TypeScript-first schema declaration and validation library and is super-easy to use.&lt;/p&gt;&lt;p&gt;Use &lt;span&gt;npm install zod&lt;/span&gt; to quickly include Zod in your project setup&lt;/p&gt;&lt;p&gt;Zod provides a number of primitive values in its documentation for fields such as strings, numbers, boolean, date etc. We only have two fields both of which use string values so we can create separate schemas for both of them.&lt;/p&gt;&lt;p&gt;Zod also provides a lot of options for string validation out of the box as shown below which we can use along with the option of chaining all these arguments to be processed sequentially.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;z.string().min(5, { message: &quot;Must be 5 or more characters long&quot; });
z.string().max(5, { message: &quot;Must be 5 or fewer characters long&quot; });
z.string().length(5, { message: &quot;Must be exactly 5 characters long&quot; });
z.string().email({ message: &quot;Invalid email address&quot; });
z.string().url({ message: &quot;Invalid url&quot; });
z.string().emoji({ message: &quot;Contains non-emoji characters&quot; });
z.string().uuid({ message: &quot;Invalid UUID&quot; });
z.string().includes(&quot;tuna&quot;, { message: &quot;Must include tuna&quot; });
z.string().startsWith(&quot;https://&quot;, { message: &quot;Must provide secure URL&quot; });
z.string().endsWith(&quot;.com&quot;, { message: &quot;Only .com domains allowed&quot; });
z.string().datetime({ message: &quot;Invalid datetime string! Must be UTC.&quot; });
z.string().ip({ message: &quot;Invalid IP address&quot; });&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;b&gt;A schema is an object which basically contains a set of rules defined with a data type that can be used to validate any kind of data passed to it.&lt;/b&gt;&lt;/p&gt;&lt;pre&gt;&lt;code&gt;const userSchema = z.string()
                    .min(5, { message: &quot;Must be 5 or more characters long&quot; });

const passSchema = z.string()
                    .min(8, { message: &quot;Must be 8 or more characters long&quot; })
                    .regex(new RegExp(&quot;.*[A-Z].*&quot;), { message: &quot;Must conatain one uppercase character&quot; })
                    .regex(new RegExp(&quot;.*\\d.*&quot;), { message: &quot;Must contains one number&quot; })
                    .regex(new RegExp(&quot;.*[`~&amp;lt;&amp;gt;?,./!@#$%^&amp;amp;*()\\-_+=\&quot;&apos;|{}\\[\\];:\\\\].*&quot;), {message: &quot;Must contain one special character&quot;}); &lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;span&gt;Example usage of this schema using &lt;/span&gt;&lt;b&gt;.safeParse()&lt;/b&gt;&lt;span&gt; method:&lt;/span&gt;&lt;/p&gt;&lt;pre&gt;&lt;code&gt;userSchema.safeParse(&quot;user&quot;);         // ❌ { success: false; error: &quot;Must be 5 or more characters long&quot; }
userSchema.safeParse(&quot;Random&quot;);       // ✅ { success: true; data: Return &quot;Random&apos; }

passSchema.safeParse(&quot;pass&quot;);         // ❌ { success: false; error: &quot;Must be 8 or more characters long&quot; }
passSchema.safeParse(&quot;password&quot;);     // ❌ { success: false; error: &quot;Must conatain one uppercase character&quot; }
passSchema.safeParse(&quot;Password&quot;);     // ❌ { success: false; error: &quot;Must contains one number&quot; }
passSchema.safeParse(&quot;Password123&quot;);  // ❌ { success: false; error: &quot;Must contain one special character&quot; }
passSchema.safeParse(&quot;Password123*&quot;); // ✅ { success: true; data: &quot;Password123*&quot; }&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;span&gt;Now once we have defined this we just need to invoke this at every keyStroke for &lt;/span&gt;&lt;b&gt;live validation&lt;/b&gt;&lt;span&gt;, to do this we can use the onChange event to call a function that uses .safeParse() to validate the input data.&lt;/span&gt;&lt;/p&gt;&lt;pre&gt;&lt;code&gt;&amp;lt;input type=&quot;text&quot; name=&quot;username&quot; onChange={checkSchema} /&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h1&gt;&lt;b&gt;Getting Form Data&lt;/b&gt;&lt;/h1&gt;&lt;p&gt;Though there are number of ways of getting form data in React we’ll again talk about the easiest way to get formData in React. Months back React released a new hook called &lt;b&gt;useFormState() &lt;/b&gt;which made interacting with forms a walk in the park.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;const [state, formAction] = useFormState(fn, initialState)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;From the official docs:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;i&gt;The form state is the value returned by the action when the form was last submitted. If the form has not yet been submitted, it is the initial state that you pass.&lt;/i&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;&lt;i&gt;Parameters&lt;/i&gt;&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;fn&lt;/span&gt;  : The function to be called when the form is submitted or button pressed. When the function is called, it will receive the previous state of the form (initially the &lt;span&gt;initialState&lt;/span&gt; that you pass, subsequently its previous return value) as its initial argument, followed by the arguments that a form action normally receives.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;initialState&lt;/span&gt;  : The value you want the state to be initially. It can be any serializable value. This argument is ignored after the action is first invoked.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;&lt;i&gt;Returns&lt;/i&gt;&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span&gt;useFormState&lt;/span&gt; returns an array with exactly two values:&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;i&gt;The current state. During the first render, it will match the &lt;/i&gt;&lt;code&gt;initialState&lt;/code&gt; you have passed. After the action is invoked, it will match the value returned by the action.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;i&gt;A new action that you can pass as the &lt;/i&gt;&lt;span&gt;action&lt;/span&gt; prop to your &lt;span&gt;form&lt;/span&gt; component or &lt;span&gt;formAction&lt;/span&gt; prop to any &lt;span&gt;button&lt;/span&gt; component within the form.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;span&gt;To use this hook we just need to define the useFormState() hook with a function called handleCredentials that will be invoked whenever the form is submitted. Then we can simply use &lt;/span&gt;&lt;span&gt;formData.get(&quot;input&quot;)&lt;/span&gt;&lt;span&gt; to get data from that input field.&lt;/span&gt;&lt;/p&gt;&lt;pre&gt;&lt;code&gt;const handleCredentials = async (prevState, formData) =&amp;gt; {

  const response = await signIn(&quot;credentials&quot;, { 
     username: formData.get(&quot;username&quot;),
     password: formData.get(&quot;password&quot;),
     redirect: false, 
  });
  
  if(!!response.error) {
    setModal(true);
    setErrorMessage(&quot;Incorrect Username or Password&quot;);
    console.log(response.error);
  }
  else {
    router.push(&apos;/dashboard&apos;);
  }
}

const [state, formAction] = useFormState(handleCredentials, initialState);&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;/p&gt;&lt;pre&gt;&lt;code&gt;&amp;lt;form action={formAction}&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;Once we have our verified our credentials on the client side we can then send it to the server for Server side validation to make sure the credentials entered are correct or not. Based on that request we’ll get a response, if the response contains an error message we’ll use a dismissible modal to display it.&lt;/p&gt;&lt;p&gt;So with this we have successfully configured Client-side Validation with Zod. For all those bums who skipped through the blog and are just interested in the code, I’ve attached the source code below.&lt;/p&gt;&lt;p&gt;&lt;i&gt;I hope you enjoyed reading this and have a great day! &lt;/i&gt;&lt;span&gt;&lt;img /&gt;&lt;/span&gt;&lt;/p&gt;&lt;h2&gt;&lt;b&gt;Source Code:&lt;/b&gt;&lt;/h2&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/884x500/5c1b62106e/where_code.jpg&quot; /&gt;&lt;a href=&quot;https://github.com/NikhilC2209/Next-Auth-v5&quot;&gt;https://github.com/NikhilC2209/Next-Auth-v5&lt;/a&gt;&lt;/p&gt;&lt;h2&gt;&lt;b&gt;References:&lt;/b&gt;&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;b&gt;useFormState() hook:&lt;/b&gt; &lt;a href=&quot;https://react.dev/reference/react-dom/hooks/useFormState&quot;&gt;&lt;u&gt;https://react.dev/reference/react-dom/hooks/useFormState&lt;/u&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;b&gt;Zod:&lt;/b&gt; &lt;a href=&quot;https://react.dev/reference/react-dom/hooks/useFormState&quot;&gt;&lt;u&gt;https://zod.dev/&lt;/u&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;b&gt;Flowbite:&lt;/b&gt; &lt;a href=&quot;https://react.dev/reference/react-dom/hooks/useFormState&quot;&gt;&lt;u&gt;https://flowbite.com/docs/getting-started/quickstart/&lt;/u&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;b&gt;Next.js docs:&lt;/b&gt; &lt;a href=&quot;https://react.dev/reference/react-dom/hooks/useFormState&quot;&gt;&lt;u&gt;https://nextjs.org/docs&lt;/u&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;br /&gt;&lt;i&gt;Next up, we’ll look to send form data to the server side and implement Authentication using Next-Auth v5.&lt;/i&gt;&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/498x380/05755858e9/skeletor-until-we-meet-again.gif&quot; /&gt;&lt;/p&gt;</content:encoded><category>Javascript</category><category>Next JS</category></item><item><title>A Disappointing Midseason Barcelona Review: By Numbers</title><link>https://c0smos.dev/blog/barca-midseason-review-2023-24/</link><guid isPermaLink="true">https://c0smos.dev/blog/barca-midseason-review-2023-24/</guid><description>A Midseason review of the most chaotic club in the world: FC Barcelona, by a data driven approach </description><pubDate>Tue, 21 May 2024 16:54:41 GMT</pubDate><content:encoded>&lt;p&gt;If you watch Barcelona at this point, you would understand how aptly this gif epitomizes the current situation of the club, as we’re halfway through the season its looking like another one of those trophyless outings for the Catalan side. After already being out of the Spanish Super Cup &amp;amp; the Copa Del Rey technically they still have 2 major trophies to fight for including La Liga and the Champions League (yeah good luck with that!) but most fans have lost hope with this season. And now with Xavi leaving the club in the summer things are not looking good this season.&lt;/p&gt;&lt;p&gt;&lt;i&gt;Let’s take a closer look at the underlying issues plaguing this club and how might Barca actually turn this around if they can that is.&lt;/i&gt;&lt;/p&gt;&lt;h1&gt;Xavi’s tactics at Barcelona&lt;/h1&gt;&lt;p&gt;Xavi as a player has been a core part of the Spanish national team and the mighty treble winning Barcelona squad which purely dictates his instinct as a manager and how he means to preserve the Barca DNA.&lt;/p&gt;&lt;p&gt;Since his arrival, Xavi has been using his 3–2–2–3 formation in possession or a 2–3–5 shape to great effect as seen below, this shape offers a lot of advantages in build up from the back and chance creation upfront.&lt;/p&gt;&lt;p&gt;This formation consists of a lone striker upfront as Lewandowski, two inside forwards preferably Pedri/Gavi &amp;amp; Gundogan, two wingers/wide players to hug the touchline preferably Balde &amp;amp; Lamine/Raphinha, two pivots preferably Frenkie &amp;amp; Cancelo/Romeu and 3 centrebacks preferably Christensen, Araujo &amp;amp; Kounde.&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/828x466/19f3cbff1f/barca_3-2-5.webp&quot; /&gt;&lt;span&gt;Credit: The Purist Football&lt;/span&gt;&lt;/p&gt;&lt;p&gt;There is absolutely nothing wrong with Xavi’s approach as he has used the same structure to win the league last season by scoring a lot of goals but also maintaining a solid rest defence at the back. Xavi wants his players to equally spread around the pitch and occupy each zone so that every player has passing options around them and can combine easily to escape pressure. Having 5 players in the front line enables them to frequently pull opposition players from the backline to create space with smart off-the ball movements.&lt;/p&gt;&lt;p&gt;With highly technical players deeper such as Frenkie, Gundogan they create loads of chances every game with balls over the top, line breaking passes, swerving crosses. Having Pedri, Gundogan &amp;amp; Gavi between the lines is important as they can easily receive the ball under pressure and turn in tight spaces to play the final pass. With young players such as Balde &amp;amp; Lamine Yamal in wide areas you get runners in-behind as well as players willing to take on fullbacks everytime. And with 3 solid centre-backs in defence they should (in theory) be able to defend well right?&lt;/p&gt;&lt;p&gt;&lt;i&gt;But that is not the case this season, now let’s take a look at some of the issues holding this team back&lt;/i&gt;&lt;/p&gt;&lt;h2&gt;&lt;span&gt;Squad depth&lt;/span&gt;&lt;/h2&gt;&lt;p&gt;After getting rid of Fati, Dembele, Eric Garcia and Ez Abde in the summer window Barcelona were mainly looking to add to their squad depth upfront. But with Barca’s never ending financial struggles, it meant that they can only look for less costly replacements, as a result Oriol Romeu and Inigo Martinez were signed to improve their squad depth at the back.&lt;/p&gt;&lt;p&gt;After showing interest in both João Félix and João Cancelo, Xavi was able to get both on loan, all thanks to them falling out with their respective clubs. Where Félix was looking for a fresh start while Cancelo was purely looking for regular playtime under Xavi. With this Barca capped of a decent summer window as compared to their Spanish rivals who went gung ho to improve their squad as well.&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/2068x810/c197ad6a30/drawing-2024-05-07-22-58-58-excalidraw.png&quot; /&gt;&lt;span&gt;Squad Depth Comparison after the Summer and Winter Transfer Window (Credit: &lt;/span&gt;&lt;a href=&quot;http://Tribuna.com&quot;&gt;&lt;span&gt;Tribuna.com&lt;/span&gt;&lt;/a&gt;&lt;span&gt;)&lt;/span&gt;&lt;/p&gt;&lt;p&gt;After a bothersome start to the season which saw Pedri &amp;amp; Frenkie getting injured and missing some important games in the first half of the season, Barca mostly relied on its youngsters with Lamine Yamal, Gavi and even Fermin getting some minutes every now and then.&lt;/p&gt;&lt;p&gt;Midway through the season they were hit hard by 2 more major injuries on regular first team players: Gavi and Ter Stegen which would see both of them missing the whole 23/24 season. Both of them were integral to Blaugrana’s success and the way they played last year which makes them difficult to replace.&lt;/p&gt;&lt;h1&gt;Lack of finishing in the final 3rd&lt;/h1&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/828x385/955dcf0cc8/fbref_xg.webp&quot; /&gt;&lt;span&gt;Source: fbref&lt;/span&gt;&lt;/p&gt;&lt;p&gt;A simple search query tells us that Barcelona have &lt;b&gt;recorded the most xG in all of Europe’s top 5 leagues&lt;/b&gt; seconded only by Bayern Munich. But their lack of finishing up top has been a major concern as they have failed to hit the mark time and again. Though xG can be deceiving sometimes when teams attempt a lot of shots at goal, but if we look at npxG per shot Barca still ranks the highest in the league along with Girona.&lt;/p&gt;&lt;p&gt;While most top teams have exceeded their xG by scoring more with a fair margin Barcelona have struggled to put the ball in the back of the net, in fact among the top 15 teams in Europe they have the &lt;b&gt;worst (Goals-xG)&lt;/b&gt; stat along with Chelsea &lt;i&gt;(which is obviously not great company at the moment!).&lt;/i&gt;&lt;/p&gt;&lt;h2&gt;Lewandowski’s dwindling numbers&lt;/h2&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/828x552/06e214a046/lewandowski.webp&quot; /&gt;&lt;span&gt;Credit: &lt;/span&gt;&lt;a href=&quot;http://Forbes.com&quot;&gt;&lt;span&gt;Forbes.com&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Robert Lewandowski who has been a stellar striker throughout his career has been struggling to even make an impact this season, he’s been pretty subpar when it comes to linking up, making incisive runs and even controlling the ball in the penalty area.&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/828x412/569cb481c1/lewa_stats.webp&quot; /&gt;&lt;/p&gt;&lt;p&gt;Part of this decline is understandable as he is not in his prime any more and is probably enjoying what might be his last few years of playing at the top level. But, with lack of clear striking options for Barcelona where they loaned out Fati in the summer window, and Ferran &amp;amp; Felix both reluctant to fill the #9 position it has become quite tricky and definitely raises questions on the squad depth.&lt;/p&gt;&lt;p&gt;Though Vitor Roque who was signed in the winter as a long-term prospect might be able to challenge Lewandowski and provide cover for him at this moment.&lt;/p&gt;&lt;h1&gt;&lt;b&gt;Defensive woes&lt;/b&gt;&lt;/h1&gt;&lt;h2&gt;&lt;b&gt;B-A-C-K The defense in Europe?&lt;/b&gt;&lt;/h2&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/720x900/ebca607385/back.webp&quot; /&gt;&lt;span&gt;Credit: Barca Worldwide (Twitter)&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Generally when we think of Barcelona we think of fast free flowing football, a team boasting of highly technical players all over the pitch playing proper Cruyff football. We rarely see Barcelona being associated with the word “defensive solidity”, but that is what happened last season when Barcelona displayed the best defensive record not just in the league but all over Europe!&lt;/p&gt;&lt;p&gt;A big part of this performance was Barcelona’s newly formed Back 4 which consisted of new summer signings Kounde &amp;amp; Christensen along with Araujo and a young academy prospect Alejandro Balde. This back 4 was Xavi’s preferred combination when fit which conceded just 20 goals in 38 league games and 46 goals in 55 matches across all competitions!&lt;/p&gt;&lt;p&gt;But this season, fans have seen a mere hint of past glory achieved by this combination as they’ve failed to keep clean sheets time and again and keep conceding goals to every opposition they play. Defensive errors at the back have become quite common and their defensive structure seems deformed most of the time. But, who is to blame?&lt;/p&gt;&lt;h2&gt;Missing Ter Stegen&lt;/h2&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/828x466/3a317e7997/mats.webp&quot; /&gt;&lt;span&gt;Credit: &lt;/span&gt;&lt;a href=&quot;http://Goal.com&quot;&gt;&lt;span&gt;Goal.com&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Marc Andre Ter-Stegen who has been a loyal servant for the Blaugrana for almost a decade now, a club where he established himself as a world-class keeper and is undoubtedly the best ball-playing goalie in Europe right now is definitely being missed by everyone. He is a core part of the Barcelona defense as he vastly overperformed his expectations last season by keeping the most clean sheets in the league.&lt;/p&gt;&lt;p&gt;But Barca aren’t just missing his spider-like reflexes on the goal line, they are also missing his great passing range and ball playing prowess from the back. His ability to take charge against high pressing sides and playing a pinpoint ball to a free man upfront has been his career highlight and part of what makes him world-class.&lt;/p&gt;&lt;p&gt;Iñaki Peña who is currently filling for him in his absence has been subpar at best with a poor save percentage, he also clearly lacks the skillset Ter-Stegen has and still needs time to develop as a proper first team goalkeeper.&lt;/p&gt;&lt;h2&gt;&lt;b&gt;Conceding early goals&lt;/b&gt;&lt;/h2&gt;&lt;p&gt;Conceding early goals almost every time has been the story so far this season as &lt;b&gt;Barca conceded first in 7 out of 19 games before the winter break&lt;/b&gt;, with most of these goals coming just within 10 minutes post kickoff. As a result of the game state, Barca are bound to chase games every now and then which causes a lot of impatience among the players as they look to create chances as soon as possible.&lt;/p&gt;&lt;p&gt;Though this in theory should work in their favor but it has instead worked against them as an impatient pass during build up leaves them outnumbered at the back leading to a turnover at times when the defense isn’t expecting. This coupled with the fact that Barca have no natural ball-winners in midfield meaning their counterpressing has been pretty wasteful this season.&lt;/p&gt;&lt;h1&gt;Gavi’s absence&lt;/h1&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/828x466/2ef5eca412/gavi.webp&quot; /&gt;&lt;span&gt;Credit: &lt;/span&gt;&lt;a href=&quot;http://Goal.com&quot;&gt;&lt;span&gt;Goal.com&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Of all injuries that have plagued this team, Barca were hit the hardest by Gavi’s absence, yes a 19-year old midfielder from La Masia is literally the &lt;b&gt;heart and soul of this Barcelona team&lt;/b&gt;. His pressing intensity and passion for winning the ball back is unmatched not just in Barca but all over Europe.&lt;/p&gt;&lt;p&gt;The Golden Boy winner is already a regular starter for club &amp;amp; country and has been hailed by Xavi as irreplaceable in his side, despite his short stature he is brimming with confidence and always gives his best in every duel despite the odds. With Barcelona boasting of a highly technical midfield in Frenkie and Gundogan, Gavi provides the bite it needs to dominate every game.&lt;/p&gt;&lt;p&gt;After Busquets’ departure, who was arguably the greatest holding midfielder of his generation and someone who perfectly fit the job description and the style of play at Barcelona, Barca have struggled to match his numbers whether it maybe in defensive actions or the ball-playing abilities he had. Gavi definitely does not match his profile but has stepped up his game alongside Busquets and after his departure in the defensive shift he puts in each game. His ability to man-mark Bellingham and nullify his presence for 70 minutes in the El-Clasico is what amazed me the most this season.&lt;/p&gt;&lt;p&gt;Gavi’s still leading the charts in the number of tackles put in by Barca players despite being out for a major part of the season as shown below. In fact, he’s the #1 ball winner for the team in the attacking 3rd phase of the game and &lt;b&gt;significantly reduces the number of turnovers Barca face.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/828x403/5396abf83e/def_actions_23-24.webp&quot; /&gt;&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/828x415/40f4105733/def_actions_22-23.webp&quot; /&gt;&lt;/p&gt;&lt;p&gt;Gavi is a player I personally adore a lot and he is someone whose mere presence would fix a lot of issues with this team right now. &lt;i&gt;My personal favorite memory of him will always be winning an aerial duel against Wout Weghorst in the Champions League who with all due respect towers over him &lt;/i&gt;&lt;span&gt;&lt;img /&gt;&lt;/span&gt;&lt;i&gt;.&lt;/i&gt;&lt;/p&gt;&lt;h1&gt;The Left-back problem&lt;/h1&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/828x552/be1156f449/balde.webp&quot; /&gt;&lt;span&gt;Credit: Barca Blaugranes&lt;/span&gt;&lt;/p&gt;&lt;p&gt;The left-back role provides a tricky problem for the Catalan side in recent times which was sought to be over until the start of this season but instead grows even deeper. A 19-year old academy prospect Alejandro Balde in his breakout season showed the world why he deserves to be on the first-team sheet ahead of veteran full-back Jordi Alba. Balde exceeded everyone’s expectations and completely obliterated his critics with his stellar performances, despite that he has struggled this season and has definitely failed to make the same impact this year. &lt;b&gt;But is it even Balde’s fault?&lt;/b&gt;&lt;/p&gt;&lt;h2&gt;&lt;b&gt;Balde’s role in Xavi’s system&lt;/b&gt;&lt;/h2&gt;&lt;p&gt;As discussed earlier Xavi wants to stretch the opposition backline by playing 5 forwards when in possession and in this system Balde is the one who provides width on the left hand side of the pitch. This totally suits Balde’s traits as he is a naturally offensive fullback who can easily slip past defenders relying solely on his pace.&lt;/p&gt;&lt;p&gt;Which brings me to my main point: &lt;b&gt;Balde is an offensive fullback and NOT a WINGER! &lt;/b&gt;Look at these stats below comparing wide players from this and last season. Comparing his stats to a proper winger we can see that he attempts less take-ons than actual wingers and instead likes to go around the opposition backline.&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/828x117/affdb8f50a/wide_players_23-24.webp&quot; /&gt;&lt;span&gt;Comparing the two wide players per90 minutes in 23/24 season&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/828x121/6a3e8a7ef8/wide_players_22-23.webp&quot; /&gt;&lt;span&gt;Comparing the two wide players per90 minutes in 22/23 season&lt;/span&gt;&lt;/p&gt;&lt;p&gt;While Balde definitely found success by taking on players last season he has been a shadow of his former self this season and part of the reason is that his game is not about taking on fullbacks or dribbling his way through the opposition backline with the ball. Instead it is more about the off the ball movements and the burst of pace he provides to attack space to play dangerous passes/crosses in the penalty area, which brings me to my final point.&lt;/p&gt;&lt;h2&gt;The left half-space problem&lt;/h2&gt;&lt;p&gt;Well “A picture is worth a thousand words” and if there is any truth to that adage here it is. Look at this image below, this picture clearly explains some issues with this squad that often go unnoticed.&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/716x412/18a279ad12/barca_betis.webp&quot; /&gt;&lt;span&gt;Barca vs Real Betis Matchday 21 (23/24 season)&lt;/span&gt;&lt;/p&gt;&lt;p&gt;This snapshot is from Barca playing against Real Betis which was also Balde’s last game after he was sidelined for the whole season. As we talked about Xavi’s structure before how he wants his players to occupy all zones when in possession so that every player has an outlet to play the ball to, in this case the left-half space is completely empty meaning that &lt;b&gt;Balde has no one to combine with and has to play 1v2 against the two Betis players.&lt;/b&gt; This sequence results in Balde trying to take-on the fullback and playing an uncharacteristic cross which finds no one and possession is lost.&lt;/p&gt;&lt;p&gt;This issue is not limited to a particular sequence in this match, it has become a common theme among all matches this season which hinders Balde’s ability. &lt;b&gt;The major issue here is player profiling&lt;/b&gt;, since the front five in possession consists of Lewandowski and Ferran playing together, both of whom like to drift into central areas and hence create this gap. Last season, this was not a problem as the front five usually consisted of Gavi and Pedri playing as the interiors so the wide players always found it easy to combine with them under pressure. But with Gavi, out of the picture Balde has been totally isolated on the left flank and can barely prove useful.&lt;/p&gt;&lt;h1&gt;Some positives&lt;/h1&gt;&lt;h2&gt;Lamine Yamal&lt;/h2&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/828x517/ed7712c014/yamal.webp&quot; /&gt;&lt;span&gt;Credit: FC Barcelona&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Barcelona have been blessed to have a Lamine Yamal among their ranks as the youngster has been beyond outstanding in his breakthrough season. In fact, Barca have been heavily reliant on this young prodigy this whole season who has lit up the league and is taking on every player left, right and center.&lt;/p&gt;&lt;p&gt;For me personally, Lamine has been the best forward in this team by a long shot and reminds me why I love watching this team. Despite being a 16-year old he is overflowing with confidence and is ready to take on defenders at will, escape from pressure and mature enough to release the ball at the right time. What amazes me is that he still has a lot of time to develop and with regular playing time in the coming seasons I’m thrilled to see what the future holds for him.&lt;/p&gt;&lt;h2&gt;İlkay Gündoğan&lt;/h2&gt;&lt;p&gt;Gündoğan has been nothing short of world-class since the start of this season and has easily become the most consistent player in the squad. While all the other midfielders have been ridiculed with some form of injury in different phases of the season Gündoğan has been Xavi’s go-to-man in the middle of the park.&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/502x280/81d3b17c15/gundo_heatmap.webp&quot; /&gt;&lt;span&gt;Gundogan’s Heatmap this season (Credit: Sofascore)&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Due to his technical brilliance and reliability he has played more minutes than other player in the squad and has contributed in single phase of play. Though his preferred position is as an interior upfront, he has also played as a pivot covering for Frenkie in his absence making him extremely flexible. With the season coming to an end Barca could definitely use his clutch potential and big game mentality to save this season.&lt;/p&gt;&lt;h1&gt;Ending Note&lt;/h1&gt;&lt;p&gt;Though most of these issues and problems discussed above just seem to be small tactical tweaks &amp;amp; psychological issues with the players and their dropping intensity this season, which is not as bad as it looks. Since, Barca don’t necessarily need new personnel they just need to reinvigorate themselves and a couple of good results might just do that.&lt;/p&gt;&lt;p&gt;&lt;i&gt;I hope this blog was worth your time if you made till the end, this took a lot of time &amp;amp; effort and was also my first attempt at bringing my Football knowledge &amp;amp; Data Analysis skills to the table.&lt;/i&gt;&lt;/p&gt;&lt;p&gt;&lt;i&gt;Thank you for reading and have a good day! &lt;/i&gt;&lt;span&gt;&lt;img /&gt;&lt;/span&gt;&lt;/p&gt;</content:encoded><category>Barcelona</category><category>Football</category></item><item><title>Integrating HSV Filtering into our Detection model for Team Identification</title><link>https://c0smos.dev/blog/hsv-filtering-for-team-identification/</link><guid isPermaLink="true">https://c0smos.dev/blog/hsv-filtering-for-team-identification/</guid><description>Adding HSV Filtering to our model to round up our Object Detection project using Yolov8.</description><pubDate>Tue, 21 May 2024 16:54:31 GMT</pubDate><content:encoded>&lt;p&gt;This article is the final part of my 3-part blog series about a project I made recently while learning Computer Vision which is about developing a complete Football Analytics Model using Yolov8 + BotSORT tracking.&lt;/p&gt;&lt;p&gt;Read the previous blogs here:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://medium.com/@nikhilc2209/an-image-annotation-guide-using-roboflow-for-object-detection-a4e30581b5cf&quot;&gt;&lt;u&gt;https://medium.com/@nikhilc2209/an-image-annotation-guide-using-roboflow-for-object-detection-a4e30581b5cf&lt;/u&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://medium.com/@nikhilc2209/an-image-annotation-guide-using-roboflow-for-object-detection-a4e30581b5cf&quot;&gt;&lt;u&gt;https://medium.com/@nikhilc2209/player-and-ball-detection-using-yolov8-botsort-tracking-on-a-custom-dataset-19f84cfdacbf&lt;/u&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;b&gt;Objective:&lt;/b&gt; This blog is about using the annotated frames from our Yolov8 model and further processing them to split the detected players into their respective teams based on their jersey colors using HSV Filtering.&lt;/p&gt;&lt;h1&gt;&lt;b&gt;A Brief look at the HSV Color space&lt;/b&gt;&lt;/h1&gt;&lt;p&gt;The HSV Color space is an alternative to the popular and frequently used RGB Color space and is widely used in Image Processing and Computer Vision tasks. This is because it offers a lot more control in terms of lighting and brightness which is helpful in separating chromatic information from its intensity.&lt;/p&gt;&lt;p&gt;The HSV model stands for &lt;b&gt;H&lt;/b&gt;ue &lt;b&gt;S&lt;/b&gt;aturation and &lt;b&gt;V&lt;/b&gt;alue. Let&apos;s break down these 3 components:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;b&gt;Hue: &lt;/b&gt;This component is responsible for discriminating between different colors. It is measured on a 360 degree scale which starts from red at 0 degree, green at 120 degrees, blue at 240 degrees and loops back again to red at 360 degrees.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;b&gt;Saturation: &lt;/b&gt;Saturation refers to the intensity or purity of the color. A color with high saturation is vivid and rich, while a color with low saturation appears more muted or grayscale. This value is represented as a percentage from 0% to 100%.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;b&gt;Brightness: &lt;/b&gt;The Value component represents the brightness or intensity of the color. This is also represented as a percentage value where 0% corresponds to black, while the maximum value 100% corresponds to the brightest possible color.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/296x222/d607d8dbf3/hsv_3d_rep.webp&quot; /&gt;&lt;span&gt;A condensed view of the HSV Color Space&lt;/span&gt;&lt;/p&gt;&lt;h1&gt;&lt;b&gt;What is HSV Filtering&lt;/b&gt;&lt;/h1&gt;&lt;p&gt;HSV Filtering is the process of isolating and extracting specific colors from an image based on a pre-defined threshold of HSV values also known as masks. Let&apos;s work on a simple image to understand how this works:&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/828x550/3091353a7d/red_flower.webp&quot; /&gt;&lt;span&gt;Input Image&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Let&apos;s use the above image and try to isolate and extract the flower from this image using OpenCV.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;First off we need to convert the given image from BGR to HSV color format, this is because OpenCV loads any image in the BGR format by default (yes, BGR not RGB format!). &lt;b&gt;&lt;i&gt;Read this article from OpenCV&apos;s CEO Satya Mallick about why OpenCV uses the BGR format by default:&lt;/i&gt;&lt;/b&gt; &lt;a href=&quot;https://learnopencv.com/why-does-opencv-use-bgr-color-format/&quot;&gt;&lt;u&gt;https://learnopencv.com/why-does-opencv-use-bgr-color-format/&lt;/u&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Next we need to define masks using the cv2.inRange() function which takes the hsv image as input and a pair of tuples with lower and upper threshold of hsv values for the target color. In our case, the target color is red so we&apos;ll define the masks accordingly.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Another thing to keep in mind is that OpenCV uses a different range for HSV values, for Hue it is between (0-180), for saturation it is between (0-255) and for value it is again between (0-255).&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/720x355/8725070c49/hsv_map.webp&quot; /&gt;&lt;span&gt;Condensed view of the HSV Color map in OpenCV&lt;/span&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;After defining threshold masks using the above image as reference, we can now use the &lt;span&gt;bitwise_and&lt;/span&gt; operator from OpenCV to combine the binary mask with the input image to get the target color as the output.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/2318x580/c9e1191a01/drawing-2024-05-07-22-58-58-excalidraw.png&quot; /&gt;&lt;span&gt;1) Input Image 2) Thresholding Binary mask 3) Output Image after Bitwise_and operation&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;h2&gt;Using a hsv trackbar&lt;/h2&gt;&lt;p&gt;Now we know how to create masks for isolating colors from our target image using the hsv color map, but creating masks for specific non-standard colors can be a bit tricky and can lead to dubious results. Therefore, we can use a hsv trackbar with sliders to change the hsv values of masks in real time to get the best possible output as shown below.&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/487x281/5f237e580e/hsv_trackbar.gif&quot; /&gt;&lt;span&gt;HSV trackbar in action&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;Ref.:&lt;/b&gt;&lt;span&gt; &lt;/span&gt;&lt;a href=&quot;https://stackoverflow.com/questions/44480131/python-opencv-hsv-range-finder-creating-trackbars&quot;&gt;&lt;u&gt;https://stackoverflow.com/questions/44480131/python-opencv-hsv-range-finder-creating-trackbars&lt;/u&gt;&lt;/a&gt;&lt;/p&gt;&lt;h2&gt;&lt;b&gt;Storing all the jersey crops and color codes for each team&lt;/b&gt;&lt;/h2&gt;&lt;p&gt;For the purpose of our project we&apos;ll only be working on teams from the Premier League, we can simply take a crop of jerseys of all the 20 teams and use our trackbar to log these values in a csv file. This way we can store hsv codes for all teams which includes home, away and third kit along with their respective goalkeeper kits.&lt;/p&gt;&lt;p&gt;The main idea behind using this approach to classify detected players into their respective teams is that football matches have teams with easily distinguishable jerseys to avoid clashes due to similar colors. We are simply leveraging this fact to our advantage as this applies to football matches all over the world.&lt;/p&gt;&lt;h1&gt;Getting bounding box and label data from Yolov8 model&lt;/h1&gt;&lt;p&gt;Now that we have built our color filtering module we&apos;ll go back to our tracking module and feed the results from the latter to the former to get the desired output. What we really need is bounding box co-ordinates for each detected player and their confidence score, we can use the bounding box co-ordinates and send crops of players to our hsv filtering module which will run it through all four masks (home &amp;amp; away team jersey, home &amp;amp; away goalkeeper jersey) and compute the output label.&lt;/p&gt;&lt;p&gt;To compute the output label we take masks for both the teams and their goalkeepers, then we can then simply count the number of non-black pixels for each output image resulting from each mask and choose the one with the maximum count.&lt;/p&gt;&lt;p&gt;We can then draw bounding boxes using OpenCV with custom labels that we just computed which represent team names and their confidence scores. Looking at Ultralytics docs, to get the bounding box co-ordinates for each detected object we can use the results Class from each frame and use methods such as &lt;span&gt;boxes.cls()&lt;/span&gt;, &lt;span&gt;boxes.xyxy()&lt;/span&gt;, &lt;span&gt;boxes.conf()&lt;/span&gt; to get the object label, its co-ordinates in xyxy format and its confidence score respectively.&lt;/p&gt;&lt;p&gt;&lt;b&gt;Ref.:&lt;/b&gt; &lt;a href=&quot;https://docs.ultralytics.com/reference/engine/results/&quot;&gt;&lt;u&gt;https://docs.ultralytics.com/reference/engine/results/&lt;/u&gt;&lt;/a&gt;&lt;/p&gt;&lt;h2&gt;Saving results using OpenCV Videowriter&lt;/h2&gt;&lt;p&gt;Now that we have plot our bounding boxes along with their custom labels for each frame we can simply compile these frames to produce the final output in video format. To do this we simply need to use the VideoWriter Class from OpenCV which takes in the following arguments:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;result = cv2.VideoWriter(&apos;filename.avi&apos;, cv2.VideoWriter_fourcc(*&apos;MJPG&apos;), 10, size) 

# cv2.VideoWriter(filename, Codec Compression method, fps, frame_size(w,h))&lt;/code&gt;&lt;/pre&gt;&lt;h1&gt;Final Results&lt;/h1&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/1200x720/3fde2ce9f2/hsv_final.gif&quot; /&gt;&lt;/p&gt;&lt;h3&gt;Source Code:&lt;/h3&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/NikhilC2209/Football_Analytics_CV&quot;&gt;https://github.com/NikhilC2209/Football_Analytics_CV&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/900x675/4940ddc545/honest-work-meme.webp&quot; /&gt;&lt;/p&gt;</content:encoded><category>OpenCV</category><category>Yolov8</category></item><item><title>Player and Ball Detection using Yolov8 + BotSORT tracking on a custom Dataset</title><link>https://c0smos.dev/blog/yolov8-botsort-tracking/</link><guid isPermaLink="true">https://c0smos.dev/blog/yolov8-botsort-tracking/</guid><description>An in depth guide to Yolov8 for Player Detection and Ball tracking.</description><pubDate>Tue, 21 May 2024 16:54:21 GMT</pubDate><content:encoded>&lt;p&gt;This article serves as part two of a 3-part blog series about a project I made recently while learning Computer Vision which is about developing a complete Football Analytics Model using Yolov8 + BotSORT tracking.&lt;/p&gt;&lt;p&gt;Read the previous blog here: &lt;a href=&quot;https://medium.com/@nikhilc2209/an-image-annotation-guide-using-roboflow-for-object-detection-a4e30581b5cf&quot;&gt;&lt;u&gt;https://medium.com/@nikhilc2209/an-image-annotation-guide-using-roboflow-for-object-detection-a4e30581b5cf&lt;/u&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;Objective:&lt;/b&gt;&lt;span&gt; &lt;/span&gt;This blog is about understanding the YOLO architecture and training it on a custom dataset, then fine-tuning the model to get better results and running&lt;span&gt; &lt;/span&gt;inference to understand what works best.&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/828x466/79a57a7b58/ars_vs_lens.webp&quot; /&gt;&lt;/p&gt;&lt;h1&gt;&lt;b&gt;What does YOLO stand for?&lt;/b&gt;&lt;/h1&gt;&lt;p&gt;YOLO(You Only Look Once) is a state-of-the-art Object Detection algorithm which found its fame due to its revolutionary technique of single-pass detection which improved its speed and accuracy to edge over its peers.&lt;/p&gt;&lt;p&gt;YOLOv1 was originally proposed in 2015 by treating Object Detection as a regression problem to compute class probabilities using bounding boxes. It has since undergone a lot of improvements and is currently under the maintained by Ultralytics which have released their latest version Yolov8.&lt;/p&gt;&lt;h1&gt;&lt;b&gt;Brief look at how YOLO algorithm works&lt;/b&gt;&lt;/h1&gt;&lt;p&gt;As the name suggests the YOLO algorithm makes predictions on an image in a single pass, this is better than traditional methods where sliding windows are used over the whole image convolutionally or region proposals are used at multiple locations to localize objects.&lt;/p&gt;&lt;p&gt;The way YOLO does this is by dividing the image into a S x S grid (shown below) where each grid cell is responsible for producing the bounding box and confidence score output.&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/582x599/ac223a4fb5/yolo-grid.png&quot; /&gt;&lt;span&gt;YOLO divides the input image into a S x S grid&lt;/span&gt;&lt;/p&gt;&lt;p&gt;For each grid cell in this image we compute the following:&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/828x341/6f05f8492e/target_data_format.webp&quot; /&gt;&lt;span&gt;Format of our target variable for each grid cell&lt;/span&gt;&lt;/p&gt;&lt;p&gt;The first cell refers to the confidence value which is nothing but a label which decides if any object lies inside the grid cell or not (0 or 1). If the answer is yes, then we move on to predict the values of the bounding box in xywh format where x &amp;amp; y are the co-ordinates of the center of the bounding box and w &amp;amp; h refers to the width and height of the bounding box. And lastly we have our Class Probability Distribution vector which contains prediction scores for each object label ranging between 0 and 1.&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/786x464/805259366e/yolo_output_grid.webp&quot; /&gt;&lt;span&gt;Example output of grid cells using the above image&lt;/span&gt;&lt;/p&gt;&lt;p&gt;If we take a look at the above image we can clearly see that the blue bounding box defines the true boundary of the dog object. When we take a look at the output vector of the green grid cell we are trying to predict the center of the blue bounding box which is our true label.&lt;/p&gt;&lt;p&gt;First we decide if there is an object in that grid cell, since the answer is yes we can continue further and assign the xywh values, you may have noticed that the width and height values exceed the 0 and 1 range. This is because the true label of that whole bounding box spans more than the green grid cell and takes a little more than 3 grid cells for height and width. Lastly, about our class probability scores the green grid cell only contains the doog object so we can easily assign the score 1 to the dog object and 0 to the car object.&lt;/p&gt;&lt;p&gt;Also, if we take a look at the yellow grid cell we know that it does not contain any object so we can simply assign confidence value 0 to its output vector. The &quot;x&quot; denotes the don&apos;t care term which means we can safely neglect all other values from the output vector.&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/600x337/b4ff83e9de/show-me-the-code.jpg&quot; /&gt;&lt;/p&gt;&lt;h1&gt;&lt;b&gt;Training Yolov8 on our custom dataset&lt;/b&gt;&lt;/h1&gt;&lt;p&gt;Now, let&apos;s continue on our Player and Ball Detection Dataset from Roboflow and train it using Yolov8:&lt;/p&gt;&lt;p&gt;&lt;b&gt;Dataset used:&lt;/b&gt; &lt;a href=&quot;https://universe.roboflow.com/nikhil-chapre-xgndf/detect-players-dgxz0&quot;&gt;&lt;u&gt;https://universe.roboflow.com/nikhil-chapre-xgndf/detect-players-dgxz0&lt;/u&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;First we need to install Ultralytics which maintains all the Yolo models:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;pip install ultralytics&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Next we need to set up a yaml file for configuring some training parameters:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;
path: absolute path to dataset (/path/to/dataset)
train: relative path from dataset (/train)
test: relative path from dataset (/test)
val: relative path from dataset (/val)

# Define Classes and their Labels

names:
  0: Ball
  1: Player
  2: Referee&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Next we need to select a Yolov8 model weight to start our training with:&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/743x353/6cd4fcef85/yolo_weights.webp&quot; /&gt;&lt;span&gt;Different versions of the Yolo model with different parameters and use-cases&lt;/span&gt;&lt;/p&gt;&lt;p&gt;For our use case we&apos;ll be using the Yolov8n (Nano) which is the lightest and the fastest model, it isn&apos;t the most accurate model according to the mAP score but with enough training it can yield good results with better fps for video tracking.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;from ultralytics import YOLO
import torch
import os

# Load the YOLOv8 model
model = YOLO(&apos;yolov8n.pt&apos;)

# TRAINING
if __name__ == &apos;__main__&apos;:      
    results = model.train(data=&quot;config.yaml&quot;, epochs=50, patience=5)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;As shown above we can simply load the data from the config.yaml file we set up earlier. We&apos;ll start training for 100 epochs with a patience parameter spanning 10 epochs, this means that if no improvement is seen over 10 continuous epochs the model will stop the training early.&lt;/p&gt;&lt;h2&gt;Upscaling Network Dimensions for better results&lt;/h2&gt;&lt;p&gt;The biggest challenge I faced during training was poor mAP score on the &apos;ball&apos; class and it took me a while to realize what&apos;s going wrong. Yolov8 in general expects the input image to be in a square format and in cases of non-square images it defaults all the images to a width of 640px and corresponding height to maintain the aspect ratio unless specified as shown below.&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/828x466/e9ee3a00b6/1920_img.webp&quot; /&gt;&lt;span&gt;Original Image with 1920x1080 size&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/640x384/0a5679728e/384_img.webp&quot; /&gt;&lt;span&gt;Yolov8 resized image to 384x640 size to maintain aspect ratio&lt;/span&gt;&lt;/p&gt;&lt;h2&gt;&lt;b&gt;Using GIMP to compare size of &quot;Ball&quot; Class&lt;/b&gt;&lt;/h2&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/1192x330/03f78df078/drawing-2024-05-07-22-58-58-excalidraw.png&quot; /&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/188x66/d88aa9b762/gimp1_px.webp&quot; /&gt;&lt;span&gt;Ball size in pixels in the Original image&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/188x68/7c5aeb290e/gimp2_px.webp&quot; /&gt;&lt;span&gt;Ball size in pixels in the Compressed image&lt;/span&gt;&lt;/p&gt;&lt;p&gt;The decrease in quality and size of the object image is easily visible in both the images, therefore leading to poor detection by the model. Increasing the image size while training, results in much better mAP score for not just the &quot;Ball&quot; class but all the other classes as well.&lt;/p&gt;&lt;p&gt;&lt;b&gt;But that means we should always use the highest resolution images for training and inference to get the best results right?&lt;/b&gt; Well the answer depends, since increasing the network dimensions of a model will cause the model to use more training resources and make it slower. Therefore, we need to find a sweet spot to balance both speed and accuracy of our model.&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/582x500/af49cef6db/thanos.png&quot; /&gt;&lt;/p&gt;&lt;p&gt;Also, keep in mind that the network dimensions can only be a multiple of 32 according to the YOLO documentation. Therefore, after some scribbling I decided to use 1088 as the image size keeping in mind that the minimum image size of the smallest object should be greater than 15x15 pixels.&lt;/p&gt;&lt;h1&gt;Model Performance&lt;/h1&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/828x414/8d8e1260a9/yolo_performance_metrics.webp&quot; /&gt;&lt;span&gt;Condensed view of all metrics involved&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Once we finish our training we can view our training/validation results using the metrics shown above, Yolov8 prepares a directory full of graphs and visualizations for each metric in detail along with the model weights, shown above is just a brief summary.&lt;/p&gt;&lt;p&gt;We can now use this training results directory and upload the weights back to Roboflow to deploy as a model, this can be used to assist Image Labeling or can be simply deployed online for public use.&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/401x80/d3e1977731/roboflow_metrics.webp&quot; /&gt;&lt;span&gt;Metrics view on Roboflow&lt;/span&gt;&lt;/p&gt;&lt;h2&gt;Running Inference using our model weights&lt;/h2&gt;&lt;p&gt;Now, instead of using our default weights we can load the best weights that we just trained and use it for tracking video clips along with the BoTSORT tracker available with Ultralytics using the script below.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;import cv2
from ultralytics import YOLO

# Load the YOLOv8 model
# model = YOLO(&apos;yolov8n.pt&apos;)          ### Pre-trained weights

model = YOLO(&apos;runs/detect/train2/weights/best.pt&apos;)          ### weights from trained model

# Open the video file
video_path = r&quot;path/to/video&quot;
cap = cv2.VideoCapture(video_path)

# Loop through the video frames
while cap.isOpened():
    # Read a frame from the video
    success, frame = cap.read()

    if success:
        # Run YOLOv8 tracking on the frame, persisting tracks between frames
        results = model.track(frame, persist=True, show=True, tracker=&quot;botsort.yaml&quot;)

        # Visualize the results on the frame
        annotated_frame = results[0].plot()

        # Display the annotated frame
        cv2.imshow(&quot;YOLOv8 Tracking&quot;, annotated_frame)

        # Break the loop if &apos;q&apos; is pressed
        if cv2.waitKey(1) &amp;amp; 0xFF == ord(&quot;q&quot;):
            break
    else:
        # Break the loop if the end of the video is reached
        break

# Release the video capture object and close the display window
cap.release()
cv2.destroyAllWindows()&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Adding tracking to our detection model will help in tracking objects across continuous frames in a video clip, it achieves this by assigning a unique ID to each detected object. Therefore, it can also help in mapping the trajectory of an object such as a football over time and drawing paths based on its movement across frames.&lt;/p&gt;&lt;h1&gt;Final Results&lt;/h1&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/600x338/539302367f/botsort_tracking_banner.gif&quot; /&gt;&lt;/p&gt;&lt;p&gt;&lt;i&gt;Next up, we&apos;ll discuss how we can separate the detected players into their respective teams using HSV Filtering&lt;/i&gt;&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/498x380/05755858e9/skeletor-until-we-meet-again.gif&quot; /&gt;&lt;/p&gt;</content:encoded><category>OpenCV</category><category>Yolov8</category></item><item><title>An Image Annotation Guide using Roboflow for Object Detection</title><link>https://c0smos.dev/blog/image-annotation-guide-roboflow/</link><guid isPermaLink="true">https://c0smos.dev/blog/image-annotation-guide-roboflow/</guid><description>Do you want to get into Object Detection, but don&apos;t know where to start? This is the perfect starting point </description><pubDate>Tue, 21 May 2024 16:54:10 GMT</pubDate><content:encoded>&lt;p&gt;This article serves as part one of a 3-part blog series about a project I made recently while learning Computer Vision which is about developing a complete Football Analytics Model using Yolov8 + BotSORT tracking.&lt;/p&gt;&lt;p&gt;&lt;b&gt;Objective:&lt;/b&gt; This blog is dedicated to finding relevant data for our project and annotating it in YOLO format using a well-known annotation tool called Roboflow.&lt;/p&gt;&lt;h2&gt;A bit of Backstory&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;The impetus of starting this project comes from sitting idle at home watching football after finishing my undergrad and reading into how much influence data has had in the Sports ecosystem in recent years.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;From scouting to keep track of player profiles to using a dedicated team of football analysts to make tactical reports for the managerial team, data has played a huge role in the past decade.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Around the same time I also started reading into different Computer Vision architectures and implementing them from scratch to get a better understanding about their evolution and thought process behind the changes and differences between them.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;While reading about Object Detection using the YOLO architecture, I decided to put my knowledge to use and started working on this project.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;i&gt;Now, that we have our objective out of the way let&apos;s dig in to the Main Course.&lt;/i&gt;&lt;/p&gt;&lt;h1&gt;Collecting Data&lt;/h1&gt;&lt;p&gt;Data Sources:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;DFL - Bundesliga Data Shootout from Kaggle, this data source contains clips from Bundesliga matches provided publicly by DFL. Data contains both short clips and long full match recordings. Link: &lt;a href=&quot;https://www.kaggle.com/competitions/dfl-bundesliga-data-shootout/data&quot;&gt;&lt;u&gt;https://www.kaggle.com/competitions/dfl-bundesliga-data-shootout/data&lt;/u&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;SoccerNet: SoccerNet is a large-scale dataset for soccer video understanding, it consists of a large array of tasks based on video data taken from major European leagues. SoccerNet also has its own python package with rich documentation for ease of use. Link: &lt;a href=&quot;https://www.kaggle.com/competitions/dfl-bundesliga-data-shootout/data&quot;&gt;&lt;u&gt;https://www.soccer-net.org/data&lt;/u&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Scraping data through Youtube highlights of major leagues from their official channels by directly importing them through Roboflow or using cli tools to download them.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Using self-recorded clips of more recent matches from the Top 5 leagues for clearer quality.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Using clips from games such as Pro Evolution Soccer and FIFA to add diversity to our dataset and make our model more robust. Another advantage here is that we can select the camera angle of our liking to get better, less clustered images.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;Choosing the right Annotation Tool&lt;/h2&gt;&lt;p&gt;Roboflow, CVAT, MakeSense are some of the most popular Computer Vision Annotation Tools out there.&lt;/p&gt;&lt;p&gt;I chose Roboflow and quickly got on board with most of its functionality, from annotating images to Model Deployment. Its rich documentation and highly curated blogs makes it easy for newbies to understand the workflow manage such projects easily.&lt;/p&gt;&lt;h1&gt;Creating a new project dataset and Image Annotation&lt;/h1&gt;&lt;p&gt;Since most of our data is in the form of video clips we can simply upload all of them to our project page to create a new dataset. Roboflow provides tons of ways to upload data from local to cloud storages and even from existing applications with annotated data. On top of this it also has a colossal data library known as the &quot;Roboflow Universe&quot; which consists of all publicly available projects&apos; dataset.&lt;/p&gt;&lt;p&gt;While uploading video clips we can also sample the video by frame rate of our choice to manage the size of the dataset. This is particularly useful while uploading longer video clips.&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/600x581/113df120cb/roboflow_frame_rate.gif&quot; /&gt;&lt;span&gt;Easily control dataset size by changing the framerate&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Another area where Roboflow outshines its peers is by having the added functionality to divide image annotation tasks into groups and easily manage them among teammates if you&apos;re working in a group. You can also outsource labeling but it is a paid feature.&lt;/p&gt;&lt;p&gt;&lt;i&gt;Now that we have all the data that we need,&lt;/i&gt;&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/450x295/0e45bbf662/hands-dirty.gif&quot; /&gt;&lt;/p&gt;&lt;p&gt;Defining Classes and Bounding Boxes&lt;/p&gt;&lt;p&gt;For our use case we define three classes namely:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Label 0 -&amp;gt; Ball&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Label 1 -&amp;gt; Player&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Label 2 -&amp;gt; Referee&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/800x477/d95c717ab5/roboflow_annotator.gif&quot; /&gt;&lt;span&gt;Robowflow&apos;s bounding box tool in action&lt;/span&gt;&lt;/p&gt;&lt;p&gt;We’ll simply use Robobflow&apos;s bounding box tool to to draw rectangles around objects and label them accordingly. But this task requires a lot of manual work since each image has around 20-25 labels.&lt;/p&gt;&lt;p&gt;&lt;i&gt;Now, let&apos;s look into how we can alleviate this workload using Roboflow&apos;s inbuilt features&lt;/i&gt;&lt;/p&gt;&lt;h1&gt;Label Assist&lt;/h1&gt;&lt;p&gt;One of the most incredible features Roboflow offers is the Label Assist, this makes annotation so much easier and gives insights into where your model might be lacking.&lt;/p&gt;&lt;p&gt;But to use this we need to manually annotate some of the images in our dataset. After annotating around 100–150 images manually we have two options, either use the existing annotated images to train a model locally and upload the model weights to Roboflow or use Roboflow&apos;s native state-of-the-art model to label our images using Roboflow credits.&lt;/p&gt;&lt;p&gt;I chose the former option and trained the small subset of annotated images using Yolov8n (Nano) which is the smallest model. The resultant model was imperfect with a mAP score of mere 57.3% but it proved to be a good starting point for annotating other images.&lt;/p&gt;&lt;p&gt;Once we upload these custom weights back to Roboflow we&apos;re all set to use our Label Assist feature and make the rest of our work easier.&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/633x432/1d7b83976c/label_assist.webp&quot; /&gt;&lt;span&gt;Now we&apos;re all set to use Label Assist to annotate the rest of our images&lt;/span&gt;&lt;/p&gt;&lt;h1&gt;Generate a new Version of the Dataset&lt;/h1&gt;&lt;p&gt;While exporting our dataset we need to generate a new version of our dataset with all the Pre-requisite steps.&lt;/p&gt;&lt;p&gt;These steps include using a Train/Val/Test split of our choice, adding Pre-processing steps such as grayscaling or resizing all images before using them for training our model.&lt;/p&gt;&lt;p&gt;Another useful step is to add an augmentation step which increases the diversity of dataset by a manifold. This step can help create new training examples from a base image to either increase the size of our dataset if it is too small or add random effects to a base image in every batch governed by a probability factor.&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/828x408/d6100fee0f/augmentation.webp&quot; /&gt;&lt;span&gt;An example on variations produced during Data augmentation&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Since, this task does not require any changes in color/contrast or flipping, I decided against adding an augmentation step. The only augmentation step useful in our scenario might be random cropping but I still went with the base images.&lt;/p&gt;&lt;p&gt;Once we&apos;ve generated our dataset we&apos;re good to go, now we can use this dataset to train our Yolov8 model.&lt;/p&gt;&lt;p&gt;&lt;b&gt;Dataset Link:&lt;/b&gt; &lt;a href=&quot;https://universe.roboflow.com/nikhil-chapre-xgndf/detect-players-dgxz0&quot;&gt;&lt;u&gt;https://universe.roboflow.com/nikhil-chapre-xgndf/detect-players-dgxz0&lt;/u&gt;&lt;/a&gt;&lt;/p&gt;&lt;h1&gt;Downloading Dataset in YOLOv8 format&lt;/h1&gt;&lt;p&gt;Roboflow provides a multitude of formats to export your data into, since we&apos;re working with Yolov8 we can simply select it while exporting the respective version of our dataset.&lt;/p&gt;&lt;p&gt;Either download directly using a zip file or use terminal commands or use the Roboflow api key to run a script to download the dataset. After downloading the dataset the data is organized separately by images and labels as shown below.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;+ - dataset
  |
  + - val
  + - test
  + - train
    |
    + images
    |
    + labels&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;i&gt;We will further discuss about the YOLOv8 architecture and its own labels format in detail in the next blog where we will train our own model and run inference.&lt;/i&gt;&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/498x380/05755858e9/skeletor-until-we-meet-again.gif&quot; /&gt;&lt;/p&gt;</content:encoded><category>Roboflow</category><category>Yolov8</category></item><item><title>Arsenal pull off a rare scrappy win against City at the Emirates</title><link>https://c0smos.dev/blog/arsenal-win-against-city-at-the-emirates/</link><guid isPermaLink="true">https://c0smos.dev/blog/arsenal-win-against-city-at-the-emirates/</guid><description>Arsenal have finally broken the pattern and defeated their pesky rivals 1-0 in a dramatic fashion to go top of the league. Here&apos;s how the game unfolded</description><pubDate>Tue, 21 May 2024 16:53:55 GMT</pubDate><content:encoded>&lt;p&gt;&lt;i&gt;Arsenal have finally broken the pattern and defeated their pesky rivals 1-0 in a dramatic fashion to go top of the league. Here&apos;s how the game unfolded:&lt;/i&gt;&lt;/p&gt;&lt;h1&gt;How both teams lined up:&lt;/h1&gt;&lt;p&gt;Both Arsenal and City lined up in a back 4 with traditional fullbacks as opposed to using inverted fullbacks and used a double pivot system during their build up phase.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Both teams almost canceled out each other by playing quite narrow and protecting the center of the pitch, making sure the pivots are not allowed easy build up through the middle.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;As a result City and Arsenal both often relied on their fullbacks to provide width where more space was available.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/828x500/b26e3478e4/1_vs-fjar8yz8c4wpkycsbvg.webp&quot; /&gt;&lt;span&gt;Arsenal vs Man City on a tactical board&lt;/span&gt;&lt;/p&gt;&lt;p&gt;An interesting tweak in City&apos;s system was made in the absence of Rodri where Guardiola deployed Bernardo deep, playing as a 6 forming a double pivot with Kovacic during build up while Rico Lewis was pressing higher up the field alongside Erling Haaland when out of possession.&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/828x411/e85f023595/rico_lewis.webp&quot; /&gt;&lt;span&gt;Rico Lewis almost playing as a Second Striker&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/828x493/e048c91c91/bernardo_6.webp&quot; /&gt;&lt;/p&gt;&lt;h2&gt;Lackluster quality in Final third from both sides&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Despite the hype for this game it might have been a tad bit boring for the fans as Arsenal could manage only 0.39 xG from 2 shots on target vs City&apos;s 0.48 xG from just one single shot on target!&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;A lot of this can be simply explained by the fact that both teams were missing their key players. No Rodri and KDB for City while Arsenal were missing the likes of Saka who was out injured and Martinelli who was benched and came on in the second half.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Instead of focusing on their wing play Arsenal lined up with Trossard and Jesus as narrow forwards to press high and protect the center.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;David Raya&apos;s nervy first half&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;David Raya is looking like Arsenal’s first choice keeper this season but he almost gifted City a goal early on in the game as he succumbed against City&apos;s high press and was chased down by Julian Alvarez. Fortunately the ball hit the side netting and the Gunners could breathe a sigh of relief.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/615x409/f6238f44ed/david_raya.webp&quot; /&gt;&lt;span&gt;David Raya&apos;s nervy clearance&lt;/span&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Raya looked out of place at times with his improper distribution under pressure with his searching long balls not able to find anybody. Also during set pieces he looked very uncomfortable in commanding his own box (first half) and collecting crosses which again could&apos;ve cost them another goal if not for Declan Rice&apos;s goal line clearance.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Though he made amends for his shaky start and improved on all fronts in the second half by making pinpoint long passes to Jesus to clear City&apos;s high press and was a lot more bold in his decision-making inside the box.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;Substitutions&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Substitutions helped breathe life into a cagey game where both teams made triple substitutions to turn the game around. City brought Matheus Nunes, Jeremy Doku and John Stones who played his first Prem match this season.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Meanwhile Arsenal put Kai Havertz, Thomas Partey and Gabriel Martinelli whose availability in this game was doubtful.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;It was Arsenal however who got the final say thanks to a lucky deflection from Nathan Ake from Martinelli&apos;s long range effort just 4 minutes from Full Time. Interestingly, this chance involved all 3 of Arsenal&apos;s substitutions as Havertz teed up Martinelli for the winner after Partey&apos;s long ball from deep.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;Key players &amp;amp; Talking points from the game&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Jesus recorded the most touches(76) out of any Arsenal player since most of Arsenal&apos;s attack was focused down the right flank. But playing out of his usual position he didn&apos;t look as threatening in the final third as Bukayo Saka who is out injured.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Arsenal&apos;s solid centre-back partnership between Gabriel and Saliba ensured that Haaland got no breathing space, they were robust in the aerial duels and calculated enough to not allow space for him to run in behind the backline.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/828x499/57f32b4e69/saliba_gabriel.webp&quot; /&gt;&lt;span&gt;Gabriel &amp;amp; Saliba in training&lt;/span&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;In the absence of Rodri many expected Guardiola to give Kalvin Phillips a chance of starting this game, but Guardiola instead used Bernardo as a pivot and played Rico Lewis over Phillips. Phillips&apos; role in this squad is still unclear depsite being a crucial starter for Bielsa&apos;s squad in the past and Southgate&apos;s favorite for the current English squad.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Despite their persistent efforts Arsenal always looked to struggle against Man City in the past and came up short when it mattered the most, but this time they managed to hold their own and seal a historic victory as &lt;b&gt;&lt;span&gt;they&lt;/span&gt;&lt;/b&gt;&lt;span&gt; &lt;/span&gt;&lt;b&gt;&lt;span&gt;defeated Man City for the first time in the Premier League since 2015!&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;</content:encoded><category>Arsenal</category><category>Football</category></item><item><title>Diving Deep into the World of Bun.js </title><link>https://c0smos.dev/blog/diving-deep-into-the-world-of-bun-js/</link><guid isPermaLink="true">https://c0smos.dev/blog/diving-deep-into-the-world-of-bun-js/</guid><description>The date is September 8, 2023 and Bun is fresh out of the Oven! The arrival of Bun v1.0 has shaken the whole JavaScript community and all of us are aboard the hype train.</description><pubDate>Tue, 21 May 2024 16:53:24 GMT</pubDate><content:encoded>&lt;p&gt;The date is September 8, 2023 and Bun is fresh out of the Oven! The arrival of Bun v1.0 has shaken the whole JavaScript community and all of us are aboard the hype train.&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/498x249/eb005ae7ca/all_aboard.gif&quot; /&gt;&lt;/p&gt;&lt;h1&gt;Why such hype around Bun?&lt;/h1&gt;&lt;p&gt;If we refer to the official docs then it says:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;i&gt;Bun is an all-in-one toolkit for JavaScript and TypeScript apps. It ships as a single executable called &lt;/i&gt;&lt;b&gt;&lt;i&gt;Bun&lt;/i&gt;&lt;/b&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;h3&gt;&lt;i&gt;But what does being an all-in-one toolkit mean exactly and what makes it better than the existing JavaScript frameworks?&lt;/i&gt;&lt;/h3&gt;&lt;p&gt;As stated by the developers&lt;span&gt;:&lt;/span&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;i&gt;The JavaScript ecosystem has become unnecessarily complicated, most code we write today has to pass through different plugins, bundlers, transpilers before it is even executable by Node.js &lt;/i&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Simply put, Bun aims to reduce this complexity by providing an all-in-one solution thus improving performance manifold. From its versatile toolkit the feature that takes the spotlight is the Bun Js runtime, which comes as a drop-in replacement for Node.js.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Other than this it also includes a native Bundler, Transpiler, Package manager and even its own Test Runner!&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;i&gt;Now let&apos;s break down all these things one at a time:&lt;/i&gt;&lt;/p&gt;&lt;h2&gt;JavaScript Runtime&lt;/h2&gt;&lt;p&gt;A runtime is simply an environment which provides all the necessary components to run a JavaScript program. It makes use of the JavaScript Engine which basically converts JavaScript code to machine code for the runtime to execute.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Bun boasts of incredible performance over Node.js thanks to its JavaScriptCore Engine developed by Apple for Safari which offers faster start times as compared to the V8 Engine used by Chrome which prioritizes faster execution time.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/498x203/7958f690a3/speed_mcqueen.gif&quot; /&gt;&lt;/p&gt;&lt;h2&gt;Transpiler&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Node.js does not natively support .ts files, which means TypeScript files have to be transpiled into corresponding JavaScript code to execute using third party libraries.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Meanwhile Bun comes with an integrated transpiler that means it can natively support .ts, .js, .jsx and even .tsx files. This also results in much faster performance than Node.js&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/600x338/154edd1268/good_at_everything.webp&quot; /&gt;&lt;/p&gt;&lt;h2&gt;ES Modules &amp;amp; Common JS&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Common JS is the original way of handling JavaScript code segments in Node.js which uses &lt;span&gt;require()&lt;/span&gt; and &lt;span&gt;module.exports&lt;/span&gt; for importing and exporting code respectively but is limited by the fact that it is synchronous.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;On the other hand ES modules is the modern way of reusing JavaScript code. It uses &lt;span&gt;import&lt;/span&gt; and &lt;span&gt;export&lt;/span&gt; statements which also support asynchronous module handling.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Bun again stands out here as it provides compatibility to both Common JS and ES modules in the same file which is not possible in Node.js&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;Bundler&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;In large web applications, code is typically organized into multiple files and directories to improve maintainability and modularity. Bundlers help bring all these individual files together into a single or a few bundles that can be efficiently loaded by web browsers.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;index.tsx

import * as ReactDOM from &apos;react-dom/client&apos;;
import {Component} from &quot;./Component&quot;

const root = ReactDOM.createRoot(document.getElementById(&apos;root&apos;));
root.render(&amp;lt;Component message=&quot;Sup!&quot; /&amp;gt;)&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code&gt;component.tsx

export function Component(props: {message: string}) {
  return &amp;lt;p&amp;gt;{props.message}&amp;lt;/p&amp;gt;
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Using &lt;span&gt;bun build ./index.tsx --outdir ./out&lt;/span&gt;&lt;span&gt; &lt;/span&gt;where &lt;span&gt;--outdir&lt;/span&gt; specifies the output directory for the bundled file. The output file looks something like this:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;out/index.js


// Component.tsx
function Component(props) {
  return $jsxDEV(&quot;p&quot;, {
    children: props.message
  }, undefined, false, undefined, this);
}

// index.tsx
var rootNode = document.getElementById(&quot;root&quot;);
var root = $createRoot(rootNode);
root.render($jsxDEV(Component, {
  message: &quot;Sup!&quot;
}, undefined, false, undefined, this));&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Bundlers help manage dependencies by bundling them together, resolving conflicts, and ensuring that the correct versions are included in the bundle.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Until the advent of Bun, Node.js applications relied on third-party libraries such as Parcel, Webpack, Rollup etc. to for common bundling tasks like minifying code, file conversions and code splitting.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Bun eliminates this need by bringing all these features under its integrated bundler which works for both TypeScript and JavaScript applications.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;Bun Roadmap&lt;/h2&gt;&lt;blockquote&gt;&lt;p&gt;&lt;i&gt;Bun is a project with an incredibly large scope and is still in its early days. Long-term, Bun aims to provide an all-in-one toolkit to replace the complex, fragmented toolchains common today: Node.js, Jest, Webpack, esbuild, Babel, yarn, PostCSS, etc.&lt;/i&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Ref.:&lt;span&gt; &lt;/span&gt;&lt;a href=&quot;https://bun.sh/docs/project/roadmap&quot;&gt;&lt;u&gt;https://bun.sh/docs/project/roadmap&lt;/u&gt;&lt;/a&gt;&lt;/p&gt;&lt;h2&gt;Installation &amp;amp; Setup&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Bun only has limited Windows support right now and can only be installed using Windows Subsytem for Linux(WSL) by enabling it. Meanwhile it is fully available for macOS and Linux systems.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;For the purpose of this blog I&apos;m running Manjaro OS on Vmware which is an Arch-based Linux distribution.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;For Mac &amp;amp; Linux Bun can be installed using npm or curl. I already have npm installed so I&apos;ll just go ahead with &lt;span&gt;npm install -g bun&lt;/span&gt; &lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;Starting a project&lt;/h2&gt;&lt;p&gt;&lt;span&gt;bun init&lt;/span&gt; will initialize a project with some essential files, also instead of default entry point index.ts we will use index.js.&lt;/p&gt;&lt;p&gt;To test our runtime we can simply run &lt;span&gt;bun run index.js&lt;/span&gt; and we get &lt;i&gt;Hello via Bun!&lt;/i&gt; as the output.&lt;/p&gt;&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;https://a-us.storyblok.com/f/1020021/828x552/bfbd975341/manjaro_bun_setup.webp&quot; /&gt;&lt;/p&gt;&lt;h2&gt;Adding Modules/Packages&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;According to official docs &lt;span&gt;bun install&lt;/span&gt; installs packages 20-100 times faster than &lt;span&gt;npm install&lt;/span&gt; on Linux.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Either use &lt;span&gt;bun install&lt;/span&gt; to install all existing packages from the package.json or &lt;span&gt;bun add&lt;/span&gt; to add packages to your project.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;File Imports &amp;amp; Exports&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Even though Common JS modules are discouraged, Bun JS supports both &lt;span&gt;import&lt;/span&gt; and &lt;span&gt;require()&lt;/span&gt; and can be used in the same file as well, something which is not natively supported in Node.js.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Bun JS also supports custom path re-mapping, this allows to shorten paths by renaming and reusing them which is another major advantage over Node.js which does not support any path re-mapping.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Ref.: &lt;a href=&quot;https://bun.sh/docs/runtime/modules#importing-packages&quot;&gt;&lt;u&gt;https://bun.sh/docs/runtime/modules#importing-packages&lt;/u&gt;&lt;/a&gt; &lt;a href=&quot;https://bun.sh/docs/runtime/modules#importing-packages&quot;&gt;&lt;u&gt;https://bun.sh/guides/runtime/tsconfig-paths&lt;/u&gt;&lt;/a&gt;&lt;/p&gt;&lt;pre&gt;&lt;code&gt;tsconfig.json

{
  &quot;compilerOptions&quot;: {
    &quot;paths&quot;: {
      &quot;my-custom-name&quot;: [&quot;zod&quot;],
      &quot;@components/*&quot;: [&quot;./src/components/*&quot;]
    }
  }
}&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code&gt;import { z } from &quot;my-custom-name&quot;; // imports from &quot;zod&quot;
import { Button } from &quot;@components/Button&quot;; // imports from &quot;./src/components/Button&quot;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Instead of importing components from &lt;span&gt;&quot;./src/components/&quot;&lt;/span&gt; everytime we can simply map a name &lt;span&gt;&quot;@components&quot;&lt;/span&gt; to this path and reuse this to write neat code. Also we can use rename a path by mapping it to a custom name as shown above.&lt;/p&gt;&lt;h2&gt;Environment Variables&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Bun reads all types of .env files automatically that means there is no need for packages like dotenv to read .env files. Use &lt;span&gt;bun run env&lt;/span&gt; to print all environment variables.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;.env file variables can be accessed using &lt;span&gt;process.env.VARIABLE_NAME&lt;/span&gt; or &lt;span&gt;Bun.env.VARIABLE_NAME&lt;/span&gt; &lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;BUN APIs&lt;/h2&gt;&lt;p&gt;Bun also comes with its own set of native APIs implemented directly on the Bun object therefore, there is no need to use external packages to create a HTTP server, read/write files and even use the inbuilt sqlite database.&lt;/p&gt;&lt;h3&gt;Bun.serve vs Node.js http module:&lt;/h3&gt;&lt;pre&gt;&lt;code&gt;Bun.serve({
  fetch(req: Request) {
    return new Response(&quot;Bun!&quot;);
  },
  port: 3000,
});&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code&gt;require(&quot;http&quot;)
  .createServer((req, res) =&amp;gt; res.end(&quot;Bun!&quot;))
  .listen(8080);&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;According to Bun docs:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;span&gt;Bun.serve&lt;/span&gt; server can handle roughly 2.5x more requests per second than Node.js on Linux.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;For File Handling &lt;span&gt;Bun.file&lt;/span&gt; and &lt;span&gt;Bun.write&lt;/span&gt; are the recommended ways of perform file related tasks. Though it is still a partial implementation of the &lt;span&gt;node:fs&lt;/span&gt; module and still lacks some key functions.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;const txt_file = Bun.file(&quot;foo.txt&quot;);  // read foo.txt

// Read json files

const json_file = Bun.file(&quot;notreal.json&quot;, { type: &quot;application/json&quot; }); //change application type to read different file types
notreal.type; // =&amp;gt; &quot;application/json;charset=utf-8&quot;

// Copy content from foo.txt and save to a different file

const output = Bun.file(&quot;output.txt&quot;); // doesn&apos;t exist yet!
await Bun.write(output, txt_file);&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;These functions for reading, writing files are highly optimized in fact according to Benchmarks using Bun to output file content using &lt;span&gt;stdout&lt;/span&gt; works 2x faster than the Linux &lt;b&gt;cat&lt;/b&gt; command!&lt;/p&gt;&lt;h2&gt;&lt;b&gt;Automatic Reloading&lt;/b&gt;&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Bun provides two CLI commands for automatic reloading which means there is no need for third party modules like &lt;span&gt;nodemon&lt;/span&gt; to refresh changes while development.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span&gt;--watch&lt;/span&gt; mode hard restarts Bun&apos;s process when imported files change&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span&gt;--hot&lt;/span&gt; flag enables hot reloading where it does not restart every time a change is made instead it performs a soft reload where only new changes are updated and global state is persisted.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;This is really important for &lt;b&gt;HTTP connections &lt;/b&gt;and &lt;b&gt;Websockets&lt;/b&gt; since using packages like &lt;span&gt;nodemon&lt;/span&gt; or &lt;span&gt;--watch&lt;/span&gt; mode will restart the entire process which results in loss of stateful objects while using &lt;span&gt;--hot&lt;/span&gt; mode ensures that the code reloads with updated changes without interrupting the HTTP connections.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;&lt;b&gt;Wrapping up&lt;/b&gt;&lt;/h2&gt;&lt;p&gt;Bun looks like a solid replacement for current Web applications built over current JavaScript frameworks, with its all-in-one functionality it is bound to take over the world of JavaScript and will re-define how modern developers will leverage its power &amp;amp; efficiency.&lt;/p&gt;&lt;p&gt;Though still in its early stages it is a bit rough around the edges, but owing to its great developer support, extensive documentation and constant updates it is improving swiftly and will soon become a staple tool in every developer&apos;s arsenal.&lt;/p&gt;</content:encoded><category>Bun</category><category>Javascript</category></item></channel></rss>