<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://xinjiav2.github.io/CSA/feed.xml" rel="self" type="application/atom+xml" /><link href="https://xinjiav2.github.io/CSA/" rel="alternate" type="text/html" /><updated>2026-11-05T03:58:44+00:00</updated><id>https://xinjiav2.github.io/CSA/feed.xml</id><title type="html">CSA Portfolio</title><subtitle>Class of 2028</subtitle><author><name>Zhengji Li (Jade)</name><email>li.xuzhu10@gmail.com</email></author><entry><title type="html">Arch on ARM!</title><link href="https://xinjiav2.github.io/CSA/AoA/" rel="alternate" type="text/html" title="Arch on ARM!" /><published>2026-10-20T00:00:00+00:00</published><updated>2026-10-20T00:00:00+00:00</updated><id>https://xinjiav2.github.io/CSA/arch-linux-arm-on-omnibook-x14</id><content type="html" xml:base="https://xinjiav2.github.io/CSA/AoA/"><![CDATA[<h1 id="arch-linux-arm-on-an-hp-omnibook-x-14-snapdragon-x-using-ubuntus-kernel">Arch Linux ARM on an HP OmniBook X 14 (Snapdragon X), using Ubuntu’s kernel</h1>

<p>Documentation of a dual-boot setup where Arch Linux ARM’s userspace runs on top of the kernel, modules, firmware, and initramfs from a working Ubuntu 26.04 aarch64 install. Ubuntu’s GRUB loads the kernel and points its <code class="language-plaintext highlighter-rouge">root=</code> at the Arch partition.</p>

<p><strong>Date:</strong> 2026-10-20
<strong>Hardware:</strong> HP OmniBook X 14 (fe0xxx), Qualcomm Snapdragon X, aarch64
<strong>Host:</strong> Ubuntu 26.04, kernel <code class="language-plaintext highlighter-rouge">7.0.0-38-generic</code>
<strong>Guest:</strong> Arch Linux ARM, <code class="language-plaintext highlighter-rouge">ArchLinuxARM-aarch64-latest.tar.gz</code> (ARMv8 AArch64 Multi-platform) from <a href="https://archlinuxarm.org/about/downloads">https://archlinuxarm.org/about/downloads</a></p>

<hr />

<h2 id="how-it-works">How it works</h2>

<p>The Arch ARM tarball is only a userspace root filesystem. It has no kernel that boots this laptop, so:</p>

<table>
  <thead>
    <tr>
      <th>Piece</th>
      <th>Comes from</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Kernel (<code class="language-plaintext highlighter-rouge">vmlinuz</code>) and initramfs</td>
      <td>Ubuntu’s <code class="language-plaintext highlighter-rouge">/boot</code> (on the Ubuntu root partition)</td>
    </tr>
    <tr>
      <td>Kernel modules</td>
      <td>Copied from Ubuntu <code class="language-plaintext highlighter-rouge">/lib/modules/&lt;version&gt;</code></td>
    </tr>
    <tr>
      <td>Firmware (GPU, Wi-Fi, DSPs)</td>
      <td>Copied from Ubuntu <code class="language-plaintext highlighter-rouge">/lib/firmware</code></td>
    </tr>
    <tr>
      <td>Userspace, pacman, packages</td>
      <td>Arch Linux ARM tarball</td>
    </tr>
    <tr>
      <td>Bootloader</td>
      <td>Ubuntu’s GRUB, with a custom menu entry</td>
    </tr>
  </tbody>
</table>

<p>The laptop boots via ACPI, so no <code class="language-plaintext highlighter-rouge">devicetree</code> line is needed in the GRUB entry. This was verified by grepping <code class="language-plaintext highlighter-rouge">grub.cfg</code> for <code class="language-plaintext highlighter-rouge">devicetree</code> and <code class="language-plaintext highlighter-rouge">dtb</code> and finding nothing.</p>

<h2 id="disk-layout-used">Disk layout used</h2>

<table>
  <thead>
    <tr>
      <th>Partition</th>
      <th>Purpose</th>
      <th>Filesystem</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">nvme0n1p1</code></td>
      <td>EFI System Partition</td>
      <td>vfat</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">nvme0n1p3</code>, <code class="language-plaintext highlighter-rouge">p4</code></td>
      <td>Windows</td>
      <td>ntfs</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">nvme0n1p5</code></td>
      <td>Ubuntu root (contains <code class="language-plaintext highlighter-rouge">/boot</code>)</td>
      <td>ext4</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">nvme0n1p6</code></td>
      <td>Other</td>
      <td>ext4</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">nvme0n1p7</code></td>
      <td><strong>Arch root</strong> (about 114 GB)</td>
      <td>ext4</td>
    </tr>
  </tbody>
</table>

<p>UUIDs used below (replace with yours from <code class="language-plaintext highlighter-rouge">lsblk -f</code>):</p>

<ul>
  <li>Ubuntu root (<code class="language-plaintext highlighter-rouge">p5</code>): <code class="language-plaintext highlighter-rouge">c8b9b28b-eab1-4441-a158-027c42288db5</code></li>
  <li>Arch root (<code class="language-plaintext highlighter-rouge">p7</code>): <code class="language-plaintext highlighter-rouge">ef3b53f1-ab9a-4ca0-a1eb-12b9fa018402</code></li>
</ul>

<hr />

<h2 id="step-1-create-the-arch-root-partition">Step 1: Create the Arch root partition</h2>

<p>Shrink Ubuntu or use free space (use a live USB if you need to shrink a mounted root), then create a partition with <code class="language-plaintext highlighter-rouge">cfdisk /dev/nvme0n1</code>. Format and extract:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>mkfs.ext4 /dev/nvme0n1p7        <span class="c"># double-check the device first, this erases it</span>
<span class="nb">sudo mkdir</span> <span class="nt">-p</span> /mnt/arch
<span class="nb">sudo </span>mount /dev/nvme0n1p7 /mnt/arch
<span class="nb">cd</span> ~/Downloads
<span class="nb">sudo </span>bsdtar <span class="nt">-xpf</span> ArchLinuxARM-aarch64-latest.tar.gz <span class="nt">-C</span> /mnt/arch
</code></pre></div></div>

<ul>
  <li>Use <code class="language-plaintext highlighter-rouge">bsdtar</code> (<code class="language-plaintext highlighter-rouge">sudo apt install libarchive-tools</code>), not GNU tar, to avoid xattr and file-capability problems.</li>
  <li>Run it as root with <code class="language-plaintext highlighter-rouge">-p</code> so permissions are preserved.</li>
  <li><code class="language-plaintext highlighter-rouge">ls /mnt/arch</code> should show <code class="language-plaintext highlighter-rouge">bin boot dev etc home usr var ...</code>.</li>
</ul>

<blockquote>
  <p><strong>Gotcha:</strong> An early attempt failed because the commands contained placeholders (<code class="language-plaintext highlighter-rouge">nvme0n1pX</code>, nonexistent <code class="language-plaintext highlighter-rouge">/mnt/arch</code>). Always substitute your real partition and create the mount point first.</p>
</blockquote>

<h2 id="step-2-copy-modules-and-firmware-from-ubuntu">Step 2: Copy modules and firmware from Ubuntu</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo mkdir</span> <span class="nt">-p</span> /mnt/arch/usr/lib/modules /mnt/arch/usr/lib/firmware
<span class="nb">sudo cp</span> <span class="nt">-a</span> /lib/modules/<span class="si">$(</span><span class="nb">uname</span> <span class="nt">-r</span><span class="si">)</span> /mnt/arch/usr/lib/modules/
<span class="nb">sudo cp</span> <span class="nt">-a</span> /lib/firmware/. /mnt/arch/usr/lib/firmware/
</code></pre></div></div>

<p>The modules must match the kernel version exactly. Firmware is critical on Snapdragon X laptops (GPU, Wi-Fi, remoteprocs).</p>

<h2 id="step-3-collect-the-boot-parameters">Step 3: Collect the boot parameters</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">uname</span> <span class="nt">-r</span>
<span class="nb">ls</span> /boot
<span class="nb">cat</span> /proc/cmdline
<span class="nb">sudo grep</span> <span class="nt">-E</span> <span class="s2">"menuentry |devicetree|dtb"</span> /boot/grub/grub.cfg
</code></pre></div></div>

<p>Working Ubuntu command line on this machine:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>BOOT_IMAGE=/boot/vmlinuz-7.0.0-38-generic root=UUID=c8b9b28b-... ro clk_ignore_unused pd_ignore_unused cma=128M efi=noruntime crashkernel=...
</code></pre></div></div>

<p>The extra parameters (<code class="language-plaintext highlighter-rouge">clk_ignore_unused pd_ignore_unused cma=128M efi=noruntime</code>) are what make Snapdragon X laptops boot reliably, so they are carried over to the Arch entry. <code class="language-plaintext highlighter-rouge">crashkernel=</code> is omitted since it only matters for crash dumps.</p>

<h2 id="step-4-chroot-setup">Step 4: Chroot setup</h2>

<p>Use mount propagation flags so unmounting the chroot cannot affect the host’s <code class="language-plaintext highlighter-rouge">/dev</code>:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>mount <span class="nt">--rbind</span> /dev /mnt/arch/dev
<span class="nb">sudo </span>mount <span class="nt">--make-rslave</span> /mnt/arch/dev
<span class="nb">sudo </span>mount <span class="nt">-t</span> proc proc /mnt/arch/proc
<span class="nb">sudo </span>mount <span class="nt">--rbind</span> /sys /mnt/arch/sys
<span class="nb">sudo </span>mount <span class="nt">--make-rslave</span> /mnt/arch/sys
<span class="nb">sudo </span>mount <span class="nt">--bind</span> /run /mnt/arch/run
<span class="nb">sudo </span>mount <span class="nt">--make-slave</span> /mnt/arch/run

<span class="c"># the tarball's resolv.conf points at a resolver that isn't running in the chroot</span>
<span class="nb">sudo mv</span> /mnt/arch/etc/resolv.conf /mnt/arch/etc/resolv.conf.bak
<span class="nb">sudo cp</span> /etc/resolv.conf /mnt/arch/etc/resolv.conf

<span class="nb">sudo chroot</span> /mnt/arch /bin/bash
</code></pre></div></div>

