Taming Verbose Commands: Introducing the U-Boot Console Pager

Have you ever run the help or env print command and watched a torrent of text scroll past, faster than you could read it? We’ve all been there. Important information disappears off the top of the screen before we have a chance to digest it.

Well, those days are over! Thanks to a new patch series, U-Boot Concept now includes a console pager, a simple but highly effective feature that makes managing long command outputs a breeze.

What is the Pager?

At its core, the pager does one thing very well: it pauses output once your screen is full. When you run a command that generates a lot of text, the pager will stop after a certain number of lines and display a prompt:

: Press SPACE to continue

This gives you all the time you need to read the output. Once you’re ready, just press the SPACE bar, and U-Boot will display the next screenful of text. It’s an intuitive and familiar experience for anyone who has used tools like less or more in a Linux environment.

How to Use and Configure It

The pager is enabled with the CONFIG_CONSOLE_PAGER option. Once enabled, U-Boot uses a smart system to determine the page size (i.e., how many lines to show before pausing). Here’s the order of priority:

  1. The pager Environment Variable: You have full control. You can set the number of lines (in hexadecimal) yourself (‘setenv pager 1e’). Setting it to 0 disables the pager.
  2. Automatic Device Detection: If the pager variable isn’t set, U-Boot tries to be clever.

    • If you’re using a video console (vidconsole), it will automatically use the number of rows your display supports.
    • If you’re on a serial console, U-Boot can query the terminal to get its dimensions. This is enabled by CONFIG_SERIAL_TERM_PRESENT.

  3. Default Value: If all else fails, it falls back to a sensible default defined by CONFIG_CONSOLE_PAGER_LINES.

Under the Hood: A Foundation of Quality-of-Life Improvements

Introducing the pager wasn’t just a single patch. This feature was built on a solid foundation of refactoring and improvements throughout the console and serial subsystems.

One of the key preparatory steps was to generalize terminal size detection. Previously, the logic to query a terminal’s rows and columns was tucked away in the EFI loader. This code has now been moved into the generic serial uclass, making it available to any part of U-Boot. To improve performance, the terminal dimensions are cached, so U-Boot only has to ask once.

Additionally, new helper functions were introduced to determine if the console is actually connected to an interactive terminal (serial_is_tty()) or if a video display is visible. This is particularly important for environments like sandbox, where U-Boot’s output might be redirected to a file. In those cases, the pager intelligently disables itself to prevent scripts from hanging.

A Boon for Testers and Developers

Speaking of automated testing, the pager could potentially cause tests to hang while waiting for user input. To solve this, two new command-line flags have been added to the sandbox environment:

  • -P: Bypasses the pager completely.
  • -A: Assumes no terminal is present, which disables the terminal-size query.

Our Python test suite has already been updated to use these flags, ensuring that automated testing remains smooth and reliable.

Conclusion

The console pager is a nice quality-of-life improvement that makes the U-Boot command line more user-friendly. It’s a small change that will have a big impact on daily development and debugging workflows, particularly on devices without a serial console. This work, along with the thoughtful refactoring that supports it, is a great example of the continuous effort to polish and improve the U-Boot user experience.

So go ahead, enable CONFIG_CONSOLE_PAGER, and enjoy a more civilized console experience!




Streamlining Your Patch Workflow with Patman Series Management

Managing patch series can be one of the most time-consuming aspects of contributing to large open-source projects like U-Boot and Linux. While patman has long been a powerful tool for creating, checking, and sending patches, the relatively new patman series feature takes workflow management to the next level by providing lifecycle management for series, with Patchwork integration.

What is ‘patman series’?

The patman series feature (available via patman s or patman ser for brevity) is a database-backed, series-management system that tracks your patch series from initial creation through upstream acceptance. Unlike traditional patch workflows where you manually track versions, reviews, and status across multiple tools, patman series provides a unified interface that integrates directly with Patchwork to automate much of this tedious bookkeeping.

Key Benefits

Automated Series Tracking: Once you add a series to patman’s database, it automatically tracks versions, maintains links to Patchwork, and monitors upstream progress.

Seamless Version Management: Creating v2, v3, etc. of your series is as simple as patman series inc, which automatically creates new branches and updates the database.

Patchwork Integration: Patman automatically discovers your series on Patchwork after sending, tracks review comments, and can gather review tags back into your commits.

