AI 资讯
Union-Find: The Fellowship of the Sets
The Quest Begins (The "Why") I still remember the first time I saw LeetCode 323 “Number of Connected Components in an Undirected Graph”. I stared at the adjacency list, thought “I’ll just run a DFS from every node”, and coded it up in ten minutes. The solution passed the easy tests, but when the hidden test cases hit a graph with 10⁵ nodes and 10⁵ edges, my DFS started to choke—stack overflows, repeated visits, and a sinking feeling that I was brute‑forcing a problem that deserved a smarter tool. That night, after a few too many coffees, I stumbled upon a tiny comment in a discussion thread: “Union‑Find can do this in almost O(1) per operation”. My curiosity sparked like a power‑up in a retro arcade game. I had to know why this seemingly simple data structure could turn a nightmare into a breeze. The Revelation (The Insight) At its heart, Union‑Find (aka Disjoint Set Union, DSU) maintains a collection of elements partitioned into disjoint subsets. It supports two operations: Find(x) – returns the representative (root) of the set containing x . Union(x, y) – merges the sets containing x and y . The magic lies in two simple heuristics: Path Compression – when we walk up the tree to find a root, we make every node on that path point directly to the root. Future finds become flat, almost constant‑time. Union by Rank/Size – we always attach the smaller tree under the root of the larger one, keeping the overall tree shallow. Why does this give us near‑O(1) amortized time? Think of each Find as paying a small “tax” to flatten the path. The tax is paid only a few times per node before it becomes a direct child of the root. Over a sequence of m operations, the total work is bounded by O(m α(n)) , where α is the inverse Ackermann function—so slow‑growing it’s practically a constant for any realistic n . In plain English: every time we climb up, we leave a shortcut behind. The next climber benefits from that shortcut, and the structure keeps getting better. It’s like building
AI 资讯
Gubernator v2.13.0: Google SRE SLOs, Native CoreDNS Suite & Caddy Ingress for Docker Compose
If you love the simplicity of Docker Swarm (native Compose files, lightweight single binary) but miss the advanced capabilities of Kubernetes (targeted label placement, SRE-grade observability, built-in DNS service discovery, and zero-trust ingress), meet Gubernator (gbnt) . We are excited to release Gubernator v2.13.0 , introducing three massive feature suites natively integrated into a single binary and a modern Material Design 3 Flutter Web Dashboard: Google SRE Multi-Burn-Rate SLO Engine & Interactive Suite CoreDNS 4-Tab Management Suite & Interactive Dig Playground Caddy Ingress & Zero-Trust Reverse Proxy Suite Fun Fact: The entirety of Gubernator's codebase, multi-node deployment pipelines, and SRE features were designed, built, and pair-programmed using **Google Antigravity (AGY) , Google DeepMind's agentic AI coding assistant! Let's dive into what's new and how you can level up your self-hosted or production container clusters! 1. Google SRE Multi-Burn-Rate SLO Engine & Web Suite Defining Service Level Objectives (SLOs) and tracking Error Budgets is the gold standard of Site Reliability Engineering. Until now, implementing SLOs meant running heavy Kubernetes CRDs (via tools like Sloth or Pyrra) or using costly SaaS platforms. Gubernator v2.13.0 brings Google SRE Workbook (Chapter 5) compliant multi-burn-rate alerting straight to simple docker-compose.yml services: version : " 3.8" services : payment-api : image : hashicorp/http-echo:latest labels : gbnt.slo.enable : " true" gbnt.slo.target : " 99.9" gbnt.slo.window : " 30d" gbnt.slo.template : " caddy-http" gbnt.slo.journey : " Checkout Flow" What makes Gubernator's SLO Suite unique? Google Multi-Burn-Rate Alerting : Automatically generates standard 4-window Prometheus recording and alert rules ( Critical Page 1h/6h & Warning Ticket 3d/14d ). Dynamic "No-Code" Management : Click "+ Configure / Add SLO" in the Web UI or call POST /v1/slo/edit to create, edit, or disable SLOs on the fly without editing Compose
开发者
How Many Introductions Away Are You From Pedro Pascal? A Practical Introduction to Graph Search
I was watching The Mandalorian the other day when it struck me that I don't know Pedro Pascal, which...
AI 资讯
Google co-founder Sergey Brin has now spent $100 million to fight the billionaire tax
California's Prop 40 would impose a one-time 5% tax on the net worth of the state's billionaires.
AI 资讯
The Matrix: Why Merge Sort Beats the Brute Force
The Quest Begins (The "Why") I still remember the first time I got hit with a sorting question in an interview. The interviewer slid a whiteboard marker across the table and said, “Sort this array of a million integers – and tell me why you chose your method.” My brain went straight to the trusty old bubble sort I’d learned in CS101. I started writing nested loops, feeling like Neo dodging bullets in slow motion, only to realize the runtime was creeping toward O(n²). After a few painful minutes, I could see the interviewer’s eyes glaze over – not because I was wrong, but because I was using a sledgehammer to crack a nut. That moment sparked a quest: What makes a sorting algorithm truly efficient, and how do I know when to reach for it? I dove into textbooks, blog posts, and late‑night YouTube deep dives. The answer kept pointing back to one algorithm that felt like discovering a hidden cheat code: Merge Sort . The Revelation (The Insight) So why does Merge Sort work so well? It’s not just about splitting and merging; it’s about guaranteeing that each level of recursion does a linear amount of work, no matter how the input is arranged. Think of an unsorted array as a messy pile of LEGO bricks. Merge Sort first divides the pile into two halves, then halves again, until each sub‑pile contains a single brick – which is, by definition, sorted. The magic happens in the merge step: we take two already‑sorted sub‑arrays and walk through them with two pointers, always picking the smaller front element and appending it to the result. Because each sub‑array is sorted, we never need to look back; we simply advance one pointer at a time. That walk is O(n) for the merge: each element is examined exactly once as it gets placed into the output array. Since we split the array log₂ n times (each level halves the size), we perform an O(n) merge at each of those log₂ n levels. Multiply them together and you get O(n log n) worst‑case time, with O(n) extra space for the temporary buffer
开发者
What to expect from Google’s 2026 Pixel hardware launch event
It's that time of year: On Wednesday, Google is set to host its annual Made by Google hardware launch event for Pixel gadgets. Google itself has already teased new slab-style and foldable Pixel smartphones, but leaks also indicate that the company could announce updated watches, a new color for familiar earbuds, and perhaps a brand […]
开发者
Following Epic loss, Google has started hosting rival app stores in the Play Store
Aptoide has become the first app store distributed inside Google Play under a judge's order.
开发者
Sila lands $1.4B Pentagon loan as militaries demand more batteries
Battery materials startup Sila will use a $1.4 billion loan from the U.S. Department of Defense to scale production at its factory in Washington State.
AI 资讯
An Android app store competitor is available in the Play Store
A competitor to Google's app store, Aptoide Games, is now available in the Play Store.
开发者
Google Play adds Venmo as a payment option
The ability to add Venmo to Google Play comes as people are spending more money on apps and games.
AI 资讯
The first rival Android app store just arrived in the US Play Store
Following the latest twist in Google's legal battles with Epic, US Android users are now able to open Google's Play Store and download a third-party digital store with its own selection of apps. Aptoide, a store specializing in mobile games, is the first to become available. Third-party app stores have always been available on Android, […]
开发者
Python Now Has a Post-Quantum Encryption Library
This is good : Post-quantum cryptography is now one pip-install away for the entire Python ecosystem. With funding from the Sovereign Tech Agency , we implemented support for ML-KEM, the NIST-standard key-establishment primitive, and ML-DSA, the NIST-standard digital-signature primitive, in pyca/cryptography. Remember, the reason to do this now is because there’s no emergency. And because you will make your systems crypto agile, which is always a good idea.
AI 资讯
Ford’s new AI assistant can check your fuel levels and tire pressure
Ford is rolling out a new AI-powered assistant that can answer questions about your Ford or Lincoln vehicle, such as how much fuel you'll need for your next road trip or whether your truck can tow that new motor boat. The app is rolling out first to the Ford and Lincoln mobile apps, where it […]
AI 资讯
Google Releases Angular v22 with Stable Signal Forms, OnPush by Default and Experimental WebMCP
Angular v22, Google's TypeScript-first framework, has introduced API stabilizations, ergonomic templates, and tooling enhancements for AI integration. Key developments include the stabilization of Signal Forms, improved change detection strategies, and a new @Service() decorator for dependency injection. The release supports TypeScript 6 and removes deprecated features. By Daniel Curtis
AI 资讯
The Stale Godot Class Cache Bug That Passed CI but Broke Local Startup
This is a submission for DEV's Summer Bug Smash: Clear the Lineup powered by Sentry . Project overview Nocturne Vania is a small pixel-art Metroidvania built with Godot 4. The game has interconnected rooms, enemy AI, save data, unlockable movement abilities, and a growing automated test suite. I hit this bug after adding a bell tower area. The new rooms, enemies, effects, and map markers used GDScript's class_name keyword so they could be referenced as global types. The new area worked in a freshly imported project and in CI. It did not always work in an existing local checkout. Bug fix or performance improvement Godot stores imported project data under .godot . An editor session that predated the bell tower scripts could still have an old global_script_class_cache.cfg . In that state, starting the game caused a parse error because scripts such as game.gd referred directly to global types that were missing from the stale cache. One room script, for example, inherited from a new global class by name: extends TowerRoom The test code also used the new classes for casts and enum access: var sentinel : = await _test_spawn_enemy ( "res://src/enemies/clockwork_sentinel.tscn" , Vector2 ( 320 , 300 ) ) as ClockworkSentinel if sentinel . _state == ClockworkSentinel . State . CHARGE : charged = true Those references were valid after Godot refreshed its global class registry. Before that refresh, the parser could not resolve them. CI missed the problem because the test workflow imported the project before running the suite. The import regenerated the cache, so CI always tested the healthy state. Local startup followed a different order and exposed the bug. Refreshing or deleting .godot could repair one checkout, but it left the startup dependency in the code. I wanted the game to parse even before the editor rebuilt the cache. Code I merged the complete fix as PR #95 in the project's private repository. Since the repository is not publicly accessible, the relevant before-and-af
AI 资讯
Building SaarDB, Part 6: How SQL Queries Become Key-Value Operations
In Blog 5, we built a SQL parser. It can take this: INSERT INTO payments VALUES ( 500 , payment_1 , pending , 1 ) and turn it into a struct: InsertIntoTable { TableName : "payments" , ColumnValues : [] string { "500" , "payment_1" , "pending" , "1" }, } But this is still not enough for the storage engine. Our storage engine only knows how to store key-value pairs. It does not know what a table is. It does not know what a column is. It does not know that 500 is an integer, pending is a string, and 1 is a boolean. So, in this post we solve the missing bridge of persisting these in our key-value store. CREATE and INSERT are PUT operations This is the first major realisation. A key-value store is extensible to store literally anything. This is what we have been saying from the first post itself. But now we will be taking actual examples to prove that. CREATE TABLE Example Let's start with the create table example and see what should be the key and the value. Serialisation The key should be something that uniquely identifies the table, which is straightforward enough in this case as the table name . The value becomes everything else except the key, which is the schema of the table. So, in order to store the table name, we can append a reserved keyword as prefix like schema as a unique identifier. The structure of the key becomes _schema:<table_name> . The next question to answer is: How do we store a struct like below into our key value store where the value is always string? CreateTable { TableName : "payments" , ColumnDetails : [] Column { { ColumnName : "amount" , DataType : Int }, { ColumnName : "id" , DataType : String }, { ColumnName : "status" , DataType : String }, { ColumnName : "captured" , DataType : Bool }, }, PrimaryKeyColumnPosition : 1 , } One way is to serialise the entire struct into a string and store that directly. But in that case, deserialisation is a complex logic. JSON or struct serialisation and deserialisation is both space-heavy and compute inte
AI 资讯
Cpynet a pastebin you talk to with curl, that forgets everything you send it
A zero-dependency, single-file Go pastebin built for terminals — burn-after-read by default, two independent encryption layers, and a curl one-liner instead of a login form. I keep ending up in situations where I need to move a small piece of text — a log snippet, a password, a container's stdout — from one machine to another, and the clipboard just isn't there. SSH session on a remote box. A locked-down corporate laptop that won't let me touch the OS clipboard at all. A container with no shared volume and no browser. Slack is right there, but pasting a database password into a channel that's archived forever is a special kind of bad idea. So I built CPYNET — a paste-sharing tool with exactly one interface that matters: curl . echo "hello world" | curl --data-binary @- https://cpynet.com/ # https://cpynet.com/482913 curl https://cpynet.com/482913 # hello world That's the whole thing. No account, no API key, no clicking around. Two curl calls and you've moved text between two machines that have nothing in common except a network path. Burn-after-read, actually The paste above is gone the instant that second curl runs. Not "gone in 24 hours" — gone the moment it's read , whether that's one second later or one minute later. Read it twice (even from the same machine) and the second request gets a plain 404 . It also auto-expires on a timer (2 minutes by default) even if nobody ever reads it, so an unread secret doesn't just sit there. None of this lives on disk. It's a Go map behind a mutex, in memory, for the lifetime of one process. Restart the server and every paste that hasn't been read yet is just... gone. That's not a limitation I'm working around — it's the actual point. A "burn after read" tool that persists to disk somewhere you're not thinking about isn't really burning anything. The shell functions, if you don't want to remember the curl flags curl -s https://cpynet.com/install.sh -o install.sh && bash -n install.sh && . install.sh That wires up two functions
AI 资讯
A backup you haven't restored isn't a backup
Migrating from MongoDB Atlas to a self-hosted replica set bought us control and cut our bill. It also quietly removed something we had stopped thinking about: Atlas had been taking continuous backups for us the entire time. After the migration, production data for Prochesta lived in /var/db/mongo on a single VPS. No snapshots. No off-box copy. A rm -rf , a bad migration script, or a dead disk would have been the end of it. We had written "backups" as a follow-up task in the migration spec, which is the engineering equivalent of a sticky note on a bank vault. The requirement we actually cared about was narrower than "back up the database". Most real-world data loss at our scale isn't hardware failure — it's a deploy that writes garbage, or someone running an update without a filter. Recovering to last night doesn't help when the damage happened at 14:20 and you noticed at 14:50. We needed to recover to an arbitrary moment , not to a nightly snapshot. The constraint nobody mentions: Community has no $backupCursor We chose Percona Backup for MongoDB (PBM), and immediately hit the limitation that shapes every decision downstream. PBM offers physical backups — fast file-level copies that restore in minutes and barely touch the running server. They work by opening a backup cursor via the $backupCursor aggregation stage. That stage exists in Percona Server for MongoDB and in MongoDB Enterprise. It does not exist in MongoDB Community, which is what the official mongo:8.0 image ships. So on Community, PBM gives you logical backups only: every document read out through mongod , compressed, and shipped off-box. Two consequences, both accepted deliberately rather than discovered later: Backups cost CPU on the primary — and with a single-member replica set there's no secondary to offload the read to. Restores insert documents and rebuild indexes, so restore time grows with data size much faster than backup time does. At our current size that's minutes, not hours. It's also the t
科技前沿
The downsides of switching from iPhone to Android
If you're considering ditching iOS for an Android device, make sure you know what you might be losing.
开源项目
🔥 pranshuparmar / witr - Why is this running? Trace any process, port, container, or
GitHub热门项目 | Why is this running? Trace any process, port, container, or file back to what started it - CLI + TUI. | Stars: 20,264 | 556 stars today | 语言: Go