<p>Inside the chroot (the prompt becomes <code class="language-plaintext highlighter-rouge">[root@... /]#</code>):</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pacman-key <span class="nt">--init</span>
pacman-key <span class="nt">--populate</span> archlinuxarm
passwd
<span class="nb">echo</span> <span class="s2">"UUID=ef3b53f1-ab9a-4ca0-a1eb-12b9fa018402 / ext4 defaults 0 1"</span> <span class="o">&gt;</span> /etc/fstab

<span class="c"># keep the generic ARM kernel out</span>
pacman <span class="nt">-R</span> linux-aarch64
pacman <span class="nt">-Syu</span> networkmanager nano <span class="nb">sudo
</span>systemctl <span class="nb">enable </span>NetworkManager

<span class="c"># restore the resolver symlink for normal boot</span>
<span class="nb">rm</span> /etc/resolv.conf
<span class="nb">ln</span> <span class="nt">-s</span> ../run/systemd/resolve/stub-resolv.conf /etc/resolv.conf
systemctl <span class="nb">enable </span>systemd-resolved

useradd <span class="nt">-m</span> <span class="nt">-G</span> wheel &lt;yourname&gt;
passwd &lt;yourname&gt;
<span class="nb">exit</span>
</code></pre></div></div>

<p>Back on the Ubuntu host, allow <code class="language-plaintext highlighter-rouge">sudo</code> for the wheel group and clean up:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo sed</span> <span class="nt">-i</span> <span class="s1">'s/^# %wheel ALL=(ALL:ALL) ALL/%wheel ALL=(ALL:ALL) ALL/'</span> /mnt/arch/etc/sudoers
<span class="nb">sudo </span>umount <span class="nt">-R</span> /mnt/arch
</code></pre></div></div>

<h3 id="gotchas-hit-during-this-step">Gotchas hit during this step</h3>

<ol>
  <li><strong><code class="language-plaintext highlighter-rouge">sudo: command not found</code>.</strong> The commands were pasted while still inside the chroot, where <code class="language-plaintext highlighter-rouge">sudo</code> is not installed. Run <code class="language-plaintext highlighter-rouge">exit</code> to return to the Ubuntu prompt (<code class="language-plaintext highlighter-rouge">jade@...</code>) before pasting host commands.</li>
  <li><strong><code class="language-plaintext highlighter-rouge">sudo: unable to open pty</code> on the host.</strong> Plain <code class="language-plaintext highlighter-rouge">--bind</code> mounts of <code class="language-plaintext highlighter-rouge">/dev</code> share propagation with the host, so unmounting inside the chroot side removed the host’s <code class="language-plaintext highlighter-rouge">/dev/pts</code>. Fix: reboot (or <code class="language-plaintext highlighter-rouge">pkexec mount -t devpts devpts /dev/pts -o gid=5,mode=620,ptmxmode=666</code>). The <code class="language-plaintext highlighter-rouge">--make-rslave</code> mounts above prevent this.</li>
  <li><strong><code class="language-plaintext highlighter-rouge">umount: /mnt/arch/dev: target is busy</code>.</strong> <code class="language-plaintext highlighter-rouge">pacman-key --init</code> leaves a <code class="language-plaintext highlighter-rouge">gpg-agent</code> / <code class="language-plaintext highlighter-rouge">dirmngr</code> running inside the chroot. Kill them, then unmount again:
    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>pkill <span class="nt">-f</span> <span class="s1">'gpg-agent --homedir /etc/pacman.d/gnupg'</span>
<span class="nb">sudo </span>pkill <span class="nt">-f</span> <span class="s1">'dirmngr --homedir /etc/pacman.d/gnupg'</span>
<span class="nb">sudo </span>umount <span class="nt">-R</span> /mnt/arch
</code></pre></div>    </div>
  </li>
  <li><strong>A user literally named <code class="language-plaintext highlighter-rouge">yourname</code> was created</strong>, because a placeholder was pasted as-is. Rename it with:
    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>usermod <span class="nt">-R</span> /mnt/arch <span class="nt">-l</span> &lt;realname&gt; <span class="nt">-d</span> /home/&lt;realname&gt; <span class="nt">-m</span> yourname
<span class="nb">sudo </span>groupmod <span class="nt">-R</span> /mnt/arch <span class="nt">-n</span> &lt;realname&gt; yourname
</code></pre></div>    </div>
  </li>
</ol>

<h2 id="step-5-verify-before-touching-grub">Step 5: Verify before touching GRUB</h2>

<p>Read-only checks from Ubuntu with <code class="language-plaintext highlighter-rouge">/mnt/arch</code> mounted:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">ls</span> <span class="nt">-l</span> /mnt/arch/usr/bin/nmcli /mnt/arch/usr/bin/NetworkManager
<span class="nb">ls</span> <span class="nt">-l</span> /mnt/arch/etc/systemd/system/multi-user.target.wants/NetworkManager.service
<span class="nb">ls</span> <span class="nt">-l</span> /mnt/arch/usr/bin/wpa_supplicant
<span class="nb">cat</span> /mnt/arch/etc/fstab
<span class="nb">ls</span> /mnt/arch/boot                       <span class="c"># should be empty</span>
<span class="nb">ls</span> /mnt/arch/usr/lib/modules            <span class="c"># should only show 7.0.0-38-generic</span>
<span class="nb">ls</span> <span class="nt">-l</span> /mnt/arch/etc/resolv.conf         <span class="c"># symlink to ../run/systemd/resolve/stub-resolv.conf</span>
</code></pre></div></div>

<p>All of these passed.</p>

<h2 id="step-6-add-the-grub-entry">Step 6: Add the GRUB entry</h2>

<p>Append to the end of <code class="language-plaintext highlighter-rouge">/etc/grub.d/40_custom</code> (keep any existing entries):</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>menuentry 'Arch Linux ARM' {
    search --no-floppy --fs-uuid --set=root c8b9b28b-eab1-4441-a158-027c42288db5
    linux /boot/vmlinuz-7.0.0-38-generic root=UUID=ef3b53f1-ab9a-4ca0-a1eb-12b9fa018402 rw clk_ignore_unused pd_ignore_unused cma=128M efi=noruntime
    initrd /boot/initrd.img-7.0.0-38-generic
}
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>update-grub
<span class="nb">sudo </span>umount /mnt/arch
</code></pre></div></div>

<p>Notes:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">search ... --set=root</code> points GRUB at the <strong>Ubuntu</strong> partition, which holds the kernel and initramfs.</li>
  <li><code class="language-plaintext highlighter-rouge">root=UUID=</code> points the kernel at the <strong>Arch</strong> partition.</li>
  <li>The version is pinned (<code class="language-plaintext highlighter-rouge">7.0.0-38-generic</code>) instead of using the <code class="language-plaintext highlighter-rouge">vmlinuz</code> symlink, so it always matches the copied modules.</li>
  <li>Ubuntu’s initramfs works for Arch because it only needs to find the root device (nvme, ext4) and <code class="language-plaintext highlighter-rouge">switch_root</code> into it.</li>
  <li>Ubuntu’s own entries are untouched, so it is always possible to boot back into Ubuntu.</li>
</ul>

<h2 id="step-7-first-boot-and-post-install">Step 7: First boot and post-install</h2>

<p>First boot reached a working shell. Networking came up through <code class="language-plaintext highlighter-rouge">enu1</code> (a wired/USB network adapter) via <code class="language-plaintext highlighter-rouge">systemd-networkd</code>, and pacman worked.</p>

<h3 id="fix-ignorepkg-placement">Fix <code class="language-plaintext highlighter-rouge">IgnorePkg</code> placement</h3>

<p><code class="language-plaintext highlighter-rouge">IgnorePkg</code> was appended to the bottom of <code class="language-plaintext highlighter-rouge">/etc/pacman.conf</code>, under the <code class="language-plaintext highlighter-rouge">[aur]</code> section, where pacman ignores it (it printed <code class="language-plaintext highlighter-rouge">directive 'IgnorePkg' in section 'aur' not recognized</code>). Move it into <code class="language-plaintext highlighter-rouge">[options]</code>:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo sed</span> <span class="nt">-i</span> <span class="s1">'/^IgnorePkg = linux-aarch64/d'</span> /etc/pacman.conf
<span class="nb">sudo sed</span> <span class="nt">-i</span> <span class="s1">'/^\[options\]/a IgnorePkg = linux-aarch64 linux-aarch64-headers'</span> /etc/pacman.conf
<span class="nb">sudo </span>pacman <span class="nt">-Syu</span>
</code></pre></div></div>

<p>Confirm the generic kernel is not installed:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>pacman <span class="nt">-Q</span> linux-aarch64      <span class="c"># should say "was not found"</span>
<span class="nb">grep</span> <span class="nt">-n</span> IgnorePkg /etc/pacman.conf
</code></pre></div></div>

<h3 id="wi-fi">Wi-Fi</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ip <span class="nb">link
</span>rfkill list
<span class="nb">sudo </span>dmesg | <span class="nb">grep</span> <span class="nt">-iE</span> <span class="s1">'ath12k|wlan|firmware'</span> | <span class="nb">tail</span> <span class="nt">-30</span>
nmtui
</code></pre></div></div>

<p>Use NetworkManager for Wi-Fi. <code class="language-plaintext highlighter-rouge">iwd</code> was installed during testing; do not run it alongside NetworkManager (two Wi-Fi daemons conflict). Once Wi-Fi is confirmed, disable the duplicate network service:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>systemctl disable <span class="nt">--now</span> systemd-networkd
</code></pre></div></div>

<h3 id="cleanup">Cleanup</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>userdel <span class="nt">-r</span> alarm
<span class="nb">sudo </span>hostnamectl set-hostname &lt;<span class="nb">hostname</span><span class="o">&gt;</span>
<span class="nb">sudo </span>timedatectl set-timezone &lt;Region/City&gt;
<span class="c"># uncomment en_US.UTF-8 UTF-8 in /etc/locale.gen, then:</span>
<span class="nb">sudo </span>locale-gen
</code></pre></div></div>

<h3 id="desktop">Desktop</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>pacman <span class="nt">-S</span> mesa vulkan-freedreno plasma-meta konsole dolphin sddm
<span class="nb">sudo </span>systemctl <span class="nb">enable </span>sddm
</code></pre></div></div>

<p>The install completed (555 packages). The <code class="language-plaintext highlighter-rouge">qcom-battmgr ... failed to send synthetic uevent: -11</code> messages during the udev hook are harmless; udev poked the battery devices while the Qualcomm battery manager was busy.</p>

<p><strong>Status at the time of writing:</strong> SDDM was enabled but not yet booted into. Result of the first graphical boot is not recorded here.</p>

<h3 id="if-the-graphical-boot-fails">If the graphical boot fails</h3>

<ul>
  <li>Press <code class="language-plaintext highlighter-rouge">Ctrl+Alt+F3</code> for a text console.</li>
  <li>Or at GRUB press <code class="language-plaintext highlighter-rouge">e</code> on the Arch entry, append <code class="language-plaintext highlighter-rouge">3</code> to the <code class="language-plaintext highlighter-rouge">linux</code> line, and press <code class="language-plaintext highlighter-rouge">Ctrl+X</code> to boot to a text console without starting SDDM.</li>
  <li>Gather logs:
    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>journalctl <span class="nt">-b</span> <span class="nt">-u</span> sddm
<span class="nb">sudo </span>dmesg | <span class="nb">grep</span> <span class="nt">-iE</span> <span class="s1">'msm|drm|adreno'</span>
</code></pre></div>    </div>
  </li>
  <li>SDDM’s default X11 greeter can be switched to Wayland, which suits Snapdragon X better.</li>
  <li>Escape hatch: <code class="language-plaintext highlighter-rouge">sudo systemctl disable sddm</code> returns to a text-mode boot.</li>
</ul>

<hr />

<h2 id="maintenance-when-ubuntu-updates-its-kernel">Maintenance: when Ubuntu updates its kernel</h2>

<p>The Arch root depends on the Ubuntu kernel’s exact modules. After every Ubuntu kernel update:</p>

<ol>
  <li>Boot Ubuntu and note the new version (<code class="language-plaintext highlighter-rouge">uname -r</code>).</li>
  <li>Copy the new modules into the Arch root:
    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>mount /dev/nvme0n1p7 /mnt/arch
<span class="nb">sudo cp</span> <span class="nt">-a</span> /lib/modules/&lt;new-version&gt; /mnt/arch/usr/lib/modules/
<span class="nb">sudo cp</span> <span class="nt">-a</span> /lib/firmware/. /mnt/arch/usr/lib/firmware/
</code></pre></div>    </div>
  </li>
  <li>Update the version numbers in the <code class="language-plaintext highlighter-rouge">Arch Linux ARM</code> entry in <code class="language-plaintext highlighter-rouge">/etc/grub.d/40_custom</code>, then run <code class="language-plaintext highlighter-rouge">sudo update-grub</code>.</li>
  <li>Keep the old kernel’s modules and entry until the new one is confirmed working.</li>
</ol>

<p>Alternative: bind-mount or symlink Ubuntu’s <code class="language-plaintext highlighter-rouge">/lib/modules</code> into the Arch root so there is a single source of truth.</p>

<h2 id="caveats">Caveats</h2>

<ul>
  <li>Do not delete <code class="language-plaintext highlighter-rouge">/usr/lib/firmware/qcom/...</code> in Arch. The laptop-specific blobs came from Ubuntu, and Arch’s <code class="language-plaintext highlighter-rouge">linux-firmware</code> package may not include them.</li>
  <li>Arch’s Mesa and Wayland are newer than Ubuntu’s. This is usually fine or better, but occasionally breaks GPU acceleration on this hardware.</li>
  <li>Keep Secure Boot configured so the Ubuntu-signed GRUB and kernel keep loading.</li>
  <li>The Arch ARM <code class="language-plaintext highlighter-rouge">linux-aarch64</code> package must stay ignored and uninstalled. It does not boot this laptop.</li>
</ul>

<h2 id="quick-reference">Quick reference</h2>

<table>
  <thead>
    <tr>
      <th>Task</th>
      <th>Command</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Mount Arch root from Ubuntu</td>
      <td><code class="language-plaintext highlighter-rouge">sudo mount /dev/nvme0n1p7 /mnt/arch</code></td>
    </tr>
    <tr>
      <td>Safe chroot</td>
      <td>see Step 4 (<code class="language-plaintext highlighter-rouge">--rbind</code> + <code class="language-plaintext highlighter-rouge">--make-rslave</code>)</td>
    </tr>
    <tr>
      <td>Clean unmount</td>
      <td>kill leftover <code class="language-plaintext highlighter-rouge">gpg-agent</code>/<code class="language-plaintext highlighter-rouge">dirmngr</code>, then <code class="language-plaintext highlighter-rouge">sudo umount -R /mnt/arch</code></td>
    </tr>
    <tr>
      <td>Regenerate GRUB</td>
      <td><code class="language-plaintext highlighter-rouge">sudo update-grub</code></td>
    </tr>
    <tr>
      <td>Boot to text console</td>
      <td>add <code class="language-plaintext highlighter-rouge">3</code> to the <code class="language-plaintext highlighter-rouge">linux</code> line in GRUB (<code class="language-plaintext highlighter-rouge">e</code> to edit)</td>
    </tr>
    <tr>
      <td>Disable the display manager</td>
      <td><code class="language-plaintext highlighter-rouge">sudo systemctl disable sddm</code></td>
    </tr>
  </tbody>
</table>

<h1 id="fix-wi-fi-issue">Fix Wi-Fi issue</h1>
<ol>
  <li>Boot into Ubuntu
First, verify that Wi-Fi still works on Ubuntu:
    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mcli device status
<span class="nb">uname</span> <span class="nt">-r</span>
</code></pre></div>    </div>
  </li>
</ol>

<p>Then identify the partitions:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>lsblk <span class="nt">-f</span>
</code></pre></div></div>

<p>We need to find the Arch root partition.</p>
<ol>
  <li>Mount your Arch installation
For example, if Arch is installed on <code class="language-plaintext highlighter-rouge">/dev/nvme0n1p7</code>:
    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo mkdir</span> <span class="nt">-p</span> /mnt/arch
<span class="nb">sudo </span>mount /dev/nvme0n1p7 /mnt/arch
</code></pre></div>    </div>
  </li>
</ol>

<p>Replace <code class="language-plaintext highlighter-rouge">/dev/nvme0n1p7</code> with your the Arch root partition. Don’t guess the partition number.</p>

<p>If Arch uses Btrfs subvolumes, LUKS encryption, or a separate /usr partition, the mounting procedure may differ.</p>
<ol>
  <li>Compare the firmware directories
Before entering the chroot, we can compare Ubuntu’s working firmware with Arch’s.</li>
</ol>

<p>On Ubuntu:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">ls</span> /lib/firmware/ath11k/
</code></pre></div></div>

<p>Then:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">ls</span> /mnt/arch/usr/lib/firmware/ath11k/
</code></pre></div></div>

<p>Since the HP OmniBook X 14 previously needed Qualcomm firmware adjustments, pay particular attention to:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ath11k/
└── WCN6855/
    ├── hw2.0/
    └── hw2.1/
</code></pre></div></div>
<p>We should also check for HP-specific firmware files.</p>

<p>If Ubuntu has firmware that Arch is missing, we can copy the relevant files.</p>

<p>Don’t copy the entire firmware directory yet. Identify exactly which files Arch needs.</p>
<ol>
  <li>Enter the Arch chroot
Once the partition is mounted:
    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>mount <span class="nt">--rbind</span> /dev /mnt/arch/dev
<span class="nb">sudo </span>mount <span class="nt">--make-rslave</span> /mnt/arch/dev
<span class="nb">sudo </span>mount <span class="nt">-t</span> proc proc /mnt/arch/proc
<span class="nb">sudo </span>mount <span class="nt">--rbind</span> /sys /mnt/arch/sys
<span class="nb">sudo </span>mount <span class="nt">--make-rslave</span> /mnt/arch/sys
<span class="nb">sudo </span>mount <span class="nt">--rbind</span> /run /mnt/arch/run
<span class="nb">sudo </span>mount <span class="nt">--make-rslave</span> /mnt/arch/run
<span class="nb">sudo chroot</span> /mnt/arch /bin/bash
</code></pre></div>    </div>
    <p>Once operating inside Arch’s filesystem while Ubuntu’s kernel is running.</p>
  </li>
</ol>

<p>You can inspect installed packages and modify Arch’s firmware.</p>

<p>For example:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pacman <span class="nt">-Q</span> | <span class="nb">grep </span>firmware
</code></pre></div></div>

<p>One limitation: loading kernel modules inside the chroot affects the running Ubuntu kernel, not a future Arch boot. So avoid using modprobe as a test of whether Arch’s Wi-Fi is fixed.</p>

<p>Now run these commands from Ubuntu:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">ls</span> <span class="nt">-lah</span> /lib/firmware/ath11k/WCN6855/hw2.1/
</code></pre></div></div>

<p>And:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">ls</span> <span class="nt">-lah</span> /mnt/arch/usr/lib/firmware/ath11k/WCN6855/hw2.1/
</code></pre></div></div>

<p>Also compare the hw2.0 directories:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">ls</span> <span class="nt">-lah</span> /lib/firmware/ath11k/WCN6855/hw2.0/
<span class="nb">ls</span> <span class="nt">-lah</span> /mnt/arch/usr/lib/firmware/ath11k/WCN6855/hw2.0/
</code></pre></div></div>

<p>From Ubuntu, outside the chroot, run:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo mkdir</span> <span class="nt">-p</span> /mnt/arch/usr/lib/firmware/ath11k/WCN6855
</code></pre></div></div>

<p>First, back up Arch’s existing firmware:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo cp</span> <span class="nt">-a</span> <span class="se">\</span>
  /mnt/arch/usr/lib/firmware/ath11k/WCN6855 <span class="se">\</span>
  /mnt/arch/root/WCN6855-backup
</code></pre></div></div>

<p>Then copy Ubuntu’s working firmware:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo cp</span> <span class="nt">-a</span> <span class="se">\</span>
  /lib/firmware/ath11k/WCN6855/. <span class="se">\</span>
  /mnt/arch/usr/lib/firmware/ath11k/WCN6855/
</code></pre></div></div>

<p>This copies both hw2.0 and hw2.1, including the firmware modifications that made Ubuntu work.</p>

<p>It doesn’t modify Ubuntu’s firmware.</p>

<p>One caveat: If Arch has uncompressed firmware files alongside Ubuntu’s compressed .zst files, copying may leave both versions present. We’ll need to check for that if Wi-Fi still doesn’t work.
Step 3: Check kernel modules
Because both installations use the same kernel version, check whether Arch has the necessary driver modules.</p>

<p>From Ubuntu:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">ls</span> /mnt/arch/usr/lib/modules/
</code></pre></div></div>

<p>Then:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>find /mnt/arch/usr/lib/modules/ <span class="nt">-name</span> <span class="s1">'ath11k_pci.ko*'</span>
</code></pre></div></div>

<p>If nothing appears, Arch may not have the appropriate modules installed, even though it’s booting Ubuntu’s kernel.</p>

<p>Reboot into arch and connect to wifi :)</p>]]></content><author><name>Jade</name></author><summary type="html"><![CDATA[Arch Linux ARM on an HP OmniBook X 14 (Snapdragon X), using Ubuntu’s kernel]]></summary></entry><entry><title type="html">Rate Limiting Problem</title><link href="https://xinjiav2.github.io/CSA/r-limit/" rel="alternate" type="text/html" title="Rate Limiting Problem" /><published>2026-10-14T00:00:00+00:00</published><updated>2026-10-14T00:00:00+00:00</updated><id>https://xinjiav2.github.io/CSA/ideationRateLimiter</id><content type="html" xml:base="https://xinjiav2.github.io/CSA/r-limit/"><![CDATA[<h1 id="the-problem">The Problem</h1>
<p>On the microblog within the lessons, if you were to make a post, you can spam the button and that would create basically a million different posts.</p>

<p>My plan is to add a rate limiting feature by adding a new file</p>

<p>Made by: Zhengji, Rudra</p>

<h1 id="microblog-rate-limiting">Microblog rate limiting</h1>

<p>Implemented in the <code class="language-plaintext highlighter-rouge">pages</code> repository on <code class="language-plaintext highlighter-rouge">fix/microblog-rate-limit</code>.
Documentation is in the separate <code class="language-plaintext highlighter-rouge">CSA</code> repository on the same branch name.</p>

<h2 id="behavior">Behavior</h2>

<ul>
  <li>Posts, edits, and replies share one 30-second cooldown per browser origin.</li>
  <li>The cooldown starts before a write request is sent. Failed requests also consume
the cooldown to prevent repeated retries from flooding the API.</li>
  <li>Save and Reply buttons display <code class="language-plaintext highlighter-rouge">Saving...</code> and are disabled while their request
runs. A second write is rejected while a request is pending, even after 30 seconds.</li>
  <li>Attempts during cooldown use the existing browser alert popup to explain how
many seconds remain. The form stays open and keeps the entered content.</li>
  <li>Local storage preserves the cooldown across refreshes, navigation, and tabs.
Web Locks prevents simultaneous admission from multiple tabs where supported.</li>
  <li>HTTP 429 responses extend the cooldown using <code class="language-plaintext highlighter-rouge">Retry-After</code> in seconds or HTTP
date format. Missing/invalid headers retain the default cooldown.</li>
  <li>Reading posts and replies is not limited.</li>
</ul>

<h2 id="files">Files</h2>

<ul>
  <li><code class="language-plaintext highlighter-rouge">pages/assets/js/api/microblog.js</code>: routes all three write functions through
the shared limiter; API paths and request bodies are unchanged.</li>
  <li><code class="language-plaintext highlighter-rouge">pages/assets/js/api/microblog-rate-limit.js</code>: cooldown, persistence, pending
request protection, cross-tab admission, and server backoff handling.</li>
  <li><code class="language-plaintext highlighter-rouge">pages/_includes/microblog_foundation.html</code>: shared create/edit/reply forms,
disabled buttons during requests, and existing error popups.</li>
  <li><code class="language-plaintext highlighter-rouge">pages/tests/microblog_rate_limit.test.mjs</code>: deterministic behavioral tests.</li>
</ul>

<p>Change <code class="language-plaintext highlighter-rouge">MICROBLOG_COOLDOWN_MS</code> in the limiter to adjust the default interval.</p>

<h2 id="scope-and-limitations">Scope and limitations</h2>

<p>This is client-side protection against UI spam, not an enforceable API quota.
Clearing storage, using another browser, or calling the API directly bypasses it.
When storage is unavailable, protection falls back to page memory and logs a
warning. Browsers without Web Locks have a potential simultaneous cross-tab race.
The shared interval also applies when switching accounts in the same browser.</p>

<p>The API module sends requests to the separate Flask service’s <code class="language-plaintext highlighter-rouge">/api/microblog</code>
and <code class="language-plaintext highlighter-rouge">/api/microblog/reply</code> endpoints; it does not directly create Git commits.
For protection against deliberate abuse, the backend must independently enforce
an authenticated-user quota before database writes or downstream side effects.
For cross-origin server backoff, expose <code class="language-plaintext highlighter-rouge">Retry-After</code> through CORS.
No backend code or deployment is changed by this patch.</p>

<h2 id="verification">Verification</h2>