Branch Organization: The system encourages a clean branching strategy where each series version gets its own branch, making it easy to maintain multiple versions simultaneously.

Getting Started: A Complete Workflow

Let’s walk through a typical workflow using patman series. First, set up your project (this only needs to be done once):

patman patchwork set-project U-Boot

Now suppose you have a branch video2 with some patches ready to send. Add it to patman’s tracking:

git checkout video2
patman series add

Patman will scan your branch and add it to the database. You might see a warning about unmarked commits – you can either let patman add Change-Id values with -m or tell it not to worry with -M:

patman series add -M

Now send your series:

patman series send

Patman will use git send-email to send your patches and then wait to see if it can automatically find your series on Patchwork. Once linked, you can track its progress. In fact you can see the progress of all your series. Here is an example:

$ patman series progress
Name             Description                               Count  Status
---------------  ----------------------------------------  -----  ---------------
apa              lib: Split fdt_print() into separate libr     4  4:unknown
apb              efi: App and devicetree improvements         20 *20:unknown
app-us           efi_loader: Separate device path into its     3  3:accepted
appc             [00/27] x86: efi: Various app improvement    27  27:n/a
appd             doc: efi_loader: Tidy up the bootefi-comm     2  1:new 1:unknown
bgr2             ACPI fixes                                    4 *4:unknown
blob             [0/4] bloblist: fdt: Clean up the code        5  4:changes 1:unknown
bmg              buildman: Correct behaviour of --in-tree      2  2:new
ci-lab           CI multi-processing                           1  1:n/a
cia              CI improvements                               1  1:changes
efiq3            [v3,00/29] arm: Support building as an EF    36  32:changes 4:unknown
efit             efi: Rename the lib/efi directory             4  4:new
expa             expo: Allow the nominal display-size to b     6  6:n/a
fast             emulation: Improve support for booting fr    19  19:unknown

Series Management Commands

The series subcommand offers a comprehensive set of operations:

Core Operations

  • add: Add a new series to tracking
  • send: Send patches (like patman send but for any tracked series)
  • ls: List all tracked series
  • scan: Rescan a branch to update patch information

Version Management

  • inc: Create next version (v2, v3, etc.) by creating a new branch
  • dec: Delete current version and branch
  • rm-version: Remove specific versions
  • rm: Remove entire series

Patchwork Integration

  • autolink: Find Patchwork link for your series
  • progress: Show upstream status and review progress
  • gather: Collect review tags from Patchwork into commits
  • open: Open series in web browser

Advanced Features

  • mark/unmark: Add/remove Change-Id tags for better patch tracking
  • archive/unarchive: Archive completed series (creates dated tags, deletes branches)
  • patches: Show patches in a specific series/version

Advanced Workflow Example

Here’s how the series feature shines in a real-world scenario:

  1. Initial submission:
   git checkout my-feature
   patman series add -m  # Mark commits with Change-Ids
   patman series send

  1. Address review feedback:
   patman series inc  # Creates my-feature-v2 branch
   # Make your changes...
   patman series send

  1. Track progress:
   patman series progress  # Shows review status
   patman series gather -Cc   # Pulls in Reviewed-by tags, shows comments

  1. Final acceptance:
   patman series archive  # Clean up, create tags

Database-Driven Benefits

The series feature maintains a SQLite database (typically in ~/.config/patman/) that persistently tracks:

  • Series metadata and descriptions
  • Version relationships between branches
  • Patchwork links and IDs
  • Patch Change-Ids for reliable tracking
  • Review status and gathered tags

This database approach means you can switch between projects, reboot your machine, or work on multiple series simultaneously without losing context.

Integration with Existing Workflows

The beauty of patman series is that it builds on top of the existing patman functionality you already know. All the same commit tags (Series-to, Series-cc, etc.) work exactly as before. The series feature simply adds persistent tracking and automation on top.

You can still use regular patman send for quick one-off patches, while leveraging patman series for more complex, multi-version patch series that need ongoing management.

Migration from Manual Workflows

If you’re currently managing patch series manually with git branches and spreadsheets, migrating to patman series is straightforward:

  1. Use patman series add on your existing branches
  2. Let patman discover Patchwork links with patman series autolink-all
  3. Start using patman series send instead of manual git send-email

Conclusion

