今日已更新 113 条资讯 | 累计 37664 条内容
关于我们

标签:#ev

找到 5139 篇相关文章

AI 资讯

How to Compress a GIF Without Losing Quality (2026 Guide)

Let's be honest about why you're here. You have a 4MB animated GIF that's slowing down a product page, bouncing back from an email attachment limit, or getting rejected by an ecommerce backend that caps images at 2MB. Or maybe a client sent you a loop that's 15MB and you need it under 1MB for a Slack header. The good news: you can usually cut a GIF's file size by 70–90% without anyone noticing the difference. The bad news? You have to stop thinking about GIFs as images and start thinking about them as video. Here's the practical guide to compressing GIFs in 2026, using only free browser-based tools. No uploads to shady servers, no software installs, just math and smart tradeoffs. Why GIFs get so big (and why your 4MB file is normal) GIF is a 1987 format. It was designed for simple graphics on dial-up internet, not for 4K animated logos. To understand why it bloats, you need one mental model: A GIF is a video pretending to be an image. Here's what happens under the hood: Limited palette: A GIF can only store 256 colors per frame. That's 8-bit color. Your screen displays millions of colors, so the GIF has to approximate. The real problem is how it stores those colors. Frame-by-frame storage: Unlike MP4, which stores only the changes between frames, a GIF stores every single frame as a full image . A 100-frame animation at 800x600px is 100 full-size images stacked on top of each other. Uncompressed data: GIF uses LZW compression, which is weak by modern standards. It works well on flat colors but fails on gradients, noise, or photographic content. A 10-second screen recording with a subtle gradient? That's a 20MB GIF waiting to happen. The math: A 500x500px, 30fps, 3-second GIF has 90 frames. Each frame is roughly 500x500x3 bytes (RGB) = 750KB raw. Before compression, that's 67.5MB of raw data. LZW might get it down to 4–8MB. That's why your file is huge. It's not a bug; it's the format being honest about its limitations. The three real levers to shrink a GIF You can't

2026-08-18 原文 →
AI 资讯

AI Observability Explained: What It Is and How It Works

Traditional monitoring rests on one quiet assumption that nobody ever writes down: the same input gives you the same output. Something breaks, you replay the request, you watch it break again, you fix it. Now send the same request to a model twice. You get two different answers, and neither one of them threw an error. AI observability is the practice of recording what happened inside an AI system on every request: the prompt, the model version, tokens, cost, latency, tool calls, and a judgement of whether the output was any good. Monitoring tells you the service is up. Observability tells you why it answered that way. That gap is the whole story here. Why your current monitoring stack misses all of this Your existing setup is watching for crashes. Status codes, error rates, p99 latency, memory. All of it is designed around the idea that a broken thing looks broken. An AI feature failing looks nothing like that. It returns HTTP 200 in 900ms, with grammatically perfect prose that happens to be wrong, or that quietly ignored the document you retrieved for it, or that called the refund tool when the user only asked a question. Your dashboard sees a healthy service, because by every measure it has, the service is healthy. And there are whole categories of failure your stack has no field for. It has nowhere to put "this response cost 14 cents", or "the model version changed under us last Tuesday", or "the retrieved context was garbage". Those are not infrastructure facts, and standard telemetry was never built to carry them. Something has to hold those fields instead, which is the entire reason this tooling exists. My team uses Bifrost , so I will use it as the example throughout this post. It's an open-source AI gateway from Maxim, so anything I claim about what it records per request is something you can go check line by line. Most tools here put their telemetry story on a marketing page and stop there. What one AI request actually looks like when you trace it This is t

2026-08-18 原文 →
AI 资讯

[Technical Discussion] IPC Message Queue Tuning for WLOADCTL on Linux