<p>From <code class="language-plaintext highlighter-rouge">CSA Folder/pages</code>, run:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>node <span class="nt">--test</span> tests/microblog_rate_limit.test.mjs tests/microblog_forms.test.mjs
git diff <span class="nt">--check</span>
</code></pre></div></div>

<p>Manual browser checks after serving the site through the repository Makefile:</p>

<ol>
  <li>Open a page that includes the microblog, sign in, and save a post. During the
request, confirm Save displays <code class="language-plaintext highlighter-rouge">Saving...</code> and cannot be clicked again.</li>
  <li>Immediately try an edit or reply. Confirm the popup gives the remaining wait,
the draft remains available, and no additional write appears in Network.</li>
  <li>Reload or open another page/tab and try again within 30 seconds; it should
remain blocked. After the interval, one new write should succeed.</li>
  <li>With a slow request, confirm no additional write can start while it is pending.</li>
  <li>Simulate an HTTP 429 with <code class="language-plaintext highlighter-rouge">Retry-After: 120</code>; confirm the longer wait is shown.</li>
</ol>

<p>Automated tests cover duplicate rejection, reload persistence, cooldown expiry,
pending requests, failed requests, numeric/date server backoff, shared admission
through all three API write functions, unrestricted reads, disabled form buttons,
popup text, and preserving a rejected draft. Requests are mocked; these tests do
not create real posts or commits.</p>

<h2 id="windows-local-setup-2026-10-14">Windows local setup (2026-10-14)</h2>

<p>The subsequent <a href="make-wsl-fix.md">Debian WSL Make repair</a> makes WSL the local
default: <code class="language-plaintext highlighter-rouge">.bundle/config</code> now uses <code class="language-plaintext highlighter-rouge">vendor/bundle-debian</code>. For the Windows commands
below, set <code class="language-plaintext highlighter-rouge">$env:BUNDLE_PATH='vendor/bundle'</code> first. Use <code class="language-plaintext highlighter-rouge">make</code> directly in Debian.</p>

<p>Ruby 3.3 was already installed. Installed Bundler 4.0.19 and RubyInstaller’s
MSYS2/MINGW toolchain (<code class="language-plaintext highlighter-rouge">ridk.cmd install 1 3</code>) to build native gems, then installed
the bundle into <code class="language-plaintext highlighter-rouge">pages/vendor/bundle</code>. The ignored <code class="language-plaintext highlighter-rouge">.bundle/config</code> records that
path, so subsequent <code class="language-plaintext highlighter-rouge">bundle exec</code> commands find the installed gems.</p>

<p>Generated Courses, Blogs, and Topics layouts with the existing
<code class="language-plaintext highlighter-rouge">scripts/publish_project.rb</code> publisher. In the agent’s restricted shell Ruby
<code class="language-plaintext highlighter-rouge">Dir.glob</code> returned empty results; publication needed an unrestricted shell.
The checked-in Python virtual environments refer to Linux paths and do not run
on Windows. The local, ignored <code class="language-plaintext highlighter-rouge">_sass/projects/_all.scss</code> was generated with the
same directory scan as <code class="language-plaintext highlighter-rouge">scripts/generate_sass_imports.py</code> using Node instead.
This prepares the existing checked-out Markdown for Jekyll; it does not run the
full notebook/DOCX conversion pipeline.</p>

<p>Cached the configured <code class="language-plaintext highlighter-rouge">jekyll/minima</code> HEAD theme in
<code class="language-plaintext highlighter-rouge">vendor/minima-local/minima-HEAD</code>. The ignored <code class="language-plaintext highlighter-rouge">_config.local.yml</code> selects that
copy and explicitly enables <code class="language-plaintext highlighter-rouge">jekyll-remote-theme</code>, <code class="language-plaintext highlighter-rouge">jekyll-include-cache</code>,
<code class="language-plaintext highlighter-rouge">jekyll-seo-tag</code>, and <code class="language-plaintext highlighter-rouge">jekyll-feed</code>. Production <code class="language-plaintext highlighter-rouge">_config.yml</code> is unchanged.</p>

<p>Start from <code class="language-plaintext highlighter-rouge">CSA Folder/pages</code>:</p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">bundle</span><span class="w"> </span><span class="nx">exec</span><span class="w"> </span><span class="nx">jekyll</span><span class="w"> </span><span class="nx">serve</span><span class="w"> </span><span class="nt">--config</span><span class="w"> </span><span class="nx">_config.yml</span><span class="p">,</span><span class="nx">_config.local.yml</span><span class="w"> </span><span class="nt">--host</span><span class="w"> </span><span class="nx">127.0.0.1</span><span class="w"> </span><span class="nt">--port</span><span class="w"> </span><span class="nx">4500</span><span class="w"> </span><span class="nt">--no-watch</span><span class="w">
</span></code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">--no-watch</code> matches the repository’s Jekyll target; restart to rebuild edits.
The full Makefile conversion workflow still requires a working Python environment
and its dependencies. MSYS2 supplies Make, accessible through <code class="language-plaintext highlighter-rouge">ridk.cmd exec make</code>.</p>

<h3 id="verified-results">Verified results</h3>

<ul>
  <li>Jekyll completed generation in 174.702 seconds and started serving on
<code class="language-plaintext highlighter-rouge">http://127.0.0.1:4500/</code>. Existing <code class="language-plaintext highlighter-rouge">post_url</code> deprecation warnings remain.</li>
  <li>HTTP 200 verified for <code class="language-plaintext highlighter-rouge">/microblog</code>, <code class="language-plaintext highlighter-rouge">/assets/js/api/microblog.js</code>,
<code class="language-plaintext highlighter-rouge">/assets/js/api/microblog-rate-limit.js</code>, and <code class="language-plaintext highlighter-rouge">/assets/js/api/config.js</code>.</li>
  <li>The served microblog HTML contains both forms, the disabled-button handling,
and popup handler; the served API imports the limiter. Config Liquid values
were rendered successfully.</li>
  <li>All five Node tests pass, including simulated simultaneous tabs with Web Locks.</li>
  <li><code class="language-plaintext highlighter-rouge">git diff --check</code> passes.</li>
  <li>No browser connection was available for visual testing. Form behavior was
tested through the actual handlers with mocked DOM/API objects. The Flask
backend was not started, and no live microblog writes were made.</li>
</ul>]]></content><author><name>Jade</name></author><summary type="html"><![CDATA[The Problem On the microblog within the lessons, if you were to make a post, you can spam the button and that would create basically a million different posts.]]></summary></entry><entry><title type="html">MCQ Review</title><link href="https://xinjiav2.github.io/CSA/mcq-r/" rel="alternate" type="text/html" title="MCQ Review" /><published>2026-10-12T00:00:00+00:00</published><updated>2026-10-12T00:00:00+00:00</updated><id>https://xinjiav2.github.io/CSA/MCQ_review</id><content type="html" xml:base="https://xinjiav2.github.io/CSA/mcq-r/"><![CDATA[<h1 id="mcq-review">MCQ Review</h1>

<p>Ok so the mcq was lowk a pain in the ass</p>

<p>but i did it :D</p>

<h2 id="7">7</h2>

<p>Which of the following expressions can be used to replace /* missing code */ so that this code segment prints the string ”HIDE”?</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">String</span> <span class="n">original</span> <span class="o">=</span> <span class="s">"DEFGHI"</span><span class="o">;</span>
<span class="nc">String</span> <span class="n">result</span> <span class="o">=</span> <span class="cm">/* missing code */</span><span class="o">;</span>
<span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">result</span><span class="o">);</span>
</code></pre></div></div>

<p>my answer:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">original</span><span class="o">.</span><span class="na">substring</span><span class="o">(</span><span class="mi">4</span><span class="o">)</span> <span class="o">+</span>  <span class="n">original</span><span class="o">.</span><span class="na">substring</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="mi">1</span><span class="o">)</span>
</code></pre></div></div>

<p>correct answer:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">original</span><span class="o">.</span><span class="na">substring</span><span class="o">(</span><span class="mi">4</span><span class="o">)</span> <span class="o">+</span>  <span class="n">original</span><span class="o">.</span><span class="na">substring</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="mi">2</span><span class="o">)</span>
</code></pre></div></div>

<p>I believed that it was inclusive 1 so it would print D and E instead it only prints D</p>

<p>0,2 is correct as it prints D and E</p>

<h2 id="9">9</h2>

<p>Which of the following best explains why an error occurs when the classes are compiled?</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">Measurement</span>
<span class="o">{</span>
   <span class="kd">private</span> <span class="kt">int</span> <span class="n">feet</span><span class="o">;</span>
   <span class="kd">private</span> <span class="kt">int</span> <span class="n">inches</span><span class="o">;</span>

   <span class="kd">public</span> <span class="nf">Measurement</span><span class="o">(</span><span class="kt">int</span> <span class="n">numFeet</span><span class="o">,</span> <span class="kt">int</span> <span class="n">numInches</span><span class="o">)</span>  
   <span class="o">{</span>
      <span class="n">feet</span> <span class="o">=</span> <span class="n">numFeet</span><span class="o">;</span>
      <span class="n">inches</span> <span class="o">=</span> <span class="n">numInches</span><span class="o">;</span>
   <span class="o">}</span>

  <span class="kd">private</span> <span class="kt">int</span> <span class="nf">toInches</span><span class="o">()</span>
  <span class="o">{</span>
     <span class="k">return</span> <span class="n">feet</span> <span class="o">*</span> <span class="mi">12</span> <span class="o">+</span> <span class="n">inches</span><span class="o">;</span>
  <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">Calculations</span>
<span class="o">{</span>
   <span class="kd">public</span> <span class="kd">static</span> <span class="kt">boolean</span> <span class="nf">compare</span><span class="o">(</span><span class="nc">Measurement</span> <span class="n">m1</span><span class="o">,</span> <span class="nc">Measurement</span> <span class="n">m2</span><span class="o">)</span>
   <span class="o">{</span>
      <span class="k">if</span> <span class="o">(</span><span class="n">m1</span><span class="o">.</span><span class="na">toInches</span><span class="o">()</span> <span class="o">&gt;=</span> <span class="n">m2</span><span class="o">.</span><span class="na">toInches</span><span class="o">())</span>
      <span class="o">{</span>
         <span class="k">return</span> <span class="kc">true</span><span class="o">;</span>
      <span class="o">}</span>
      <span class="k">return</span> <span class="kc">false</span><span class="o">;</span>
   <span class="o">}</span>
<span class="o">}</span> 
</code></pre></div></div>

<p>my answer:
The variables feet and inches cannot be accessed from the method toInches.</p>

<p>correct answer:
The toInches method cannot be accessed from a class other than Measurement.</p>

<p>why ?
The problem is not that feet and inches are private.</p>

<p>The real issue is this line:</p>

<p>toInches() is declared as:</p>

<p>and private means:</p>

<p>it can only be used inside the Measurement class itself
it cannot be called from another class like Calculations</p>

<p>So when Calculations.compare(…) tries to call m1.toInches(), Java throws a compile-time error because the method is not accessible outside Measurement.</p>

<p>## 
<img src="image.png" alt="alt text" /></p>

<h2 id="19">19</h2>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="n">r</span> <span class="o">=</span> <span class="o">(</span><span class="kt">int</span><span class="o">)</span> <span class="o">(</span><span class="nc">Math</span><span class="o">.</span><span class="na">random</span><span class="o">()</span> <span class="o">*</span> <span class="mi">6</span><span class="o">)</span> <span class="o">+</span> <span class="mi">10</span><span class="o">;</span>
</code></pre></div></div>

<p>my answer: It generates a random integer between  10  and  16,  inclusive, and assigns it to r.</p>

<p>answer : It generates a random integer between  10  and  15,  inclusive, and assigns it to r.</p>

<h2 id="35">35</h2>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">static</span> <span class="kt">boolean</span> <span class="nf">mystery</span><span class="o">(</span><span class="nc">ArrayList</span><span class="o">&lt;</span><span class="nc">Integer</span><span class="o">&gt;</span> <span class="n">numbers</span><span class="o">)</span>
<span class="o">{</span>
   <span class="kt">int</span> <span class="n">prev</span> <span class="o">=</span> <span class="nc">Integer</span><span class="o">.</span><span class="na">MAX_VALUE</span><span class="o">;</span>
   <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">num</span> <span class="o">:</span> <span class="n">numbers</span><span class="o">)</span>
   <span class="o">{</span>
      <span class="k">if</span> <span class="o">(</span><span class="n">num</span> <span class="o">&gt;</span> <span class="n">prev</span><span class="o">)</span>
      <span class="o">{</span>
         <span class="k">return</span> <span class="kc">false</span><span class="o">;</span>
      <span class="o">}</span>
      <span class="n">prev</span> <span class="o">=</span> <span class="n">num</span><span class="o">;</span>
   <span class="o">}</span>
   <span class="k">return</span> <span class="kc">true</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>

<p>my answer: 
It returns  true  if  numbers  is sorted from least to greatest and returns  false  otherwise.</p>

<p>correct answer:
It returns  true  if  numbers  is sorted from greatest to least and returns  false  otherwise.</p>]]></content><author><name>Jade</name></author><summary type="html"><![CDATA[MCQ Review]]></summary></entry><entry><title type="html">Fucking Around</title><link href="https://xinjiav2.github.io/CSA/fucking-around/" rel="alternate" type="text/html" title="Fucking Around" /><published>2026-09-23T00:00:00+00:00</published><updated>2026-09-23T00:00:00+00:00</updated><id>https://xinjiav2.github.io/CSA/fingaround</id><content type="html" xml:base="https://xinjiav2.github.io/CSA/fucking-around/"><![CDATA[<p>Hey there!</p>

<p>i made this entire file within vim, hence the name “fucking around” :)</p>

<p>godspeed</p>

<p>-jade</p>]]></content><author><name>Jade</name></author><summary type="html"><![CDATA[Hey there!]]></summary></entry><entry><title type="html">Booting Fedora on my Arm laptop</title><link href="https://xinjiav2.github.io/CSA/fedora/" rel="alternate" type="text/html" title="Booting Fedora on my Arm laptop" /><published>2026-09-15T00:00:00+00:00</published><updated>2026-09-15T00:00:00+00:00</updated><id>https://xinjiav2.github.io/CSA/boot-fedora-aarch64</id><content type="html" xml:base="https://xinjiav2.github.io/CSA/fedora/"><![CDATA[<h1 id="basic-information">Basic Information</h1>
<p>System info:
HP OmniBook X 14 (Model 14-fe0xxx)
Snapdragon X Elite
16gb
1TB ssd
Win 11 Home, Ubuntu 26.04 LTS</p>

<p>Try to boot Fedora 44, KDE Plasma desktop env,</p>

<p>4GB usb, flashed w/ rufus in dd mode.</p>

<p>In Fedora GRUB, countdown and boots into fedora workstation, however nothing happens</p>

<h2 id="fix">Fix</h2>

<p>As I already have a working Ubuntu install on my laptop, I can directly chainload off of my Ubuntu GRUB</p>

<ol>
  <li>Have usb plugged into laptop, run <code class="language-plaintext highlighter-rouge">lsblk -o NAME,LABEL,UUID,FSTYPE</code></li>
  <li>find uuid of <code class="language-plaintext highlighter-rouge">Fedora-KDE-Live-44</code>, in my case my uuid was <code class="language-plaintext highlighter-rouge">2026-04-22-14-19-37-00</code></li>
  <li>Add Fedora to the Ubuntu GRUB, run <code class="language-plaintext highlighter-rouge">sudo nano /etc/grub.d/40_custom</code>, paste the following text (replace 2026-04-22-14-19-37-00 with your uuid)
    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>menuentry "Start Fedora Live via Ubuntu GRUB" --class fedora {
 insmod part_gpt
 insmod ext2
 search --no-floppy --fs-uuid --set=root 2026-04-22-14-19-37-00
 linux /boot/aarch64/loader/linux root=live:UUID=2026-04-22-14-19-37-00 rd.live.image quiet rhgb clk_ignore_unused pd_ignore_unused arm64.nopauth modprobe.blacklist=qcom_q6v5_pas systemd.tpm2_wait=0
 initrd /boot/aarch64/loader/initrd
}
</code></pre></div>    </div>
  </li>
  <li>update grub by running <code class="language-plaintext highlighter-rouge">sudo update-grub</code></li>
</ol>

<p>After this I restarted laptop, and on Ubuntu GRUB screen there is option “Start Fedora Live via Ubuntu GRUB”, where I can boot Fedora via Ubuntu’s GRUB
After this I continue w/ Fedora installation normally</p>]]></content><author><name>Jade</name></author><summary type="html"><![CDATA[Basic Information System info: HP OmniBook X 14 (Model 14-fe0xxx) Snapdragon X Elite 16gb 1TB ssd Win 11 Home, Ubuntu 26.04 LTS]]></summary></entry><entry><title type="html">Java Lesson - ‘this’ keyword</title><link href="https://xinjiav2.github.io/CSA/tkeyword/" rel="alternate" type="text/html" title="Java Lesson - ‘this’ keyword" /><published>2026-09-15T00:00:00+00:00</published><updated>2026-09-15T00:00:00+00:00</updated><id>https://xinjiav2.github.io/CSA/lesson_thisKeyword</id><content type="html" xml:base="https://xinjiav2.github.io/CSA/tkeyword/"><![CDATA[<h2 id="the-this-keyword">The <code class="language-plaintext highlighter-rouge">this</code> Keyword</h2>

<h3 id="learning-targets">Learning Targets</h3>

<ul>
  <li>Explain which object <code class="language-plaintext highlighter-rouge">this</code> refers to.</li>
  <li>Distinguish instance variables from parameters with the same name.</li>
  <li>Use <code class="language-plaintext highlighter-rouge">this</code> in constructors and instance methods.</li>
  <li>Pass the current object as an argument.</li>
  <li>Explain why a static method cannot use <code class="language-plaintext highlighter-rouge">this</code>.</li>