The patman series feature represents a significant evolution in patch management tooling. By providing database-backed series tracking with deep Patchwork integration, it eliminates much of the manual bookkeeping that makes contributing to large projects tedious.

Whether you’re a seasoned contributor juggling multiple patch series or a newcomer looking to streamline your workflow, patman series offers a compelling upgrade to the traditional patch-by-patch approach. The investment in learning these commands pays dividends in reduced errors, better organization, and more time spent on actual development rather than patch logistics.

Try incorporating patman series into your next contribution workflow – your future self will thank you when managing v4 of that complex patch series becomes as simple as patman series inc followed by patman series send.


The patman series feature is available in recent versions of U-Boot’s patman tool (pip install patch-manager). For complete documentation, see tools/patman/patman.rst in the U-Boot source tree, or here.




EFI app on ARM hits a milestone

The EFI app on x86 has supported booting for a while. With a recent 19-part series, the EFI app can now also boot an OS on ARM. This uses standard boot and the standard extlinux boot flow.


The Core Fixes

To successfully hand off control from the EFI environment to a new operating system, a few key steps must happen in the right order.

  • Exit Boot Services: The most important change is ensuring that U-Boot calls ExitBootServices() before it jumps to the OS kernel. This is a fundamental requirement of the EFI specification. It tells the underlying firmware that its boot-time services (like memory allocation, device I/O, etc.) are no longer needed, effectively handing exclusive control of the hardware over to the operating system.
  • Pass the Memory Map: An operating system needs to know the physical layout of the memory. This series adds the logic to obtain the EFI memory map and write the physical memory information into the Flattened Device Tree (FDT). This allows the Linux kernel to understand the memory layout and manage it correctly.
  • Improved Keyboard Compatibility: On some real-world hardware, such as certain Qualcomm laptops with USB keyboards, simply waiting for a keypress isn’t enough. The underlying system needs time to process other events for the keyboard input to register. The EFI serial driver is updated to use a periodic timer, making the console much more reliable on these devices.
  • General Tidying Up: Alongside these major functional updates, the series includes a lot of valuable code maintenance, such as correcting typos, reorganizing Kconfig options, and standardizing the format of EFI GUID declarations.

Tested and Ready

To ensure this new capability remains robust, the patch series also introduces a new continuous integration (CI) test. We now automatically build the efi-arm_app64 target and use it to boot a full Ubuntu 25.04 image on a QEMU virtual machine in the sjg lab. This provides a strong safeguard against future regressions.


A Note for Testers on QEMU

If you’re planning to test this yourself using QEMU, there’s an important detail to be aware of. The changes do not work correctly with QEMU 8.2 when booting Ubuntu 24.04, as the kernel fails very early in the process with a regime_is_user error.

The good news is that this has been fixed in QEMU 9.2 and newer. So, make sure you’re using an up-to-date version of QEMU for your testing! You can read more about the QEMU issue in this bug report.


Next up?

Work on the app continues, with the goal of having it boot the OS using EFI as well.




Seeing is Believing: Video Support Lands for the ARM EFI App! 🎨

For a while now, U-Boot’s EFI application (efi_app) has been a handy tool, but with one noticeable difference between architectures: x86 could show things on the screen, while ARM was stuck in the dark. If you wanted a splash screen or a graphical boot menu in your ARM EFI app, you were out of luck.

Well, not anymore! A new patch series in Concept closes this gap, bringing full video output capabilities to the ARM EFI application. Let’s dive into how it works.


The Challenge: Drawing Pixels on ARM

The main hurdle for ARM video support within an EFI environment, especially in virtualized setups, is how graphics are handled. Many ARM systems, like QEMU configured with virtio-gpu, don’t provide a simple, direct-access framebuffer to which you can just write the pixel data.

Instead, they rely on the EFI Graphics Output Protocol (GOP) and specifically its Bit Block Transfer function, more commonly known as blt. The blt function is a versatile tool that can copy rectangular blocks of pixels around—from memory to the screen, from the screen to memory, or even from one part of the screen to another.

Thes series uses the blt function to enable video support. U-Boot now draws the display into an in-memory buffer and then uses a blt call to “push” that entire buffer to the visible screen.


A Quick Tour of the Changes