WLOADCTL is built as a distributed scheduling platform composed of multiple cooperating processes. Communication between different nodes, such as: Server ↔ Agent Server ↔ Client is handled through TCP/IP socket communication. However, communication between components on the same node relies heavily on Linux Inter-Process Communication (IPC) mechanisms, including: Message Queues Shared Memory Semaphores In some environments, the default Linux IPC configuration may not be sufficient for high-volume scheduling workloads. When this happens, WLOADCTL may encounter message queue-related errors or communication bottlenecks. This article explains how to: Check current IPC limits Increase message queue capacity Inspect IPC resource usage Remove unused IPC resources Understanding Current IPC Limits Before making any changes, it is important to inspect the current IPC configuration. Use: ipcs -l This command displays the system-wide limits for IPC resources, including: Maximum number of semaphore sets Maximum number of semaphores Maximum message queue size Maximum shared memory limits Pay special attention to the Message Limits section. Example: ------ Messages Limits -------- max queues system wide max size of message (bytes) default max size of queue (bytes) If the value of: default max size of queue (bytes) is around: 16384 the queue capacity may be too small for larger scheduling environments. Increasing Message Queue Capacity If the current limits are low, we recommend adjusting the Linux kernel IPC parameters. As the root user, edit: /etc/sysctl.conf and add the following settings: kernel.msgmni=1600 kernel.msgmax=8192 kernel.msgmnb=1638400 Parameter descriptions: Parameter Description Typical Default Recommended msgmni Maximum number of message queues 16 1600 msgmax Maximum size of a single message (bytes) 8192 8192 msgmnb Maximum capacity of a message queue (bytes) 16384 1638400 In WLOADCTL, a typical internal message is approximately: 512 bytes After modifying the con

2026-08-18 原文 →
AI 资讯

TypeScript 6.0 Strict Function Types: Why Contravariance Breaks Your Existing Callbacks

TypeScript 6.0 Strict Function Types: Why Contravariance Breaks Your Existing Callbacks This article was written with the assistance of AI, under human supervision and review. Most TypeScript migration failures stem from a single misunderstood compiler flag: strictFunctionTypes . The pattern that breaks production is deceptively simple—a callback that accepts a base type where the consumer expects a derived type. TypeScript 6.0 enables strict mode by default, which means codebases that never configured contravariance checking will fail to compile overnight. The failure mode here is subtle but expensive. A callback registered to an array method expects Animal , but the implementation passes Dog . Pre-6.0 TypeScript allowed this through bivariant parameter checking. Post-6.0, the compiler rejects it as unsafe. Teams scramble to fix hundreds of type errors without understanding the underlying variance rules, often choosing any or incorrect casts that introduce runtime bugs. The distinction between function properties and method signatures becomes critical—one enforces contravariance, the other permits bivariance for historical reasons. %% alt: Bivariant checking allows derived types where base types are expected The correct approach requires understanding contravariance: function parameters must accept types that are the same or less specific than what the function signature declares. When strictFunctionTypes activates, TypeScript enforces this rule for function properties but not method signatures. The solution is not to weaken types with any , but to restructure callbacks using proper variance-aware patterns or switch to method syntax where bivariance is intentional. %% alt: Contravariant checking enforces parameter safety at compile time This matters because the TypeScript 6.0 ecosystem assumes strict mode. Third-party libraries ship types built for contravariance. Disabling strictFunctionTypes to silence errors creates a type system that diverges from reality, wher

2026-08-18 原文 →
AI 资讯

Five AI coding tools, five completely different ways to break

I've now routed five different AI coding tools through a proxy layer. Each one broke differently. None of them told me why. Writing this partly as a reference for myself, partly because the failure modes turn out to be genuinely interesting — they say a lot about how these tools are built. Claude Code: reads config once, then never again The simplest of the five. Config lives in ~/.claude/settings.json , two keys get modified: env.ANTHROPIC_BASE_URL env.ANTHROPIC_AUTH_TOKEN The failure mode: it reads that file exactly once, at startup. Change it while a session is running and nothing happens. No warning, no reload. This is the single most common "the switch is on but nothing works" report, across every tool. Close all windows, open a fresh one. One thing I appreciate: it only touches those two keys, backs up the original, and restores it exactly when you flip the switch off. Codex: doesn't read the model from your request This one is architecturally weird and cost me an hour. Every other tool specifies which model it wants in the request. Codex doesn't. It picks from its own internal model catalog. Consequence: if you don't explicitly select a model, it sits on a default internal GPT model that the market can't serve. And you don't get "please select a model" — you get a string of failures with no stated cause. The config it writes: ~/.codex/config.toml → model_provider, [model_providers.asale], model, model_catalog_json ~/.codex/auth.json → OPENAI_API_KEY Note model_catalog_json . That's the part that makes your selection show up in the app's model menu. And the desktop app reads that catalog at startup , so a model written while it's running won't appear until you restart. Two separate restart requirements stacked on each other. Credit where due: it preserves your existing comments and formatting in config.toml . Not every tool does. Gemini CLI: loses to your own shell config Config goes into ~/.gemini/.env . Two keys added, nothing else touched. The failure mode