</ul>

<hr />

<h2 id="what-does-this-mean">What Does <code class="language-plaintext highlighter-rouge">this</code> Mean?</h2>

<p><strong><code class="language-plaintext highlighter-rouge">this</code> is a reference to the current object.</strong> In an instance method, it refers to the object receiving the method call. In a constructor, it refers to the object being initialized.</p>

<p>Think of <code class="language-plaintext highlighter-rouge">this.score</code> as “this object’s score.” Each object has its own instance variables, so the object receiving the call determines which score is accessed.</p>

<h3 id="example-two-players">Example: Two Players</h3>

<p>Save this complete example as <code class="language-plaintext highlighter-rouge">Player.java</code> and run it. Later snippets labeled as methods belong inside their indicated class; driver statements belong in <code class="language-plaintext highlighter-rouge">main</code>.</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">Player</span> <span class="o">{</span>
    <span class="kd">private</span> <span class="nc">String</span> <span class="n">name</span><span class="o">;</span>
    <span class="kd">private</span> <span class="kt">int</span> <span class="n">score</span><span class="o">;</span>

    <span class="kd">public</span> <span class="nf">Player</span><span class="o">(</span><span class="nc">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">int</span> <span class="n">score</span><span class="o">)</span> <span class="o">{</span>
        <span class="k">this</span><span class="o">.</span><span class="na">name</span> <span class="o">=</span> <span class="n">name</span><span class="o">;</span>
        <span class="k">this</span><span class="o">.</span><span class="na">score</span> <span class="o">=</span> <span class="n">score</span><span class="o">;</span>
    <span class="o">}</span>

    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">addPoints</span><span class="o">(</span><span class="kt">int</span> <span class="n">points</span><span class="o">)</span> <span class="o">{</span>
        <span class="k">this</span><span class="o">.</span><span class="na">score</span> <span class="o">+=</span> <span class="n">points</span><span class="o">;</span>
    <span class="o">}</span>

    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">printInfo</span><span class="o">()</span> <span class="o">{</span>
        <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="k">this</span><span class="o">.</span><span class="na">name</span> <span class="o">+</span> <span class="s">": "</span> <span class="o">+</span> <span class="k">this</span><span class="o">.</span><span class="na">score</span><span class="o">);</span>
    <span class="o">}</span>

    <span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">main</span><span class="o">(</span><span class="nc">String</span><span class="o">[]</span> <span class="n">args</span><span class="o">)</span> <span class="o">{</span>
        <span class="nc">Player</span> <span class="n">jade</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Player</span><span class="o">(</span><span class="s">"Jade"</span><span class="o">,</span> <span class="mi">10</span><span class="o">);</span>
        <span class="nc">Player</span> <span class="n">alex</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Player</span><span class="o">(</span><span class="s">"Alex"</span><span class="o">,</span> <span class="mi">20</span><span class="o">);</span>

        <span class="n">jade</span><span class="o">.</span><span class="na">addPoints</span><span class="o">(</span><span class="mi">5</span><span class="o">);</span>
        <span class="n">jade</span><span class="o">.</span><span class="na">printInfo</span><span class="o">();</span>
        <span class="n">alex</span><span class="o">.</span><span class="na">printInfo</span><span class="o">();</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p><strong>Output:</strong></p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Jade: 15
Alex: 20
</code></pre></div></div>

<h3 id="how-does-this-work">How Does This Work?</h3>

<p>For <code class="language-plaintext highlighter-rouge">jade.addPoints(5)</code>, <code class="language-plaintext highlighter-rouge">this</code> refers to the same object as <code class="language-plaintext highlighter-rouge">jade</code>. The method changes that object’s score. When <code class="language-plaintext highlighter-rouge">alex.printInfo()</code> runs, <code class="language-plaintext highlighter-rouge">this</code> refers to Alex’s object instead.</p>

<table>
  <thead>
    <tr>
      <th>Call</th>
      <th>Object referred to by <code class="language-plaintext highlighter-rouge">this</code></th>
      <th>Result</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">jade.addPoints(5)</code></td>
      <td>Jade’s player</td>
      <td>Score becomes 15</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">jade.printInfo()</code></td>
      <td>Jade’s player</td>
      <td>Prints <code class="language-plaintext highlighter-rouge">Jade: 15</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">alex.printInfo()</code></td>
      <td>Alex’s player</td>
      <td>Prints <code class="language-plaintext highlighter-rouge">Alex: 20</code></td>
    </tr>
  </tbody>
</table>

<h3 id="popcorn-hacks">Popcorn Hacks</h3>

<ol>
  <li>Create a third player and add points to it.</li>
  <li>Predict all three scores before printing them.</li>
  <li>Explain why changing one player’s score does not change the others.</li>
</ol>

<hr />

<h2 id="parameter-shadowing">Parameter Shadowing</h2>

<p><strong>Shadowing</strong> happens when a parameter or local variable has the same name as a field. Within that variable’s scope, the plain name refers to that variable; <code class="language-plaintext highlighter-rouge">this.name</code> explicitly accesses the current object’s field. <a href="https://docs.oracle.com/javase/tutorial/java/javaOO/thiskey.html">Oracle’s <code class="language-plaintext highlighter-rouge">this</code> tutorial</a> explains this distinction.</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Constructor inside Player</span>
<span class="kd">public</span> <span class="nf">Player</span><span class="o">(</span><span class="nc">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">int</span> <span class="n">score</span><span class="o">)</span> <span class="o">{</span>
    <span class="k">this</span><span class="o">.</span><span class="na">name</span> <span class="o">=</span> <span class="n">name</span><span class="o">;</span>
    <span class="k">this</span><span class="o">.</span><span class="na">score</span> <span class="o">=</span> <span class="n">score</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>

<p>In <code class="language-plaintext highlighter-rouge">this.score = score;</code>:</p>

<ul>
  <li><strong>Left side, <code class="language-plaintext highlighter-rouge">this.score</code>:</strong> the object’s instance variable.</li>
  <li><strong>Right side, <code class="language-plaintext highlighter-rouge">score</code>:</strong> the constructor parameter.</li>
  <li><strong>Assignment:</strong> copies the parameter’s value into the field.</li>
</ul>

<h3 id="the-self-assignment-bug">The Self-Assignment Bug</h3>

<p>The <a href="https://stackoverflow.com/questions/516291/the-use-of-this-in-java">Stack Overflow discussion supplied for this lesson</a> asks why a constructor using <code class="language-plaintext highlighter-rouge">j = j;</code> and <code class="language-plaintext highlighter-rouge">k = k;</code> leaves integer fields at zero. Both sides refer to parameters, so neither field changes.</p>

<p>Here is an original version of that bug:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Incorrect replacement for the Player constructor</span>
<span class="kd">public</span> <span class="nf">Player</span><span class="o">(</span><span class="nc">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">int</span> <span class="n">score</span><span class="o">)</span> <span class="o">{</span>
    <span class="n">name</span> <span class="o">=</span> <span class="n">name</span><span class="o">;</span>
    <span class="n">score</span> <span class="o">=</span> <span class="n">score</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>

<p>This compiles, but <code class="language-plaintext highlighter-rouge">new Player("Jade", 10)</code> leaves <code class="language-plaintext highlighter-rouge">name</code> as <code class="language-plaintext highlighter-rouge">null</code> and <code class="language-plaintext highlighter-rouge">score</code> as <code class="language-plaintext highlighter-rouge">0</code>. Calling <code class="language-plaintext highlighter-rouge">printInfo()</code> immediately afterward prints <code class="language-plaintext highlighter-rouge">null: 0</code>.</p>

<p>Those are field default values. A field with an explicit initializer would retain that value instead. Local variables do not automatically receive these defaults.</p>

<h3 id="when-is-this-optional">When Is <code class="language-plaintext highlighter-rouge">this</code> Optional?</h3>

<p>If the names differ, there is no shadowing:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Alternative constructor inside Player</span>
<span class="kd">public</span> <span class="nf">Player</span><span class="o">(</span><span class="nc">String</span> <span class="n">playerName</span><span class="o">,</span> <span class="kt">int</span> <span class="n">startingScore</span><span class="o">)</span> <span class="o">{</span>
    <span class="n">name</span> <span class="o">=</span> <span class="n">playerName</span><span class="o">;</span>
    <span class="n">score</span> <span class="o">=</span> <span class="n">startingScore</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>

<p>In a getter with no shadowing, <code class="language-plaintext highlighter-rouge">return score;</code> and <code class="language-plaintext highlighter-rouge">return this.score;</code> have the same effect.</p>

<h3 id="popcorn-hacks-1">Popcorn Hacks</h3>

<p>Fix this method inside <code class="language-plaintext highlighter-rouge">Player</code>. It should replace the player’s score with the argument’s value.</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kt">void</span> <span class="nf">setScore</span><span class="o">(</span><span class="kt">int</span> <span class="n">score</span><span class="o">)</span> <span class="o">{</span>
    <span class="n">score</span> <span class="o">=</span> <span class="n">score</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Explain what each occurrence of <code class="language-plaintext highlighter-rouge">score</code> means before and after your fix.</p>

<hr />

<h2 id="calling-an-instance-method-with-this">Calling an Instance Method with <code class="language-plaintext highlighter-rouge">this</code></h2>

<p>An instance method can call another instance method on the current object:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Add inside Player</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">celebrate</span><span class="o">()</span> <span class="o">{</span>
    <span class="k">this</span><span class="o">.</span><span class="na">addPoints</span><span class="o">(</span><span class="mi">10</span><span class="o">);</span>
    <span class="k">this</span><span class="o">.</span><span class="na">printInfo</span><span class="o">();</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Calling <code class="language-plaintext highlighter-rouge">jade.celebrate()</code> adds points to Jade and prints Jade’s information. In this example, writing <code class="language-plaintext highlighter-rouge">addPoints(10);</code> and <code class="language-plaintext highlighter-rouge">printInfo();</code> would work too.</p>

<h2 id="passing-this-as-an-argument">Passing <code class="language-plaintext highlighter-rouge">this</code> as an Argument</h2>

<p>Sometimes another method needs the whole current object. Passing <code class="language-plaintext highlighter-rouge">this</code> supplies that reference. This use appears in both the uploaded Fiveable lesson and the supplied Stack Overflow discussion.</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Add inside Player</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">join</span><span class="o">(</span><span class="nc">Team</span> <span class="n">team</span><span class="o">)</span> <span class="o">{</span>
    <span class="n">team</span><span class="o">.</span><span class="na">addPlayer</span><span class="o">(</span><span class="k">this</span><span class="o">);</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Add this separate class after the closing brace of <code class="language-plaintext highlighter-rouge">Player</code> in <code class="language-plaintext highlighter-rouge">Player.java</code>:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">Team</span> <span class="o">{</span>
    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">addPlayer</span><span class="o">(</span><span class="nc">Player</span> <span class="n">player</span><span class="o">)</span> <span class="o">{</span>
        <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">print</span><span class="o">(</span><span class="s">"Joined team: "</span><span class="o">);</span>
        <span class="n">player</span><span class="o">.</span><span class="na">printInfo</span><span class="o">();</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Then add these driver statements to <code class="language-plaintext highlighter-rouge">main</code>:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Team</span> <span class="n">team</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Team</span><span class="o">();</span>
<span class="n">jade</span><span class="o">.</span><span class="na">join</span><span class="o">(</span><span class="n">team</span><span class="o">);</span>
</code></pre></div></div>

<p>Here, <code class="language-plaintext highlighter-rouge">this</code> in <code class="language-plaintext highlighter-rouge">join</code> and the parameter <code class="language-plaintext highlighter-rouge">player</code> in <code class="language-plaintext highlighter-rouge">addPlayer</code> refer to Jade’s same object. No new <code class="language-plaintext highlighter-rouge">Player</code> is created. This simplified team announces the player; it does not store a roster.</p>

<h3 id="popcorn-hacks-2">Popcorn Hacks</h3>

<p>Modify <code class="language-plaintext highlighter-rouge">Team.addPlayer</code> to award the incoming player three points before printing. Predict whether printing <code class="language-plaintext highlighter-rouge">jade</code> afterward will show that increase, and explain why.</p>

<hr />

<h2 id="why-static-methods-cannot-use-this">Why Static Methods Cannot Use <code class="language-plaintext highlighter-rouge">this</code></h2>

<p>A static method belongs to the class and has no current object. This method inside <code class="language-plaintext highlighter-rouge">Player</code> produces a <strong>compile-time error</strong>:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Intentionally invalid</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">showScore</span><span class="o">()</span> <span class="o">{</span>
    <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="k">this</span><span class="o">.</span><span class="na">score</span><span class="o">);</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Two valid alternatives are:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Instance method: the receiving object supplies this</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">showScore</span><span class="o">()</span> <span class="o">{</span>
    <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="k">this</span><span class="o">.</span><span class="na">score</span><span class="o">);</span>
<span class="o">}</span>
</code></pre></div></div>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Static method inside Player: use an explicit object reference</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">showScore</span><span class="o">(</span><span class="nc">Player</span> <span class="n">player</span><span class="o">)</span> <span class="o">{</span>
    <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">player</span><span class="o">.</span><span class="na">score</span><span class="o">);</span>
<span class="o">}</span>
</code></pre></div></div>

<p>The second method assumes <code class="language-plaintext highlighter-rouge">player</code> is non-null. It can access the private field because the method is declared inside <code class="language-plaintext highlighter-rouge">Player</code>.</p>

<p>In <code class="language-plaintext highlighter-rouge">main</code>, use <code class="language-plaintext highlighter-rouge">jade.showScore()</code> for the first version or <code class="language-plaintext highlighter-rouge">Player.showScore(jade)</code> for the second.</p>

<hr />

<h2 id="optional-extension-this-and-return-this">Optional Extension: <code class="language-plaintext highlighter-rouge">this(...)</code> and <code class="language-plaintext highlighter-rouge">return this</code></h2>

<p>The uploaded Fiveable guide treats constructor chaining and fluent method chaining as enrichment. Focus first on object references, shadowing, passing <code class="language-plaintext highlighter-rouge">this</code>, and static contexts.</p>

<h3 id="constructor-chaining">Constructor Chaining</h3>

<p><code class="language-plaintext highlighter-rouge">this(...)</code> calls another constructor in the <strong>same class</strong>. Add this overload alongside the original two-parameter <code class="language-plaintext highlighter-rouge">Player</code> constructor:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="nf">Player</span><span class="o">(</span><span class="nc">String</span> <span class="n">name</span><span class="o">)</span> <span class="o">{</span>
    <span class="k">this</span><span class="o">(</span><span class="n">name</span><span class="o">,</span> <span class="mi">0</span><span class="o">);</span>
<span class="o">}</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">new Player("Sam")</code> delegates initialization to <code class="language-plaintext highlighter-rouge">Player(String, int)</code>, using zero as the initial score. It initializes one object. Put <code class="language-plaintext highlighter-rouge">this(...)</code> first for compatibility with Java 21 and earlier; newer Java versions have more flexible constructor-body rules. Constructor calls must not form a recursive cycle.</p>

<h3 id="returning-the-current-object">Returning the Current Object</h3>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Add inside Player</span>
<span class="kd">public</span> <span class="nc">Player</span> <span class="nf">award</span><span class="o">(</span><span class="kt">int</span> <span class="n">points</span><span class="o">)</span> <span class="o">{</span>
    <span class="k">this</span><span class="o">.</span><span class="na">score</span> <span class="o">+=</span> <span class="n">points</span><span class="o">;</span>
    <span class="k">return</span> <span class="k">this</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>

<p>The driver statement <code class="language-plaintext highlighter-rouge">jade.award(5).award(2);</code> adds seven points to the same player. Returning <code class="language-plaintext highlighter-rouge">this</code> allows another method call on that object.</p>

<table>
  <thead>
    <tr>
      <th>Syntax</th>
      <th>Meaning</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">this.score</code></td>
      <td>Access this object’s field</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">this.printInfo()</code></td>
      <td>Call a method on this object</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">team.addPlayer(this)</code></td>
      <td>Pass this object as an argument</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">this(name, 0)</code></td>
      <td>Invoke another constructor in this class</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">return this</code></td>
      <td>Return a reference to this object</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="practice-trace-and-debug">Practice: Trace and Debug</h2>

<h3 id="1-predict-the-output">1. Predict the Output</h3>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">Counter</span> <span class="o">{</span>
    <span class="kd">private</span> <span class="kt">int</span> <span class="n">count</span><span class="o">;</span>

    <span class="kd">public</span> <span class="nf">Counter</span><span class="o">(</span><span class="kt">int</span> <span class="n">count</span><span class="o">)</span> <span class="o">{</span>
        <span class="k">this</span><span class="o">.</span><span class="na">count</span> <span class="o">=</span> <span class="n">count</span><span class="o">;</span>
    <span class="o">}</span>

    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">add</span><span class="o">(</span><span class="kt">int</span> <span class="n">count</span><span class="o">)</span> <span class="o">{</span>
        <span class="k">this</span><span class="o">.</span><span class="na">count</span> <span class="o">+=</span> <span class="n">count</span><span class="o">;</span>
        <span class="n">count</span><span class="o">++;</span>
    <span class="o">}</span>

    <span class="kd">public</span> <span class="kt">int</span> <span class="nf">getCount</span><span class="o">()</span> <span class="o">{</span>
        <span class="k">return</span> <span class="n">count</span><span class="o">;</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Driver statements in <code class="language-plaintext highlighter-rouge">main</code>:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Counter</span> <span class="n">c</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Counter</span><span class="o">(</span><span class="mi">4</span><span class="o">);</span>
<span class="n">c</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="mi">3</span><span class="o">);</span>
<span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">c</span><span class="o">.</span><span class="na">getCount</span><span class="o">());</span>
</code></pre></div></div>

