AI 资讯
Your console.log Is Lying to You
Open your browser DevTools and run this: const user = { name : " Bob " } console . log ( user ) user . name = " Alice " You would expect the log to show { name: "Bob" } , the value at the time of the console.log call. The collapsed line is what you expect: ▶ Object { name: "Bob" } But expand it, and you will see: name: "Alice" Oops. So what's going on? console.log() is the most-used debugging tool in JavaScript, but it can be subtly unreliable. Not because it is broken, but because it optimizes for speed and interactivity rather than for accuracy . It was built for fast exploration in a live, interactive environment, and those priorities come with tradeoffs that can genuinely mislead you during debugging. Over the next sections, we'll look at a few ways the console can mislead you - and, more importantly, why each one exists. Objects Aren't Snapshots When you pass an object to console.log() in browser DevTools, the browser does not immediately serialize it into a string. Instead, it stores a live reference to that object and defers the actual rendering until you expand the entry. This is called lazy evaluation, and it is what caused the surprise. The collapsed ▶ Object you see is essentially a placeholder: the properties shown inside it are evaluated at the moment you click the arrow, not at the moment you called console.log() . By then, your code has already continued running. That means what you're seeing is not a frozen record of the object at the time of logging, but a live view into whatever the object happens to look like when DevTools renders it. In the example: You log { name: "Bob" } DevTools stores a reference to the user object The code continues executing user.name is mutated to "Alice" You expand the logged object later and see the current state This behavior can feel unintuitive at first, because most developers mentally model console.log() as "print this value right now", but in browser DevTools, it is closer to "show me this object as it exists when
AI 资讯
From Regex Hell to AI: How I Finally Tamed Messy PDF Invoices
Last month, I spent three days wrestling with 500 PDF invoices. Each one had the same data—vendor name, invoice number, total amount—but the layouts were all over the place. Different fonts, missing headers, tables that somehow broke across pages. I tried regex. I tried OCR with layout analysis. I even tried building a rule-based parser that looked for keywords like "Total:" . Nothing worked reliably. Every time I fixed one pattern, another invoice broke. I was one commit away from throwing my laptop out the window. Then I took a step back. I realized I didn't need to understand every layout variation. I just needed to understand the data . And that's where AI came in. What didn’t work Let me be clear: I tried the usual suspects first. Regex. Classic. I wrote patterns like r"Total\s*:\s*\$?(\d+\.\d{2})" . Worked on 60% of invoices. The rest had "Total Due" or "Amount Total" or the dollar sign in a different place. Regex is great when you control the input. I didn't. OCR with layout parsing. I used Tesseract with --psm 6 and tried to extract lines by bounding boxes. It helped a bit, but tables with merged cells or rotated text threw it off. Plus, I had to write code to guess which box was a field name and which was a value. Rule-based parser. I built a dictionary of known vendors and their layouts. That worked … until I got an invoice from a new vendor. Maintenance became a nightmare. I was solving the wrong problem. Instead of fighting formatting, I needed to focus on meaning . The AI approach that saved me I remembered that large language models are surprisingly good at understanding context. If I could give the model the raw text from a PDF and a description of what I wanted, maybe it could extract the fields directly. Here’s the core idea: treat extraction as a structured generation task. Provide a prompt with a few examples (few-shot) or just describe the schema, and let the model output JSON. I found an API that did exactly this with a simple HTTP call. (Full d
开发者
สามภาษา — หนึ่งเดียว | โคลงสี่สุภาพแห่ง HTML, CSS, JavaScript
— โคลงสี่สุภาพ ว่าด้วยสามภาษาแห่งการสร้างเว็บ — HTML — โครงสร้าง <html> เปิดทางฟ้า ประกาศ <head> ซ่อนนัยน์นาถ นามนี้ <body> ร่างกายปราศ ซึ่งชีวิต ทุกแท็กเปิดปิดที่ หล่อหล่อมความจริง CSS — ความงาม สีสันลอยลิบฟ้า แต่งแต้ม ตัวอักษรเรียงแถม ถ้วนถี่ ขอบเขตเว้นระยะแย้ม เผยโฉม ทุกพิกเซลที่ปรี่ ปรุงแต่งให้งาม JavaScript — ชีวิต เมื่อคลิกนิ้วหนึ่งครั้ง โลดแล่น ฟังก์ชันทำงานแย้ม ยามใช้ if else ตรรกะแจ่ม จักรกล ทุกบรรทัดที่ให้ ชีวิตแก่หน้าเว็บ สามภาษา — หนึ่งเดียว html คือร่างให้ โครงครัน css แต่งแต้มฝัน สวยหรู javascript พลิกผัน ให้เคลื่อนไหว สามภาษาคู่ฟู ฟื้นฟูโลกา — Nokka | มิถุนายน 2569 เชิงอรรถ: โคลงสี่สุภาพบทนี้ใช้ฉันทลักษณ์มาตรฐาน — บทละ 4 บาท บาทละ 2 วรรค วรรคหน้า 5 พยางค์ วรรคหลัง 2 พยางค์ สัมผัสบังคับระหว่างวรรคท้ายของบาทที่ 1, 2, 3 กับวรรคแรกของบาทถัดไป เนื้อหากล่าวถึงสามเทคโนโลยีหลักของการพัฒนาเว็บไซต์ในฐานะ "กาย — ใจ — วิญญาณ" ของทุกหน้าเว็บ
AI 资讯
"Building an HSK Speaking Test AI: Real-time Tone Grading with Gemini
Building an HSK Speaking Test AI: Real-time Tone Grading with Gemini I built a free Mandarin speaking assessment tool that grades tone + grammar in real time. Here's the engineering behind it. The Problem HSK (Chinese proficiency test) has a speaking component (HSKK), but most learners can't self-assess their level. Online tutors are expensive. Generic AI conversation tools don't grade tones. So I built ToneTutor: a 3-minute spoken-HSK test that estimates your speaking level and identifies weak points. The Tech Stack Frontend: Web Audio API (record user voice → PCM → LINEAR16) React + TypeScript (real-time transcript display) Backend: FastAPI (Python) on Google Cloud Run Gemini 2.5 Flash (real-time conversation + transcript grading) Firestore (user sessions + results) The Challenge: Web Audio API records as WebM. Gemini expects LINEAR16 (WAV). iOS Safari doesn't support WebM. So: Transcode WebM → PCM in browser (Web Audio context) Send raw PCM bytes to backend Backend wraps PCM in WAV header → sends to Gemini Speech-to-Text Gemini analyzes transcript + provides HSK level estimate The Grading Loop python async def grade_session(transcript: str): prompt = """ Rate this Mandarin response on HSK 1-6 scale. Assess: tone accuracy, grammar, vocabulary range. Provide: level estimate + weak points. """ response = await gemini.generate_content(prompt, stream=True) return parse_hsk_level(response) Results - 3-min test - Real-time feedback - Shareable HSK score card - Free (limited sessions) Open source coming soon. Built because I'm a native speaker + voice actor frustrated with generic tools. Try it: tonetutor.tefusiang.com (free for 3 sessions) Curious about the speech-to-text pipeline or tone grading logic? Ask below.
AI 资讯
V.E.L.O.C.I.T.Y.-OS: Kimi K2.7 and the 'Safe-Room Security' Illusion (Part 1)
It all started on June 23rd with a casual post about a VPS Manager benchmark. Out of curiosity, I decided to ask the author of the benchmark, Pascal CESCATO Follow Full-stack dev sharing practical guides on WordPress, n8n automation, AI tools, Docker & self-hosting. Always experimenting with new tech to make life easier. , if he had tried Cloudflare's new Workers AI offering—specifically Kimi K2.7, a massive 1-trillion parameter MoE (Mixture of Experts) model that was incredibly cheap ($0.27 per million input tokens) and highly capable at code generation. Pascal was intrigued. He pointed out a brilliant hypothesis: if a model makes significantly fewer mistakes, the total session cost drops dramatically even if the per-token price is higher. He cited GLM 5.2 as a model that self-corrected multiple bugs during verification to achieve 37/37 tests passing. Curiosity got the better of me. I spun up my development environment, wrote a custom agent harness, and ran it on Kimi K2.7 using Cloudflare Workers AI. The V.E.L.O.C.I.T.Y.-OS Series Table of Contents We are building a bare-metal, self-healing operating system running entirely inside the CPU's L3 cache. Here is the roadmap for this 12-part series: Part 1: The Spark — Exposing the "Safe-Room" security leak and building the compiler gate. (You are here) Part 2: The NDA Language — Designing a content-addressed triplet representation to cure context bloat. Part 3: Ditching the Web Stack — Building a native 30MB IDE with 1,500,000x IPC latency drops. Part 4: The Closure JIT — Compiling AST blocks to nested closures and bypassing borrow checker limits. Part 5: JIT Math Optimizations — Replacing division operations with precomputed 16-bit lookup tables. Part 6: x86-64 Assembler & SCEV-Lite — Compiling scalar loops directly to native code in constant time. Part 7: Classic Compiler Passes — Implementing inter-procedural Dead Code Elimination and loop unrolling. Part 8: Reclaiming Ring 0 — Exiting UEFI boot services and transi
AI 资讯
PDF::Make - PDF Generation, Extraction and Modification.
I’ve always been fascinated by PDFs. They look simple on the surface. Just a document you can open anywhere but underneath they’re a full layout engine, object graph, drawing model, and archival format all at once. I enjoy that mix of precision and complexity and that is exactly what led me to build PDF::Make (and yes I had some help from Claude LLM). I wanted a fully featured toolkit that could both generate PDFs and let me inspect/edit them programmatically. At the low level, PDF::Make exposes the raw building blocks of the format: PDF objects, pages, the drawing canvas, a parser/reader, and import/merge primitives. This is the layer you reach for when you need fine grained control or want to work with the structure of a document directly. For everyday document creation, PDF::Make::Builder sits on top of that foundation and provides a higher level API. It handles the boilerplate of page setup, fonts, text flow, and layout so you can produce a polished PDF in just a few lines of Perl. The same toolkit is also designed for post-processing. You can open an existing PDF, extract structured text along with its coordinates, and then draw annotations or overlays back onto the page, making it straightforward to build review, QA, or markup workflows on top of documents you didn’t originally generate. This post shows a practical two-step flow: Create a PDF Re-open it, extract text coordinates, and draw border highlights around matched words 1) Create a PDF with PDF::Make::Builder Script: #!/usr/bin/perl use strict ; use warnings ; use PDF::Make:: Builder ; my $pdf = PDF::Make:: Builder -> new ( file_name => ' source_demo.pdf ', configure => { text => { font => { family => ' Helvetica ', size => 12 , colour => ' #222222 ' }, }, }, ); $pdf -> add_page ( page_size => ' Letter ') -> add_h1 ( text => ' PDF::Make blog demo ') -> add_text ( text => ' PDF::Make builds and edits PDF files directly from Perl. ') -> add_text ( text => ' In the next step we extract text coordinates and
AI 资讯
TMD’s keyless bike lock is a $280 solution to a $60 problem
I've seen lots of so-called "smart" bike locks over the years, but none so far could justify the added cost. A newcomer that got its start securing ATMs for banks is trying to change that. There's nothing wholly unique about the TMD Chain Lock, but the combination of materials, performance, and insurance-friendly ART-2 certification makes […]
AI 资讯
I built a free planting calendar with 365 daily pages using AI
Ever planted seeds at the wrong time and watched them die? Me too. That's why I built PlantingCalendar.net - a free tool that tells you exactly what to plant every single day based on your climate zone. Built with AI coding tools in about 4 hours. 365 pages, each with unique planting instructions. Static site on Cloudflare Pages, zero server cost. Free, no sign-up.
AI 资讯
The n8n bug that took three tries to find (and the free workflow it broke)
I built a free n8n workflow that writes your launch content for you. It broke three times before it worked, and the third break is the only part of this post worth reading. The problem Every time I ship a new digital product, I write the same five things: a short blog intro, a LinkedIn post, an X post, an Instagram caption, and a launch email. Same structure every time, different product. The kind of task that's boring enough to automate but annoying enough that I kept putting it off. So I built Launch Content Pack : an n8n workflow that takes one product description and generates all five, using an LLM node wired up with Claude Code on the customization side. It's free, it's on Gumroad, and the JSON is the whole product — open it, see every node. Why bother when there are 9,000+ free n8n templates already There are. I checked before building this, because there's no point shipping a workflow that already exists for free somewhere else. What's actually missing from most of those templates: nobody validates the nodes. A huge chunk of free n8n templates floating around were generated by someone (often an LLM) guessing at node types and parameters, and they quietly break the moment n8n ships a version update. I used n8n-mcp , a free MCP server, to confirm every single node type, version, and parameter against n8n's actual schema before writing any JSON. No guessing. That sounds like a small difference. It's the reason this post exists. The bug that actually mattered I tested the workflow in n8n Cloud. Two nodes ran clean — green checkmarks, no errors. Then the Code node that's supposed to take the LLM's output and split it into five labeled fields threw: Cannot read property 'text' of undefined My first guess was wrong. I assumed the LLM node's output field was named something other than text — output , maybe, or response — and that I just had the wrong field name in the Code node. Reasonable guess. Also not the actual bug. Here's what was really happening. The OpenAI
AI 资讯
Stop trusting environment variables in your TypeScript apps
Environment variables look simple until one of them is missing, empty, malformed, or interpreted in a way your application did not expect. In TypeScript projects, this can be easy to overlook. The code may be typed, the build may pass, and the app may still ship with broken configuration. This is especially common in frontend builds, server-side rendering, backend services, CLI tools, Docker images, and CI/CD pipelines, where configuration is injected from outside the codebase. That is the problem valitype is designed to address: strict, type-safe validation of environment variables with zero dependencies. The problem with environment variables Environment variables are always external input. They can come from: .env files CI/CD variables Docker or container platforms hosting providers build scripts deployment environments TypeScript can describe what your code expects, but it cannot guarantee that the environment actually contains valid values. This looks harmless: const apiUrl = import . meta . env . VITE_API_URL const debug = Boolean ( import . meta . env . VITE_DEBUG ) const port = Number ( process . env . PORT ) But simple casting can hide invalid configuration: Boolean ( ' false ' ) // true Boolean ( ' 0 ' ) // true Number ( ' 0xff ' ) // 255 Number ( ' 1e5 ' ) // 100000 Number ( '' ) // 0 For application configuration, “parseable” is not the same as “valid”. Invalid configuration should be caught before deployment, either during build, CI, server startup, or a dedicated validation step. The problem in React and frontend builds React applications usually do not read environment variables directly at runtime in the browser. Instead, tools like Vite and frameworks like Next.js inject selected values during build time. That makes validation important. Once the frontend bundle is built and deployed, changing a bad environment variable usually means rebuilding and redeploying the application. For frontend apps, validation should answer a few basic questions before
开发者
How to Send iMessages Programmatically (REST API, Python & Node.js)
If you've ever tried to send an iMessage programmatically , you've probably hit the same wall everyone does: Apple has no public iMessage API. There's no POST /imessage in the developer docs, no SDK, no OAuth scope. Yet "blue bubble" delivery has 3–4× the open rates of SMS, so the demand to send iMessages from code — for CRMs, bots, notifications, and outbound — keeps growing. This guide covers the realistic options, then walks through actually sending and receiving iMessages over a REST API with working Python , Node.js , and curl examples you can paste and run today. Why there's no official iMessage API iMessage is a closed, end-to-end-encrypted protocol tied to Apple IDs and Apple hardware. Apple has never shipped a public API to send iMessages, and "Messages for Business" is a support-inbox product gated behind an approval process — not a way to send outbound messages from a script. So historically, developers reached for hacks: Approach Works from a server? Reliability Receiving messages Notes AppleScript / osascript No — needs a logged-in Mac with Messages open Brittle Polling the local SQLite chat.db Mac-only, breaks on macOS updates Shortcuts automation No Brittle No Manual, not built for scale "Just use SMS" (Twilio etc.) Yes High Yes Green bubbles, no typing indicators/tapbacks/HD media Hosted iMessage REST API Yes High Yes (webhooks) What this guide uses The AppleScript route is fine for a one-off script on your own Mac. The moment you want to send from a server, send at scale, or receive replies reliably, you need a hosted API that manages the Apple side for you and exposes a normal HTTP interface. The setup For the examples below I'm using Blooio , an iMessage REST API. Any provider with a similar HTTP surface will follow the same patterns — the concepts (Bearer auth, a send endpoint, webhooks for inbound) are what matter. You'll need: An API key (Blooio gives you one in the dashboard — no credit card, no A2P/10DLC registration, no DUNS number) A phone
AI 资讯
Why I Built Aegis Pulse - Part 1
Why did I build Aegis Pulse? As always, it started with a simple thought that keeps getting me time and time again: "I should automate this." So, I announced Aegis Stack publicly on Reddit on December 3rd. From that very moment, I became great friends with the Unique Clones / Total Clones & Unique Visitors / Total Views charts in GitHub's analytics page. Due to the nature of aegis-stack, every stack that is spun up will clone the actual repo itself (outside of caching situations, which may vary from user to user). I didn't realize it at the time, but those clone numbers, especially the Unique Clones, would become the most important metric for me to track usage. There's this funny thing that happens when you release an OSS tool. You expect people to say something, maybe tell others, ask questions... just... something... Instead, the person looks at the tool, sees if it makes their life easier, and puts it in their bag of other tools. I know this, because this is me! I never thought about it until I'm on the other side. I had to mentally go through all the tools I had used over the years, and realized I never cared about anything other than the tool itself. And if it didn't work, I would try to make it work, and if not, just move on. Time is money, and all of that. All of that is to say, clones are something I have been tracking since day one. Now... GitHub has a 14-day rolling window period in which they have daily values, and the 14-day rolling totals. And when I say 14 days, I mean it. That's all you get, and it's on you to keep track of everything outside of that. Fair enough. Thus began the daily ritual of going and grabbing the latest numbers from the previous day, and pasting the data into 3 separate AI chats: ChatGPT, Claude Opus, and Google Gemini. I figured that since I was already storing all of this data, I might as well see what type of insights I could get from these chats (which were preloaded with enough context to know what's going on). It was a great
开发者
【互動藝術 DIY】用 p5.js 做一塊會呼吸的粒子背景(無程式背景可)
【互動藝術 DIY】用 p5.js 做一塊會呼吸的粒子背景 先問自己:阿哲會想動手嗎? 看完這個效果,阿哲可能會想: 「那如果我把粒子排成自己的名字,滑鼠靠近時會散開嗎?」 這就是正確的方向—— 讓讀者想自己動手改參數 ,而不是背程式碼。 這個方法厲害在哪? p5.js 官網有很多炫技的粒子效果,但大部分只是給你看「很厲害」。 這次不一樣——我要教你 用最少程式碼,做出最有呼吸感的互動 。 秘密是:用「距離」控制行為,用「lerp」讓移動變溫柔。 教學順序 先建立粒子:讓一群點組成畫面 教動畫:用 sin() 做出呼吸節奏 教距離感:用 dist() 偵測滑鼠 教溫柔散開:用 lerp() 柔和移動,不是瞬移 最後加美感:透明度、殘影、暖色 第一步:讓粒子回家 class Particle { constructor ( x , y ) { this . homeX = x ; // 記住家的位置 this . homeY = y ; this . x = x ; this . y = y ; } // 讓粒子回家的力量 returnHome () { this . x = lerp ( this . x , this . homeX , 0.05 ); // 每次移動5%的距離 this . y = lerp ( this . y , this . homeY , 0.05 ); } show () { noStroke (); fill ( 255 , 180 , 120 , 200 ); // 暖橙色 ellipse ( this . x , this . y , 4 ); } } 第二步:偵測滑鼠距離 function draw () { for ( let p of particles ) { let d = dist ( mouseX , mouseY , p . x , p . y ); if ( d < 100 ) { // 滑鼠靠近時,輕輕推開 let force = 0.05 * ( 100 - d ) / 100 ; p . x += ( p . x - mouseX ) / d * force ; p . y += ( p . y - mouseY ) / d * force ; } p . returnHome (); p . show (); } } 第三步:加呼吸節奏 let breathPhase = 0 ; function draw () { breathPhase += 0.02 ; let breath = sin ( breathPhase ); // -1 ~ +1 來回循環 background ( 10 , 8 , 5 ); // 暖暗色背景 for ( let p of particles ) { let d = dist ( mouseX , mouseY , p . x , p . y ); if ( d < 100 ) { let force = 0.05 * ( 100 - d ) / 100 ; p . x += ( p . x - mouseX ) / d * force ; p . y += ( p . y - mouseY ) / d * force ; } p . returnHome (); p . show ( breath ); // 把呼吸相位傳進去 } } function show ( breath ) { noStroke (); // 呼吸時變亮,吐氣時變暗 let alpha = map ( breath , - 1 , 1 , 150 , 255 ); fill ( 255 , 180 , 120 , alpha ); ellipse ( this . x , this . y , 4 ); } 第四步:殘影效果 function draw () { // 不要每幀清掉背景,而是蓋一層半透明黑色 fill ( 10 , 8 , 5 , 30 ); rect ( 0 , 0 , width , height ); // ... 其餘粒子邏輯 } 這樣粒子移動時會留下淡淡的光跡——很有沉浸式裝置的 feel。 阿哲可以怎麼玩? 參數 預設值 改成... 效果 感知半徑 100px 50px 只有非常靠近才有反應 回家速度 0.05 0.02 超級慢,像在水裡 回家速度 0.05 0.2 快一點回覆 粒子數量 200 50 稀疏的星塵感 粒子颜色 暖橙 淡粉 更柔和的感覺 延伸練習 把粒子排成自己的名字 :讓粒子組成「阿哲」或英文字母輪廓,滑鼠靠近時文字散開,離開後慢慢聚回來。 滑鼠不是破壞者,是一陣風 :不只是排斥,而是讓粒子沿著滑鼠移動方向飄
AI 资讯
I switched 23 sites from JPEG to WebP/AVIF last month — here's what I learned
I spent last month migrating 23 client sites from JPEG/PNG to WebP and AVIF. Here's what I wish someone told me before I started. AVIF vs WebP: the real numbers AVIF is about 30% smaller than WebP at the same quality level. But Safari support is still patchy — if your traffic is 40%+ iOS, you need <picture> tags with WebP fallback. No way around it. The biggest win wasn't the format The single biggest reduction came from capping max image width at 1200px and setting quality to 80. One site went from 9.4MB to 318KB per page — a 97% reduction — just from those two settings plus lazy loading. The format switch was the cherry on top, not the cake. Tools I used daily SmartImgKit — quick batch conversions in the browser. No uploads, no signup, drag and drop. Handles the 80% case where you don't need a CLI pipeline. Supports JPG, PNG, WebP, AVIF, GIF, BMP, TIFF. ImageMagick — server-side batch jobs for when you need automation. Squoosh — one-off fine-tuning with visual comparison. Sharp (Node.js) — build pipeline integration. The HEIC surprise Every iPhone user's photos are HEIC. Most web tools crash on them. You need a converter that handles them before the pipeline — SmartImgKit's HEIC converter works locally in-browser, no uploads. The 80/20 rule Format + max width + lazy loading = 80% of the gain. Everything else is diminishing returns. Don't over-engineer it.
AI 资讯
Update on Zen — we now have a package ecosystem
A few weeks back I shared some early Zen code examples. Since then, a lot has changed. We're now at v1.1.1 and the language actually has real tooling. What's new: Full CLI with package management zen publish - publish packages directly from CLI zen install - install packages from the registry zen list - browse all published packages with pagination Language improvements Struct support with literals and returns Regex with POSIX ERE ( matchRegex ) File I/O with binary support FFI bindings to C functions 162 stdlib functions across math, strings, fs, os, http, crypto, path utilities Package Registry (v1.0.0) JWT-based authentication GitHub-hosted packages Support for both runnable apps and libraries Semantic versioning The reactive variables concept from the first post is still there (that was my favorite feature), and now you can actually write real programs and share them with the community. Full docs: https://jishith-dev.github.io/zen-doc/site/ Install: curl -fsSL https://raw.githubusercontent.com/jishith-dev/Zen/main/install.sh | bash Next up: HTTP server APIs, better imports, and whatever the community asks for. Open to feedback and collaborators 💻 ✨ zen #programming #compiler #llvm #packagemanager #opensource #programminglanguage
AI 资讯
Set per-customer send quotas with agent policies
Most multi-tenant email-agent setups give every customer the same caps. Your free-tier user who signed up an hour ago and your enterprise account doing thousands of sends a day hit the exact same daily send limit, the exact same storage ceiling, the exact same retention window. That's fine right up until a free trial account starts hammering your infrastructure, or an enterprise customer files a ticket because their agent stopped sending at noon UTC and nobody can explain why. Free-tier and enterprise tenants shouldn't share the same caps. They have different risk profiles, different contractual obligations, and different billing. The trick is to make the quota a property of the tier, not a property of each individual account — so when you provision a new tenant you don't compute limits, you just drop them into the right bucket and the limits come along for free. With Nylas Agent Accounts that bucket is a workspace , and the caps live on a policy you attach to it. Set up one policy per tier, attach each to its tier's workspace, and every Agent Account in that workspace inherits the policy's send, storage, and retention limits automatically. No per-account configuration, no drift. I work on the Nylas CLI, so the terminal commands below are the exact ones I reach for when I'm wiring this up. As always, I'll show both the raw HTTP call and the CLI equivalent for every step, because half of you live in scripts and the other half live in your app code. What you actually get An Agent Account is just a Nylas grant with a grant_id — a managed mailbox that can send and receive on a domain you've registered. Everything grant-scoped works against it: Messages, Drafts, Threads, Folders, the lot. There's nothing new to learn on the data plane. A policy is a reusable bundle of limits and spam settings. One policy can govern many accounts. The limits we care about for tiering are: limit_count_daily_email_sent — how many messages an account can send per day. limit_storage_total — t
开发者
I Built a Unit Converter in Pure Vanilla JS — 7 Categories, 70+ Units, 165 Tests, Zero Dependencies
Unit converters are everywhere online, but they all seem to either require an account, run ads that cover half the screen, or send your input to a server for no reason. I built one that runs entirely in your browser, with no dependencies, no tracking, and no round-trips. 👉 https://unit-converter-dev.pages.dev What It Does Seven conversion categories, 70+ units, real-time bidirectional conversion: Category Example units Length mm, cm, m, km, in, ft, yd, mi, nmi, light-year Weight mg, g, kg, t, oz, lb, st, short ton Temperature °C, °F, K, °R Volume ml, l, m³, fl oz, cup, pint, quart, gallon, tbsp, tsp Area mm², cm², m², km², ha, acre, ft², in², mi², yd² Speed m/s, km/h, mph, ft/s, knot, Mach Data bit, byte, KB/KiB, MB/MiB, GB/GiB, TB — both SI and binary Features: Bidirectional — type in either field, the other updates instantly Swap button — flip from/to with one click All-units panel — see your input converted to every unit in the category simultaneously Formula display — shows the conversion factor (e.g. "1 Mile = 1.609344 Kilometer") Zero dependencies — single HTML file, no build step, no npm Implementation Notes Linear vs. non-linear conversions Most unit conversions are linear: multiply by a factor to get to the base unit, divide by another factor to get to the target. The approach: function convert ( catKey , fromUnit , toUnit , value ) { const base = toBase ( catKey , fromUnit , value ); // → base unit return fromBase ( catKey , toUnit , base ); // base unit → target } function toBase ( catKey , unit , value ) { const u = CATEGORIES [ catKey ]. units [ unit ]; if ( u . toBase ) return u . toBase ( value ); // non-linear (temperature) return value * u . factor ; } Temperature is the classic non-linear case. You can't just multiply to convert between Celsius, Fahrenheit, and Kelvin — you need offset arithmetic: temperature : { units : { C : { toBase : v => v + 273.15 , // °C → K fromBase : v => v - 273.15 , // K → °C }, F : { toBase : v => ( v - 32 ) * 5 / 9 + 2
AI 资讯
Perl PAGI Middleware
Middleware in PAGI A port of the sample app from What Is Middleware? — which builds the same three-layer stack in Plack/PSGI (Perl) and Starlette/ASGI (Python) — to PAGI , an async, ASGI-style application interface for Perl. The app is deliberately tiny but exercises the three things middleware exists to do: Logger — wrap the request, time it, log method/path in and status/duration out. Authenticator — inspect a header, inject context for downstream layers on success, or short-circuit with a 401 on failure. ProfileRouter — answer one specific route from inside the stack, reading the context the Authenticator injected. All code below was run under perl-5.40.0 with PAGI::Test::Client ; the log lines and responses shown in Running it are the actual captured output, not hand-written. The PAGI middleware contract A PAGI application is, in the spec's words, "a single coderef returning a Future": an async sub over the ($scope, $receive, $send) triple — the same shape as ASGI. $scope is the per-connection metadata hash ( type , method , path , headers , …), $receive pulls inbound events, $send pushes outbound ones ( http.response.start , then http.response.body ), and the Future it returns resolving is what tells the server the response is complete. Middleware is just as plain: a subroutine that takes an application and returns a new application, wrapping the inner one. That is the whole spec-level contract — app in, app out: sub middleware { my ( $app ) = @_ ; return async sub ($scope, $receive, $send) { # ... before ... await $app -> ( $scope , $receive , $send ); # call the inner app # ... after ... }; } A middleware propagates the inner app's Future — its completion and any exception flow straight through — and never reads its return value, which the spec defines as inert; to observe or rewrite the response it wraps $send instead, and to add per-request context it clones $scope (top-level edits stay visible downward only). PAGI::Middleware , from PAGI-Tools rather than
AI 资讯
MotionKit Figma Motion: import, sync, and push native animation (yes, even baked physics)
Figma shipped native Motion. A real animation timeline, right inside the file. When that landed, a lot of people emailed me some version of the same question: "is MotionKit dead now?" Fair question. My honest first reaction was a quiet "...maybe." But the more I used native Motion, the clearer it got — it's genuinely good, and it's not trying to be everything. No physics. No frame-by-frame. No Lottie export. No morphing. So the move was never to compete with it. The move was to bridge to it — let the two tools hand work back and forth, and let MotionKit be the power layer that does the stuff native Motion can't. So that's what this update is. A two-way bridge between MotionKit and Figma's native Motion. Here's everything it does, and exactly how to use it. The short version Four moves, one little control in the header: Import native Motion into MotionKit as real, editable keyframes Live sync (read-only by default) so changes in Figma Motion flow into MotionKit as you work Link for export so your native Motion renders inside a Lottie without duplicating anything Push MotionKit keyframes back into native Motion — including motion you baked from the physics engine And the headline trick: bake a real physics drop in MotionKit, then push it into Figma Motion as native keyframes. Native Motion has no physics engine. Now it kind of does. First, find the bridge Look at the top-right of the toolbar, next to the Pro star. There's a small badge: the MotionKit diamond, an arrow, and the Figma logo . That little arrow is the status. You don't have to open anything to read it: faint dotted line → not connected arrow pointing into MotionKit → reading from Figma, live, read-only arrows on both ends → two-way, MotionKit also writes back If there's native Motion sitting on the current frame but you haven't connected, you'll see a small purple dot on the Figma side — that's "hey, there's something here to import." Click the badge to open the bridge. That's the whole mental model. Dire
AI 资讯
I Built an AI Tool That Emails Hiring Managers Instead of Clicking "Easy Apply"
Most job search tools focus on submitting more applications. I wanted to solve a different problem: reaching the people actually making hiring decisions. So I built PitchHired , an AI-powered platform that helps job seekers find hiring managers, generate personalized outreach emails, review them with AI, and send them from their own Gmail account on a business-hours schedule. The goal isn't to replace the job search, it's to remove repetitive work while keeping the candidate in control. I also chose a one-time credit model instead of monthly subscriptions because job seekers shouldn't have to keep paying while they're between opportunities. PitchHired is still evolving, and I'd genuinely appreciate feedback from fellow developers. What features would you want in a tool like this, and what would make you trust (or not trust) AI-assisted job search?