This feature was delivered in a series of seven patches, each building on the last.

  1. Store the GOP (Patch 1/7): The first step was foundational. The existing driver could find the GOP, but it didn’t save the pointer for later use. This patch introduces a private struct (efi_video_priv) to store the GOP handle, making it accessible after the initial probe.
  2. Implement the Blit Method (Patches 2/7 & 3/7): This is the core of the new feature.
    • A new pixel format EFI_GOT_BITBLT is recognized. When detected, the driver knows it must use blt operations instead of writing to a direct framebuffer.A video_sync operation is added, which calls the GOP’s blt function to update the display from U-Boot’s internal framebuffer. An enum, efi_gop_blt_op, was also added to make the code clearer.
  3. Enable a Full Boot Experience (Patches 5/7 & 7/7): What good is a screen if you can’t boot an OS? This series also enables the necessary configs to make the ARM EFI app a fully functional bootloader.

    • CONFIG_BOOTSTD_FULL is now enabled, allowing the app to automatically find and boot an operating system.
    • CONFIG_BOARD_EARLY_INIT_R is turned on to ensure block devices are available.
    • The VBE-OS boot method is also enabled, providing another way to locate and boot an OS.

  4. Supporting Cast (Patches 4/7 & 6/7): A couple of smaller patches provide essential plumbing. The QEMU build scripts were adjusted to prevent conflicts when using multiple disk images, and a fix was added to oftree_dispose() to allow builds where CONFIG_OF_LIVE is disabled.

What This Means for Developers and Users

With these changes, the U-Boot EFI application on ARM is now on par with its x86 counterpart. You can now:

  • Display splash screens for a professional boot experience.
  • Utilize a full graphical console.
  • Use bootstd to automatically scan for and boot an OS from connected block devices.

This makes the ARM efi_app far more useful, particularly in virtualized environments where virtio-gpu is the standard. It provides a complete, visually-enabled pre-boot environment straight out of the box. Go ahead and give it a try with the efi-arm_app64_defconfig! 🚀




Supercharging FITs: U-Boot’s New Two-Stage Boot Capability

The Flattened Image Tree (FIT) is at the heart of modern U-Boot booting, providing a flexible and verifiable way to package kernels, ramdisks, and devicetrees. A new series introduces a significant enhancement to how U-Boot processes FITs, enabling a powerful two-stage boot process. This allows a “load-only” FIT to configure the system (like setting up a devicetree) before a second FIT loads the operating system.

This capability unlocks more flexible and dynamic boot scenarios, especially for systems where the hardware configuration (devicetree) and the OS have different update cadences or sources.


The Concept: Load-Only and Restartable Booting

The core of this feature revolves around two new concepts:

  1. Load-Only Configurations: A FIT configuration can now be marked as “load-only.” When U-Boot’s bootm command processes such a configuration, it understands that there might not be a kernel to boot. Instead of failing, it will load any specified components—like a devicetree or other binaries—into memory and then gracefully exit with a special status code (-ENOPKG).
  2. Restartable bootm: The bootm command, which orchestrates the boot process, now has a new restart subcommand. Unlike start, which clears all previous state, restart continues the boot process while preserving the components that have already been loaded.

When combined, these features allow for a sequence like this:

  1. bootm start <fit1_addr>: U-Boot loads a load-only FIT. It finds no OS but successfully loads a devicetree into memory.
  2. bootm restart <fit2_addr>: U-Boot loads a second, standard FIT. It finds the OS kernel and ramdisk. Because this is a restart, it retains the devicetree from the first step.
  3. bootm go: The kernel is booted using the devicetree from the first FIT and the kernel/ramdisk from the second.

Key Changes in the Series

Bringing this feature to life required a fair amount of refactoring:

  • Core bootm Logic: The bootm state machine was updated to recognize “load-only” configurations and to handle the new restart state, ensuring that previously loaded images (like the devicetree) are not discarded.
  • FIT Image Loading: The function fit_image_load() was enhanced to correctly handle the “load-only” property and return the new -ENOPKG error code when an OS is not present in such a configuration.
  • Function Refactoring: Several key functions in the boot flow, like boot_get_ramdisk() and boot_get_fdt(), were refactored for better clarity and more consistent error handling, making the code easier to maintain.
  • Comprehensive Testing: The FIT test suite in Python was significantly refactored and expanded. New tests were added to validate the “load-only” case and the two-stage boot process with a second FIT, ensuring the new functionality is robust.
  • Documentation: The bootm command’s documentation has been fleshed out to describe the boot flow, the new restart subcommand, and all the other states, making this powerful command easier for developers to understand and use.