<p>Which value is printed?</p>

<ul>
  <li>A. <code class="language-plaintext highlighter-rouge">3</code></li>
  <li>B. <code class="language-plaintext highlighter-rouge">4</code></li>
  <li>C. <code class="language-plaintext highlighter-rouge">7</code></li>
  <li>D. <code class="language-plaintext highlighter-rouge">8</code></li>
</ul>

<h3 id="2-identify-the-error">2. Identify the Error</h3>

<p>Why does <code class="language-plaintext highlighter-rouge">score = score;</code> compile in the buggy constructor, while <code class="language-plaintext highlighter-rouge">this.score</code> inside a static method fails to compile?</p>

<h3 id="3-apply-the-idea">3. Apply the Idea</h3>

<p>Create a <code class="language-plaintext highlighter-rouge">Book</code> class with <code class="language-plaintext highlighter-rouge">title</code> and <code class="language-plaintext highlighter-rouge">pages</code> fields. Include:</p>

<ol>
  <li>A constructor whose parameter names match the fields.</li>
  <li>A <code class="language-plaintext highlighter-rouge">setPages(int pages)</code> method.</li>
  <li>A method that prints the book’s information.</li>
  <li>Two objects demonstrating that changing one does not affect the other.</li>
</ol>

<h3 id="answer-check">Answer Check</h3>

<ol>
  <li><strong>C: <code class="language-plaintext highlighter-rouge">7</code>.</strong> <code class="language-plaintext highlighter-rouge">this.count += count</code> adds three to the field. <code class="language-plaintext highlighter-rouge">count++</code> changes only the local parameter, so the field stays seven.</li>
  <li>Self-assignment is legal Java even though it fails to update the intended field. A static method has no current object, so <code class="language-plaintext highlighter-rouge">this</code> is unavailable.</li>
  <li>The constructor should use <code class="language-plaintext highlighter-rouge">this.title = title;</code> and <code class="language-plaintext highlighter-rouge">this.pages = pages;</code>. The setter should use <code class="language-plaintext highlighter-rouge">this.pages = pages;</code>.</li>
</ol>

<h2 id="quick-review">Quick Review</h2>

<ul>
  <li>Identify the object receiving the call to determine what <code class="language-plaintext highlighter-rouge">this</code> means.</li>
  <li>Check parameter and local-variable names before tracing a field update.</li>
  <li>Use <code class="language-plaintext highlighter-rouge">this.field</code> to access a field hidden by a parameter.</li>
  <li>Passing or returning <code class="language-plaintext highlighter-rouge">this</code> does not copy the object.</li>
  <li>Static methods need an explicit object reference to access instance data.</li>
</ul>

<h2 id="sources">Sources</h2>

<ul>
  <li><strong>Lesson structure:</strong> the supplied <code class="language-plaintext highlighter-rouge">2025-09-21-3.9.ipynb</code> notebook, adapted into learning targets, examples, explanations, and Popcorn Hacks.</li>
  <li><strong>Core topics and debugging emphasis:</strong> uploaded <em>AP CSA 3.9: this Keyword in Java</em>, <a href="https://fiveable.me/ap-comp-sci-a/unit-3/this-keyword/study-guide/Zste3M7m756uzwR0zCQK">Fiveable</a>.</li>
  <li><strong>Self-assignment question and additional uses:</strong> <a href="https://stackoverflow.com/questions/516291/the-use-of-this-in-java">The use of “this” in Java — Stack Overflow</a>.</li>
  <li><strong>Java language reference:</strong> <a href="https://docs.oracle.com/javase/tutorial/java/javaOO/thiskey.html">Using the <code class="language-plaintext highlighter-rouge">this</code> Keyword — Oracle</a>.</li>
</ul>]]></content><author><name>Jade</name></author><summary type="html"><![CDATA[The this Keyword]]></summary></entry><entry><title type="html">Backend Implementation &amp;amp; Testing</title><link href="https://xinjiav2.github.io/CSA/spt1/backend" rel="alternate" type="text/html" title="Backend Implementation &amp;amp; Testing" /><published>2026-09-09T00:00:00+00:00</published><updated>2026-09-09T00:00:00+00:00</updated><id>https://xinjiav2.github.io/CSA/spt1/Sprint-1-BACKEND</id><content type="html" xml:base="https://xinjiav2.github.io/CSA/spt1/backend"><![CDATA[<h1 id="why-i-chose-mvc">Why I chose MVC</h1>

<p>My <a href="/CSA/spt1">original design</a> is an administrator-facing account directory. I chose Option B so Spring can load records and render HTML in one application. The portfolio contains this documentation; the working forms must run on the Spring server.</p>

<p>The following implementation examples build on the <a href="/CSA/spt1/persistence">Phase 2 entity</a>. They require integration into the backend before they can run. The linked backend could not be retrieved from this environment, so its package name, dependency compatibility, login flow, and security filter rules have not been verified.</p>

<h1 id="repository">Repository</h1>

<p><code class="language-plaintext highlighter-rouge">DirectoryAccountRepository.java</code>, in the same package as the entity:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">package</span> <span class="nn">YOUR_APPLICATION_PACKAGE.directory</span><span class="o">;</span>

<span class="kn">import</span> <span class="nn">org.springframework.data.jpa.repository.JpaRepository</span><span class="o">;</span>

<span class="kd">public</span> <span class="kd">interface</span> <span class="nc">DirectoryAccountRepository</span>
        <span class="kd">extends</span> <span class="nc">JpaRepository</span><span class="o">&lt;</span><span class="nc">DirectoryAccount</span><span class="o">,</span> <span class="nc">Long</span><span class="o">&gt;</span> <span class="o">{</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Spring Data creates the repository implementation at runtime. <code class="language-plaintext highlighter-rouge">findAll()</code> retrieves records, <code class="language-plaintext highlighter-rouge">findById(id)</code> returns an <code class="language-plaintext highlighter-rouge">Optional</code>, <code class="language-plaintext highlighter-rouge">save(account)</code> inserts or updates an entity, and <code class="language-plaintext highlighter-rouge">delete(account)</code> removes it. The interface inherits these operations, so I do not write SQL for each route. No custom query is needed for this first version.</p>

<h1 id="routes">Routes</h1>

<table>
  <thead>
    <tr>
      <th>Method</th>
      <th>Route</th>
      <th>Result</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>GET</td>
      <td>/mvc/directory</td>
      <td>List HTML</td>
    </tr>
    <tr>
      <td>GET</td>
      <td>/mvc/directory/{id}</td>
      <td>Detail HTML, or 404</td>
    </tr>
    <tr>
      <td>GET</td>
      <td>/mvc/directory/new</td>
      <td>Empty creation form</td>
    </tr>
    <tr>
      <td>POST</td>
      <td>/mvc/directory</td>
      <td>Validate, create, redirect</td>
    </tr>
    <tr>
      <td>GET</td>
      <td>/mvc/directory/{id}/edit</td>
      <td>Prefilled form, or 404</td>
    </tr>
    <tr>
      <td>POST</td>
      <td>/mvc/directory/{id}</td>
      <td>Validate, update, redirect</td>
    </tr>
    <tr>
      <td>POST</td>
      <td>/mvc/directory/{id}/delete</td>
      <td>Delete, redirect, or 404</td>
    </tr>
  </tbody>
</table>

<h1 id="controller">Controller</h1>

<p><code class="language-plaintext highlighter-rouge">DirectoryAccountController.java</code>:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">package</span> <span class="nn">YOUR_APPLICATION_PACKAGE.directory</span><span class="o">;</span>

<span class="kn">import</span> <span class="nn">jakarta.validation.Valid</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">org.springframework.http.HttpStatus</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">org.springframework.stereotype.Controller</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">org.springframework.ui.Model</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">org.springframework.validation.BindingResult</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">org.springframework.web.bind.WebDataBinder</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">org.springframework.web.bind.annotation.*</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">org.springframework.web.server.ResponseStatusException</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">org.springframework.web.servlet.mvc.support.RedirectAttributes</span><span class="o">;</span>

<span class="nd">@Controller</span>
<span class="nd">@RequestMapping</span><span class="o">(</span><span class="s">"/mvc/directory"</span><span class="o">)</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">DirectoryAccountController</span> <span class="o">{</span>
    <span class="kd">private</span> <span class="kd">final</span> <span class="nc">DirectoryAccountRepository</span> <span class="n">repository</span><span class="o">;</span>

    <span class="kd">public</span> <span class="nf">DirectoryAccountController</span><span class="o">(</span><span class="nc">DirectoryAccountRepository</span> <span class="n">repository</span><span class="o">)</span> <span class="o">{</span>
        <span class="k">this</span><span class="o">.</span><span class="na">repository</span> <span class="o">=</span> <span class="n">repository</span><span class="o">;</span>
    <span class="o">}</span>

    <span class="nd">@InitBinder</span><span class="o">(</span><span class="s">"account"</span><span class="o">)</span>
    <span class="kt">void</span> <span class="nf">bindEditableFields</span><span class="o">(</span><span class="nc">WebDataBinder</span> <span class="n">binder</span><span class="o">)</span> <span class="o">{</span>
        <span class="c1">// A submitted form cannot choose the primary key or creation time.</span>
        <span class="n">binder</span><span class="o">.</span><span class="na">setAllowedFields</span><span class="o">(</span><span class="s">"name"</span><span class="o">,</span> <span class="s">"email"</span><span class="o">,</span> <span class="s">"school"</span><span class="o">,</span> <span class="s">"studentID"</span><span class="o">,</span>
                <span class="s">"githubUsername"</span><span class="o">,</span> <span class="s">"accountType"</span><span class="o">);</span>
    <span class="o">}</span>

    <span class="nd">@ModelAttribute</span><span class="o">(</span><span class="s">"accountTypes"</span><span class="o">)</span>
    <span class="nc">AccountType</span><span class="o">[]</span> <span class="nf">accountTypes</span><span class="o">()</span> <span class="o">{</span>
        <span class="k">return</span> <span class="nc">AccountType</span><span class="o">.</span><span class="na">values</span><span class="o">();</span>
    <span class="o">}</span>

    <span class="nd">@GetMapping</span>
    <span class="nc">String</span> <span class="nf">list</span><span class="o">(</span><span class="nc">Model</span> <span class="n">model</span><span class="o">)</span> <span class="o">{</span>
        <span class="n">model</span><span class="o">.</span><span class="na">addAttribute</span><span class="o">(</span><span class="s">"accounts"</span><span class="o">,</span> <span class="n">repository</span><span class="o">.</span><span class="na">findAll</span><span class="o">(</span>
                <span class="n">org</span><span class="o">.</span><span class="na">springframework</span><span class="o">.</span><span class="na">data</span><span class="o">.</span><span class="na">domain</span><span class="o">.</span><span class="na">Sort</span><span class="o">.</span><span class="na">by</span><span class="o">(</span><span class="s">"id"</span><span class="o">)));</span>
        <span class="k">return</span> <span class="s">"directory/list"</span><span class="o">;</span>
    <span class="o">}</span>

    <span class="nd">@GetMapping</span><span class="o">(</span><span class="s">"/{id}"</span><span class="o">)</span>
    <span class="nc">String</span> <span class="nf">detail</span><span class="o">(</span><span class="nd">@PathVariable</span> <span class="nc">Long</span> <span class="n">id</span><span class="o">,</span> <span class="nc">Model</span> <span class="n">model</span><span class="o">)</span> <span class="o">{</span>
        <span class="n">model</span><span class="o">.</span><span class="na">addAttribute</span><span class="o">(</span><span class="s">"account"</span><span class="o">,</span> <span class="n">requireAccount</span><span class="o">(</span><span class="n">id</span><span class="o">));</span>
        <span class="k">return</span> <span class="s">"directory/detail"</span><span class="o">;</span>
    <span class="o">}</span>

    <span class="nd">@GetMapping</span><span class="o">(</span><span class="s">"/new"</span><span class="o">)</span>
    <span class="nc">String</span> <span class="nf">createForm</span><span class="o">(</span><span class="nc">Model</span> <span class="n">model</span><span class="o">)</span> <span class="o">{</span>
        <span class="k">return</span> <span class="nf">form</span><span class="o">(</span><span class="k">new</span> <span class="nc">DirectoryAccount</span><span class="o">(),</span> <span class="kc">null</span><span class="o">,</span> <span class="n">model</span><span class="o">);</span>
    <span class="o">}</span>

    <span class="nd">@PostMapping</span>
    <span class="nc">String</span> <span class="nf">create</span><span class="o">(</span><span class="nd">@Valid</span> <span class="nd">@ModelAttribute</span><span class="o">(</span><span class="s">"account"</span><span class="o">)</span> <span class="nc">DirectoryAccount</span> <span class="n">account</span><span class="o">,</span>
                  <span class="nc">BindingResult</span> <span class="n">errors</span><span class="o">,</span> <span class="nc">Model</span> <span class="n">model</span><span class="o">,</span>
                  <span class="nc">RedirectAttributes</span> <span class="n">redirect</span><span class="o">)</span> <span class="o">{</span>
        <span class="k">if</span> <span class="o">(</span><span class="n">errors</span><span class="o">.</span><span class="na">hasErrors</span><span class="o">())</span> <span class="k">return</span> <span class="n">form</span><span class="o">(</span><span class="n">account</span><span class="o">,</span> <span class="kc">null</span><span class="o">,</span> <span class="n">model</span><span class="o">);</span>
        <span class="nc">DirectoryAccount</span> <span class="n">saved</span> <span class="o">=</span> <span class="n">repository</span><span class="o">.</span><span class="na">save</span><span class="o">(</span><span class="n">account</span><span class="o">);</span>
        <span class="n">redirect</span><span class="o">.</span><span class="na">addFlashAttribute</span><span class="o">(</span><span class="s">"message"</span><span class="o">,</span> <span class="s">"Account created."</span><span class="o">);</span>
        <span class="k">return</span> <span class="s">"redirect:/mvc/directory/"</span> <span class="o">+</span> <span class="n">saved</span><span class="o">.</span><span class="na">getId</span><span class="o">();</span>
    <span class="o">}</span>

    <span class="nd">@GetMapping</span><span class="o">(</span><span class="s">"/{id}/edit"</span><span class="o">)</span>
    <span class="nc">String</span> <span class="nf">editForm</span><span class="o">(</span><span class="nd">@PathVariable</span> <span class="nc">Long</span> <span class="n">id</span><span class="o">,</span> <span class="nc">Model</span> <span class="n">model</span><span class="o">)</span> <span class="o">{</span>
        <span class="k">return</span> <span class="nf">form</span><span class="o">(</span><span class="n">requireAccount</span><span class="o">(</span><span class="n">id</span><span class="o">),</span> <span class="n">id</span><span class="o">,</span> <span class="n">model</span><span class="o">);</span>
    <span class="o">}</span>

    <span class="nd">@PostMapping</span><span class="o">(</span><span class="s">"/{id}"</span><span class="o">)</span>
    <span class="nc">String</span> <span class="nf">update</span><span class="o">(</span><span class="nd">@PathVariable</span> <span class="nc">Long</span> <span class="n">id</span><span class="o">,</span>
                  <span class="nd">@Valid</span> <span class="nd">@ModelAttribute</span><span class="o">(</span><span class="s">"account"</span><span class="o">)</span> <span class="nc">DirectoryAccount</span> <span class="n">submitted</span><span class="o">,</span>
                  <span class="nc">BindingResult</span> <span class="n">errors</span><span class="o">,</span> <span class="nc">Model</span> <span class="n">model</span><span class="o">,</span>
                  <span class="nc">RedirectAttributes</span> <span class="n">redirect</span><span class="o">)</span> <span class="o">{</span>
        <span class="nc">DirectoryAccount</span> <span class="n">existing</span> <span class="o">=</span> <span class="n">requireAccount</span><span class="o">(</span><span class="n">id</span><span class="o">);</span>
        <span class="k">if</span> <span class="o">(</span><span class="n">errors</span><span class="o">.</span><span class="na">hasErrors</span><span class="o">())</span> <span class="k">return</span> <span class="n">form</span><span class="o">(</span><span class="n">submitted</span><span class="o">,</span> <span class="n">id</span><span class="o">,</span> <span class="n">model</span><span class="o">);</span>
        <span class="n">copyEditableFields</span><span class="o">(</span><span class="n">submitted</span><span class="o">,</span> <span class="n">existing</span><span class="o">);</span>
        <span class="n">repository</span><span class="o">.</span><span class="na">save</span><span class="o">(</span><span class="n">existing</span><span class="o">);</span>
        <span class="n">redirect</span><span class="o">.</span><span class="na">addFlashAttribute</span><span class="o">(</span><span class="s">"message"</span><span class="o">,</span> <span class="s">"Account updated."</span><span class="o">);</span>
        <span class="k">return</span> <span class="s">"redirect:/mvc/directory/"</span> <span class="o">+</span> <span class="n">id</span><span class="o">;</span>
    <span class="o">}</span>

    <span class="nd">@PostMapping</span><span class="o">(</span><span class="s">"/{id}/delete"</span><span class="o">)</span>
    <span class="nc">String</span> <span class="nf">delete</span><span class="o">(</span><span class="nd">@PathVariable</span> <span class="nc">Long</span> <span class="n">id</span><span class="o">,</span> <span class="nc">RedirectAttributes</span> <span class="n">redirect</span><span class="o">)</span> <span class="o">{</span>
        <span class="n">repository</span><span class="o">.</span><span class="na">delete</span><span class="o">(</span><span class="n">requireAccount</span><span class="o">(</span><span class="n">id</span><span class="o">));</span>
        <span class="n">redirect</span><span class="o">.</span><span class="na">addFlashAttribute</span><span class="o">(</span><span class="s">"message"</span><span class="o">,</span> <span class="s">"Account deleted."</span><span class="o">);</span>
        <span class="k">return</span> <span class="s">"redirect:/mvc/directory"</span><span class="o">;</span>
    <span class="o">}</span>

    <span class="kd">private</span> <span class="nc">DirectoryAccount</span> <span class="nf">requireAccount</span><span class="o">(</span><span class="nc">Long</span> <span class="n">id</span><span class="o">)</span> <span class="o">{</span>
        <span class="k">return</span> <span class="n">repository</span><span class="o">.</span><span class="na">findById</span><span class="o">(</span><span class="n">id</span><span class="o">).</span><span class="na">orElseThrow</span><span class="o">(()</span> <span class="o">-&gt;</span>
                <span class="k">new</span> <span class="nf">ResponseStatusException</span><span class="o">(</span><span class="nc">HttpStatus</span><span class="o">.</span><span class="na">NOT_FOUND</span><span class="o">,</span>
                        <span class="s">"Directory account not found"</span><span class="o">));</span>
    <span class="o">}</span>

    <span class="kd">private</span> <span class="nc">String</span> <span class="nf">form</span><span class="o">(</span><span class="nc">DirectoryAccount</span> <span class="n">account</span><span class="o">,</span> <span class="nc">Long</span> <span class="n">editingId</span><span class="o">,</span> <span class="nc">Model</span> <span class="n">model</span><span class="o">)</span> <span class="o">{</span>
        <span class="n">model</span><span class="o">.</span><span class="na">addAttribute</span><span class="o">(</span><span class="s">"account"</span><span class="o">,</span> <span class="n">account</span><span class="o">);</span>
        <span class="n">model</span><span class="o">.</span><span class="na">addAttribute</span><span class="o">(</span><span class="s">"editingId"</span><span class="o">,</span> <span class="n">editingId</span><span class="o">);</span>
        <span class="k">return</span> <span class="s">"directory/form"</span><span class="o">;</span>
    <span class="o">}</span>

    <span class="kd">private</span> <span class="kt">void</span> <span class="nf">copyEditableFields</span><span class="o">(</span><span class="nc">DirectoryAccount</span> <span class="n">source</span><span class="o">,</span>
                                    <span class="nc">DirectoryAccount</span> <span class="n">target</span><span class="o">)</span> <span class="o">{</span>
        <span class="n">target</span><span class="o">.</span><span class="na">setName</span><span class="o">(</span><span class="n">source</span><span class="o">.</span><span class="na">getName</span><span class="o">());</span>
        <span class="n">target</span><span class="o">.</span><span class="na">setEmail</span><span class="o">(</span><span class="n">source</span><span class="o">.</span><span class="na">getEmail</span><span class="o">());</span>
        <span class="n">target</span><span class="o">.</span><span class="na">setSchool</span><span class="o">(</span><span class="n">source</span><span class="o">.</span><span class="na">getSchool</span><span class="o">());</span>
        <span class="n">target</span><span class="o">.</span><span class="na">setStudentID</span><span class="o">(</span><span class="n">source</span><span class="o">.</span><span class="na">getStudentID</span><span class="o">());</span>
        <span class="n">target</span><span class="o">.</span><span class="na">setGithubUsername</span><span class="o">(</span><span class="n">source</span><span class="o">.</span><span class="na">getGithubUsername</span><span class="o">());</span>
        <span class="n">target</span><span class="o">.</span><span class="na">setAccountType</span><span class="o">(</span><span class="n">source</span><span class="o">.</span><span class="na">getAccountType</span><span class="o">());</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">@Controller</code> interprets a returned string such as <code class="language-plaintext highlighter-rouge">directory/list</code> as a template name. <code class="language-plaintext highlighter-rouge">@RestController</code> would write that string to the HTTP response body instead. <code class="language-plaintext highlighter-rouge">@PathVariable</code> reads the row ID from the URL. <code class="language-plaintext highlighter-rouge">@ModelAttribute</code> binds form fields, and <code class="language-plaintext highlighter-rouge">@Valid</code> applies the entity’s validation rules. <code class="language-plaintext highlighter-rouge">BindingResult</code> immediately follows the validated argument so invalid values can be displayed in the form.</p>

<p>Constructor injection makes the repository dependency explicit. Updates load the existing row and copy only editable fields, preserving the original creation timestamp. The path ID selects the record; an injected form field named <code class="language-plaintext highlighter-rouge">id</code> cannot redirect the update to a different row.</p>

<h1 id="session-security-integration">Session security integration</h1>

<p>This directory contains personal information. Before enabling it, protect <strong>all</strong> <code class="language-plaintext highlighter-rouge">/mvc/directory</code> routes with the backend’s existing administrator authority, use its session login flow, and keep CSRF enabled on these routes. Do not create a competing security filter chain or assume the backend uses the authority name <code class="language-plaintext highlighter-rouge">ROLE_ADMIN</code>; inspect its existing rules first.</p>

<p>The form in Phase 4 includes a CSRF token. Spring Security must expose and validate that token. Thymeleaf rendering alone does not enable CSRF protection. If the existing backend ignores CSRF globally, that configuration must be corrected for these session-based MVC routes before deployment. Same-origin MVC forms do not need <code class="language-plaintext highlighter-rouge">@CrossOrigin</code>.</p>

<h1 id="error-handling">Error handling</h1>

<table>
  <thead>
    <tr>
      <th>Case</th>
      <th>Intended behavior</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Missing record</td>
      <td>404 through <code class="language-plaintext highlighter-rouge">ResponseStatusException</code></td>
    </tr>
    <tr>
      <td>Blank name or malformed email</td>
      <td>Redisplay form with validation errors; do not save</td>
    </tr>
    <tr>
      <td>Unsupported account type</td>
      <td>Binding error; do not save</td>
    </tr>
    <tr>
      <td>Non-numeric ID</td>
      <td>Spring rejects conversion with 400</td>
    </tr>
    <tr>
      <td>Forged ID or creation time field</td>
      <td>Binder excludes the field</td>
    </tr>
    <tr>
      <td>Missing/invalid CSRF token</td>
      <td>403 when the security configuration is correct</td>
    </tr>
    <tr>
      <td>Unauthenticated/non-admin request</td>
      <td>Existing login/access-denied policy; no directory data exposed</td>
    </tr>
    <tr>
      <td>Database unavailable</td>
      <td>Request fails; no success flash message</td>
    </tr>
  </tbody>
</table>

<p>Database failures are not caught and silently treated as success. Use the backend’s existing error page and logging policy to show a generic failure while keeping SQL and personal data out of the response. This small version uses last-write-wins updates; concurrent edit protection would require a version field and conflict handling.</p>

<h1 id="browser-testing-plan">Browser testing plan</h1>

<p>These are expected results to verify, <strong>not recorded passing tests</strong>. Run the backend on its configured port; the assignment uses <code class="language-plaintext highlighter-rouge">http://localhost:8585</code>.</p>

<table>
  <thead>
    <tr>
      <th>Test</th>
      <th>Action</th>
      <th>Expected result</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Create</td>
      <td>Submit name <code class="language-plaintext highlighter-rouge">Sample Student</code>, email <code class="language-plaintext highlighter-rouge">student@example.com</code>, student ID <code class="language-plaintext highlighter-rouge">001234</code>, type STUDENT</td>
      <td>Redirect to detail; generated ID and UTC join time</td>
    </tr>
    <tr>
      <td>Read all</td>
      <td>Open /mvc/directory</td>
      <td>New row appears</td>
    </tr>
    <tr>
      <td>Read one</td>
      <td>Select View</td>
      <td>Every saved field appears</td>
    </tr>
    <tr>
      <td>Update</td>
      <td>Change school, save</td>
      <td>New school shown; ID and join time unchanged</td>
    </tr>
    <tr>
      <td>Guest</td>
      <td>Create GUEST with no student ID or school</td>
      <td>Valid entry with optional fields empty</td>
    </tr>
    <tr>
      <td>Validation</td>
      <td>Submit blank name or email <code class="language-plaintext highlighter-rouge">invalid</code></td>
      <td>Error shown; row count unchanged</td>
    </tr>
    <tr>
      <td>Type validation</td>
      <td>Alter accountType to an unknown value in DevTools</td>
      <td>Binding error; no save</td>
    </tr>
    <tr>
      <td>Protected fields</td>
      <td>Add id and createdAt fields to a POST</td>
      <td>Server ID/time remain authoritative</td>
    </tr>
    <tr>
      <td>Missing ID</td>
      <td>Open an ID absent from the database</td>
      <td>404</td>
    </tr>
    <tr>
      <td>CSRF</td>
      <td>Remove the token from a form POST</td>
      <td>403; no database change</td>
    </tr>
    <tr>
      <td>Access control</td>
      <td>Visit routes logged out, then as a non-admin</td>
      <td>Login/access denial according to backend policy</td>
    </tr>
    <tr>
      <td>Delete</td>
      <td>Use Delete on a synthetic entry’s detail page</td>
      <td>Redirect to list; row gone; old detail URL returns 404</td>
    </tr>
    <tr>
      <td>Refresh</td>
      <td>Refresh after successful creation</td>
      <td>GET refresh does not repeat creation</td>
    </tr>
  </tbody>
</table>

<p>For each successful mutation, inspect DevTools Network: the form POST should return a redirect, followed by a GET for the destination HTML. Capture the list, detail, edit, validation, and success states. Re-run <code class="language-plaintext highlighter-rouge">SELECT</code> in SQLite to confirm browser actions changed stored rows.</p>

<p><strong>Evidence to add:</strong> real browser screenshots and actual test outcomes. Postman JSON collections belong to Option A and are not required for this MVC choice.</p>

<p>Continue to <a href="/CSA/spt1/frontend">Full-Stack MVC Application</a>.</p>]]></content><author><name>Jade</name></author><summary type="html"><![CDATA[Phase 3 MVC routes, repository, validation, and testing for my account directory]]></summary></entry><entry><title type="html">Full-Stack MVC Application</title><link href="https://xinjiav2.github.io/CSA/spt1/frontend" rel="alternate" type="text/html" title="Full-Stack MVC Application" /><published>2026-09-09T00:00:00+00:00</published><updated>2026-09-09T00:00:00+00:00</updated><id>https://xinjiav2.github.io/CSA/spt1/Sprint-1-FRONTEND</id><content type="html" xml:base="https://xinjiav2.github.io/CSA/spt1/frontend"><![CDATA[<h1 id="my-full-stack-architecture">My full-stack architecture</h1>