2026-08-18 原文 →
AI 资讯

Building a Client-Side Zodiac Calculator: When "Just Use an API" Isn't the Answer

I recently found myself in one of those classic developer rabbit holes. A friend asked me if I knew their Chinese zodiac sign, and instead of just Googling it like a normal person, I thought: "I could build a tool for this." Because apparently I enjoy reinventing wheels. The twist? I wanted it to work entirely in the browser. No API calls, no server, no database. Just a date input and some JavaScript logic. The challenge was figuring out how to accurately compute Chinese zodiac signs, the Chinese lunar calendar year, and the traditional Ganzhi (干支) system without pulling in a massive calendar library. The Problem with Existing Solutions My first instinct was to search for an API. There are plenty of Chinese calendar APIs out there, but they all had issues: Most require API keys and rate limiting Many are Chinese-language only, which is fine for me but not great for a broader audience They're overkill for what should be a simple calculation Some have questionable accuracy for historical dates I also looked at JavaScript libraries like lunar-javascript and chinese-calendar . They're comprehensive, but they're also huge. For a simple "what's my zodiac sign" tool, pulling in a 100KB+ library felt like using a flamethrower to light a candle. The Math Behind the Madness Here's what I discovered: the Chinese zodiac and Ganzhi calculations are surprisingly straightforward if you understand the underlying math. The Zodiac: Simple Modulo Arithmetic The 12 Chinese zodiac animals follow a cycle that aligns with the 12-year Jupiter cycle. The calculation is embarrassingly simple: const ZODIAC = [ ' 鼠 ' , ' 牛 ' , ' 虎 ' , ' 兔 ' , ' 龙 ' , ' 蛇 ' , ' 马 ' , ' 羊 ' , ' 猴 ' , ' 鸡 ' , ' 狗 ' , ' 猪 ' ]; const zodiac = ZODIAC [( year - 4 ) % 12 ]; That's it. The year 4 AD was the first year of the Rat, so everything since then follows a simple modulo pattern. The Ganzhi System: Two Interlocking Cycles The Ganzhi (干支) system combines the 10 Heavenly Stems (天干) with the 12 Earthly Branches (地支

2026-08-18 原文 →
开发者

🚀 30 React.js Interview Questions You Should Know Before Your Next Frontend Interview ⚛️

30 React.js Interview Questions You Should Know Before Your Next Frontend Interview ⚛️ Whether you're preparing for a frontend interview or simply want to brush up on your React.js knowledge , this guide covers 30 real-world, scenario-based React interview questions that interviewers frequently ask. The goal isn't just to memorize definitions. These questions are designed to help you understand how and when to apply React concepts in real-world applications . 📌 Bookmark this article and come back to it during your next interview preparation session. 📚 What We'll Cover In this guide, we'll explore questions around: Conditional rendering API calls and side effects Form validation Performance optimization State management Component re-rendering Keys and lists Dark mode Dynamic components useEffect vs useLayoutEffect Large-list optimization And much more... 1. How do you handle conditional rendering in React? Conditional rendering allows you to render different UI based on application state or conditions. You can use standard JavaScript techniques such as: if...else Ternary operators Logical && Example { isLoggedIn ? < Dashboard /> : < Login />} 💡 Interview Tip For simple conditions, a ternary operator or && is usually sufficient. For more complex conditions, consider moving the logic outside the JSX to keep the component readable. 2. You need to fetch API data when a component mounts. What's the best way to do it? 💡 Key Concept The typical approach is to perform the API request inside a useEffect hook when the component needs to fetch data after rendering. A common pattern is: useEffect (() => { // Fetch API data }, []); The empty dependency array indicates that the effect is intended to run after the initial render. Note: In modern React applications, the best approach can also depend on the framework or data-fetching library you're using. 3. How would you handle form validation in React? A common approach is to use controlled inputs and perform validation during even

2026-08-18 原文 →
AI 资讯

🤖 AI agents are becoming “digital employees”