This series significantly enhances the flexibility of U-Boot’s FIT handling, paving the way for more sophisticated and modular boot architectures.




New VBE Boot Method: Decoupling Your OS and Devicetrees

In the world of embedded systems, a Flattened Image Tree (FIT) is the standard way to package a bootable OS, typically bundling the kernel, a ramdisk, and the necessary devicetree (FDT) into a single, verifiable file. While convenient, this approach tightly couples the OS with its hardware description. But what if the OS and the devicetree could have independent lifecycles?

A new patch series introduces an enhancement to U-Boot’s Verified Boot for Embedded (VBE) flow that does just that, adding significant flexibility for system integrators and distributors.

The Challenge: Separate Lifecycles

For a Linux distribution aiming to support a wide range of hardware, it’s often desirable to separate the OS from the OEM-controlled devicetrees. This allows the OEM to update the devicetree to fix hardware-specific issues or enable new features without requiring a full OS update from the distro. Conversely, the OS can be updated without touching the OEM’s hardware configuration.

This series addresses this challenge by introducing a new boot method, CONFIG_BOOTMETH_VBE_ABREC_OS, which allows a devicetree to be loaded from a separate, “load-only” FIT before the main OS FIT is processed.


How It Works: A Two-Step Boot Process

The new VBE boot method orchestrates a two-step process, relying on a state file and enhancements to mkimage and the bootm command.

  1. State-Driven Boot Selection: The process starts by looking for a vbe-state file in the boot partition. This file, which is a simple devicetree blob, tells U-Boot which OS slot to boot next: A, B, or recovery. This maintains the robust A/B update scheme that VBE is known for.
  2. The OEM Devicetree FIT: After selecting a slot (e.g., slot ‘A’), U-Boot checks for an OEM-provided FIT, such as a/oem.fit. Thanks to a new --load-only option in mkimage, this FIT can be created to contain only devicetrees, without a kernel image.
  3. Restartable bootm: If an OEM FIT is found, U-Boot loads it using bootm. Since there’s no OS to boot, bootm simply loads the best-matching devicetree into memory and exits. The key innovation here is that the bootm process can now be restarted.
  4. Booting the OS: U-Boot then proceeds to load the main OS FIT (e.g., as specified in an extlinux.conf file). It calls bootm again, but this time with a flag indicating it’s a restart. This tells bootm to skip loading a devicetree from the OS FIT and instead use the one already loaded from the OEM FIT.

The end result is that the OS boots using the devicetree provided by the OEM, achieving a clean separation of concerns.


Under the Hood

This powerful new feature is enabled by a series of changes:

  • mkimage Enhancement: The mkimage tool can now create load-only FITs, which are essential for packaging the devicetrees separately.
  • PXE/Extlinux Integration: The PXE and extlinux boot methods have been updated to support restarting a boot sequence, allowing the devicetree to be preserved across the two bootm calls.
  • Refactoring and Cleanup: The series includes numerous cleanups, such as improving FIT information display and refactoring the PXE parsing logic for better maintainability.
  • Comprehensive Testing: A new set of unit tests for the VBE OS flow has been added for sandbox, ensuring the feature is robust and reliable.
  • Documentation: The new feature is accompanied by detailed documentation, which you can find in doc/develop/bootstd/vbe_os.rst.

This series is a great example of how U-Boot continues to evolve to meet the complex demands of modern embedded systems. By decoupling the OS and devicetree, it provides a more flexible and maintainable boot architecture for product developers and OEMs alike.




Virtio-SCSI Arrives, Backed by a Major SCSI Overhaul

We’re excited to announce a significant new feature in U-Boot: a virtio-scsi driver. While U-Boot has long supported virtio-blk for block device access in virtualized environments, virtio-scsi offers greater flexibility, allowing a single virtio device to host multiple disks (LUNs) and supporting features like hotplug.

This comprehensive 27-patch series, does more than just add a new driver. To make virtio-scsi a reality, U-Boot’s entire SCSI subsystem has received a much-needed modernization, resulting in a faster, more robust, and more maintainable implementation for all SCSI devices.


Smarter Scanning with REPORT LUNS