<p>I chose Option B in <a href="/CSA/spt1">my ideating post</a>. My frontend is a set of Thymeleaf templates served by Spring. GitHub Pages hosts the write-up, while Spring hosts the interactive directory.</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Browser request
    -&gt; Spring Security: session, administrator access, CSRF for POST
    -&gt; DirectoryAccountController
    -&gt; DirectoryAccountRepository
    -&gt; JPA / Hibernate -&gt; SQLite directory_accounts
    -&gt; Controller adds records to Model
    -&gt; Thymeleaf renders HTML -&gt; Browser
</code></pre></div></div>

<p>The <a href="/CSA/spt1/persistence">entity</a> defines the data and the <a href="/CSA/spt1/backend">controller</a> defines the workflows. The templates below complete the implementation example. They have not been installed or browser-tested in the Spring backend, so this post does not claim a deployed application or completed screenshot evidence.</p>

<h1 id="list-view">List view</h1>

<p>Create <code class="language-plaintext highlighter-rouge">src/main/resources/templates/directory/list.html</code> in the Spring repository:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;!DOCTYPE html&gt;</span>
<span class="nt">&lt;html</span> <span class="na">lang=</span><span class="s">"en"</span> <span class="na">xmlns:th=</span><span class="s">"http://www.thymeleaf.org"</span><span class="nt">&gt;</span>
<span class="nt">&lt;head&gt;</span>
  <span class="nt">&lt;meta</span> <span class="na">charset=</span><span class="s">"UTF-8"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;meta</span> <span class="na">name=</span><span class="s">"viewport"</span> <span class="na">content=</span><span class="s">"width=device-width, initial-scale=1"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;title&gt;</span>Account directory<span class="nt">&lt;/title&gt;</span>
<span class="nt">&lt;/head&gt;</span>
<span class="nt">&lt;body&gt;</span>
<span class="nt">&lt;main&gt;</span>
  <span class="nt">&lt;h1&gt;</span>Account directory<span class="nt">&lt;/h1&gt;</span>
  <span class="nt">&lt;p</span> <span class="na">th:if=</span><span class="s">"${message}"</span> <span class="na">th:text=</span><span class="s">"${message}"</span> <span class="na">role=</span><span class="s">"status"</span><span class="nt">&gt;&lt;/p&gt;</span>
  <span class="nt">&lt;p&gt;&lt;a</span> <span class="na">th:href=</span><span class="s">"@{/mvc/directory/new}"</span><span class="nt">&gt;</span>Add account<span class="nt">&lt;/a&gt;&lt;/p&gt;</span>
  <span class="nt">&lt;p</span> <span class="na">th:if=</span><span class="s">"${#lists.isEmpty(accounts)}"</span><span class="nt">&gt;</span>No accounts yet. Add the first account.<span class="nt">&lt;/p&gt;</span>
  <span class="nt">&lt;table</span> <span class="na">th:unless=</span><span class="s">"${#lists.isEmpty(accounts)}"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;caption&gt;</span>Students and guests<span class="nt">&lt;/caption&gt;</span>
    <span class="nt">&lt;thead&gt;&lt;tr&gt;</span>
      <span class="nt">&lt;th</span> <span class="na">scope=</span><span class="s">"col"</span><span class="nt">&gt;</span>Name<span class="nt">&lt;/th&gt;&lt;th</span> <span class="na">scope=</span><span class="s">"col"</span><span class="nt">&gt;</span>School<span class="nt">&lt;/th&gt;</span>
      <span class="nt">&lt;th</span> <span class="na">scope=</span><span class="s">"col"</span><span class="nt">&gt;</span>Student ID<span class="nt">&lt;/th&gt;&lt;th</span> <span class="na">scope=</span><span class="s">"col"</span><span class="nt">&gt;</span>GitHub<span class="nt">&lt;/th&gt;</span>
      <span class="nt">&lt;th</span> <span class="na">scope=</span><span class="s">"col"</span><span class="nt">&gt;</span>Type<span class="nt">&lt;/th&gt;&lt;th</span> <span class="na">scope=</span><span class="s">"col"</span><span class="nt">&gt;</span>Joined (UTC)<span class="nt">&lt;/th&gt;</span>
      <span class="nt">&lt;th</span> <span class="na">scope=</span><span class="s">"col"</span><span class="nt">&gt;</span>Actions<span class="nt">&lt;/th&gt;</span>
    <span class="nt">&lt;/tr&gt;&lt;/thead&gt;</span>
    <span class="nt">&lt;tbody&gt;&lt;tr</span> <span class="na">th:each=</span><span class="s">"account : ${accounts}"</span><span class="nt">&gt;</span>
      <span class="nt">&lt;td</span> <span class="na">th:text=</span><span class="s">"${account.name}"</span><span class="nt">&gt;&lt;/td&gt;</span>
      <span class="nt">&lt;td</span> <span class="na">th:text=</span><span class="s">"${account.school}"</span><span class="nt">&gt;&lt;/td&gt;</span>
      <span class="nt">&lt;td</span> <span class="na">th:text=</span><span class="s">"${account.studentID}"</span><span class="nt">&gt;&lt;/td&gt;</span>
      <span class="nt">&lt;td</span> <span class="na">th:text=</span><span class="s">"${account.githubUsername}"</span><span class="nt">&gt;&lt;/td&gt;</span>
      <span class="nt">&lt;td</span> <span class="na">th:text=</span><span class="s">"${account.accountType}"</span><span class="nt">&gt;&lt;/td&gt;</span>
      <span class="nt">&lt;td</span> <span class="na">th:text=</span><span class="s">"${account.createdAt}"</span><span class="nt">&gt;&lt;/td&gt;</span>
      <span class="nt">&lt;td&gt;</span>
        <span class="nt">&lt;a</span> <span class="na">th:href=</span><span class="s">"@{/mvc/directory/{id}(id=${account.id})}"</span><span class="nt">&gt;</span>View<span class="nt">&lt;/a&gt;</span>
        <span class="nt">&lt;a</span> <span class="na">th:href=</span><span class="s">"@{/mvc/directory/{id}/edit(id=${account.id})}"</span><span class="nt">&gt;</span>Edit<span class="nt">&lt;/a&gt;</span>
      <span class="nt">&lt;/td&gt;</span>
    <span class="nt">&lt;/tr&gt;&lt;/tbody&gt;</span>
  <span class="nt">&lt;/table&gt;</span>
<span class="nt">&lt;/main&gt;</span>
<span class="nt">&lt;/body&gt;</span>
<span class="nt">&lt;/html&gt;</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">th:each</code> repeats a row for every account supplied by the controller. <code class="language-plaintext highlighter-rouge">th:text</code> escapes displayed values, so a name containing HTML is displayed as text. <code class="language-plaintext highlighter-rouge">th:if</code> and <code class="language-plaintext highlighter-rouge">th:unless</code> select the success message and empty/list states. Account type is shown in text so distinguishing students from guests does not depend on color.</p>

<h1 id="detail-view">Detail view</h1>