SpaceXAI recently introduced Grok Bot, an always-on AI-agent service designed to work more like an autonomous teammate. The agents have their own cloud computer environment and can log into applications, websites and tools to perform multi-step tasks. They can also operate in parallel and coordinate with other agents. The product is entering a market that already includes competing agentic workplace products from OpenAI, Anthropic and Microsoft. Traditional chatbot: User ↓ Question ↓ LLM ↓ Answer And Now Agent: Goal ↓ LLM ↓ Plan ↓ Tool ↓ Observe ↓ Reason ↓ Tool ↓ Validate ↓ Continue ↓ Result * But there's a major problem : * Giving an AI agent access to: Email Slack GitHub CRM Cloud Browser Databases Internal documents creates a huge identity and security problem. An agent with permission to send an email or modify production infrastructure effectively becomes another privileged identity. About the Author -> I am Ashutosh Maurya , a Senior Full-Stack Developer ** with 6+ years of experience in high-performance UI development and the MERN stack. I specialize in building scalable architectures like Schooliko and **AI-integrated platforms . My goal is to bridge the gap between complex backend logic and seamless frontend experiences.

2026-08-18 原文 →
AI 资讯

Docker Compose Isn't What I Thought It Was

post 7: A practical guide to understanding Docker Compose—what it is, how it works, and the misconceptions that catch most beginners. You've mastered single containers. Now it's time to build a real application. A frontend. A backend. A database. A Redis cache. Suddenly you're juggling multiple docker run commands. Ports. Networks. Volumes. Environment variables. Chaos. Then someone says: "Just use Docker Compose." It works beautifully. But here's the twist most people never realize… Why Docker Compose Exists Imagine starting an application like this: Frontend Backend PostgreSQL Redis Running each container manually quickly becomes repetitive and error-prone. Docker Compose lets you describe your entire application in a single YAML file and start everything with one command. Instead of remembering dozens of commands, you define your infrastructure once. What Docker Compose Actually Is Docker Compose is not a container orchestrator . Docker Compose is a tool that reads your Compose YAML file and uses the Docker Engine to create and manage the resources defined in it.” Modern Docker uses Compose V2 , which runs as: docker compose instead of the older: docker-compose Compose runs only when you execute a command. It creates the required Docker resources, starts the containers, and then exits. This makes it ideal for development, testing, and single-host deployments , but it doesn't provide orchestration features like automatic scheduling, self-healing, or multi-node management. A Simple docker-compose.yml services : web : build : . ports : - " 8080:80" environment : - DB_HOST=db depends_on : - db db : image : postgres:15 volumes : - postgres_data:/var/lib/postgresql/data redis : image : redis:alpine volumes : postgres_data : YAML Quick Reference Key Purpose services Defines containers (web, db, redis) build Builds an image from a Dockerfile image Uses an existing image from a registry ports Maps host ports to container ports environment Sets environment variables depend

2026-08-18 原文 →
AI 资讯

How to Turn Latitude and Longitude into an Address with JavaScript

Sometimes you have GPS coordinates like: 40.7128, -74.0060 But coordinates alone are not very useful to most users. They usually want to know something much simpler: What place is this? The process of converting latitude and longitude into a human-readable address is called reverse geocoding . In this article, we'll build a simple reverse geocoding example with JavaScript. What Is Reverse Geocoding? Normal geocoding converts an address into coordinates: New York, NY ↓ 40.7128, -74.0060 Reverse geocoding does the opposite: 40.7128, -74.0060 ↓ New York, NY, United States This is useful for location tools, GPS applications, travel websites, delivery systems, photo location tools, and map interfaces. Reverse Geocoding with JavaScript For a simple example, we can use the OpenStreetMap Nominatim reverse geocoding endpoint. async function reverseGeocode ( lat , lon ) { const url = `https://nominatim.openstreetmap.org/reverse` + `?lat= ${ lat } &lon= ${ lon } &format=jsonv2` ; const response = await fetch ( url ); if ( ! response . ok ) { throw new Error ( " Reverse geocoding failed " ); } const data = await response . json (); return data ; } reverseGeocode ( 40.7128 , - 74.0060 ) . then ( data => { console . log ( data . display_name ); }) . catch ( error => { console . error ( error ); }); The returned data usually contains a readable location name together with structured address information. Display the Address on a Page We can turn the example into a small browser tool. <input id= "lat" placeholder= "Latitude" > <input id= "lon" placeholder= "Longitude" > <button onclick= "findAddress()" > Find Address </button> <p id= "result" ></p> <script> async function findAddress () { const lat = document . getElementById ( " lat " ). value ; const lon = document . getElementById ( " lon " ). value ; const result = document . getElementById ( " result " ); try { const url = `https://nominatim.openstreetmap.org/reverse` + `?lat= ${ lat } &lon= ${ lon } &format=jsonv2` ; const res