One of the most significant improvements is in how U-Boot discovers SCSI devices. Previously, a scsi scan would blindly iterate through every possible target and Logical Unit Number (LUN). In a QEMU environment, this could mean checking up to 256 targets, each with 16,384 LUNs—a time-consuming process for finding just one or two disks.

The SCSI subsystem now uses the REPORT LUNS command. Instead of guessing, U-Boot simply asks each target which LUNs it actually has. This can dramatically speed up the scanning process and reduce unnecessary bus traffic, providing a much snappier user-experience.


Better Error Reporting and Code Quality

A key focus of this series was improving the robustness and maintainability of the SCSI and partition code.

No More Silent Failures

Have you ever tried to list partitions on a disk and received a cryptic “unsupported partition type” message, even when you knew the disk was valid? This often happened because a lower-level read error (e.g., from a bad LUN or an inaccessible disk) was silently ignored by the partition drivers.

This has now been fixed. The partition probing functions now correctly propagate I/O errors, so if a disk read fails, you will see a clear “Error reading from device” message instead of being led down a confusing diagnostic path.

Cleaning Up the Code

The core scsi_read() and scsi_write() functions have been thoroughly refactored. The changes make the logic much easier to follow by:

  • Improving the logic for handling read/write loops
  • Replacing magic numbers with proper constants and inquiry response structures
  • Ensuring compliance with modern SCSI specifications, which handle LUN addressing differently
  • Fixing subtle bugs, like off-by-one errors in the device scan loop

The New virtio-scsi Driver 🚀

With these foundational improvements in place, the new virtio-scsi driver integrates smoothly into U-Boot. It registers itself as a SCSI host, allowing the standard scsi commands to work transparently with virtio-based disks.

To make testing and usage easier, the QEMU build scripts have also been updated to support booting from a disk attached via virtio-scsi, allowing developers and users to immediately take advantage of this new capability.

In summary, this series is a good example of holistic development. It not only delivers a powerful new feature but also strengthens the core infrastructure it’s built upon, benefiting all users of U-Boot’s SCSI subsystem.




A boot logo for EFI

U-Boot Concept now supports the EFI Boot Graphics Resource Table (BGRT) feature. This enhancement allows for a more seamless and branded boot experience on devices that use EFI_LOADER, i.e. the Unified Extensible Firmware Interface (UEFI).

What is BGRT?

The BGRT is a table in the ACPI (Advanced Configuration and Power Interface) that allows the firmware to pass a logo or image to the operating system during the boot process. This means that instead of a generic boot screen, users can be greeted with a custom logo, such as a company or product brand. This creates a more professional and polished user experience.

Why is this important for U-Boot?

By supporting BGRT, U-Boot can now provide a more consistent and visually appealing boot experience on a wider range of devices, particularly those running operating systems like Windows or Linux that support UEFI. This is especially valuable in embedded systems and custom hardware where branding and a unique user experience are important.

This new feature further solidifies U-Boot’s position as a leading bootloader for a diverse range of applications, from embedded systems to servers. It demonstrates the community’s commitment to keeping U-Boot up-to-date with the latest industry standards and providing developers with the tools they need to create modern and user-friendly products.




Booting Up the U-Boot Blog!

Welcome to the new official blog for Das U-Boot! For over two decades, the U-Boot mailing list has been the vibrant hub of our development discussions. While the mailing list remains our primary channel for patches and technical conversations, this blog will serve as a new platform to share deeper insights, project news, and community stories in a more accessible format.

As of mid-2025, U-Boot is more critical to the embedded ecosystem than ever. Our development is thriving, with robust support spanning a vast array of architectures from ARM and x86 to the rapidly expanding world of RISC-V. U-Boot provides a flexible, powerful foundation for countless products in the industrial, automotive and consumer-electronics spaces, incorporating modern standards like FIT, EFI and Firmware Handoff to meet today’s demanding security and interoperability requirements.

This blog is a community platform, and we need your voice to make it a success. We invite developers, maintainers, and users to contribute posts. Have you recently ported U-Boot to a novel board? Do you have a technical deep-dive on a specific subsystem you’d like to share? Or perhaps a case study on how U-Boot solved a unique challenge in your project?

If you have an idea for a post, please email the admin to get a login for this site. We’re excited to build this resource with you.

Happy hacking!