AI 资讯
Common Web Application Technologies
Introduction Modern web applications are rarely built with a single technology. A typical application combines a web server, a programming language, a framework, a database, data formats, and backend services to deliver its functionality. For anyone learning web application security, it’s important to understand these technologies at a basic level—not only to recognize them, but to understand where they sit in the architecture, how data moves through the system, and where weaknesses can be introduced. This article covers: Java Platform ASP.NET PHP Ruby on Rails SQL XML Web Services & SOAP Web Application Architecture: The Big Picture You can think of a web application as a pipeline: User (Browser) ↓ Web Server / App Server ↓ Application Code ↓ Database / Backend Services ↓ Response back to Browser A useful security question to keep in mind: Once user input enters the application, where does it go, how is it processed, and is it handled safely? 1) The Java Platform (Enterprise Web Applications) Java is widely used for large-scale enterprise applications. Java-based web apps can run on operating systems such as Windows, Linux, and Solaris and can use different application servers, frameworks, and third-party components. Simplified Flow Browser ↓ HTTP Request ↓ Java Web Container ↓ Java Application ↓ Database / Other Services ↓ HTTP Response Common Java Terms (Quick Explanations) Enterprise Java Bean (EJB) An Enterprise Java Bean is a relatively heavyweight Java component that encapsulates the logic of a particular business function. It can also handle enterprise requirements such as transaction management. Plain Old Java Object (POJO) POJO stands for Plain Old Java Object —a regular Java object rather than a specialized component like an EJB. POJOs are typically simpler and more lightweight, which is why they are common in modern Java applications. Java Servlet A Java Servlet is a Java component that receives HTTP requests and returns HTTP responses. In many Java web
AI 资讯
Perry Mason in: The Case of the Drifting Timer
Perry Mason in: The Case of the Drifting Timer Opening Statement You need a reactive "current time" in your Vue 3 app. A schedule grid with a red line showing "now." A live clock. A dashboard that updates every minute. Every Vue developer reaches for setInterval first. It works. But "works" and "works well" are different things. This is the story of taking a naive timer from "it ticks" to production-grade — and the four iterations it took to get there. The prosecution calls four exhibits. Let's begin. Exhibit A: The Memory Leak const currentTime = ref ( new Date ()) onMounted (() => { setInterval (() => { currentTime . value = new Date () }, 60000 ) }) It works. Sort of. The defense rests — but the prosecution is just getting started. Exhibits of negligence: The interval is never cleared. When the component unmounts, the timer keeps firing every 60 seconds forever — updating a ref nothing reads anymore, and holding its closure (and everything the ref references) in memory for the lifetime of the page. Silent. Invisible. The kind of leak that shows up in production after a user navigates around your app for 20 minutes. Exhibit B: The Cleanup That Failed const currentTime = ref ( new Date ()) let timeInterval = null onMounted (() => { currentTime . value = new Date () timeInterval = setInterval (() => { currentTime . value = new Date () }, 60000 ) }) onUnmounted (() => { if ( timeInterval ) clearInterval ( timeInterval ) }) Now we clean up. The interval is stored in a variable, cleared on unmount. A step forward — but the prosecution has three more objections: Further evidence: This only works inside components. If someone calls this logic from a Pinia store or outside a component's setup() context, onUnmounted never fires. The timer leaks silently. (Composables called synchronously during setup() are fine — Vue's docs recommend exactly that. The problem is when there's no component instance at all.) The timer fires 60 seconds after load , not at the top of the minute
AI 资讯
Why Rust and WebAssembly Are Replacing JavaScript for Heavy AI Workloads in 2026
Why Rust and WebAssembly Are Replacing JavaScript for Heavy AI Workloads in 2026 While JavaScript remains the reigning language for web UI rendering, high-throughput client-side compute—such as local browser AI inference, video encoding, and cryptographic verification —has completely shifted to Rust compiled to WebAssembly (WASM) . In 2026, running 1B+ parameter models directly inside the browser using WebGPU and WASM SIMD has become standard practice. ⚡ Benchmarks: JS vs WASM SIMD execution Execution Time (Lower is Better) ┌────────────────────────────────────────────────────────┐ │ JavaScript (V8 Engine) : █ █ █ █ █ █ █ █ █ █ 1,420 ms │ │ Rust WASM SIMD : █ █ 210 ms │ └────────────────────────────────────────────────────────┘ Building a Rust WASM Compute Module Add the wasm-bindgen dependency in your Cargo.toml : [package] name = "wasm_ai_engine" version = "0.1.0" edition = "2021" [lib] crate-type = [ "cdylib" ] [dependencies] wasm-bindgen = "0.2" Implement high-speed array processing in src/lib.rs : use wasm_bindgen :: prelude :: * ; #[wasm_bindgen] pub fn process_tensor_data ( inputs : & [ f32 ], multiplier : f32 ) -> Vec < f32 > { inputs .iter () .map (| & x | x * multiplier ) .collect () } #[wasm_bindgen] pub fn compute_cosine_similarity ( vec_a : & [ f32 ], vec_b : & [ f32 ]) -> f32 { let dot_product : f32 = vec_a .iter () .zip ( vec_b .iter ()) .map (|( a , b )| a * b ) .sum (); let norm_a : f32 = vec_a .iter () .map (| a | a * a ) .sum :: < f32 > () .sqrt (); let norm_b : f32 = vec_b .iter () .map (| b | b * b ) .sum :: < f32 > () .sqrt (); if norm_a == 0.0 || norm_b == 0.0 { return 0.0 ; } dot_product / ( norm_a * norm_b ) } Compile directly to WebAssembly: wasm-pack build --target web Integrating into Next.js / Frontend Stack import init , { compute_cosine_similarity } from ' ./pkg/wasm_ai_engine.js ' ; async function runVectorSearch () { await init (); const vec1 = new Float32Array ([ 0.12 , 0.45 , 0.98 ]); const vec2 = new Float32Array ([ 0.15 , 0.42 ,
AI 资讯
Stop Leaking API Keys: The Backend for Frontend (BFF) Pattern Explained
👉 TL;DR: Frontend applications (SPAs, mobile apps, desktop clients) cannot securely store secrets: any embedded API key is extractable by users and attackers. The Backend for Frontend (BFF) pattern solves this by placing a server-side layer between your frontend and third-party APIs. The BFF holds the secrets; the frontend never sees them. For production deployments, use a secrets manager (AWS Secrets Manager, HashiCorp Vault) rather than environment variables to enable rotation and auditing. A BFF adds infrastructure complexity, but for any API key with financial or administrative implications, the tradeoff is worth it. Frontends are notoriously leaky environments. Cybernews found in 2022 that 56% of Android apps on the Google Play Store contained hardcoded secrets extractable through basic automation. A similar study in 2025 concluded that iOS apps are not better, with over 815,000 secrets harvested from 156,000+ apps (71% leaking at least one credential). These studies plainly expose the widespread issue of hard-coding secrets in production-deployed frontend code. This article aims to warn developers about this risk and present a simple, reusable pattern for safeguarding their applications: the Backend for Frontend (BFF) pattern. Before we start, let's be clear on the crucial point: Whether you are building a React Single Page Application (SPA), a mobile app, or a desktop client, if the code runs on the user's device, the user (and potential attackers) can always inspect it. The solution isn't to try and hide the keys better ; it's to move them somewhere safe. "Public Clients" vs. "Confidential Clients" In OAuth terminology, there are two types of clients, with completely different security models : Confidential Clients : Applications running on a secure server (e.g., a Node.js backend, Python API) that can securely store secrets (like a CLIENT_SECRET) because end-users don't have access to the server's file system or memory. Public Clients : Applications running
AI 资讯
MCP 2026-07-28 from the server side: Codex already speaks it, Claude doesn't yet
On July 28, the Model Context Protocol project shipped a new spec revision, 2026-07-28 . I run backend engineering at GoodBarber, and our public MCP server is a live production surface: real apps, real content, real push notifications. So for us a new revision is not a changelog to skim on a Friday. It is a migration with our name on it. We have just brought the server up to the new revision. This post is three things: the operator's cut of what changed, what upgrading a public server actually involves, and the thing we found in our logs while checking the work. The last one is the reason I'm writing. The operator's cut of 2026-07-28 The headline is the stateless core. MCP grew up as a stateful, bidirectional protocol: an initialize handshake, a negotiated session, an Mcp-Session-Id header to carry it all. The new revision retires that entirely. Every request now self-describes in _meta : protocol version, client identity, capabilities. The practical consequence is the one server operators have wanted since day one: you can put an MCP server behind a plain round-robin load balancer with no shared session storage. If you have ever kept session affinity alive with duct tape, you know exactly which muscle just relaxed. The rest, fast: Method and tool names now also travel in Mcp-Method and Mcp-Name HTTP headers, so gateways can route and meter without parsing JSON bodies. Multi Round-Trip Requests: a call can come back with resultType: "input_required" and continue over stateless connections. Mid-call questions no longer need a held-open stream. List results (tools, prompts, resources) carry ttlMs and cacheScope , so clients can finally cache your inventory honestly instead of guessing. Authorization hardening: RFC 9207 issuer validation, and Client ID Metadata Documents replacing Dynamic Client Registration. Tasks, MCP Apps, and Enterprise Managed Authorization become formal extensions instead of core features. Roots, Sampling, and Logging are deprecated, with a minim
AI 资讯
A static site that collects form submissions, in one HTML attribute
A static site has no backend. That is the point of one — and it is also why the contact form is the first thing that breaks. The usual answers are a third-party form service with its own signup, a serverless function you now maintain, or a mailto: link nobody clicks. There is a third option that falls out of how static hosting already works: the host is in the path of every HTML response it serves. It can collect the form itself. On harvis.dev that is one attribute: <form harvis-form= "contact" > <input name= "email" type= "email" required > <textarea name= "message" ></textarea> <button> Send </button> </form> Deploy, and submissions show up in the dashboard. No script tag, no API key in the page, no fetch() , no JavaScript at all — the form works with JS disabled, because it is a plain HTML form doing what plain HTML forms have always done. The page I am describing is live at harvis-forms-example.harvis.dev — submit the form and see where you land. Everything below is what makes that page work. What actually happens The rewrite happens on the way out, while the HTML is being served: action and method are replaced with /__harvis/form/contact on your site's own subdomain. Same origin, so there is no CORS, no preflight, and nothing in the page has to know a project id. A honeypot field is inserted. It is positioned off-screen rather than display: none , because a bot that skips hidden inputs is a bot that would otherwise get through. Anything that fills it in gets the success page and is stored nowhere — a bot that can tell it was caught is a bot that tries again differently. data-harvis-redirect="/thanks.html" becomes a hidden field, since the handler never sees your HTML — only what the browser posts. It is re-validated on arrival, and a protocol-relative //somewhere-else is refused. The reply is a 303 , so the browser follows it with a GET and a refresh on the thank-you page cannot post the form twice. The form name is part of a URL and a dashboard heading, so it
AI 资讯
You know what's worse than not being able to log in?
This is a submission for DEV's Summer Bug Smash: Smash Stories powered by Sentry . You Know What's Worse Than Not Being Able to Log In? Being told everything worked right up until you try to actually use your account. Yes, that was a real bug. And, somehow, I ended up being pulled into another authentication mystery. At this point, I’m starting to think authentication bugs have a personal grudge against me. 😅 In my previous Smash Story , I wrote about a bug where users simply couldn't log in. This time, the problem was sneakier because most of the flow looked completely healthy. The user was approved, the background task ran, the email and SMS arrived, and Cognito had a user. Then the user actually tried to use their account. And everything fell apart. It Started With Two User Pools The authentication setup was fairly large and had evolved over time, so there wasn't one shiny User Pool doing everything. We had an older Cognito User Pool supporting existing authentication flows, including mobile-based signup, while a newer User Pool handled a newer flow where users received an email containing their PIN. Both pools were intentional because they supported different parts of the authentication journey. That wasn't the problem. The interesting part was that the application database had its own representation of a user, while Cognito had another. On top of that, some of the work connecting those two systems happened asynchronously. As long as everyone agreed about who the user was, nobody cared. The moment they disagreed, authentication became very interested. The Tiny Timing Window The problem appeared in the partner and dependant journey. A member could create a partner or dependant during signup or later from the member details area. A relevant non-member user would then approve the account, which scheduled an asynchronous task called SendingEmailsAfterApprovalBot in a TaskList database table. That task ran every 15 minutes, and once it executed, the partner or depend
AI 资讯
I built a free, no-signup AI text toolkit - here's the stack and why
I kept hitting the same small friction: I'd want to quickly rewrite an email, clean up some text, or summarize a long thread — and every tool wanted me to sign up, pick a plan, or watch an ad first. For a ten-second task, that's absurd. So I built the thing I wanted: a set of free, no-signup AI text tools , each doing one job well. This is a quick write-up of the stack and the decisions behind it. 👉 Live: https://www.texttoolsai.app The core idea: one tool, one job, zero friction Instead of a single mega-app, it's a collection of single-purpose tools — rewrite, tone change, summarize, prompt generation — each on its own page. You land, paste, get output. No account, no modal, no paywall. The "no signup" rule forced good constraints: everything has to work instantly and statelessly, which kept the whole thing simple. The stack Next.js (App Router) — server components for the content/SEO pages, client components only where the tool actually needs interactivity. Vercel for hosting — the deploy story is boringly good, which is what you want. An LLM API on the backend — the browser never sees a key; requests go through a Next.js route handler that owns the prompt and the provider call. Tailwind for styling — fast to iterate, easy to keep consistent across dozens of tool pages. One decision that paid off: data-driven pages Every tool is defined as a config object (label, placeholder, system prompt, endpoint) rather than a hand-built page. Adding a new tool is mostly adding data, not wiring up new routing. That's what made it realistic to ship a lot of tools without the codebase turning into spaghetti. // simplified shape { slug: 'rewrite', label: 'Paste your text', endpoint: '/api/tools/rewriter', systemPrompt: '...' } The route handler resolves the endpoint key against a map of system prompts, so the API surface stays tiny even as the tool count grows. What I'd tell anyone building something similar Keep the API key server-side. Obvious, but easy to leak through a miscon
AI 资讯
One Prompt Can Make a Game Demo. That Is Not the Same as Making a Game.
A playable first-person shooter generated from one prompt would have sounded absurd not long ago. Now, videos of AI-built browser games that resemble Call of Duty and Counter-Strike are spreading across social media. On August 10, Axios reported on the rise of “one-shot” AI game prompting : give a model one detailed instruction, let it produce the code, and receive something you can play. This is a real milestone. It is also easy to misunderstand. A one-prompt game can prove that a model knows how to assemble controls, graphics, physics, enemies, and a recognizable game loop. It cannot prove that the result will stay interesting after the first few minutes. The first prompt creates the demo. The decisions after that create the game. Why These Demos Feel So Important Game ideas used to face a large gap between imagination and interaction. You could describe a mechanic, draw a map, or write a design document. But discovering whether the idea actually felt good required code, assets, an engine, and enough technical work to reach a playable build. Prompt-to-game tools are shrinking that gap. This change is not limited to experimental AI demos. Roblox recently announced mobile-first creation tools that turn text prompts into basic games , giving creators a starting point they can playtest, change, share, and publish. That starting point matters. A playable failure teaches you more than a beautiful design document. You can immediately discover that the movement is slow, the arena is empty, the objective is confusing, or the central mechanic is less interesting than it sounded. The value of one-shot generation is not that the first result is finished. It is that the first result arrives early enough to challenge your assumptions. A Recognizable Game Is Not Necessarily a Good Game A model can generate the visible parts of a familiar genre surprisingly well. Ask for a browser FPS and it may produce: First-person movement Weapons and ammunition Enemies that chase or shoot Hea
AI 资讯
MetaMask launches its agent wallet, Glamsterdam Testnet goes public, a lattice-crypto attack draws doubt, NEAR Intents unifies liquidity
Welcome to our weekly digest, where we unpack the latest in account and chain abstraction and the broader infrastructure shaping Ethereum. This week: MetaMask launches a self-custodial wallet built for AI agents; Ethereum core devs send Glamsterdam to a public testnet while Frame Transactions pick up client support for Hegota; a new quantum attack on lattice-based cryptography draws quick skepticism; and NEAR Intents grows into a single cross-chain liquidity layer. MetaMask Launches Its Agent Wallet Glamsterdam Testnet Goes Public as Hegota Advances A Lattice-Crypto Attack Draws Doubt NEAR Intents Becomes a Unified Liquidity Layer Please fasten your belts! MetaMask Launches Its Agent Wallet MetaMask launched its Agent Wallet , a self-custodial wallet built for AI agents to execute onchain actions inside rules the user sets. It lets traders and builders connect an agent framework, then define spend limits, allowlisted protocols, and a risk profile before the agent acts. The pitch is that safety is the product. Agent Wallet is not blind delegation, so supported transactions pass through MetaMask’s security pipeline, including transaction simulation, Blockaid-powered threat scanning, and MEV protection, and anything outside policy pauses for two-factor approval. Users pick between two modes. Guard Mode, the default, enforces daily spend limits, allowlists, and human approval for out-of-policy actions, while opt-in Beast Mode reduces approval interruptions but still runs security checks and still stops flagged transactions. On capabilities, agents can connect frameworks like Claude Code, Codex, and Cursor and execute across HyperLiquid and EVM chains such as Robinhood and Monad. They can run ERC-7821 batch swaps, and they never need a chain’s native gas token, since MetaMask settles the fee in the token being moved. This is account abstraction in a very practical form. Spend limits, allowlists, gasless execution, and batching are exactly the programmable account feature
AI 资讯
Your rate limiter is broken behind a tunnel — the X-Forwarded-For problem
You put your app behind a tunnel (or any reverse proxy) to test webhooks. Everything works. Then you notice something odd in your logs: every single request comes from the same IP address. Congratulations, you've met the X-Forwarded-For problem. What actually happens When a request flows through a tunnel, the TCP connection to your app comes from the relay, not the real client. So request.remote_addr — the value your framework uses for rate limiting, IP logging, geo-blocking, brute-force detection — is the relay's address. For every request. From every user. The consequences are quiet and nasty: Your rate limiter now rate-limits the relay, not the client. One aggressive user trips the limit and everyone gets blocked. Or worse, the limit is per-IP and effectively unlimited, because each relay node looks like one "user." * Your access logs are fiction. Security review of an incident? Every entry says the same address. * IP allowlists silently break. "Only allow my office IP" now allows nothing, or everything, depending on how it's wired. The fix (and its trap) The proxy already tells you the real client IP — in the X-Forwarded-For header. Every framework has a setting to trust it. Flask: ProxyFix . Express: app.set('trust proxy', ...) . Rails, Django, Laravel: equivalents exist. Here's the trap: trust that header blindly and anyone can spoof it. A client can send X-Forwarded-For: 1.2.3.4 directly, and if your app believes headers from anyone, your rate limiter is bypassed with a curl flag. The correct setup has two halves: 1. Trust `X-Forwarded-For` only when the immediate connection comes from a proxy you control (your tunnel relay, your load balancer). 2. Strip or ignore the header on direct connections. Most frameworks express this as "trusted proxies" — a list of proxy IPs whose forwarded headers you believe. Set it. It's five minutes of config that determines whether your security features are real or decorative. Why this matters more in the tunnel era Tunnels us
AI 资讯
I Built HackForPinas to Make Philippine Hackathons Easier to Discover
In my previous article, I talked about Train Track, the transit app I built around Metro Manila's railway systems. This project started with a completely different problem. I kept thinking about how difficult it can be to discover hackathons and coding competitions. Not because they don't exist. They do. The problem is that they're scattered everywhere. A university might announce one. A government agency might host another. A private company might run one. A developer community might post another. And suddenly you're checking multiple websites just to figure out: What can I actually join? So I built HackForPinas. What is HackForPinas? HackForPinas is a free, public, and open-source directory for Philippine: Hackathons Coding challenges Technology competitions The idea is pretty straightforward: Make opportunities easier to discover. Events can be filtered by: Region Format Organizer type Status Organizers are categorized as: Government University Private Instead of browsing through unrelated websites, users can explore opportunities in one place. But the more I worked on it, the more I realized that the directory itself wasn't the hardest part. The data was. The Data Problem Imagine trying to collect hackathons from different websites. One might have an RSS feed. Another might use WordPress. Another might expose an API. Another might have an ordinary HTML page. And another might not have anything structured at all. So HackForPinas uses multiple scraping strategies: WordPress REST API RSS GDG Community Eventbrite HTML + Cheerio The scraper runs through a background endpoint and collects events from different Philippine technology sources. The interesting part wasn't: "Can I scrape a website?" It was: Can I turn information from completely different sources into one consistent dataset? That became a much more interesting engineering problem. I Didn't Want Anyone to Publish Directly There's another problem with a public directory. If anyone can submit an event, what s
AI 资讯
# I Built My Developer Portfolio as Peter Parker's Lab 🕷️
I could have built another developer portfolio. You know the one. Dark background. Glowing buttons. "Full Stack Developer | AI | Cloud | DevOps" Six project cards. GitHub link. Done. But honestly, that doesn't feel like me. Before I was interested in AI, software engineering, cloud, automation and all the other things I keep breaking and rebuilding, I was just a kid who loved Spider-Man. And the older I got, the more I realized that I didn't actually relate to Spider-Man because he was a superhero. I related to Peter Parker . The curious kid. The awkward kid. The kid who builds things. The kid who experiments. The kid who fails and somehow keeps going. That felt familiar. So when I started building my portfolio, I wanted it to represent that. I called it: 🧪 Peter Parker's Lab The idea is that my portfolio is basically my digital lab. A place where I can show what I'm building, what I'm learning and what I'm experimenting with. 🕷️ Peter Parker → curiosity 🕸️ Spider-Man → persistence 💻 Developer → everything I'm building today And honestly, "lab" describes my development journey pretty well. I build something. It breaks. I investigate why. I fix it. Then I get another idea and break something else. 😂 That's the fun part. I'm currently interested in building things around: AI AI agents automation full-stack applications developer tools cloud infrastructure DevOps local-first software I'm not trying to pretend I've mastered all of it. I'm trying to keep learning by building real things . That's what I want this portfolio to show. Not just a list of technologies. Not just a list of GitHub repositories. But the problems I'm curious about and the things I'm actually trying to create. 🌐 Peter Parker's Lab https://peterparker-lab.vercel.app/ This is version one. I'll keep changing it as I change. New projects. New experiments. New ideas. Probably new bugs too. Because maybe the best portfolio isn't one that says: "Look how much I know." Maybe it's one that says: "Look what I
AI 资讯
CSS Just Got a Parent Selector. Your Forms Will Never Look the Same
For as long as I've been writing CSS, there's been one direction it refused to look: up. You could style a child based on its parent all day long, but the second you wanted a parent to react to something happening inside it — a checked checkbox, an invalid field, a filled-in input — you were reaching for JavaScript. Every time. It didn't matter how small the interaction was. :has() breaks that rule on purpose, and it's been safe to use in production for a while now — it's supported across Chrome, Edge, Firefox, Safari, and Opera, no polyfill required. I didn't fully appreciate what that meant until I rebuilt a form I'd been maintaining for two years and deleted most of the JavaScript in it. Not all of it — I'll get to where it still earns its place — but most. The rule CSS used to have /* This has always worked: style a child based on the parent */ .card.featured .title { color : gold ; } /* This has never worked, until :has(): style the parent based on a child */ .card :has ( .badge--sold-out ) { opacity : 0.6 ; } :has() reads as "select this element, if it contains a match for whatever's inside the parentheses." Once that clicks, a huge category of things people were writing classList.toggle() calls for turns into a single selector. Styling a label when its input is focused This used to mean a focus and blur listener on the input, toggling a class on the label. Now: .field :has ( input :focus ) { border-color : var ( --accent-color ); box-shadow : 0 0 0 3px color-mix ( in srgb , var ( --accent-color ) 25% , transparent ); } Wrap the label and input in a .field container, and the whole field lights up the moment the input inside it gets focus — no listener, no class toggle, and it can never drift out of sync with the actual focus state, because it is the actual focus state. Required-field indicators that can't go stale I've fixed this bug more times than I want to admit: a form gets a field added, and someone forgets to also add the little red asterisk that's suppo
AI 资讯
Astro 7: Rust Compiler, Rust Markdown Pipeline and Vite 8 for Builds Up to 61% Faster
Astro 7 focuses on build performance, utilizing native tooling and a rewritten compiler in Rust. The new version includes faster Markdown processing and stricter HTML rules. Recent updates introduced advanced routing and incremental builds, while issues around legacy file compatibility and dependency counts were raised in feedback. Astro targets content-driven sites with minimal JavaScript. By Daniel Curtis
AI 资讯
Stop Comparing AI Coding Tools by Autocomplete Quality
The biggest mistake in choosing an AI coding tool is comparing autocomplete latency. Cursor and Windsurf are editors with agent abilities. Claude Code works mostly through a terminal on your local repository. GitHub Copilot spans IDEs, GitHub, code review, and a cloud agent. Replit Agent connects generation to a hosted environment where the app actually runs. CodeGeeX provides affordable IDE help for Chinese-language development. They execute in different places. That means a single "best AI coding tool" ranking is a category error — the right question is where the AI should run your work. The four execution models IDE assistants and agentic editors (Cursor, Windsurf, Copilot IDE features, CodeGeeX) stay close to your current edits. Feedback is immediate, and you stay in control of scope. The cost is that complex work still consumes your attention, and two overlapping AI editor subscriptions rarely make sense — run a two-week crossover pilot and keep one. Local terminal agents (Claude Code) read repositories, edit files, and run commands on your machine. This fits debugging, dependency migrations, and test loops. The security docs describe a read-only default with permission requests, and you should keep that default: start read-only, smallest directory, no broad allowlists for network, deletion, or deployment commands. Cloud coding agents (GitHub Copilot cloud agent) work in an ephemeral Actions-powered environment and come back with commits or a pull request. Good for bounded issues, tests, and docs. Budget is not just the seat — AI credits and Actions minutes are separate. Hosted application environments (Replit Agent) go from natural language to a running prototype in the browser. Great for education and proof-of-concept. Test git import/export, database migration, and code export before you depend on it. Quick decision table Primary workflow Evaluate first Main risk Frequent coding inside one AI editor Cursor Editor migration; broad changes still need review Cr
AI 资讯
The Case of the Lying Clock: 5 Vue Mysteries Solved
Every detective has their cold cases. These are mine — five Vue concepts that confused me until I investigated them properly. Grab your magnifying glass. Case #1: The Lying Clock Imagine you set an alarm to go off every 60 seconds. You press start at 10:00:00. First alarm: 10:01:00 — perfect Second alarm: 10:02:00 — still good But your phone is also doing other things: checking email, refreshing weather, running background tasks. Sometimes it fires the alarm a tiny bit late. Third alarm: 10:03:01 (1 second late) Fourth alarm: 10:04:02 (2 seconds off now) Five hours later: your alarm fires at 15:05:12 when it should fire at 15:05:00 That gap growing bigger over time — that's drift . The timer slowly slides away from where it should be. Why Does This Happen? JavaScript runs on a single thread — it can only do one thing at a time. When a timer is supposed to fire, the browser puts it in a queue. But if the thread is busy doing something else, the timer waits. The MDN documentation for setTimeout lists several reasons timers fire late: Nested timeouts are throttled to a minimum of 4ms after 5 levels of nesting (per the HTML5 spec ) Background tabs are throttled to a maximum of once per second ( MDN : "timeouts are throttled to firing no more often than once per second (1000 ms) in inactive tabs") Chrome 88+ introduced intensive throttling for hidden pages: timers that have been hidden for more than 5 minutes are checked only once per minute Tracking scripts in Firefox get even more aggressive throttling: 10 second minimum in background tabs Does This Happen on New Devices Too? Yes, but less. Modern devices are faster, so the delay per tick is smaller — maybe 1-2 milliseconds instead of 10-20. But over hours, even 1ms per tick adds up. And background tab throttling happens on every device, no matter how fast — it's a browser policy, not a hardware limitation. Is This Common Knowledge? It's the kind of thing you learn when your boss says "why does the clock on our dashboa
产品设计
Font Preview Is a Classification Problem, Not a Beauty Contest
An Arabic type preview becomes more useful when it helps a designer classify intent. “Which one looks best?” is too vague. The better question is whether the phrase needs readability, geometry, ceremony, ornament, handwriting energy, or poetic flow. Six familiar script directions make that distinction visible: Naskh, Kufic, Thuluth, Diwani, Ruq'ah, and Nastaliq. They should not be treated as interchangeable decorations. Each changes the apparent density, rhythm, and purpose of the same phrase. Define the intent before rendering A preview UI can ask for a short design intent alongside the text: type PreviewIntent = | ' readable ' | ' structural ' | ' ceremonial ' | ' ornamental ' | ' informal ' | ' poetic ' The mapping is not a legal or historical verdict, but it is a practical starting point. Naskh commonly supports readable, balanced text. Kufic emphasizes geometry and strong outlines. Thuluth benefits from display scale and ceremonial space. Diwani creates dense, flowing ornament. Ruq'ah feels direct and handwritten. Nastaliq's descending rhythm is especially relevant to Persian and Urdu presentation. Preview the real phrase Specimen text hides problems. A designer should render the actual name, quotation, or headline because letter combinations alter width, joins, baseline rhythm, and negative space. The same style can feel excellent for a short name and crowded for a longer sentence. The comparison surface should keep content constant while changing one variable at a time. That makes differences attributable to the font direction rather than color, size, or wording. Respect right-to-left layout Font selection and layout cannot be separated. A preview needs explicit RTL direction, sensible alignment, and enough room for vertical and descending forms. Nastaliq in particular may need more line height than a compact Latin-oriented component assumes. .preview { direction : rtl ; text-align : right ; overflow : visible ; } This looks elementary, but many design tools
AI 资讯
Designing Puzzle Hints Around Blockers, Not Tap Sequences
A weak puzzle walkthrough records every input. A stronger one explains why the board refuses to move. That distinction matters in traffic-sorting puzzles, where a correct tap can still be useless if a garage exit, crossing lane, or temporary holding space remains blocked. I used Car Sort level 13 as a small case study for a better hint model. The useful unit is not “tap car number seven.” It is a dependency: this vehicle cannot leave until that lane opens; that lane cannot open until a matching garage accepts its front car. Model the board as dependencies The visible board can be represented as a directed graph. Cars and blockers are nodes. An edge from A to B means A must move before B becomes actionable. The graph does not need to reproduce the game engine. It only needs to describe the decisions a player can verify on screen. type MoveNode = { id : string color : string blockedBy : string [] releases : string [] checkpoint : string } This structure makes a hint resilient. If a player has already cleared one harmless car, the guide can still say, “restore the center exit, then release the stack behind it.” A memorized tap list often becomes useless as soon as the board differs by one move. Separate release moves from cleanup moves Puzzle solvers tend to treat every successful departure as equal. They are not equal. A release move changes the dependency graph by opening a lane or exposing a buried color. A cleanup move removes a car that was already free. Good guidance labels those roles explicitly. The player should know whether the current move creates new options or merely reduces clutter. That is especially useful on compact boards, where an attractive matching car may tempt the player even though it does not improve the central bottleneck. The reserved route for this analysis is documented as Car Sort puzzle help . The value of that page is its focus on visible blockers and release points rather than an unexplained command stream. Add visual checkpoints After
AI 资讯
SPF, DKIM, and DMARC together — why the missing DMARC record was blocking registration emails
Background Registration confirmation emails were not reliably reaching users on Gmail and Outlook outside Japan — sometimes landing in spam, sometimes not arriving at all. Investigation pointed to a single root cause: the wpmm.jp domain had SPF and DKIM configured, but no DMARC record . What each of the three does SPF (Sender Policy Framework) declares in DNS which IP addresses are authorized to send mail for a domain. Receiving servers check the sending IP against the SPF record to confirm the source is legitimate. DKIM (DomainKeys Identified Mail) adds a cryptographic signature to the message headers and body. The receiving server looks up the public key in DNS and verifies that the message has not been tampered with and was signed by a party controlling that domain. DMARC (Domain-based Message Authentication, Reporting and Conformance) sits above both. It tells receiving servers what to do when SPF and DKIM alignment fails, and it collects aggregate reports about how mail from the domain is being treated. The key point is that SPF and DKIM are independent checks. Without DMARC, there is no single authoritative statement about how the alignment result should influence delivery decisions. Major providers including Gmail weigh the absence of DMARC when scoring incoming mail. Adding the DMARC record The following TXT record was added to the wpmm.jp DNS: _dmarc.wpmm.jp TXT "v=DMARC1; p=none; rua=mailto:info@wpmm.jp" p=none means "collect data, but do not reject or quarantine mail that fails alignment." Starting with p=reject or p=quarantine risks blocking legitimate mail if DKIM alignment turns out to be misconfigured somewhere. The safe approach is to start with p=none , monitor the reports, and tighten the policy gradually. rua=mailto:info@wpmm.jp sets the destination for aggregate reports. Google and other receivers periodically send XML summaries showing which mail passed or failed SPF/DKIM alignment. This moves visibility from passive (you notice when users compl