AI 资讯
A Practical Guide to Converting Inches, Centimeters, Meters, Feet and Millimeters
If you work with measurements often enough, you eventually run into the same problem: the value you have isn't in the unit you need. A product specification might be in inches. A construction drawing might use feet. A European supplier might give you dimensions in centimeters or millimeters. The actual formulas are usually simple. Finding the right conversion, avoiding rounding mistakes, and checking a large list of values can be more annoying than the math itself. Here are the conversions I use most often and a few practical ways to work with them. Inches to centimeters The basic relationship is: 1 inch = 2.54 centimeters So the formula is: centimeters = inches × 2.54 For example: 10 inches × 2.54 = 25.4 cm This is probably the most common conversion when moving between imperial and metric measurements. If you just need to check a value quickly, Pulgadas a CM has an interactive converter along with a conversion table and frequently asked questions. Centimeters to inches Going in the opposite direction means dividing by 2.54: inches = centimeters ÷ 2.54 For example: 25.4 cm ÷ 2.54 = 10 inches You can use the CM a Pulgadas converter when you need to work in this direction. This is particularly useful when a measurement is provided in centimeters but the product, tool, or specification you're working with uses inches. Meters to inches Meters are larger units, so the conversion factor is correspondingly larger. One meter contains approximately: 39.3700787 inches Therefore: inches = meters × 39.3700787 For example: 2 meters ≈ 78.7401574 inches For a quick calculation, you can use the Metros a Pulgadas converter . This conversion can come up when working with room dimensions, furniture measurements, fabric, sports equipment, or other products where metric and imperial specifications are mixed. Inches to meters The reverse calculation is: meters = inches × 0.0254 For example: 100 inches × 0.0254 = 2.54 meters The Pulgadas a Metros converter is useful when an imperial meas
AI 资讯
I Kept Hearing "Didn't We Already Send That?" So I Built a Tool to Fix It
I'm a self-taught developer. No CS degree, no funding, no team. Just me, a laptop, and a problem I kept watching people struggle with. The Problem Every freelancer and small agency I know deals with the same mess: client details scattered across WhatsApp chats, email threads, Google Drive folders, and random Notion pages. Nothing lives in one place. When a client asks "wait, didn't we already send you the logo files?" you're digging through three different apps trying to remember. I didn't just hear about this problem — I lived it. So four months ago, I started building Kray. What Kray Actually Does Kray gives freelancers and agencies one organized workspace per client — projects, links, and notes, all in a single place instead of scattered across five different tools. The part I'm most proud of: when you share a project with a client, they can open the link and see everything instantly — no sign-up, no account creation, no friction. Just a clean, simple view of what they need to see. The Stack Since I was building this entirely solo with zero budget, I leaned on tools that let me move fast without infrastructure headaches: React 19 + Vite + TypeScript (strict mode — no shortcuts) Tailwind v4 for styling Supabase for auth, database, and storage Deployed on Vercel No backend servers to manage. No DevOps to worry about. Just me shipping features. What I Learned Building Solo You will hit bugs that eat entire days. I spent hours debugging a sitemap indexing issue that turned out to be one missing header. That's the job — most of building isn't writing new features, it's fixing the thing that should've worked but didn't. Deploy discipline matters more than you think. I once tested a feature locally, assumed it was live, and spent 20 minutes confused about why production wasn't behaving — because I'd forgotten to push. Lesson learned: always verify what's actually deployed before debugging further. Marketing is its own skill, and it's humbling. I've spent the last severa
AI 资讯
Your firewall is your AI policy — I probed 18 major sites to read it
Everyone's arguing about AI search visibility. Almost nobody is measuring the boring part: whether AI crawlers can fetch your pages at all . So I built a small open-source tool — geo-crawl-audit — that probes any site with the user-agents of every AI crawler that matters (GPTBot, OAI-SearchBot, ClaudeBot, PerplexityBot, ChatGPT-User, and friends), measures how each is treated versus a normal browser, and checks the thing most people never think about: how many words exist in the raw HTML before any JavaScript runs . Because here's the detail the industry keeps missing — GPTBot, ClaudeBot, and PerplexityBot don't execute JavaScript. For most sites, Googlebot (feeding Gemini) and Applebot are the only AI-adjacent crawlers that render it. A site can rank #1 in Google and be a blank page to nearly everything else. I pointed it at 18 major sites on August 7. Five findings worth your time. 1. Access patterns line up with the business relationships The Guardian — which has a content deal with OpenAI — serves my simulated GPTBot, OAI-SearchBot, and ChatGPT-User a clean 200 . The same request wearing ClaudeBot, PerplexityBot, or CCBot : 403 , and those names are in its robots.txt disallow list too. Policy and enforcement agree. The New York Times — in litigation with OpenAI — 403s nearly everyone: GPTBot, OAI-SearchBot, ClaudeBot, PerplexityBot, Common Crawl, meta-externalagent. Two user-agents got through: bingbot and Amazonbot. I want to be careful about the claim here: a status code tells you who is blocked , not why . Any individual 403 has mundane explanations. But when the allow/deny matrix maps this cleanly onto public deals and public lawsuits, the firewall config has become a business document — and it's readable by anyone with a terminal. 2. robots.txt is a polite sign. Some doors are unlocked anyway. Reddit's robots.txt blocks every AI bot in my list — fourteen tokens, no exceptions. Enforcement tells a different story: my GPTBot UA got a 403 and ClaudeBot and CCB
AI 资讯
I Tried Building JavaScript Games Without a Game Engine. Here's What I Learned
I am a digital marketer, not a professional developer or game developer. Most of my career has been focused on SEO, growth marketing, paid acquisition, content, and digital strategy. When I started building GamesMom, however, I found myself learning much more about web development than I expected. GamesMom is a collection of free educational games and learning activities for kids that run directly in the browser. The site includes math games, word games, typing games, memory games, puzzle games, classroom games, quizzes, and other interactive activities. The idea was simple: make games that children can open and play without downloading an application or creating an account. I initially assumed that building browser games would require a dedicated game engine or a large JavaScript framework. After experimenting with different approaches, I found that many of the games I wanted to create could be built with ordinary HTML, CSS, and JavaScript. That was probably the most useful lesson I learned from the project. You don't always need a complicated technology stack to create an interactive web experience. I Started With the Simplest Approach When you're not a professional developer, it is tempting to look for the most sophisticated solution available. I did this too. I spent time looking at frameworks, game engines, libraries, and different ways of structuring interactive applications. Eventually I started asking a much simpler question: what does this particular game actually need? A basic educational game might need to display a question, accept an answer, update a score, show feedback, and move to the next question. Another might need a timer, a few buttons, and some randomization. Those requirements don't automatically justify a game engine. For simple browser games, the browser already provides a lot of what you need. HTML, CSS and JavaScript Can Go a Long Way The basic combination is surprisingly capable. HTML provides the structure of the page. CSS controls the v
AI 资讯
What Are Autonomous AI Agents? A Practical Guide for Developers
Most AI applications wait for a user to ask a question and then return an answer. Autonomous AI agents go further: they can interpret a goal , decide what steps are required, use external tools, evaluate the results, and continue working until the task is completed or human help is needed. For example, a chatbot can explain how to resolve a customer complaint. An AI agent can read the complaint, retrieve the customer's order, check company policy, prepare a response, update the support ticket, and request approval before issuing a refund. That ability to make decisions and take actions is what makes autonomous AI agents different from traditional chatbots and fixed automation. 1. What Is an Autonomous AI Agent? An autonomous AI agent is a software system that uses an AI model to pursue a goal with limited human intervention. It can understand instructions, create a plan, select tools, perform actions, observe the results, and adjust its approach when necessary. A typical agent can: Understand a high-level objective Break the objective into smaller tasks Choose which tools or APIs to use Retrieve relevant information Take actions in external systems Maintain context across multiple steps Evaluate whether each action succeeded Recover from some failures Stop, retry, or escalate to a human Autonomous does not mean completely independent or unrestricted. A well-designed agent operates inside defined permissions, policies, spending limits, approval rules, and stopping conditions. 2. How Autonomous AI Agents Work Most autonomous agents follow a continuous decision loop: Receive Goal ↓ Observe Context ↓ Create or Update Plan ↓ Choose a Tool ↓ Perform an Action ↓ Evaluate the Result ↓ Continue, Retry, Stop, or Escalate Suppose a user gives an agent this goal: Find three suitable meeting times with the product team next week and send invitations after I approve one. The agent may: Identify the required participants. Retrieve their calendar availability. Check working hours a
AI 资讯
Biryani CSS Art — India's Soul in Every Grain 🍛
This is a submission for Frontend Challenge - Comfort Food Edition, CSS Art . Inspiration I chose to build a classic Dum Biryani — the ultimate comfort food! 🍛 There is nothing quite like opening a steaming handi of biryani and seeing the rich, saffron-colored rice dotted with fried onions, mint, and spices. It's a dish that brings people together and feels like a warm hug, making it the perfect inspiration for the Comfort Food challenge. Demo Here is my CSS Art representation of a traditional Biryani Handi! I built this primarily using vanilla CSS to create the realistic clay texture of the pot, the individual grains of rice, the steam animations, and the garnishes. I added a tiny bit of JavaScript just for a subtle mouse-parallax tilt effect and a saffron sparkle when you click the pot. https://github.com/pandeynitish23/dev_css_chalange/ https://dev-css-chalange.nitishkumar-nk-np.workers.dev/ Journey Building this was a really fun exercise in CSS gradients and positioning! What I'm most proud of: The Clay Handi: I used layered radial and linear gradients along with inset box shadows to give the pot a realistic, 3D clay texture with lighting highlights. The Rice & Garnishes: Creating individual rice grains, mint leaves, and onion crisps using CSS border-radius and positioning was tedious but incredibly rewarding when it all came together. The Atmosphere: Adding animated steam and floating background spice particles helped bring the scene to life and make it feel hot and fresh. It was a great challenge keeping the JavaScript minimal and relying on pure CSS for the heavy lifting of the art itself!
AI 资讯
Your AI agent's UI is mediocre—and here's how to fix it
If you’ve been building with Claude or Cursor for the last year, you’ve noticed a pattern. The code comes out clean. The logic is sound. But the interfaces? They look like 2015-era Bootstrap clones. Everything has the same rounded corners, arbitrary shadows that don't communicate depth, and linear animations that feel robotic rather than organic. AI agents are incredible at generating functional HTML and CSS, but they lack a fundamental concept: design intent. They can write the code to make a button blue, but they struggle to understand why that button needs a specific spring-based scale effect when pressed, or how its elevation should change relative to the background surface. They produce 'zombie' interfaces—functional, but lifeless and fundamentally broken for high-end production use. This isn't just an aesthetic problem; it’s a technical one involving accessibility, usability, and user agency. I recently started using something called the UI/UX Excellence Prover via Vinkius to close this gap. It doesn't generate code—that's not its job. Instead, it acts as a design unit test for your agentic pipeline. You aren't asking it to 'make it look better'; you are asking it to validate that the generated component meets 2026-era standards across six specific pillars. The Death of Flat Decoration The first thing I noticed in most AI-generated layouts is what I call "flat decoration." Agents love using box-shadow as an ornament. They'll add a shadow to every card just because it looks 'modern.' But shadows aren't decorations; they are spatial communication tools. A properly engineered interface uses elevation (levels 0 through 5) to communicate hierarchy. Level 0 is your base surface. Level 3 might be a modal overlay that physically sits closer to the user in Z-space. If everything has a shadow, nothing has importance. When you run an agent's output through the Prover ( UI/UX Excellence Prover ), it flags these arbitrary shadows. It forces the agent to define elevation se
AI 资讯
I Deployed My Backend to Render… and Then Everything Broke 💀
I Deployed My Django App to Render… and Then Everything Broke 💀 Deploying an application sounds simple. Push the code. Configure the service. Deploy it. Done. Yeah… not exactly. 💀 I recently deployed one of my Django applications to Render, and the deployment itself looked successful. The service was live. Gunicorn started. Render gave me a live URL. But when I actually opened the application and started making requests… 500 Internal Server Errors. And that's where the real debugging started. 🚀 Deploying the Application to Render My application had a frontend and a Django backend. The basic flow looked like this: User ↓ Frontend ↓ Django Backend ↓ Database Everything was working correctly on my local machine. So I connected the repository to Render and configured the deployment. The build completed successfully, and the server started with Gunicorn. Render even showed the service as live. At this point, I thought: "Okay, we're done." I was very wrong. 😭 💥 The Actual Problem Started After Deployment Once the application was live, I started seeing requests returning: 500 Internal Server Error There were also other requests returning 400 errors. The important part was that the deployment itself wasn't necessarily failing. The application was running, but the application was failing when handling requests. That distinction was important. Instead of immediately changing random code, I went back to the Render logs. 🔍 The Render Logs Were the First Place I Looked The logs showed that Gunicorn was starting successfully: Gunicorn starting Listening for requests So the server process itself was alive. But then requests started showing errors like: GET ... 500 GET ... 500 GET ... 400 This made me realize something: A deployment being marked as "Live" doesn't mean every part of the application is working correctly. The next step was to find out why the requests were failing . 📁 Then I Found a Frontend Build Problem One of the warnings in the logs was: No directory at: /opt/rend
AI 资讯
Four false positives in one evening: telling a broken web app from a broken measurement
I spent an evening opening other companies' product configurators — 3D and parametric tools on manufacturers' sites — looking for things that were genuinely broken. Twenty-seven of them. The findings were real. But the part worth writing down is that four separate times in one evening, my tooling told me an application was broken when it was fine. Every one of those four passed automated checks that looked rigorous. What caught them was a screenshot. If you write scripts that judge pages you don't own — uptime checks, competitor teardowns, scraping health, QA of an embedded widget — you will hit these. Here is the full list of signals that lied to me, and the one control that never has. The four false positives All four produced the same symptom: no <canvas> on the page, and an almost empty innerText . That looks damning when the page is literally titled "Configurator". It is also what three completely healthy situations look like: The tool starts on a click. An orange button launches it. My script measured an unopened door and reported an empty room. Four automated passes — raw HTTP with a browser UA, my own browser, two runs from a clean profile, a control on the same domain — all four confidently examined a page that hadn't started yet. The entire UI lives inside the canvas. One hall configurator draws its menus, its undo/redo and its PDF export in WebGL. Empty DOM text is correct there, not a defect. The tool is behind a login. I was measuring a sign-in page. Fifty-four characters of text and one button reading "Anmelden". The page is a landing page about the configurator, not the configurator. No network-level or DOM-level check distinguishes these from an actual failure. A screenshot distinguishes all four instantly. So the first rule I now follow, before any measurement at all: Take the screenshot first. Look at the picture. What you cannot see in the image, you do not measure. It costs one second and it is the highest-yield step in the whole process. The cor
AI 资讯
Error Messages When the Model Fails
“Something went wrong. Please try again.” is correct for about a third of AI failures and actively harmful for the rest, because for the rest, trying again cannot possibly help and you have just told the user to spend money finding that out. Everything that can go wrong Errors arrive from at least four layers, and the user-facing consequences differ enough that collapsing them into one message destroys the only information you had. Failure Description Transport Connection dropped, DNS, TLS, the stream died mid-token. Retryable, usually transient, and the user did nothing wrong. This is the only class where 'try again' is straightforwardly true. Rate limited (429) Yours or the provider's capacity, not the request. Retryable but only after a wait, and the wait is often stated in a header. Telling the user to retry immediately guarantees a second 429. Provider 5xx / overloaded Retryable with backoff, and the single best case for automatic failover to another provider rather than for any message at all. Timeout Ambiguous by construction: the request may have completed on the provider's side and been billed. Retrying may duplicate a side effect, which is why idempotency matters more here than anywhere. Context length exceeded Deterministic. Retrying the identical request fails identically. The only fix is fewer tokens, and the interface knows that — so the message should offer the fix, not the retry. Content filter The provider blocked the input or the output. Not retryable unchanged. Distinct from a model refusal, and users experience the two very differently. Truncated output The generation hit max_tokens. Not an error at the transport layer at all — status 200, a finish reason of 'length', and an answer that stops mid-sentence. Silently the most common broken experience. Malformed structured output Valid HTTP, invalid JSON or a schema violation. Retryable and often succeeds on a second sample, because it is a sampling accident rather than a capability failure. Empty o
AI 资讯
The SVG Color Cascade Nobody Explains (fill, stroke, currentColor, and why img src breaks it)
Change an SVG's color by editing fill and stroke , either as attributes or through CSS. Simple in theory. In practice there are three places a color can be declared in the same file, they follow the normal CSS cascade, and if you don't know that, "I changed the fill and nothing happened" turns into a twenty-minute debugging session. Here's the part of SVG color handling that usually doesn't get spelled out. fill and stroke are separate properties Every shape has an inside ( fill ) and an outline ( stroke ), set independently: <circle cx= "50" cy= "50" r= "40" fill= "#3366ff" stroke= "#000" stroke-width= "2" /> Unset fill defaults to black. Unset stroke defaults to none. If an icon is pure fill with no stroke at all (most converted icon-font SVGs are), editing stroke-width is never going to do anything visible, and that's usually the first dead end people hit. The cascade is the actual bug source A color can come from three places, and they don't have equal priority: A presentation attribute: <path fill="red" /> An inline style attribute: <path style="fill: red;" /> A <style> block or external stylesheet: path { fill: red; } Normal CSS specificity applies: style attribute beats stylesheet, stylesheet beats presentation attribute. Edit the fill="red" attribute directly, and if a <style> block elsewhere in the same file also targets that path, your edit is overridden and nothing changes on screen. No error, no warning, it just loses. If a color edit isn't sticking, grep the file for <style before assuming your tool, or your edit, is broken. This one thing accounts for most "the SVG editor is buggy" reports that are actually the cascade working exactly as designed. currentColor: SVG's inheritance trick Set fill="currentColor" and the shape stops carrying its own color and instead inherits whatever color is set to on an ancestor element, the same mechanism that makes text inherit color: <path fill= "currentColor" d= "..." /> .icon { color : #ff0000 ; } <span class= "icon
AI 资讯
The SVG Path Data Format, Explained (M, L, C, Q, A, Z)
If you've opened a <path d="..."> string and had no idea what you were looking at, here's the short version: it's a tiny drawing language. A pen moves around a coordinate space, and each letter in the string is an instruction telling it what to do next. TL;DR M / m moves the pen, L / l draws a straight line, C / c and Q / q draw bezier curves, A / a draws an arc, Z / z closes the shape. Uppercase is absolute coordinates, lowercase is relative to the pen's current position. A visual path editor drags the exact same numbers you'd type by hand, it just shows you the curve instead of making you compute it. Reading a path string <path d="M10 10 L90 10 L90 90 Z" /> Broken down: move to (10, 10), draw a line to (90, 10), draw a line to (90, 90), close the path back to the start. That's a right triangle. Every path, no matter how complex, is this same pattern: a command letter followed by however many numbers that command needs, repeated. The command set Command Name What it takes M / m Move to x, y L / l Line to x, y C / c Cubic bezier control1 x/y, control2 x/y, end x/y Q / q Quadratic bezier control x/y, end x/y A / a Arc rx, ry, rotation, large-arc-flag, sweep-flag, end x/y Z / z Close path none C and Q are both bezier curves, the difference is one control point ( Q ) vs two ( C ). Two control points give you more independent influence over each end of the curve; one control point gives you a simpler, more symmetric curve. There are also shorthand continuations ( S / s , T / t ) for chaining smooth curves without repeating a control point, but the six above are what you'll hit constantly. A is the one people avoid writing by hand. Six parameters, two of which are flags (0 or 1) that determine which of four possible arcs you get for the same radii and endpoints. Flip one and you're not slightly off, you're on the opposite side of the ellipse. Absolute vs relative is the part that bites Every command above has an uppercase and lowercase form, and it's not cosmetic: <!-- a
开发者
Microsoft Edge is about to lock out older ad blockers, just like Chrome did
Microsoft Edge is ending support for the Manifest V2 extensions platform, which will cut off the uBlock Origin adblocker and others like it, just like Google Chrome did earlier this year. According to Microsoft, there are only 58 extensions on the Edge Add-On Store "with any meaningful usage" that still use MV2, and only three […]
AI 资讯
The Anatomy of IPv4 Address
I used to think IPv4 addresses were just random numbers until recently. It blew my mind when I started digging and understanding that they have an anatomy where every number after the dot means something very important. Note: To understand what IP addresses are, please consult this post because I won't be going over them here. IP Addresses: Digital Connectivity What is IPv4 in the First Place? IPv4 is short for Internet Protocol version 4 . As you might have already realized, it's the 4th version of the early test designs during the development of the Internet Protocol in test labs in the 1970s. The first real release, v4, came out in 1981 in a public document called RFC 791. RFC 791: STD 5: Internet Protocol IPv4 is an Internet Protocol that's written in what's called Dotted Decimal Notation (e.g., 172.17.0.3 ), where each portion is separated by a dot, and these portions are called octets. For example, 172 is the first octet and 17 is the second octet (more on this later). Before We Explore What Octets Are, Let's Take a Stroll to the Basics of Binary (Simplified) Have you ever wondered why your computer or phone requires electricity to function? Though electricity can be used as a raw power source for things like fans or speakers, where it's converted into other forms of energy such as movement or sound, it's good to know that electricity can function differently in your computer's RAM or SSD. Inside your computer are billions of extremely tiny transistors. These transistors form circuits that can create and maintain different electrical states, which the computer interprets as 0s and 1s. In simple terms, 0 represents the absence of the electrical state (OFF), while 1 represents its presence (ON). These states, which we represent with 0s and 1s, are called binary digits (or simply bits). 1 bit has the possibility of representing either 0 or 1, which doesn't represent much information, and that's where multi-bits come in. Every additional bit doubles the number of
AI 资讯
Why We Built MicroLeague Sports Vol. 3
Why Sports Data Is Harder Than Most People Think Building believable cross-era simulations turned out to be less about the engine and more about the data underneath it. Here is what we learned. MicroLeague Dev Blog, Vol. 3 By Eddie Solar When we started building MicroLeague Sports, I assumed the simulation engine would be the hard part. The vision was ambitious enough to justify that assumption. Let fans ask whether the 1996 Bulls beat the 2017 Warriors. Whether the 1985 Bears could slow down Patrick Mahomes. Which Cowboys team was actually the greatest. Teaching software to play those games across eras felt like the mountain. I was wrong about which mountain it was. The engine is hard, but it is a solvable, bounded kind of hard. The data underneath it is a different animal. Like most developers approaching this for the first time, we figured sports data was largely a collection exercise: gather historical teams, player stats, schedules, and box scores, feed it to the model, done. That assumption fell apart almost immediately, and the reason it fell apart is the subject of this article. Sports data is not a collection problem. It is an identity problem. Franchises do not stay the same thing. Players are not one entity. And the historical record does not agree with itself. The Real Problem Is Modeling Identity Over Time Volume 2 covered the era problem: statistics are confounded by the conditions that produced them, so a raw number pulled across decades lies to you. That is a normalization challenge, and it is real. But normalization assumes you already know what you are normalizing. Before you can compare the 1992 Cowboys to the 2023 Chiefs, your system has to have a confident answer to a more basic question: what exactly is a "team," and what exactly is a "player," when your dataset spans a hundred years? Those sound like trivial questions. They are not. They are the questions that ate most of our early engineering time, and getting them wrong quietly corrupts ever
开发者
«es» no es un mercado: el bug de i18n que nos costó reescribir una campaña entera
Nota: en Lumora construimos libros infantiles personalizados con IA, y escribimos en diez idiomas. Este artículo cuenta un problema de i18n con el que chocamos de frente y cómo lo resolvimos. Lo contamos desde dentro, con nuestro nombre, porque el error nos costó reescribir una campaña entera. Casi todos los equipos tratamos el idioma como si fuera el país. Ponemos es en el selector, sacamos las cadenas a un JSON y damos el problema por cerrado. Funciona hasta el día en que tu producto tiene algo que ver con una fecha. Y entonces descubres que es no es un mercado, son varios calendarios distintos que comparten vocabulario. El día en que el regalo no llega el 25 Teníamos una campaña de regalos escrita en español. Correcta gramaticalmente, revisada, sin errores de traducción. Y aun así estaba mal para una parte grande de quien la leía: En España , el gran momento de regalo infantil no es el 25 de diciembre: son los Reyes Magos, el 6 de enero . Un mensaje que dice "pídelo antes del 24" le está dando a una familia española una fecha límite equivocada por casi dos semanas. En México conviven las dos cosas: Navidad y Reyes, con la rosca del 6 de enero. En Argentina, Chile o Uruguay , la Navidad es el 25 de diciembre… en pleno verano . A 30 grados. Con las vacaciones escolares largas empezando, no terminando. Fíjate en lo incómodo del asunto: los tres casos hablan español. Los tres pasan el mismo test de traducción. Y los tres necesitan un mensaje distinto, una imagen distinta y una fecha límite distinta. El mismo golpe existe en portugués. En Brasil la Navidad también cae en pleno verano, enero es mes de vacaciones, y el día en que de verdad se reinicia la rutina familiar no es el 1 de enero: es la volta às aulas , en febrero. Si tu calendario de contenidos asume "año nuevo, hábitos nuevos" en enero, en Brasil llegas un mes antes de que a nadie le importe. Por qué el código de locale no te salva La respuesta obvia es "usa es-ES y es-AR ". Es correcta y casi nunca es sufic
AI 资讯
How to Repair Corrupted PDFs in the Browser with Vue 3 and pdf-lib
A corrupted PDF is one of the most frustrating file problems. You have important content inside, but the document won't open, opens with garbled text, or shows missing pages. The file might be damaged from a bad download, a converter error, or a storage glitch. Recovering content from a broken PDF doesn't require complex forensic tools. Often, the individual pages are still readable — it's the document's structure (cross-reference tables, object streams) that's damaged. By extracting pages one by one into a fresh PDF, we can bypass the structural corruption. Here's how to build a browser-based PDF repair tool with Vue 3 and pdf-lib . The repair strategy The core insight: PDF structure and page content are somewhat independent . A PDF can have a broken cross-reference table or missing trailer objects, but the actual page content streams may still be perfectly readable. The repair approach: Load the damaged PDF and attempt to read each page For each successfully read page, copy it to a new PDF document Discard unreadable pages (they're lost anyway) Save the new document This is fundamentally different from "fixing" the original PDF. We're extracting what we can and rebuilding from the ground up. The stack Vue 3 with Composition API pdf-lib for PDF reading and page extraction Vite for bundling The core implementation < script setup lang= "ts" > import { ref } from ' vue ' import { PDFDocument } from ' pdf-lib ' const file = ref < File | null > ( null ) const totalPages = ref ( 0 ) const recoveredPages = ref ( 0 ) const repairing = ref ( false ) const result = ref < Uint8Array | null > ( null ) const error = ref < string | null > ( null ) async function repairPdf () { if ( ! file . value ) return repairing . value = true error . value = null try { const arrayBuffer = await file . value . arrayBuffer () const damaged = await PDFDocument . load ( arrayBuffer , { ignoreEncryption : true , updateMetadata : false , }) totalPages . value = damaged . getPageCount () const resu
AI 资讯
Why Your ZATCA Phase 2 Invoice Passes Compliance and Fails Reporting
If you are integrating ZATCA Phase 2 (Saudi Arabia's Fatoora e-invoicing) and you have seen this: { "type" : "ERROR" , "code" : "signed-properties-hashing" , "category" : "CERTIFICATE_ERRORS" , "message" : "Invalid signed properties hashing, SignedProperties with id='xadesSignedProperties'" } ...after your invoice sailed through /compliance/invoices , this post is for you. It is the single most confusing failure mode in the whole integration, and the fix is not what the error suggests. The trap: SignedProperties exists in two byte-shapes The XAdES SignedProperties block is referenced twice in your signed document: ds:Reference URI="#xadesSignedProperties" carries a digest of the block. The block itself is embedded inside ds:Object > xades:QualifyingProperties . The natural assumption is that both refer to the same bytes. They do not. The hashed shape carries namespace declarations and starts at column 0: <xades:SignedProperties xmlns:xades= "http://uri.etsi.org/01903/v1.3.2#" Id= "xadesSignedProperties" > <xades:SignedSignatureProperties> <xades:SigningTime> 2026-08-07T02:14:33 </xades:SigningTime> <xades:SigningCertificate> <xades:Cert> <xades:CertDigest> <ds:DigestMethod xmlns:ds= "http://www.w3.org/2000/09/xmldsig#" Algorithm= "http://www.w3.org/2001/04/xmlenc#sha256" /> The embedded shape carries no namespace declarations (they are inherited from ancestors) and its root element is indented to column 32 : <xades:SignedProperties Id= "xadesSignedProperties" > <xades:SignedSignatureProperties> Embed the hashed shape verbatim - the intuitive thing to do - and the gateway rejects with signed-properties-hashing , even though your indentation "looks right". The second half of the trap: the digest encoding The digest is not the raw SHA-256 bytes in base64. It is base64 of the hex string : const crypto = require ( ' crypto ' ); // hashedShape = the namespaced, column-0 variant above const propsDigest = Buffer . from ( crypto . createHash ( ' sha256 ' ). update ( Buffer .
开发者
Excited to finally join DEV!
👋 Hello DEV Community! I'm excited to finally join DEV! I'm a developer, entrepreneur, and lifelong learner who enjoys building practical web solutions with WordPress, PHP, and modern web technologies. Over the past few years I've been working on: 🚀 WordPress plugins and starter websites 💻 Affordable web solutions for individuals and small businesses 📈 Web analytics and digital marketing tools 🌱 Exploring software architecture, clean code, and open-source development I'm also building and experimenting with digital products that solve real-world problems while documenting what I learn along the way. Here you'll find posts about: WordPress development PHP programming Building and launching web products Software engineering lessons Productivity and business insights for developers Occasionally, mathematics and calculus when it connects to programming or analytics I'm looking forward to learning from this amazing community, contributing where I can, and connecting with fellow developers. Thanks for having me! 😊
AI 资讯
Why Plumeria?
"CSS Modules are fine after all." If you build web interfaces for a living, you have probably said this. After wrestling with runtime CSS-in-JS configuration, chasing specificity bugs across dynamic boundaries, or watching a utility-first framework bloat your markup, returning to the humble CSS Module feels like a relief. That isn't a compromise made for lack of features. CSS Modules win because they are predictable : the CSS you write behaves exactly as written. There is no runtime parser guessing your intent, no injection-order races between chunks, and almost no runtime JavaScript — just a class mapping object. But the safety has a price. You give up TypeScript-integrated styling, compile-time validation, dynamic theming, and seamless colocation. Plumeria is designed to eliminate this compromise. It matches — and in several areas exceeds — the predictability of CSS Modules, while delivering the type-safe developer experience of a modern CSS-in-JS library. The Zero-Trace Runtime Try compiling this — note that the style is actually applied, not left unused: import * as css from ' @plumeria/core ' ; const styles = css . create ({ box : { padding : 16 , color : ' red ' } }); export const Box = () => < div classStyle = { styles . box } > Box </ div >; Here is the entire JavaScript build output: export const Box = () => < div className = { ' xqqbxt1d xq96bg3w ' } > Box </ div >; The declarations move to a generated stylesheet: .xqqbxt1d { padding : 16px ; } .xq96bg3w { color : red ; } The style still renders, yet import * as css from '@plumeria/core' and the entire css.create declaration have vanished. This is not dead-code elimination — nothing in this file is unused, and no bundler could remove a live call for you. The compiler resolves the class names statically and rewrites the call site, so the library never has a runtime form to eliminate in the first place. That disappearing import is the most concise illustration of a Zero-Trace Runtime — anything that shouldn'