# Damon's Blog

> The magic you are looking for is in the work you're avoiding.

## Gems

### 2026

#### April

* 1:

#### March

* 12: [Modern C++ In-Depth — Is string\_view Worth It?](https://medium.com/factset/modern-c-in-depth-is-string-view-worth-it-7ae7570b7830)

  > * [When to use std::string\_view](https://learnmoderncpp.com/2024/10/29/when-to-use-stdstring_view/)
  > * A std::string\_view object is typically implemented as a pointer and a length, so on 64-bit machines is 16 bytes in size and is best passed by value.
  > * be aware that string\_view will not extend the lifetime of a temporary object like a normal reference to const will.
* 11: [Sustainable Java Applications With Quick Warmup](https://dzone.com/articles/sustainable-java-applications-with-quick-warmup)

  > Coordinated Restore at Checkpoint (CRaC) offers a Checkpoint/Restore API mechanism solution allowing the creation of an image of a running application at an arbitrary point in time ("checkpoint") and then starting the image from the checkpoint file (snapshot). CRaC snapshots ("checkpoints") include the entire state of the HotSpot process at a specific point in time.
* 10: [FastQueue](https://github.com/andersc/fastqueue)

  > TODO
  >
  > * [FastQueue2](https://github.com/andersc/fastqueue2)
  > * [boost::lockfree::spsc\_queue](https://www.boost.org/doc/libs/latest/doc/html/doxygen/classboost_1_1lockfree_1_1spsc__queue.html)
* 9: [TriviallyCopyable](https://en.cppreference.com/w/cpp/named_req/TriviallyCopyable)

  > A trivially copyable object in C++ is an object whose underlying bytes can be safely copied using low-level memory operations like std::memcpy or std::memmove. This property is crucial for performance optimizations and binary serialization.
  >
  > * thread: non-copyable but movable
  > * mutex: non-copyable and non-movable
  > * unique\_ptr: non-copyable but movable
* 8: [modern-cpp-features](https://github.com/AnthonyCalandra/modern-cpp-features/tree/master)

  > A repository to collect the modern cpp features of different version.
* 7: [Every C++ Concept Explained in 12 Minutes](https://www.youtube.com/watch?v=BlDXiRaNjLU)

  > TODO
* 6: [From pip to uv: A Complete Guide to the Modern Python Project Management Workflow](https://www.youtube.com/watch?v=jd1aRE5pJWc)

  > TODO
* 5: [Using Precompiled Headers](https://doc.qt.io/qt-6/qmake-precompiledheaders.html)

  > In C++, a PCH (Precompiled Header) file is a performance feature that stores an intermediate, compiled representation of a stable body of code (typically common, infrequently changed header files like the Standard Template Library or Windows API headers) to significantly speed up subsequent compilation times. The initial compilation that creates the PCH file takes longer, but later compilations that use the PCH are much faster because the compiler doesn't need to re-read and re-process the large headers repeatedly.
  >
  > * [Precompiled Headers in C++](https://youtu.be/eSI4wctZUto?si=7FdpiMF2wybzvwlt)
* 4: [Understanding Static in C++](https://www.youtube.com/watch?v=g4Dn2cwSrC4)

  > * controls
  >   * linkage:
  >     * non-static global variable is placed into data section or BSS section;
  >     * when a static global variable is declared, it has only internal linkage, which restricts the variable's visibility to the translation unit (source file) in which it is defined. This means that a static global variable cannot be accessed from other source files, preventing naming conflicts and unintended interactions between different parts of a program.
  >     * if non-static global variable name conflicts, another way is to declare one of them as `extern` and remove the definition.
  >   * lifetime: how long the variable stays in memory; static is allocated before runtime and remains throughout the entire lifetime.
* 3: [What I learned building an opinionated and minimal coding agent](https://mariozechner.at/posts/2025-11-30-pi-coding-agent/)

  > * TODO
* 2: [microgpt](https://karpathy.github.io/2026/02/12/microgpt/)

  > * Two hundred lines, zero dependencies.
  > * TODO:
  > * [GPT From Zero to Hero](https://mp.weixin.qq.com/s/-VJo2kOHPSXFYaLvjPDuyA)
  > * [microgpt.py](https://gist.github.com/karpathy/8627fe009c40f57531cb18360106ce95)
  > * [MicroGPT explained interactively](https://growingswe.com/blog/microgpt)
* 1: [Modern C++: The Pimpl Idiom](https://medium.com/@weidagang/modern-c-the-pimpl-idiom-53173b16a60a)

  > * Reduced Header Dependencies
  > * Minimal Recompilation Cascade
  > * Hidden Implementation
  > * ABI Stability
  > * Easy Refactoring
  > * Dependency Management
  > * Forward Declarations: Use forward declarations in the header file to avoid including the implementation header.
  > * Rule of Five: Consider implementing the Rule of Five (copy/move constructors, copy/move assignment operators) if your class needs custom copy/move semantics.
  > * In C++20 and beyond, modules offer an alternative way to manage dependencies and compile times. While modules are a powerful tool, Pimpl remains relevant in scenarios where you need to maintain ABI compatibility or desire strict encapsulation boundaries.
  > * [Modern C++](https://medium.com/@weidagang/modern-c-cbcd565a0716)

#### February

* 8: [Big endian and little endian](https://ntietz.com/blog/endianness/)

  > * If you write it into memory on a little-endian system, though, and read bytes from the address (with the remaining ones zero, very important!), then it is the same value no matter how many bytes you read. As long as you don't truncate the value, at least; 0x0A0B read as an 8-bit int would not be equal to being read as a 16-bit ints, since an 8-bit int can't hold the entire thing.
  > * most modern systems (x86/x64 Macs included) are little-endian. However, this code is doing manual big-endian serialization regardless of the host byte order.
  > * The purpose here is to serialize the integer into a network/protocol byte buffer in a specific byte order (big-endian / MSB first). By explicitly shifting and masking, the code bypasses the host's native endianness entirely — the result in buf is always the same regardless of whether the machine is little-endian or big-endian. If you instead did memcpy(\&buf\[2], \&timeMicros, 4) on a little-endian machine, you'd get the bytes in reversed order (0xDD, 0xCC, 0xBB, 0xAA), which would be wrong for this protocol format.
  > * By using bitwise operations, you extract each byte based on the numeric value, not based on how the value is stored in memory. Bit shifts and masks operate on the integer value itself, which is independent of endianness.
  > * [Why is data sent across the network converted to network byte order?](https://stackoverflow.com/questions/15859649/why-is-data-sent-across-the-network-converted-to-network-byte-order)
* 7: [Java NIO: Using Memory-mapped file to load big data into applications](https://medium.com/@trunghuynh/java-nio-using-memory-mapped-file-to-load-big-data-into-applications-5058b395cc9d)

  > * [Memory-mapped files](https://learn.microsoft.com/en-us/dotnet/standard/io/memory-mapped-files)
  > * [NIO Buffer](https://jenkov.com/tutorials/java-nio/buffers.html)
* 6: [Histograms and summaries](https://prometheus.io/docs/practices/histograms/)

  > * The essential difference between summaries and histograms is that summaries calculate streaming φ-quantiles on the client side and expose them directly, while histograms expose bucketed observation counts and the calculation of quantiles from the buckets of a histogram happens on the server side using the histogram\_quantile() function.
  > * However, aggregating the precomputed quantiles from a summary rarely makes sense. In this particular case, averaging the quantiles yields statistically nonsensical values.
  > * The histogram implementation guarantees that the true 95th percentile is somewhere between 200ms and 300ms. To return a single value (rather than an interval), it applies linear interpolation, which yields 295ms in this case.
  > * A summary would have had no problem calculating the correct percentile value in both cases, at least if it uses an appropriate algorithm on the client side (like the one used by the Go client ). Unfortunately, you cannot use a summary if you need to aggregate the observations from a number of instances.
  > * Also, the closer the actual value of the quantile is to our SLO (or in other words, the value we are actually most interested in), the more accurate the calculated value becomes.
  > * Two rules of thumb:
  >   * If you need to aggregate, choose histograms.
  >   * Otherwise, choose a histogram if you have an idea of the range and distribution of values that will be observed. Choose a summary if you need an accurate quantile, no matter what the range and distribution of the values is.
* 5: [UNDERSTANDING NEURAL NETWORKS, VISUALLY](https://visualrambling.space/neural-network/)
* 4: [Derivation and Intuition behind Poisson distribution](https://antaripasaha.notion.site/Derivation-and-Intuition-behind-Poisson-distribution-1255314a56398062bf9dd9049fb1c396)

  > A classic way to approach this is by considering the probability of observing a certain number of rare events occurring in a fixed interval of time or space, with these events occurring independently and at a constant average rate.
* 3: [You don't need Kafka: Building a message queue with only two UNIX signals](https://leandronsp.com/articles/you-dont-need-kafka-building-a-message-queue-with-only-two-unix-signals)

  > forms of IPC in UNIX include:
  >
  > * anonymous pipes
  > * named pipes (mkfifo)
  > * sockets
  > * regular files
  > * signal
  >
  > There are many signals we can send to a process, including:
  >
  > * SIGTERM - sends a notification to the process to terminate. It can be “trapped,” which means the process can do some cleanup work before termination, like releasing OS resources and closing file descriptors
  > * SIGKILL - sends a termination signal that cannot be trapped or ignored, forcing immediate termination
  > * SIGINT - the interrupt signal, typically sent when you press Ctrl+C in the terminal. It can be trapped, allowing the process to perform cleanup before exiting gracefully
  > * SIGHUP - the hangup signal, originally sent when a terminal connection was lost. Modern applications often use it to reload configuration files without restarting the process
  > * SIGQUIT - similar to SIGINT but also generates a core dump for debugging
  > * SIGSTOP - pauses (suspends) a process. Cannot be trapped or ignored
  > * SIGCONT - resumes a process that was paused by SIGSTOP
  > * SIGCHLD - sent to a parent process when a child process terminates or stops
  > * SIGUSR1 and SIGUSR2 - user-defined signals that applications can use for custom purposes
* 2: [Linux中的CFS调度器是如何一步步发明出来的](https://mp.weixin.qq.com/s/1CJE1XWn6YW94Q47xWhHBA?from=singlemessage\&isappinstalled=0\&scene=1\&clicktime=1770811877\&enterid=1770811877)

  > 1. looping through the tasks
  > 2. looping through the tasks with priority
  > 3. looping through the tasks with quota and heuristic priority
  > 4. CFS: Completely Fair Scheduler
  >    * check the task with the smallest virtual runtime, and run it for a small time slice, then update its virtual runtime and put it back to the red-black tree.
  >    * use the nic value to adjust the virtual runtime of a task, thus adjusting its priority.
  >    * IO bounding tasks will have smaller virtual runtime, thus higher priority, and CPU bound tasks will have larger virtual runtime, thus lower priority.
* 1: [Claude Code in Action](https://anthropic.skilljar.com/claude-code-in-action)

  > TODO

#### January

* 25: Get the classpath through mvn: `mvn dependency:build-classpath -Dmdep.outputFile=cp.txt`
* 24: [Java Performance Troubleshooting with JFR: A Complete Guide — Part 2 — Diagnose Slow Java Application Response Time Using JFR](https://imedhyaweerasinghe.medium.com/java-performance-troubleshooting-with-jfr-a-complete-guide-part-2-diagnose-slow-java-0c78f72f0ba0)
* 23: [Java Service Provider Interface](https://www.baeldung.com/java-spi)

  > * Java SPI -> api + impl with meta-info + app
  >   * Annotation processing is one usage of Java SPI. API is the Processor interface, impl is the annotation processor implementation, meta-info is the file in META-INF/services/ that lists the implementation class, app is the Java compiler that will load the annotation processor and execute it during compilation.
  > * Java Instrumentation: can be used to transform existing bytecode / add extra-opens/exports to existing modules
  >   * [Guide to Java Instrumentation](https://www.baeldung.com/java-instrumentation)
  >   * [Introduction to Javassist](https://www.baeldung.com/javassist)
  > * Annotation processor can only be used to generate new files, not to change existing ones.
  >   * [ava Annotation Processing and Creating a Builder](https://www.baeldung.com/java-annotation-processing-builder)
  >   * The notable exception is the Lombok library which use annotation processing as bootstrapping mechanism to include itself into the compilation process and modify the AST via some internal compiler APIs.
  >   * [Google AutoService](https://www.baeldung.com/google-autoservice): used for SPI, Processor is the interface, and AnnotationProcessor is the implementation that need to be found during compile time by ServiceLoader.
* 22: [An insight into the mathematical mind: Box-Muller transforms](https://www.flyingcoloursmaths.co.uk/an-insight-into-the-mathematical-mind-box-muller-transforms/)
* 21: [为什么C语言高手偏爱void\* ？](https://mp.weixin.qq.com/s/nJo7MGNT80ftVF3i2U4udQ)

  > 1. generic programming
  > 2. memory allocation
  > 3. interface design
* 20: [链接器是如何一步步发明出来的？](https://mp.weixin.qq.com/s/Ie99bZu3fAkS2ndVOflOAA)

  > 1. 编译器处理各个模块，但不必关心跨模块引用
  >
  > 2. 根据各个模块提供的信息来确定符号最终的内存地址并合并所有的模块为一个最终可执行文件
  >
  > 3. Relocation Table
  >
  > 4. Symbol Table
  >
  > * [为什么链接器能“预言”程序运行时地址？](https://mp.weixin.qq.com/s/IEf7hiY9IXSAbXytvF6Zrg)
  >   * 0x400000
* 19: [mmap是如何巧妙绕过传统IO性能陷阱的？](https://mp.weixin.qq.com/s/SylwBMYxNPhbvqPOSxaPWg)

  > 1. zero copy
  > 2. 当程序访问映射区域时，如果所需的页面不在内存中，虚拟内存子系统会自动触发缺页中断，并将相应的页面从磁盘加载到内存中。
  > 3. 频繁修改分散的小数据块（如散列写入）可能导致大量缺页中断和TLB（Translation Lookaside Buffer）未命中，性能可能低于传统read/write。mmap适合需要零拷贝访问、大文件随机读或共享内存的高性能场景（如内存数据库、图像处理）。
  > 4. 如果是实时系统的话，那么这种场景对操作延迟有严格上限，mmap的缺页中断和磁盘I/O延迟不可预测。
  >    * Chronicle Queue mitigates mmap page‑fault unpredictability with design choices aimed at determinism:
  >      * Preallocation and pre‑touching: files are pre‑created and pages are proactively touched via a pretoucher, so writes hit resident pages instead of triggering page faults.
  >      * Sequential, append‑only I/O: linear writes avoid random access, letting the OS keep pages hot and leverage readahead efficiently.
  >      * Off‑heap/direct memory: minimizes GC pauses and heap contention, keeping latency stable.
  >      * Bounded, fixed‑size blocks and rolling cycles: predictable allocation patterns reduce surprise faults and fragmentation.
  >      * Warm‑up on startup: touches mappings and populates TLB/page cache before latency‑sensitive work.
  >      * Optional mlock/pinning (where allowed): keeps critical pages resident to avoid paging.
  >      * Controlled durability: fsync can be tuned (or batched) to match real‑time latency budgets.
  >    * Pretouch (or pre-touching) means proactively accessing mmaped pages before latency-sensitive I/O so they are resident in memory and TLB/cache, avoiding on-demand page faults.
  >      * In Chronicle Queue, a pretoucher thread walks ahead in the append path and touches upcoming pages/blocks (often by writing small dummy bytes or reading headers). This:
  >        * Faults pages in early, populating the page cache and TLB.
  >        * Ensures sequential, append-only writes hit hot pages.
  >        * Reduces first-touch latency spikes during real-time operation.
* 18: [Linux性能分析工具汇总](https://mp.weixin.qq.com/s/W-BDRffMY3k3yj527HAGMw)

  > * vmstat
  > * iostat
  > * dstat
  > * iotop
  > * pidstat
  > * top
  > * htop
  > * mpstat
  > * netstat
  > * ps
  > * strace
  > * uptime
  > * lsof
  > * perf
* 17: [What Is a TLAB or Thread-Local Allocation Buffer in Java?](https://www.baeldung.com/java-jvm-tlab)

  > * The JVM addresses this concern using Thread-Local Allocation Buffers, or TLABs. These are areas of heap memory that are reserved for a given thread and are used only by that thread to allocate memory.
  > * launch the JVM with the -Xlog:gc+tlab=trace flag to see this information
* 16: [Java 25](https://mp.weixin.qq.com/s/lDWuhnBw0o1lDef0EHGElg)

  > 1. vectorization
  > 2. scoped values
  > 3. structured concurrency
  >    * [Structured Concurrency in Java](https://www.baeldung.com/java-structured-concurrency)
  >    *
* 15: [Guest Post: How I Scanned all of GitHub’s “Oops Commits” for Leaked Secrets](https://trufflesecurity.com/blog/guest-post-how-i-scanned-all-of-github-s-oops-commits-for-leaked-secrets)

  > * GitHub Archive logs every public commit, even the ones developers try to delete. Force pushes often cover up mistakes like leaked credentials by rewriting Git history. GitHub keeps these dangling commits, from what we can tell, forever. In the archive, they show up as “zero-commit” PushEvents.
* 14: [为啥C++程序会在main函数之前崩溃？](https://mp.weixin.qq.com/s/y5qU166QGdCJMizjXtQqYw)

  > * "静态初始化顺序问题"（Static Initialization Order Fiasco，简称SIOF）
  > * 解决方案：Meyers Singleton
  > * C++11保证局部静态变量初始化是线程安全的
* 13: [改进FAST协议解码性能](https://mp.weixin.qq.com/s?__biz=MzkxNDMyNzQxMw==\&mid=2247484333\&idx=1\&sn=c3ecfcd1d329efc3939ffe87b526db50\&scene=21\&poc_token=HEnTfmmjiCebEFDI7kE0q7O3cfqKpblG6GVQEtqa)

  > * Stop Bit Encoded
  > * chronicle bytes -> Typically, when we talk about a byte, a byte can represent one of 256 different characters. Yet, rather than being able to represent one of 256 characters, because we used Base64LongConverter we are saying that the 8-bit byte can only represent one of 64 characters. By limiting the number of characters that can be represented in a byte, we are able to compress more characters into a long.
  > * ASCII
  > * UTF-8 vs UTF-16
  > * VByte 是一种“面向字节”的方案。在每个字节中，保留最高有效位作为控制位：当该字节是编码整数中的最后一个时，该位设置为 0，否则设置为 1。
  > * 将一组控制位集中到前面后，减少了VByte对每个byte判断第一位控制位时引发的分支预测失败率。
  > * vint-G8IU快在利用SIMD指令。vint-GB也能被SIMD，但它对于Group控制位后的数据位长度是不固定的（4\~16位）。因此在数据预取时会因长度不固定而导致cpu不时的停顿。而vint-G8IU每块数据都是固定的9位byte，在数据预取时，更加的可预测。
  > * VByte -> vint-GB -> vint-G8IU -> Stream VByte
* 12: [Building a full-text search engine in 150 lines of Python code](https://bart.degoe.de/building-a-full-text-search-engine-150-lines-of-code/)

  > [Bart de Goede](https://bart.degoe.de/) A full-text search engine consists of three main components:
  >
  > 1. analyze
  >    1. tokenize
  >    2. lower case normalization
  >    3. punctuation removal
  >    4. stop word removal
  >    5. stem
  > 2. inverted index
  > 3. search
  >    1. query parsing
  >    2. precision search
  >    3. relevancy search - [Understanding TF-IDF (Term Frequency-Inverse Document Frequency)](https://www.geeksforgeeks.org/machine-learning/understanding-tf-idf-term-frequency-inverse-document-frequency/)
  >       1. Term frequency
  >       2. Inverse Document Frequency
* 11: [Lessons Learned Shipping 500 Units of my First Hardware Product](https://www.simonberens.com/p/lessons-learned-shipping-500-units)

  > From software engineer to hardware engineer.
* 10: [How to Scale a System from 0 to 10 million+ Users](https://blog.algomaster.io/p/scaling-a-system-from-0-to-10-million-users)

  > A re-warm up.
* 9: [What is the purpose of std::launder?](https://stackoverflow.com/questions/39382501/what-is-the-purpose-of-stdlaunder)

  > * [Programming Languages — C++](https://timsong-cpp.github.io/cppwp/)
  > * Money laundering is used to prevent people from tracing where you got your money from. Memory laundering is used to prevent the compiler from tracing where you got your object from, thus forcing it to avoid any optimizations that may no longer apply.
* 8: [Placement `new` C++.](https://medium.com/@ajay.patel305/placement-new-c-b7f1e2e2077a)

  > The placement new operator in C++ allows you to construct an object in a pre-allocated memory buffer.
* 7: [std::jthread: A safer and more capable way of concurrency in C++20](https://medium.com/bosphorusiss/std-jthread-a-safer-and-more-capable-way-of-concurrency-in-c-20-07121cec3a84)

  > The destructor of a std::thread object with an associated thread calls std::terminate if join() has not been called.
* 6: [upper\_bound和lower\_bound](https://www.cnblogs.com/devgc/p/14599203.html)

  > * [upper\_bound](https://en.cppreference.com/w/cpp/algorithm/upper_bound.html): Returns the first iterator iter in \[first, last) where bool(value < \*iter) is true, or last if no such iter exists.
  > * [lower\_bound](https://en.cppreference.com/w/cpp/algorithm/lower_bound.html): Returns the first iterator iter in \[first, last) where bool(\*iter < value) is false, or last if no such iter exists.
* 5: [Debugging C++ with GDB](https://skewed.de/lab/manual/gdb/)

  > * Compiling in debug mode will then include debug symbols (-g), disable optimisation (-00), and enable assert() by omitting -DNDEBUG.
  > * [Debugging with LLDB](https://kevinushey.github.io/blog/2015/04/13/debugging-with-lldb/)
  > * [codesign gdb in MacOS](https://gist.github.com/gravitylow/fb595186ce6068537a6e9da6d8b5b96d)
* 4: [超越 lock-free 的是 wait-free](https://mp.weixin.qq.com/s/kDKkNVWqjPaSzmvOc4U-7Q)

  > * 在读操作占主导时，Wait-Free 表现极佳。因为读线程的“协助”行为分散了写线程的竞争压力，而且读操作本身不需要像 CAS 循环那样反复争抢缓存行。
  > * 但在写操作占主导时，Lock-Free 反而更快。为什么？因为 Wait-Free 的那些位运算、状态判断、原子交换握手，都是实打实的 CPU 指令开销。而 Lock-Free 在竞争不激烈的时候，就是一个简单的原子加减，极其轻量。
  > * [Introduction to Wait-free Algorithms in C++ Programming - Daniel Anderson - CppCon 2024](https://www.youtube.com/watch?v=kPh8pod0-gk)
  > * [如何在不加锁的情况下解决多线程问题？](https://mp.weixin.qq.com/s/jo2nmv6ULijTuhk3wHHdPQ)
* 3: vcpkg and CMake
  * [How CMake, vcpkg, and JSON Work Together: Explained for C++ Developers](https://www.youtube.com/watch?v=10kqdZR4rmU\&t=30s)
  * CLion
    * [Vcpkg integration](https://www.jetbrains.com/help/clion/package-management.html)
    * [CMake profiles](https://www.jetbrains.com/help/clion/cmake-profile.html)
    * [Quick CMake tutorial](https://www.jetbrains.com/help/clion/quick-cmake-tutorial.html)
    * [CMake presets](https://www.jetbrains.com/help/clion/cmake-presets.html)
  * [A TL;DR about CMake Presets](https://martin-fieber.de/blog/cmake-presets/)
* 2: [Create Your Own Compiler](https://citw.dev/tutorial/create-your-own-compiler)

  > TODO
* 1: [Transforming Uniform Random Variables to Normal](https://codefying.com/2015/02/25/transforming-uniform-random-variables-to-normal/)

  > * Central Limit Theorem (CLT) Method (12 Uniforms): [Generate Gaussian samples by central limit theorem](https://medium.com/@seismatica/how-to-generate-gaussian-samples-1cbf46b49751)
  > * Inverse Transform Sampling: [How to generate Gaussian samples](https://medium.com/mti-technology/how-to-generate-gaussian-samples-347c391b7959)
  > * Box-Muller Transform: [Box-Muller](https://medium.com/@seismatica/how-to-generate-gaussian-samples-3951f2203ab0)
  > * Beasley-Springer-Moro Algorithm
  > * [Marsaglia polar method](https://khanhnguyendata.medium.com/how-to-generate-gaussian-samples-c645c09d142e)
  >
  > [Random Numbers Generator](https://codefying.com/2015/02/11/random-numbers-generator/)
  >
  > * linear congruential generator
  >
  > [Transforming Uniform Random Variables to Normal](https://codefying.com/2015/02/25/transforming-uniform-random-variables-to-normal/)
  >
  > * Box-Muller Transform
  > * Beasley-Springer-Moro Algorithm
  > * Inverse Transform Method

### [2025](https://www.damonyuan.com/gems/2025-gems)

### [2024](https://www.damonyuan.com/gems/2024-gems)

### [blogs](https://www.damonyuan.com/gems/blogs)

## Contacts

<div align="left"><figure><img src="https://1654019121-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F6hOVer1rj3roWUJaVRd8%2Fuploads%2Fgit-blob-52dfee5c429d997621dbbaac028749f23d408881%2Flinkedin.png?alt=media" alt="LinkedIn" width="188"><figcaption><p>LinkedIn</p></figcaption></figure></div>