2026-08-18 原文 →
AI 资讯

A Security Fix Should Show Where the Attack Stopped

The concrete problem A security pull request can be green for the wrong reason. Unit tests may pass, the vulnerable endpoint may return a different status code, and a scanner may stop reporting the original finding. None of those results necessarily shows that the attacker lost the capability that mattered. The same identity might reach the sensitive action through another route, inherit a broader token, or trigger an equivalent workflow with slightly different input. This becomes especially uncomfortable when an automated tool proposes or reviews the fix. A plausible patch explanation is not behavioral evidence. The reviewer still needs to know which identity was used, which preconditions were established, which requests ran, where privilege was gained before the fix, and at which exact step the patched build denied it. Without that trace, “fixed” is partly an assertion about code rather than an observation of the attack path. The current signal On August 17, Wiz described a GitHub Actions script-injection flaw in a Snowflake repository. The vulnerable workflow change reached production on June 18 and Wiz reported exploiting it on June 23. The final squash commit credited Copilot Autofix as a co-author, while AI-assisted review did not flag the injection. Wiz later clarified that it could not determine whether the code change itself was AI-generated. That distinction matters: the lesson is about assurance around AI-assisted workflows, not proof that a model wrote the bug. The Hacker News discussion was active when RayTally captured it at 2026-08-18 00:33 UTC: 306 points, 123 comments, and rank 5. Those are historical attention numbers, not market validation. The useful engineering signal is narrower. Teams now have a concrete incident in which an apparently protective condition and an escaping routine still produced a reachable credential-exfiltration path. Bright STAR and StackHawk show that dynamic testing in CI is already real. Bright documents building and star

2026-08-18 原文 →
AI 资讯

7 MCP Tool-Schema Mistakes That Make AI Agents Less Reliable

