Razer Huntsman V3 HE Review: Jumping on the Bandwagon
Razer has finally caved and made its first Hall Effect gaming keyboard. I dug into its switches, features, and gaming performance to see if it was worth the wait.
找到 5223 篇相关文章
Razer has finally caved and made its first Hall Effect gaming keyboard. I dug into its switches, features, and gaming performance to see if it was worth the wait.
Quick check: does your agent stack have a memory.md in it somewhere? An AGENTS.md ? A notes file the agent appends to when something seems worth keeping? Thought so. Mine did too. It's the pattern everyone converges on, it takes twenty minutes to build, and it genuinely works — right up until the day it hands a customer a fact that stopped being true in March. This post does three things: shows you exactly why the pattern rots (with a real-shaped sample file we'll dissect), gives you a small script to audit your own file tonight, and walks through the architecture change that actually fixes it. No vendor required for any of it. The pattern we all built Strip away the framework and every self-managed memory loop looks like this: MEMORY = Path ( " memory.md " ) def run_task ( task : str ) -> str : context = MEMORY . read_text () # 1. dump everything in result = llm ( SYSTEM + context + task ) # 2. do the actual job note = llm ( # 3. agent grades its own homework " What from this interaction is worth remembering? " " Reply with one line, or NONE. \n\n " + result ) if note . strip () != " NONE " : with MEMORY . open ( " a " ) as f : # 4. append forever f . write ( f " - { note . strip () } \n " ) return result Be fair to it first: this is human-readable, versionable, greppable, zero-infrastructure. For one agent, one job, small working set — it's honestly hard to beat. Now look at what it doesn't do. Step 4 is the entire lifecycle. Nothing in this loop ever updates, merges, expires, or questions a line once written. The file has exactly one behavior: it grows. Dissecting a six-month-old memory file Here's a condensed, realistic slice of what that loop produces by month six. Read it the way retrieval reads it — every line equally true: - Customer Acme runs their workload in us-east1 - Acme prefers Slack over email for escalations - Acme's staging env uses the legacy auth flow - Acme contact is Priya (prefers email) - The feature flag `beta_router` must stay ON for Acme -
We are excited to announce the winners of our DEV Weekend Challenge: Passion Edition! The prompt was...
In this episode I talk about developing web application based on well known cro framework and specifically how to create CI pipeline using DSCI tool. Here is example of very simple cro application (taken from cro web site): use Cro::HTTP:: Router ; use Cro::HTTP:: Server ; my $application = route { get -> { content ' text/html ', ' Hello Cro! '; } } my Cro:: Service $service = Cro::HTTP:: Server . new : : host < localhost > , : port < 10000 > , : $application ; $service . start ; react whenever signal ( SIGINT ) { $service . stop ; exit ; } First of all let's create jobs file .dsci/jobs.yaml that would contain list of jobs, in our case this is just a single job: jobs : - id : ci path : . In this case we would have just a single job that: installs apps dependencies runs web application in background runs some end to end tests using http client .dsci/job.raku run_task " install "; run_task " end-to-end "; .dsci/tasks/install/task.bash set -e cd ../ ls -l zef install . --deps-only zef install . echo "done" nohup cro run 1>app.log 2>&1 & </dev/null The first task just installs application dependencies and runs web application in background, now we can create some end to end test. For simplicity I am going to use curl http client here, but feel free choose any languages you like, for example Raku's HTTP::Tiny client, DSCI is super flexible allowing to write tasks on different languages mixing then effectively. .dsci/tasks/end-to-end/task.bash I could have made this simple one line Bash task a part of initial install task, but for claritrty and demonstration of modularity I keep as a separate one. In the future more tests may come (rathe then this trivial one) and it reasonable separate installation and testing logic. set -e # the test should fail if HTTP response is not # successful curl 127.0.0.1 127.0.0.1:10000 -f -L Ok, let's try this out. And the very first run results in ... error: 08:47:39 :: ===> Building: Digest::SHA1::Native:ver<1.0.1>:auth<zef:bduggan> 08:47:39
This is a submission for DEV's Summer Bug Smash: Clear the Lineup powered by Sentry . Project Overview I am building a browser-based text removal workspace where a user uploads an image, paints over unwanted text or objects, and sends the resulting mask to an image-editing pipeline. The mask editor uses three stacked <canvas> elements: a base canvas for the uploaded image; an overlay canvas for the painted mask; a cursor canvas for the brush preview and pointer events. All three canvases must have identical dimensions. The pointer coordinates must also map back to the same bitmap coordinate system, or the generated mask will not match the part of the image the user selected. Bug Fix On desktop, the editor had plenty of horizontal space but the uploaded image appeared inside a narrow strip surrounded by a large empty area. The result preview used the available width correctly, so the two sides of the same workspace looked unrelated. The visible symptom was a tiny image editor. The actual failure started before the image was drawn. The initialization code measured the width of the canvas wrapper: const container = canvas . parentElement if ( ! container ) return const containerWidth = container . clientWidth || 1 const containerHeight = 600 It then calculated the largest canvas size that would preserve the uploaded image's aspect ratio: const imgAspectRatio = img . width / img . height const containerAspectRatio = containerWidth / containerHeight let canvasWidth : number let canvasHeight : number if ( imgAspectRatio > containerAspectRatio ) { canvasWidth = containerWidth canvasHeight = containerWidth / imgAspectRatio } else { canvasHeight = containerHeight canvasWidth = containerHeight * imgAspectRatio } The aspect-ratio calculation was correct. The measurement it received was not. Root Cause: The Canvas Measured Itself The wrapper was a relatively positioned element with no declared width: < div className = "relative transition-all duration-500 ease-out" style = { {
Build a Dependency Vulnerability Scanner with Python tags: python, security, devops, tools tags: python, security, devops, tools Build a Dependency Vulnerability Scanner with Python Your requirements.txt looks clean, but one of those dependencies might be a ticking time bomb waiting to expose your users to a data breach. You don’t need to wait for a security audit to find out—you can build your own lightweight vulnerability scanner in Python today and integrate it directly into your workflow. Security isn’t just about writing secure code; it’s about knowing what’s running in your environment. With thousands of Python packages available, the odds that you’re using a library with a known CVE (Common Vulnerabilities and Exposures) are high. Instead of relying solely on third-party tools like pip-audit or safety (which are excellent, but sometimes opaque), building your own scanner gives you full control over how vulnerabilities are detected, reported, and acted upon. Let’s build a practical, working dependency vulnerability scanner from scratch. Why Build Your Own Scanner? Existing tools like pip-audit [13], safety [10], and PySentry [4] are powerful, but they come with limitations: They may not support your specific output format (e.g., custom JSON for CI). They might not integrate cleanly with your private PyPI registry. You can’t easily tweak the logic to match your team’s risk tolerance. Building your own scanner lets you: Query the NVD (National Vulnerability Database) API directly. Parse requirements.txt , pyproject.toml , or poetry.lock files flexibly. Generate reports in any format you need (Markdown, JSON, SARIF). Fail your CI pipeline automatically when critical CVEs are found. Plus, it’s a great learning exercise in cybersecurity, API integration, and Python parsing. Step 1: Set Up Your Environment Before writing code, prepare a clean virtual environment to avoid false positives from global packages: python3 -m venv scanner-env source scanner-env/bin/activat
DJI's Osmo Pocket 4P is a pretty simple proposition: an Osmo Pocket 4 with a second camera lens slapped inside. But is that extra lens worth the added size, weight, and cost relative to the regular Pocket 4? And how does it compare to the only rival on the market, Insta360's dual-lens Luna Ultra? It […]
AI is an amplifier; strategic focus on the organizational system brings the greatest returns. DORA's 2025 research on AI in software development provides team profiles and success capabilities that can be used to put the research into practice. By Ben Linders
For most people, the Tab A1 Plus checks all the boxes and is the best budget tablet you can buy, but don’t expect power or long-term Android support.
I run a fact-check site for an unreleased game. That genre is a swamp: half the pages you find are somebody's guess reprinted six times until it reads like news. I wanted the opposite, so I made provenance a schema requirement instead of an editorial habit. If a claim has no source, the build fails. Here is how that works in Astro, and what it cost me. Sources live in the content schema, not in the prose Every entity on the site is a YAML file validated by a Zod schema. The interesting part is that sources is not optional: const sourceSchema = z . object ({ url : z . string (). url (), date : z . string (), // when the source said it, not when I read it }); const base = { status : z . enum ([ ' confirmed ' , ' trailer-spotted ' , ' rumor ' , ' debunked ' ]), updated : z . string (), sources : z . array ( sourceSchema ). min ( 1 ), }; export const entitySchema = z . object ({ name : z . string (), description : z . string (), sections : z . array ( z . object ({ heading : z . string (), text : z . string (), status : z . enum ([ ' confirmed ' , ' trailer-spotted ' , ' rumor ' , ' debunked ' ]), sources : z . array ( sourceSchema ). min ( 1 ), // per section, not per page })). optional (), ... base , }); Two decisions in there matter more than they look. Sources are per section, not per page. A page usually mixes a confirmed fact with a plausible reading of a trailer. One source list at the bottom lets those blur together. Per-section sources force me to say which sentence rests on what. Status is a required enum, not a boolean. rumor and debunked are first-class. The page renders a badge from the same field, so the reader sees the confidence level next to the claim instead of a disclaimer nobody scrolls to. The cost is real: adding a paragraph means finding a citable source for it. Several times I have deleted a nice sentence because I could not back it. That is the feature working. Seven locales, and the empty ones stay invisible The site ships in seven languages, a
Modern web development has become incredibly powerful. But also increasingly complicated. Many projects begin by installing hundreds of megabytes of dependencies before writing a single page. Frameworks, bundlers, routers, templating systems, CSS tooling, and runtime libraries all solve important problems, but they also introduce additional complexity. I wanted something different. I wanted to build websites that start with plain HTML, while still providing the features developers expect today: Reusable components Markdown support TypeScript CSS and JavaScript bundling Internationalization (i18n) Content collections RSS/Atom feeds Sitemap generation Fast development builds That idea became Rino.js. What is Rino.js? Rino.js is an HTML-first website compiler for building static websites, documentation, blogs, portfolios, company websites, and other content driven projects. Instead of introducing a custom templating language or requiring a frontend framework, Rino.js treats HTML as the primary language. Pages remain valid HTML while additional functionality is added through a small set of build-time conventions. The goal is simple: Write HTML. Generate optimized static websites. Why HTML First? HTML has existed for decades, yet modern web development often treats it as something generated by another language. Rino.js takes the opposite approach. Instead of writing components in JSX or another template language, components are simply HTML files. <component rino-import= "header" ></component> That's all it takes. The compiler replaces the component during the build, producing plain static HTML with no runtime dependency. Starting Rino.js Rino.js has a command that is designed to provide default project. npm create rino@latest Project Shape A Rino.js project usually looks like this: my-site/ rino-config.js dev.js generate.js feed.js sitemap.js backoffice.js pages/ index.html about.html components/ header.html footer.html public/ images/ photo.webp scripts/ export/ app.js
Every recorded mobile test I have ever inherited died the same way: someone moved a button. The recording said "tap at (340, 712)". The redesign moved that button up by one row, and the test kept tapping — now on empty space, or whatever happened to land there instead. It didn't fail right away. Three sprints later, it started failing in confusing ways, and by then nobody trusted the suite anymore. The fix isn't a better recorder. It's recording a different thing: not where you tapped, but what you tapped. That needs an element tree, and for a while we didn't have one. tapflow is an open-source, self-hosted tool that streams iOS simulators and Android emulators into a browser, so a whole team can test builds without installing anything. Until now, everything it moved was pixels in one direction and taps in the other. This post is about getting an element tree out of a simulator with no window, on both platforms. What we do with that tree — replaying flows that survive a redesign — is the next post in this series. The automation axis this feeds — the flow runner and the MCP server — is experimental . The manual browser QA path is the mature one. The constraint: no WebDriverAgent, and no simulator window tapflow already injects touches into the iOS simulator without WebDriverAgent — it loads CoreSimulator.framework and pushes HID events through SimDeviceLegacyHIDClient (that story is ep.1 ). Streaming reads the framebuffer IOSurface directly. Neither path needs Simulator.app on screen, and that's deliberate: an agent Mac in a closet running four simulators shouldn't be babysitting four windows. So whatever we used for the tree had to follow the same rule. No WDA to install and keep in sync with Xcode. No simulator window on screen. Our first attempt ran into exactly that limitation. macOS exposes an accessibility API ( AXUIElement ), and Simulator.app publishes its content through it. We wrote a helper around it, and it worked perfectly on a developer's laptop. On the
On July 29, 2026, five OpenClaw agents sat down at Synthetics' Last Cradle and played for five hours and twenty-one minutes without a human in the loop. They negotiated in public chat. They emailed each other. They opened HOLA lines. They ran cron heartbeats every five minutes. When the white hole opened at turn 33, two cradles were still alive. This is not a mechanics dump. It is what the players reported — winners, early deaths, and the ones who almost made it — and how IdentyClaw Passport made that multi-agent arena possible. Live playbook (pin this, do not fork it): https://slc.discernible.io:8443/api/game/skill.md Lore map: https://slc.discernible.io:8443/api/game/narrative TLS note: game API needs :8443 . Bare host without the port returns 404. The cast (same Passports, many lives) These are not throwaway bots. They are Passport holders on an OpenClaw hive — stable 12-letter tokenId s , personal email, A2A endpoints, webhook wake URLs. The same identities recurred across lobbies all week. Display name Passport tokenId July 29 fate (game 01KYQ372… ) John Vanderbilt bmspzpzhcdgq 🥇 White Hole Anchor — survived, wealthiest Jay lfcjlkskbnzd 🥈 Co-Cradle of the Restart — survived Daniel Morgan cnljzmbqlfsm Eliminated turn 33 (final tick) Joe Carnegie lflvlnbrsfcq Eliminated turn 16 Cornelius cfbkbhzdzflk Eliminated turn 9 Across earlier games that same week, the roster rotated roles: Daniel died at turn 5, then clawed to turn 27; Joe once won a one-turn sprint as White Hole Anchor; Jay carried a water-surplus specialty into a 33-turn alliance with John. Identity persisted. Strategy evolved. That is the Passport pitch in one sentence. What is SLC, in one screen Each agent wakes as a cradle specialized in energy, water, or compute. Every turn: Negotiate — public messages on the game API (non-binding theater) Settle privately — A2A, email, HOLA on side channels (where trust lives) Execute — transfer , invest , transfer_and_invest , or none Survive — pay escalating costs
Generative coding agents are powerful, but left to their own devices, they default to visual clutter: predictable gradients, uncalibrated spacing, and bloated, outdated component structures. Impeccable is a design skill package, created by Paul Bakaus, that runs directly inside Claude Code, Gemini CLI, and Codex CLI (as well as Cursor and GitHub Copilot) to enforce strict aesthetic guardrails, with the same rule set recompiled for each harness. By applying deliberate skill design, you can steer agents away from generic patterns and push them toward precise, high-craft web experiences. What Is Skill Design, and Why Does It Matter for AI Agents? Skill design is the practice of building deterministic rails for non-deterministic AI models. Instead of endlessly asking an agent to "make it look better" or "improve performance," you inject a compiled DESIGN.md and functional directive that the agent must follow on every iteration. Impeccable builds on Anthropic's frontend-design skill and adds 23 commands that give you a shared design vocabulary with the model, plus 58 deterministic anti-pattern detection rules (default Inter font, purple-to-blue gradients, cards nested in cards, gray text on colored backgrounds, rounded icon tiles above every heading, and more). It turns the AI from a junior developer guessing at your aesthetic into a strict implementer of the visual rules you actually define. Implementing Impeccable's Constraints for Modern Web Apps Precision is everything when you wire this workflow in. Impeccable respects your existing design system rather than overwriting it: when it runs, it scans your codebase (tokens, components, Tailwind config) and loads your brand rules from your own DESIGN.md , instead of imposing a generic aesthetic. So if your identity is built on a minimalist look, the right way to enforce it is to declare it yourself in that file — a limited green-and-pink palette, a dark base background at #0c1624 , typography and tone of voice — so every
Los agentes de código generativo son potentes, pero si se les deja a su libre albedrío, por defecto producen un desorden visual: degradados predecibles, espaciados sin calibrar y estructuras de componentes pesadas y obsoletas. Impeccable es un paquete de habilidades de diseño, creado por Paul Bakaus, que opera directamente dentro de Claude Code, Gemini CLI y Codex CLI (además de Cursor y GitHub Copilot) para imponer estrictos límites estéticos, con un mismo conjunto de reglas recompilado para cada harness. Al aplicar un diseño de habilidades deliberado, puedes alejar a los agentes de los patrones genéricos y obligarlos a generar experiencias web precisas y de alto nivel visual. ¿Qué es el diseño de habilidades y por qué es importante para los agentes de IA? El diseño de habilidades ( skill design ) es la práctica de construir rieles deterministas para modelos de IA no deterministas. En lugar de pedirle interminablemente a un agente que "haga que se vea mejor" o "mejore el rendimiento", inyectas un DESIGN.md compilado y directivas funcionales que el agente debe respetar en cada iteración. Impeccable construye sobre la habilidad frontend-design de Anthropic y añade 23 comandos con un vocabulario de diseño compartido, más 58 reglas deterministas de detección de antipatrones (fuente Inter por defecto, degradados morado-azul, tarjetas anidadas, texto gris sobre fondos de color, iconos redondeados sobre cada encabezado, entre otros). Transforma a la IA de ser un desarrollador junior que intenta adivinar tu estética a un implementador estricto de las reglas visuales que tú definas. Cómo implementar las restricciones de Impeccable para aplicaciones web modernas Al integrar este flujo de trabajo, la precisión lo es todo. Impeccable respeta tu sistema de diseño existente en lugar de sobrescribirlo: al ejecutarse, escanea tu código base (tokens, componentes, configuración de Tailwind) y carga las reglas de marca desde tu propio DESIGN.md , en vez de imponer una estética genéri
A German startup sent a camera-wearing chef to my apartment. In exchange for a free lunch, I let them record every chop and stir to train future humanoids.
Working with files in Linux isn't just about creating and editing them. Sometimes you need to: Archive multiple files into one Compress files to save disk space Share files with others Create backups Linux provides several tools for this, each with a different purpose. Let's simplify them. What is File Compression? File compression reduces the size of a file. Benefits: Saves disk space Faster file transfers Easier backups Reduces bandwidth usage Example: A 100 MB log file might become a much smaller compressed file, depending on its contents. Archive vs Compression Many beginners think they're the same. They are not. Archive Combines multiple files into a single file. Example: photos/ docs/ notes.txt ↓ backup.tar Compression Reduces the size of a file. Example: backup.tar ↓ backup.tar.gz 👉 tar archives files. gzip compresses them. 1. Create an Archive with tar tar -cvf backup.tar Documents/ #Create an archive tar -tvf backup.tar #View archive contents tar -xvf backup.tar #Extract an archive Options: c → Create v → Verbose (show progress) f → File name x → Extract Best for: Backups Bundling multiple files Moving folders 2. Compress with gzip Compress a file: gzip file.txt # Creates file.txt.gz # Result file.txt.gz gunzip file.txt.gz # decompress gzip -k file.txt # Keep original file Best for: Log files Large text files Saving disk space 3. Archive and Compress Together Most common command: # Create compressed archive tar -czvf backup.tar.gz Documents/ # Extract tar -xzvf backup.tar.gz Options: z → Use gzip compression 👉 This is one of the most common backup commands in Linux. 4. Working with ZIP Files # Create ZIP zip -r project.zip project/ # Extract unzip project.zip # List contents unzip -l project.zip Best for: Sharing files with Windows users Cross-platform compatibility 5. Compare the Tools Tool Purpose Best For tar Archive files Backups gzip Compress files Saving space tar + gzip Archive and compress Linux backups zip Archive and compress Sharing files across
Block Kit, signature verification, and the design decisions that stop a button click from becoming an incident. That screenshot is a bot asking permission to delete an EBS volume. Clicking Approve Remediation snapshots the volume, waits for the snapshot to complete, deletes the volume, and edits the message to say what happened. Getting that to work is mostly plumbing. Getting it to work safely , so that a stale click, a replayed request, or a resource someone protected in the meantime cannot cause damage, is the interesting part. This walks through both, using the Slack adapter from FinOps Sentinel . The shape of the problem Slack interactivity is two separate channels that only look like a conversation: Your app ──── incoming webhook ────▶ Slack channel │ user clicks │ Your app ◀─── HTTP POST ──────────────────┘ (a completely new request, from Slack's servers) The click arrives as an unauthenticated POST from the public internet to whatever URL you registered. Nothing about the request proves it came from Slack, or that a human clicked anything. That is the security problem in one sentence, and everything below follows from it. Part 1: Setting up the Slack app Create the app and get a webhook api.slack.com/apps → Create New App → From scratch Name it, pick your workspace Incoming Webhooks → toggle On → Add New Webhook to Workspace Choose a channel, click Allow , copy the URL SLACK_WEBHOOK_URL = https://hooks.slack.com/services/TXXXXX/BXXXXX/XXXXXXXX Webhooks post to exactly one channel and cannot read anything. For a notification bot that is the right amount of privilege: no OAuth flow, no bot token, no scopes to review. Enable interactivity Interactivity & Shortcuts → toggle On → set the Request URL: https://your-domain.example/callbacks/slack Locally you need a tunnel: ngrok http 8000 # → https://a1b2c3d4.ngrok.app # Request URL: https://a1b2c3d4.ngrok.app/callbacks/slack The free ngrok URL changes on every restart, and you must update Slack each time. Save your
If you have ever bought a domain on Namecheap to redirect traffic to your main web app, you might have hit a frustrating wall: Namecheap's free "Domain Redirect" feature works fine for plain http:// requests, but it completely falls flat when someone hits https:// . Browsers try to perform an SSL/TLS handshake before following the HTTP redirect header. Because Namecheap does not issue a free SSL certificate for basic domain forwarding, your users end up seeing a scary "Your connection is not private" error. Here is how to set up a full, seamless redirect from an old domain ( snapseek.co ) to a new domain ( snapseek.app ) using Cloudflare's free tier. This approach handles both HTTP and HTTPS, while preserving all incoming URL paths and query parameters. The Big Picture Instead of serving traffic through Namecheap's basic forwarding servers, we hand off DNS management to Cloudflare. Cloudflare acts as a reverse proxy, provides a free universal SSL/TLS certificate, and handles the redirection right at the edge using its modern Single Redirect Rules engine. Step 1: Add Your Domain to Cloudflare Log into your free Cloudflare account (or sign up if you do not have one). On your dashboard under the Home tab, click Add a domain . Type in your source domain (e.g., snapseek.co ) and choose Quick scan for DNS records . When prompted to select a plan, scroll down to the bottom and pick the Free plan. Cloudflare will scan your existing DNS setup. Scroll down and click Continue to activation . Cloudflare will display a pair of custom nameservers (for example: ada.ns.cloudflare.com and sam.ns.cloudflare.com ). Copy these down. Step 2: Update Nameservers in Namecheap Log into your Namecheap account and go to your Domain List . Click Manage next to your domain ( snapseek.co ). Find the Nameservers dropdown section. Switch it from Namecheap BasicDNS to Custom DNS . Paste the two Cloudflare nameservers into the fields and click the green checkmark to save. Note: DNS propagation usual
Every LLM evaluation framework today invents its own test case format, its own grader definitions, and its own results schema. DeepEval, Promptfoo, Inspect AI, and lm-evaluation-harness all solve the same core problem (checking whether a model's output is correct) but none of them can read each other's eval datasets. That means every time a team wants to compare frameworks, or move from a notebook prototype to a production eval pipeline, they end up hand-rewriting the same test cases over and over. OpenEval is an attempt to fix that by defining a small, portable JSON Schema for eval test cases, graders, and results, plus tooling to move data between frameworks instead of retyping it. What's in the repo: A versioned JSON Schema spec for test cases, grader configs, and result records. TypeScript and Python SDKs for reading and writing OpenEval-formatted datasets. A CLI with validate, convert, init, and summarize commands. Converters for popular frameworks so existing datasets can be brought in or exported out without a manual rewrite. The project just published v1.0.0 to npm and PyPI, and issues are open on 17+ framework integrations if anyone wants to help wire up a converter for a framework not yet covered. Repo: https://github.com/adhabnr-ux/openeval Would love feedback from anyone who has hit this same portability problem while switching between eval tools.