<p>Create <code class="language-plaintext highlighter-rouge">src/main/resources/templates/directory/detail.html</code>:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;!DOCTYPE html&gt;</span>
<span class="nt">&lt;html</span> <span class="na">lang=</span><span class="s">"en"</span> <span class="na">xmlns:th=</span><span class="s">"http://www.thymeleaf.org"</span><span class="nt">&gt;</span>
<span class="nt">&lt;head&gt;</span>
  <span class="nt">&lt;meta</span> <span class="na">charset=</span><span class="s">"UTF-8"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;meta</span> <span class="na">name=</span><span class="s">"viewport"</span> <span class="na">content=</span><span class="s">"width=device-width, initial-scale=1"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;title&gt;</span>Account details<span class="nt">&lt;/title&gt;</span>
<span class="nt">&lt;/head&gt;</span>
<span class="nt">&lt;body&gt;</span>
<span class="nt">&lt;main&gt;</span>
  <span class="nt">&lt;h1</span> <span class="na">th:text=</span><span class="s">"${account.name}"</span><span class="nt">&gt;</span>Account details<span class="nt">&lt;/h1&gt;</span>
  <span class="nt">&lt;p</span> <span class="na">th:if=</span><span class="s">"${message}"</span> <span class="na">th:text=</span><span class="s">"${message}"</span> <span class="na">role=</span><span class="s">"status"</span><span class="nt">&gt;&lt;/p&gt;</span>
  <span class="nt">&lt;dl&gt;</span>
    <span class="nt">&lt;dt&gt;</span>ID<span class="nt">&lt;/dt&gt;&lt;dd</span> <span class="na">th:text=</span><span class="s">"${account.id}"</span><span class="nt">&gt;&lt;/dd&gt;</span>
    <span class="nt">&lt;dt&gt;</span>Name<span class="nt">&lt;/dt&gt;&lt;dd</span> <span class="na">th:text=</span><span class="s">"${account.name}"</span><span class="nt">&gt;&lt;/dd&gt;</span>
    <span class="nt">&lt;dt&gt;</span>Email<span class="nt">&lt;/dt&gt;&lt;dd</span> <span class="na">th:text=</span><span class="s">"${account.email}"</span><span class="nt">&gt;&lt;/dd&gt;</span>
    <span class="nt">&lt;dt&gt;</span>School<span class="nt">&lt;/dt&gt;&lt;dd</span> <span class="na">th:text=</span><span class="s">"${account.school}"</span><span class="nt">&gt;&lt;/dd&gt;</span>
    <span class="nt">&lt;dt&gt;</span>Student ID<span class="nt">&lt;/dt&gt;&lt;dd</span> <span class="na">th:text=</span><span class="s">"${account.studentID}"</span><span class="nt">&gt;&lt;/dd&gt;</span>
    <span class="nt">&lt;dt&gt;</span>GitHub username<span class="nt">&lt;/dt&gt;&lt;dd</span> <span class="na">th:text=</span><span class="s">"${account.githubUsername}"</span><span class="nt">&gt;&lt;/dd&gt;</span>
    <span class="nt">&lt;dt&gt;</span>Account type<span class="nt">&lt;/dt&gt;&lt;dd</span> <span class="na">th:text=</span><span class="s">"${account.accountType}"</span><span class="nt">&gt;&lt;/dd&gt;</span>
    <span class="nt">&lt;dt&gt;</span>Joined (UTC)<span class="nt">&lt;/dt&gt;&lt;dd</span> <span class="na">th:text=</span><span class="s">"${account.createdAt}"</span><span class="nt">&gt;&lt;/dd&gt;</span>
  <span class="nt">&lt;/dl&gt;</span>
  <span class="nt">&lt;p&gt;</span>
    <span class="nt">&lt;a</span> <span class="na">th:href=</span><span class="s">"@{/mvc/directory}"</span><span class="nt">&gt;</span>Back to directory<span class="nt">&lt;/a&gt;</span>
    <span class="nt">&lt;a</span> <span class="na">th:href=</span><span class="s">"@{/mvc/directory/{id}/edit(id=${account.id})}"</span><span class="nt">&gt;</span>Edit account<span class="nt">&lt;/a&gt;</span>
  <span class="nt">&lt;/p&gt;</span>
  <span class="nt">&lt;form</span> <span class="na">method=</span><span class="s">"post"</span>
        <span class="na">th:action=</span><span class="s">"@{/mvc/directory/{id}/delete(id=${account.id})}"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"hidden"</span> <span class="na">th:name=</span><span class="s">"${_csrf.parameterName}"</span> <span class="na">th:value=</span><span class="s">"${_csrf.token}"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;p&gt;</span>Deleting removes this directory entry. It does not delete a login account.<span class="nt">&lt;/p&gt;</span>
    <span class="nt">&lt;button</span> <span class="na">type=</span><span class="s">"submit"</span><span class="nt">&gt;</span>Delete directory entry<span class="nt">&lt;/button&gt;</span>
  <span class="nt">&lt;/form&gt;</span>
<span class="nt">&lt;/main&gt;</span>
<span class="nt">&lt;/body&gt;</span>
<span class="nt">&lt;/html&gt;</span>
</code></pre></div></div>

<p>Deleting uses POST rather than a link that changes data with GET. The detail view shows all eight fields, while the list keeps email off the overview. Both views still require administrator authorization.</p>

<h1 id="creation-and-edit-form">Creation and edit form</h1>

<p>Create <code class="language-plaintext highlighter-rouge">src/main/resources/templates/directory/form.html</code>:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;!DOCTYPE html&gt;</span>
<span class="nt">&lt;html</span> <span class="na">lang=</span><span class="s">"en"</span> <span class="na">xmlns:th=</span><span class="s">"http://www.thymeleaf.org"</span><span class="nt">&gt;</span>
<span class="nt">&lt;head&gt;</span>
  <span class="nt">&lt;meta</span> <span class="na">charset=</span><span class="s">"UTF-8"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;meta</span> <span class="na">name=</span><span class="s">"viewport"</span> <span class="na">content=</span><span class="s">"width=device-width, initial-scale=1"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;title&gt;</span>Edit directory account<span class="nt">&lt;/title&gt;</span>
<span class="nt">&lt;/head&gt;</span>
<span class="nt">&lt;body&gt;</span>
<span class="nt">&lt;main&gt;</span>
  <span class="nt">&lt;h1</span> <span class="na">th:text=</span><span class="s">"${editingId == null ? 'Add account' : 'Edit account'}"</span><span class="nt">&gt;&lt;/h1&gt;</span>
  <span class="nt">&lt;form</span> <span class="na">method=</span><span class="s">"post"</span> <span class="na">th:object=</span><span class="s">"${account}"</span>
        <span class="na">th:action=</span><span class="s">"${editingId == null} ? @{/mvc/directory} : @{/mvc/directory/{id}(id=${editingId})}"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"hidden"</span> <span class="na">th:name=</span><span class="s">"${_csrf.parameterName}"</span> <span class="na">th:value=</span><span class="s">"${_csrf.token}"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;div</span> <span class="na">th:if=</span><span class="s">"${#fields.hasErrors('*')}"</span> <span class="na">role=</span><span class="s">"alert"</span><span class="nt">&gt;</span>
      <span class="nt">&lt;p&gt;</span>Please correct these fields:<span class="nt">&lt;/p&gt;</span>
      <span class="nt">&lt;ul&gt;&lt;li</span> <span class="na">th:each=</span><span class="s">"error : ${#fields.errors('*')}"</span> <span class="na">th:text=</span><span class="s">"${error}"</span><span class="nt">&gt;&lt;/li&gt;&lt;/ul&gt;</span>
    <span class="nt">&lt;/div&gt;</span>
    <span class="nt">&lt;p&gt;</span>
      <span class="nt">&lt;label</span> <span class="na">for=</span><span class="s">"name"</span><span class="nt">&gt;</span>Name (required)<span class="nt">&lt;/label&gt;</span>
      <span class="nt">&lt;input</span> <span class="na">id=</span><span class="s">"name"</span> <span class="na">th:field=</span><span class="s">"*{name}"</span> <span class="na">required</span> <span class="na">maxlength=</span><span class="s">"100"</span> <span class="na">autocomplete=</span><span class="s">"name"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;/p&gt;</span>
    <span class="nt">&lt;p&gt;</span>
      <span class="nt">&lt;label</span> <span class="na">for=</span><span class="s">"email"</span><span class="nt">&gt;</span>Email (required)<span class="nt">&lt;/label&gt;</span>
      <span class="nt">&lt;input</span> <span class="na">id=</span><span class="s">"email"</span> <span class="na">type=</span><span class="s">"email"</span> <span class="na">th:field=</span><span class="s">"*{email}"</span> <span class="na">required</span>
             <span class="na">maxlength=</span><span class="s">"254"</span> <span class="na">autocomplete=</span><span class="s">"email"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;/p&gt;</span>
    <span class="nt">&lt;p&gt;</span>
      <span class="nt">&lt;label</span> <span class="na">for=</span><span class="s">"school"</span><span class="nt">&gt;</span>School (optional)<span class="nt">&lt;/label&gt;</span>
      <span class="nt">&lt;input</span> <span class="na">id=</span><span class="s">"school"</span> <span class="na">th:field=</span><span class="s">"*{school}"</span> <span class="na">maxlength=</span><span class="s">"120"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;/p&gt;</span>
    <span class="nt">&lt;p&gt;</span>
      <span class="nt">&lt;label</span> <span class="na">for=</span><span class="s">"studentID"</span><span class="nt">&gt;</span>Student ID (optional)<span class="nt">&lt;/label&gt;</span>
      <span class="nt">&lt;input</span> <span class="na">id=</span><span class="s">"studentID"</span> <span class="na">th:field=</span><span class="s">"*{studentID}"</span> <span class="na">maxlength=</span><span class="s">"40"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;/p&gt;</span>
    <span class="nt">&lt;p&gt;</span>
      <span class="nt">&lt;label</span> <span class="na">for=</span><span class="s">"githubUsername"</span><span class="nt">&gt;</span>GitHub username (optional)<span class="nt">&lt;/label&gt;</span>
      <span class="nt">&lt;input</span> <span class="na">id=</span><span class="s">"githubUsername"</span> <span class="na">th:field=</span><span class="s">"*{githubUsername}"</span> <span class="na">maxlength=</span><span class="s">"39"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;/p&gt;</span>
    <span class="nt">&lt;p&gt;</span>
      <span class="nt">&lt;label</span> <span class="na">for=</span><span class="s">"accountType"</span><span class="nt">&gt;</span>Account type<span class="nt">&lt;/label&gt;</span>
      <span class="nt">&lt;select</span> <span class="na">id=</span><span class="s">"accountType"</span> <span class="na">th:field=</span><span class="s">"*{accountType}"</span> <span class="na">required</span><span class="nt">&gt;</span>
        <span class="nt">&lt;option</span> <span class="na">th:each=</span><span class="s">"type : ${accountTypes}"</span> <span class="na">th:value=</span><span class="s">"${type}"</span> <span class="na">th:text=</span><span class="s">"${type}"</span><span class="nt">&gt;&lt;/option&gt;</span>
      <span class="nt">&lt;/select&gt;</span>
    <span class="nt">&lt;/p&gt;</span>
    <span class="nt">&lt;button</span> <span class="na">type=</span><span class="s">"submit"</span><span class="nt">&gt;</span>Save account<span class="nt">&lt;/button&gt;</span>
    <span class="nt">&lt;a</span> <span class="na">th:href=</span><span class="s">"@{/mvc/directory}"</span><span class="nt">&gt;</span>Cancel<span class="nt">&lt;/a&gt;</span>
  <span class="nt">&lt;/form&gt;</span>
<span class="nt">&lt;/main&gt;</span>
<span class="nt">&lt;/body&gt;</span>
<span class="nt">&lt;/html&gt;</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">th:object</code> selects the form’s model object. <code class="language-plaintext highlighter-rouge">th:field</code> binds each input’s name and current value, including rejected values after validation. <code class="language-plaintext highlighter-rouge">th:value</code> supplies each dropdown option’s value. The controller supplies <code class="language-plaintext highlighter-rouge">accountTypes</code> for both new forms and forms returned with errors.</p>

<p>For minimal typing, editing preloads the saved values and account type uses a dropdown. ID and join date are generated, so they are not inputs. Names and identifiers still require text because their possible values are not known in advance. These templates use semantic HTML with no inline styling; visual integration should reuse the admin panel’s existing layout and SCSS pipeline.</p>

<h1 id="click--save--display">Click → save → display</h1>

<ol>
  <li>The administrator clicks Edit. The browser sends <code class="language-plaintext highlighter-rouge">GET /mvc/directory/1/edit</code>.</li>
  <li>The controller loads record 1 and puts it into the model as <code class="language-plaintext highlighter-rouge">account</code>.</li>
  <li>Thymeleaf renders the existing values in the form.</li>
  <li>Save submits URL-encoded form fields and the CSRF token to <code class="language-plaintext highlighter-rouge">POST /mvc/directory/1</code>.</li>
  <li>Spring validates the fields, loads record 1, copies editable values, and saves it through JPA.</li>
  <li>The controller redirects to <code class="language-plaintext highlighter-rouge">GET /mvc/directory/1</code> with a one-time success message.</li>
  <li>Thymeleaf renders the updated row. Refresh now repeats the GET rather than the mutation.</li>
</ol>

<p>This is POST-Redirect-GET. Invalid submissions return the form directly with errors instead of redirecting and losing validation feedback.</p>

<h1 id="csrf-and-model-binding">CSRF and model binding</h1>

<p>Session cookies are automatically sent by the browser, which is why a malicious website could otherwise attempt a form submission using a logged-in administrator’s session. Spring Security validates the form’s CSRF token against the expected token. The templates explicitly include <code class="language-plaintext highlighter-rouge">_csrf.parameterName</code> and <code class="language-plaintext highlighter-rouge">_csrf.token</code>; a correctly configured Spring Security/Thymeleaf integration can also add a hidden token automatically.</p>

<p>The <code class="language-plaintext highlighter-rouge">_csrf</code> attribute must exist. Do not hide a missing token by conditionally omitting it; fix the security integration. CSRF protection requires enabled server-side validation, and it does not replace administrator authorization. The controller’s allowlist also prevents form binding from accepting an attacker-supplied primary key or creation timestamp.</p>

<h1 id="mvc-compared-with-rest">MVC compared with REST</h1>

<table>
  <thead>
    <tr>
      <th>Concern</th>
      <th>My MVC choice</th>
      <th>REST alternative</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Controller</td>
      <td><code class="language-plaintext highlighter-rouge">@Controller</code> returns template names</td>
      <td><code class="language-plaintext highlighter-rouge">@RestController</code> returns response data</td>
    </tr>
    <tr>
      <td>Rendering</td>
      <td>Thymeleaf runs on Spring</td>
      <td>JavaScript builds the page in the browser</td>
    </tr>
    <tr>
      <td>Updates</td>
      <td>HTML form POST and redirect</td>
      <td>fetch/axios POST, PUT, DELETE</td>
    </tr>
    <tr>
      <td>Authentication design</td>
      <td>Existing session login and CSRF checks</td>
      <td>Depends on API security; cookies can still require CSRF protection</td>
    </tr>
    <tr>
      <td>Origins</td>
      <td>Forms and backend share an origin</td>
      <td>GitHub Pages needs backend CORS configuration</td>
    </tr>
    <tr>
      <td>Deployment</td>
      <td>UI and backend deployed together</td>
      <td>Frontend and backend deployed separately</td>
    </tr>
  </tbody>
</table>

<p>MVC suits the server-hosted admin panel I described in Phase 1. A separate REST frontend would be useful for additional clients, but it is not required for this choice. There is no <code class="language-plaintext highlighter-rouge">config.js</code> or browser <code class="language-plaintext highlighter-rouge">fetch()</code> call in this workflow; Thymeleaf’s <code class="language-plaintext highlighter-rouge">@{...}</code> URLs target the Spring application and respect its context path.</p>

<h1 id="screenshots-and-completion-evidence">Screenshots and completion evidence</h1>

<p>After backend integration, visit <a href="http://localhost:8585/mvc/directory">the local directory</a> while signed in with the appropriate administrator account. This address is a local test target, not a published demo.</p>

<table>
  <thead>
    <tr>
      <th>Required screenshot</th>
      <th>What it should demonstrate</th>
      <th>Current status</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>List view</td>
      <td>Synthetic student and guest rows with school, IDs, and join dates</td>
      <td>Pending runtime capture</td>
    </tr>
    <tr>
      <td>Detail view</td>
      <td>One account’s complete stored values</td>
      <td>Pending runtime capture</td>
    </tr>
    <tr>
      <td>Edit form</td>
      <td>Prefilled fields and account-type dropdown</td>
      <td>Pending runtime capture</td>
    </tr>
    <tr>
      <td>Success message</td>
      <td>Updated record after redirect</td>
      <td>Pending runtime capture</td>
    </tr>
    <tr>
      <td>Validation</td>
      <td>Invalid input stays on the form with a useful error</td>
      <td>Pending runtime capture</td>
    </tr>
    <tr>
      <td>DevTools form data</td>
      <td>CSRF field present; redact its value in shared evidence</td>
      <td>Pending runtime capture</td>
    </tr>
  </tbody>
</table>

<p>Run the <a href="/CSA/spt1/backend">Phase 3 test matrix</a> and add observed results alongside the screenshots. The documentation and implementation examples are provided; compiling, security integration, live schema validation, and browser evidence remain to be completed in the Spring environment.</p>]]></content><author><name>Jade</name></author><summary type="html"><![CDATA[Phase 4 Thymeleaf list, detail, and edit views for my admin directory]]></summary></entry><entry><title type="html">ideating/documentation</title><link href="https://xinjiav2.github.io/CSA/spt1" rel="alternate" type="text/html" title="ideating/documentation" /><published>2026-09-09T00:00:00+00:00</published><updated>2026-09-09T00:00:00+00:00</updated><id>https://xinjiav2.github.io/CSA/Sprint-1-IDEATING</id><content type="html" xml:base="https://xinjiav2.github.io/CSA/spt1"><![CDATA[<p>By the end of this assignment, you will:</p>