AI agents can only use tools as reliably as those tools are described. That’s why I built ToolReady AI —a free tool that reviews MCP and AI-agent tool schemas, identifies reliability problems, and recommends specific fixes. A function might work perfectly when a developer calls it directly, yet still fail when an agent has to decide when to call it, which arguments to provide, and what values are safe. In many cases, the problem is not the underlying API. It is the tool schema placed between the API and the model. Here are seven issues worth checking before releasing an MCP or AI-agent tool. A description that is too vague Descriptions such as "Searches documents" do not give an agent enough routing context. The description should identify the supported content, expected result, important limits, and a clear use case. Better: «Search indexed support documents and return the most relevant text excerpts. Use this when answering questions about product setup or troubleshooting. Do not use it for account-specific or real-time billing information.» No boundary conditions A useful description should also explain when the tool should not be used. Exclusions help an agent distinguish similar tools and avoid calls that cannot succeed. Examples include: Do not use for personal account data. Do not use when the user requests current inventory. Do not use for destructive actions without confirmation. Undocumented inputs An input name such as "query", "id", or "limit" may seem obvious to its author, but the agent still has to guess the required meaning and format. Each property should explain: What the value represents The expected format A realistic example Any important constraints Missing required fields If the schema does not identify the minimum necessary inputs as required, an agent may send an empty or incomplete call that cannot produce a useful result. For example: { "type": "object", "properties": { "query": { "type": "string", "description": "Natural-language search q

2026-08-18 原文 →
AI 资讯

We Tested 4 Text-to-Speech Engines on 12,000 Live Healthcare Calls — Here's Which One Patients Actually Trust

Last quarter, we ran our production voice AI receptionist — Loquent — across four different TTS engines simultaneously, split-testing real patient calls at dental and healthcare clinics. The results surprised us: the most "natural sounding" engine in demos performed the worst with actual patients. Why We Ran This Test At Autor, we've been running Loquent in production for over a year now. It handles thousands of automated calls per month for healthcare and dental clinics across Canada — booking appointments, answering insurance questions, handling after-hours triage. The voice is the product. If patients don't trust the voice, they hang up, and the clinic loses a booking. When we first built Loquent, we picked our TTS engine the way most teams do: we generated a few sample clips, played them for ourselves, and went with the one that sounded best in a quiet office. That worked fine until we started digging into our call analytics and noticed something weird. Our completion rate — the percentage of calls where patients actually finished the full interaction instead of hanging up or asking for a human — was hovering around 74%. Good, but not great. We suspected the voice itself was part of the problem. So we designed a proper A/B test. Not a demo comparison. A production comparison on live calls. The Setup We tested four TTS engines across 12,247 calls over 8 weeks. Each engine handled roughly equal volume, randomly assigned at call start. All other variables stayed constant: same prompts, same Anthropic Claude backbone for conversation, same Twilio infrastructure, same clinics. The four engines: Engine A : ElevenLabs (Turbo v2.5) — our existing production engine Engine B : OpenAI TTS (tts-1-hd) — the model most teams default to Engine C : Deepgram Aura — optimized for real-time, low-latency use cases Engine D : A newer entrant we'd been evaluating (under NDA, so I can't name it) We measured five things: Completion rate — did the patient finish the full call flow? Time

2026-08-18 原文 →
AI 资讯

Building Fault-Tolerant, Event-Driven Kafka Pipelines in Go: Reliable Reprocessing & Dead Letter Queues

A practical guide to building reliable event-driven systems in Go using Apache Kafka. Learn how to implement tiered retry strategies with delayed reprocessing, route permanently failed messages to dead letter queues in Golang with Sarama. Prerequisites What do you need to follow along? Working knowledge of Golang. Go & Docker installed on your PC. What is an Event-Driven Architecture? An Event-Driven Architecture (EDA) is a design approach where services communicate by producing and responding to events. Each service operates independently, producing or reacting to events as they happen. What are Events? An event is a record of something that has happened in a system, typically representing a state change or a significant action. An event contains data (payload) describing what happened. An example of an event could be: A user signing up for a service. A user placing an order in your system. Components of an Event-Driven Architecture To understand how events flow through a system, we need to know three key players: Event Producers : They are the sources of events. They generate and publish events like signup events, order placed events, etc. Producers generate events and transmit them to the rest of the system. They do not know who is listening for or handling the events. Event Brokers : They sit between producers and consumers, decoupling them so neither needs a direct connection to the other. Brokers receive event messages, maintain their chronological order, make them available for consumption, and route them to the right consumers. Apache Kafka is an example of an event broker, and it's the one we'll use throughout this guide. Event Consumers : They handle the processing tasks. They listen on event channels and react when an event they are subscribed to is published, then they process the event, which can include making API calls, updating a database, triggering other events, or logging information. The Complete Flow With those three pieces in place, the flow of

2026-08-18 原文 →
AI 资讯

Your backup is not a backup until you have restored it

This is an English write-up of a post from my Japanese dev diary. Original: https://saas-diary.com/tech-log/backup-restore-drill-automation/ For over a year, my backup job has reported success every single night. Green check, every day, no exceptions. Then I asked myself one question and went cold: "How many times have I actually restored from it?" Zero. Not once. "It was backed up" and "it can be restored" are different states My setup has two paths. One mirrors all source to a private repo. The other packs the things I can never recreate — notes, config, and Android signing keys — into an encrypted bundle and ships it to a private channel every night. Both were green every day. But green only proved the upload finished . It never proved the contents were right, or that the archive could even be opened. Within one month, I had two failures that stayed green the whole time. Failure 1. The collector for signing keys used three hardcoded paths. I kept shipping new apps, so the number of keys kept growing — but the collector didn't. By the time I noticed, 7 of 10 keys were missing from the backup . Five of those apps were live on the store. If my machine had died, I could never have shipped an update for them again. The backup reported success every night through all of it. Failure 2. The mirror push failed 7 days in a row (a large binary hit the host's file-size limit). But the script printed "✅ done" and returned exit code 0 even when one half failed. A failure that isn't visible isn't a failure — it's a time bomb. So I automated a restore drill Once a month, a job now does this: Rebuild the encrypted bundle (without shipping it) Actually decrypt it with the stored passphrase Extract it and count what's inside Check the mirror is not stalled (latest commit timestamp via API) Delete the scratch folder and the generated bundle The encryption is openssl-compatible AES-256-CBC with PBKDF2 (SHA-256, 100k iterations). I deliberately avoided depending on the openssl binary,

2026-08-18 原文 →