<ul>
  <li>Master POJO Design — Understand how Plain Old Java Objects form the foundation of both the AP CSA exam and modern frameworks like Spring</li>
  <li>Implement Data Persistence — Use JPA and SQLite to reliably store and retrieve your data object</li>
  <li>Build a REST API — Create Spring Boot endpoints that expose your data with proper HTTP methods (GET, POST, PUT, DELETE)</li>
  <li>Design Full-Stack Architecture — Connect a backend API to a frontend (GitHub Pages OR Thymeleaf admin page)</li>
  <li>Portfolio &amp; Exam Preparation — Document your work in a blog that demonstrates OOP mastery and prepares you for AP CSA exam</li>
</ul>

<h1 id="data-object-domain-model">DATA OBJECT DOMAIN MODEL</h1>
<p>what is my team per se <br />
my team is like<br />
backend<br />
we have admin panel<br />
what coudl be useful?<br /></p>

<p>i find things useful</p>

<p>i find that simple infographics and ui screen useful</p>

<p>i make</p>

<h1 id="a-dedicated-chart-with-graphics-of-different-users-their-schools-their-github-and-student-ids-as-well-as-name-and-join-date-this-chart-will-differentiate-between-students-as-well-as-guest-accounts-added-through-the-mentors">a dedicated chart with graphics of different users, their schools, their github and student ids, as well as name and join date. this chart will differentiate between students as well as guest accounts added through the mentors</h1>

<p>therefore i choose option b</p>

<p>Design your POJO based on your data object</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Identify all required fields (e.g., id, name, description, createdAt, updatedBy)
Choose appropriate data types (primitives, Strings, LocalDateTime, etc.)
Consider relationships (e.g., a Project belongs to a Team)
</code></pre></div></div>

<p>required fields:<br />
id<br />
name<br />
createdAt<br />
email<br /></p>

<p>data types:<br />
localdatetime<br />
strings<br /></p>

<p>relationships:<br />
my project should tie into the admin panel and be a useful tool for administrators when dealing with account problems/reset passwords and similar.</p>

<p>Lombok Annotations:</p>

<p>https://dev.to/gianfcop98/10-lombok-annotations-every-java-developer-should-know-pcd</p>

<p>review review review</p>

<p>https://medium.com/javarevisited/all-the-16-lombok-annotations-explained-in-a-4-minute-article-926f71934ec6</p>

<p>this is my pojo</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">jakarta.persistence.*</span>
<span class="kn">import</span> <span class="nn">lombok.*</span>

<span class="nd">@Entity</span>
<span class="nd">@Getter</span>
<span class="nd">@Setter</span>
<span class="nd">@NoArgsConstructor</span>
<span class="nd">@AllArgsConstructor</span>

<span class="kd">public</span> <span class="kd">class</span> <span class="nc">POJO</span> <span class="o">{</span>
    <span class="nd">@Id</span>
    <span class="nd">@GeneratedValue</span><span class="o">(</span><span class="n">strategy</span> <span class="o">=</span> <span class="nc">GenerationType</span><span class="o">.</span><span class="na">IDENTITY</span><span class="o">)</span>
    <span class="kd">private</span> <span class="nc">Long</span> <span class="n">id</span><span class="o">;</span>

    <span class="kd">private</span> <span class="nc">String</span> <span class="n">name</span><span class="o">;</span>
    <span class="kd">private</span> <span class="nc">String</span> <span class="n">email</span><span class="o">;</span>
    <span class="kd">private</span> <span class="nc">String</span> <span class="n">school</span><span class="o">;</span>
    <span class="kd">private</span> <span class="nc">String</span> <span class="n">studentID</span><span class="o">;</span>
    <span class="kd">private</span> <span class="nc">String</span> <span class="n">githubUsername</span><span class="o">;</span>
    <span class="kd">private</span> <span class="nc">String</span> <span class="n">accountType</span><span class="o">;</span>
    <span class="kd">private</span> <span class="nc">LocalDateTime</span> <span class="n">createdAt</span><span class="o">;</span>

<span class="o">}</span>
</code></pre></div></div>

<p>Lombok generates the repeitive code, and the annotations automatically generate the missing code when compiling.</p>

<p>The <code class="language-plaintext highlighter-rouge">@Entity</code> annotation is part of the JPA library, it bridges the gap between java code and the database</p>

<p>The <code class="language-plaintext highlighter-rouge">@Id</code> annotation is part of the JPA library, it specifies the primary key of an entity – this allows for multipule users of the same name</p>

<p>The <code class="language-plaintext highlighter-rouge">@GeneratedValue</code> annnotation is used with the <code class="language-plaintext highlighter-rouge">@Id</code> annotation, and is used to generate primary values for an entity</p>

<p>The <code class="language-plaintext highlighter-rouge">@NoArgsConstructor</code> creates a constructor with no paramaters, however if not possible then compiler error. On the other hand, <code class="language-plaintext highlighter-rouge">@AllArgsConstructor</code> ccreates a constructor with one parameter for each field in the class.</p>

<p>The <code class="language-plaintext highlighter-rouge">@Getter</code> and <code class="language-plaintext highlighter-rouge">@Setter</code> annotations are used to generate the default getter/setter, without needing to write them down</p>

<p>A getter allows another part of the program to retrieve a private instance variable. <br />
For example in the following code:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="nc">String</span> <span class="nf">getName</span><span class="o">()</span> <span class="o">{</span>
    <span class="k">return</span> <span class="n">name</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>

<p>I can then write:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Admin</span> <span class="n">user</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Admin</span><span class="o">();</span>

<span class="n">user</span><span class="o">.</span><span class="na">setName</span><span class="o">(</span><span class="s">"Ish Anjha"</span><span class="o">);</span>

<span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">user</span><span class="o">.</span><span class="na">getName</span><span class="o">());</span>
</code></pre></div></div>

<p>The output will be:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Ish Anjha
</code></pre></div></div>

<p>A setter modifies an object’s instance variable. <br />
For example in the following code:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kt">void</span> <span class="nf">setEmail</span><span class="o">(</span><span class="n">stringEmail</span><span class="o">)</span> <span class="o">{</span>
    <span class="k">this</span><span class="o">.</span><span class="na">email</span> <span class="o">=</span> <span class="n">email</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Interjecting the</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">user</span><span class="o">.</span><span class="na">setEmail</span><span class="o">(</span><span class="s">"ishanjha100@gmail.com"</span><span class="o">)</span>
</code></pre></div></div>

<p>The state of the <code class="language-plaintext highlighter-rouge">user</code> object has now changed
The keyword <code class="language-plaintext highlighter-rouge">this</code> refers to the object</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">this</span><span class="o">.</span><span class="na">email</span> <span class="o">=</span> <span class="n">email</span><span class="o">;</span>
</code></pre></div></div>

<p>In this example:</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">this.email = email;</code> is the instance variable</li>
  <li><code class="language-plaintext highlighter-rouge">email</code> is the parameter in the method</li>
</ul>

<h1 id="connection-to-apcsa">Connection to APCSA</h1>

<p>Even if it is used in professional enviornments, <strong>Lombok</strong> is not used in the APCSA exam <br />
Therefore, I need to learn how to write the methods Lombok generates by myself.</p>

<h3 id="instance-variables">Instance Variables</h3>
<p>My POJO contains these variables <br />
<code class="language-plaintext highlighter-rouge">private String name;</code> <br />
<code class="language-plaintext highlighter-rouge">private String email;</code> <br /></p>

<p>These variables have the same class design used in APCSA <br />
Using the <code class="language-plaintext highlighter-rouge">private</code> variable helps show encapsulation, which is one of the core OOP pillars of java</p>

<h3 id="constructors">Constructors</h3>

<p>In CSA, code I normally write code such as this</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="nf">AdminUser</span><span class="o">(</span><span class="nc">String</span> <span class="n">name</span><span class="o">,</span> <span class="nc">String</span> <span class="n">email</span><span class="o">)</span> <span class="o">{</span>
    <span class="k">this</span><span class="o">.</span><span class="na">name</span> <span class="o">=</span> <span class="n">name</span><span class="o">;</span>
    <span class="k">this</span><span class="o">.</span><span class="na">email</span> <span class="o">=</span> <span class="n">email</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Lombok automatically generates these annotations, 
however I still need to know what a constructor is</p>

<p>A constructor:</p>
<ul>
  <li>Creates the initial state of an object</li>
  <li>recives values through parameters</li>
  <li>assigns those values to instance variables</li>
</ul>

<h3 id="accessor-methods">Accessor Methods</h3>

<p>In CSA, getters are known as acessor methods, as they provide access to a state of object, without changing it.</p>

<p>For example,</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="nc">String</span> <span class="nf">getName</span><span class="o">(){</span>
    <span class="k">return</span> <span class="n">name</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>
<p><code class="language-plaintext highlighter-rouge">@Getter</code> performs the same task</p>

<h3 id="mutator-methods">Mutator Methods</h3>

<p>Setters are known as mutator methods as they “mutate” (modify) the state of an object</p>

<p>Example:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kt">void</span> <span class="nf">setName</span><span class="o">(</span><span class="nc">String</span> <span class="n">name</span><span class="o">)</span> <span class="o">{</span>
    <span class="k">this</span><span class="o">.</span><span class="na">name</span> <span class="o">=</span> <span class="n">name</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Lombok generates this through <code class="language-plaintext highlighter-rouge">@Setter</code></p>

<h2 id="lombok-vs-csa">Lombok vs CSA</h2>

<p>basically its like this:</p>

<p>csa:
I learn how and why these methods work <br />
                 | <br />
V <br />
Lombok&amp;Spring boot: <br />
Getter<br />
Setter<br />
Constructor<br /></p>

<h4 id="tldr">TL;DR</h4>
<p>Lombok removes repetitive code, <strong>after</strong> I know how it works</p>

<h1 id="my-code">My Code</h1>
<p><img src="POJO.png" alt="POJO Code" /></p>

<p><img src="bytecode.png" alt="bytecode" /></p>]]></content><author><name>Jade</name></author><summary type="html"><![CDATA[ideas for everyhting sprint 1 related]]></summary></entry><entry><title type="html">Sprint 1 Implementation Record — Codex</title><link href="https://xinjiav2.github.io/CSA/spt1/implementation-record" rel="alternate" type="text/html" title="Sprint 1 Implementation Record — Codex" /><published>2026-09-09T00:00:00+00:00</published><updated>2026-09-09T00:00:00+00:00</updated><id>https://xinjiav2.github.io/CSA/spt1/Sprint-1-IMPLEMENTATION-RECORD</id><content type="html" xml:base="https://xinjiav2.github.io/CSA/spt1/implementation-record"><![CDATA[<h1 id="purpose-and-authorship">Purpose and authorship</h1>

<p>This is Codex’s implementation record, separate from Jade’s assignment posts. Jade supplied the completed Phase 1 work and selected Option B: a Spring MVC/Thymeleaf administrator directory for students and guests. I used that design to prepare the Phase 2–4 documentation and extract individual implementation files. I did not change the original Phase 1 post, POJO, bytecode, screenshots, Jokes example, or existing pom.xml.</p>

<h1 id="documentation-created">Documentation created</h1>

<table>
  <thead>
    <tr>
      <th>File in <code class="language-plaintext highlighter-rouge">_posts/sprint_1Final/</code></th>
      <th>Contents</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">2026-09-09-Sprint-1-PERSISTENCE.md</code></td>
      <td>Entity and enum, schema decisions, JPA mappings, SQLite setup and inspection queries</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">2026-09-09-Sprint-1-BACKEND.md</code></td>
      <td>Repository and MVC controller, routes, validation, security integration requirements, browser test matrix</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">2026-09-09-Sprint-1-FRONTEND.md</code></td>
      <td>List/detail/form templates, model binding, POST-Redirect-GET, CSRF explanation, screenshot checklist</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">2026-09-09-Sprint-1-IMPLEMENTATION-RECORD.md</code></td>
      <td>This assistant-authored inventory and handoff record</td>
    </tr>
  </tbody>
</table>

<p>Published documentation routes are <a href="/CSA/spt1/persistence">Persistence</a>, <a href="/CSA/spt1/backend">Backend</a>, and <a href="/CSA/spt1/frontend">Frontend</a>.</p>

<h1 id="individual-files-created">Individual files created</h1>

<p>The source bundle is beside these posts in <code class="language-plaintext highlighter-rouge">directory-implementation/</code>. Its folder structure groups files by their destination in the Spring application; it is not a standalone Spring project.</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>directory-implementation/
  README.md
  java/directory/
    AccountType.java
    DirectoryAccount.java
    DirectoryAccountRepository.java
    DirectoryAccountController.java
  templates/directory/
    list.html
    detail.html
    form.html
  config/
    application-directory-example.properties
  validation/
    inspect-directory.sql
</code></pre></div></div>

<table>
  <thead>
    <tr>
      <th>File</th>
      <th>Responsibility</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">AccountType.java</code></td>
      <td>Defines STUDENT and GUEST categories</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">DirectoryAccount.java</code></td>
      <td>Maps eight directory fields to JPA; validates input and records UTC creation time</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">DirectoryAccountRepository.java</code></td>
      <td>Inherits Spring Data CRUD operations</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">DirectoryAccountController.java</code></td>
      <td>Routes MVC requests, binds permitted fields, validates submissions, saves changes, redirects after success</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">list.html</code></td>
      <td>Displays the account table, empty state, and navigation</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">detail.html</code></td>
      <td>Displays all fields and provides a POST delete form</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">form.html</code></td>
      <td>Provides creation/edit inputs, account-type dropdown, and validation feedback</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">application-directory-example.properties</code></td>
      <td>Explicitly labeled disposable SQLite configuration example; not automatically activated</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">inspect-directory.sql</code></td>
      <td>Read-only schema and row inspection queries</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">README.md</code></td>
      <td>Explains where to copy files and prerequisites for running them</td>
    </tr>
  </tbody>
</table>

<h1 id="implementation-decisions">Implementation decisions</h1>

<p>I renamed the generic example class to <code class="language-plaintext highlighter-rouge">DirectoryAccount</code> while preserving the Phase 1 data fields. Student IDs remain strings to retain leading zeros. Account type is an enum to limit accepted categories. Creation time and primary key are server-managed; the controller’s binding allowlist excludes both from submitted fields. Updates load the existing entity so creation time is preserved.</p>

<p>The implementation uses <code class="language-plaintext highlighter-rouge">@Getter</code> and <code class="language-plaintext highlighter-rouge">@Setter</code> rather than <code class="language-plaintext highlighter-rouge">@Data</code>. The documentation explains why these annotations differ and avoids claiming that getter/setter annotations generate equality or string methods. Templates display user values with escaped <code class="language-plaintext highlighter-rouge">th:text</code> expressions.</p>

<p>The directory has no login credentials, password-reset feature, mentor approval workflow, or relationship to the existing authentication entity. Administrator access control must be integrated with the backend’s actual security configuration. CSRF tokens in HTML are only effective if the server validates them.</p>

<h1 id="integration-steps">Integration steps</h1>

<ol>
  <li>In the Spring repository, inspect its application package, build instructions, dependencies, existing account entities, and security configuration.</li>
  <li>Copy the four Java files into a <code class="language-plaintext highlighter-rouge">directory</code> package below that application package. Replace <code class="language-plaintext highlighter-rouge">YOUR_APPLICATION_PACKAGE</code> in every Java file with the actual parent package.</li>
  <li>Copy the three templates to <code class="language-plaintext highlighter-rouge">src/main/resources/templates/directory/</code>.</li>
  <li>Confirm compatible Jakarta Persistence, Jakarta Validation, Lombok annotation processing, Spring MVC, Spring Data JPA, Thymeleaf, Spring Security, SQLite JDBC, and Hibernate SQLite dialect support. Use the backend’s dependency management; no new pom.xml was invented.</li>
  <li>Protect all directory routes with its established administrator authority and session login. Enable CSRF validation for these MVC POST routes using the existing security setup.</li>
  <li>Select a disposable database and intentionally merge the example properties into a development profile. Ensure the configured database directory exists and is writable. Do not activate <code class="language-plaintext highlighter-rouge">create-drop</code> on retained or shared data.</li>
  <li>Build and start with the backend’s documented workflow, then run the Phase 3 browser test matrix and the supplied SQL inspection queries.</li>
  <li>Add genuine schema and browser screenshots to the assignment posts, and record actual outcomes. No screenshots or passing results were fabricated.</li>
</ol>

<h1 id="verification-and-limitations">Verification and limitations</h1>

<p>The individual Java and HTML files were extracted from the documentation examples and checked against their corresponding code blocks. The bundle contains four Java sources, three templates, one properties example, and one SQL script. Source names match their public Java types; templates match the controller’s return paths. The three new assignment posts have balanced code fences and distinct permalinks.</p>

<p>The remote Spring repository could not be retrieved during the earlier documentation work. Therefore its actual package, dependency versions, login behavior, and security rules remain unverified. The generated Java files deliberately retain a visible package placeholder rather than guessing the backend’s package.</p>

<p>No Spring compilation, automated runtime tests, SQLite execution, Jekyll build, or live browser workflow was run. This request extracts existing examples without changing their behavior. The Phase 3 manual test matrix supplies validation cases but is not evidence that they passed. The remaining work is backend integration and runtime verification, including access control and CSRF rejection tests.</p>

<p>No remote repository was modified, no application was deployed, and no database was deleted. These files are implementation sources for review and integration in Spring; storing Thymeleaf HTML in the portfolio repository does not make a running MVC application.</p>]]></content><author><name>Codex</name></author><summary type="html"><![CDATA[Assistant-authored inventory, integration instructions, and verification status for the directory implementation]]></summary></entry></feed>