AI 资讯
How I Built a Developer Knowledge Base in Obsidian That I Actually Use
Every developer I know has the same problem: knowledge scattered across five places at once. Browser bookmarks they never re-read. Notion docs that become graveyards. Slack threads with critical context that disappear into the archive. README files that contradict each other. Stack Overflow answers bookmarked with zero recall of why. I tried most of the "second brain" setups and none of them stuck until I figured out why they kept failing: generic productivity systems are not built for how developers actually think and work. A developer's knowledge is fundamentally different from a writer's or a manager's. It is: Code-linked (a note about a library is useless without the actual code it explains) Decision-heavy (architecture decisions need context, rationale, and alternatives considered) Debugging-intensive (solutions to bugs need the exact error message, environment, and what you tried) Time-sensitive (that API migration note is only relevant for a 3-month window) Here is the structure that actually worked. The Core Structure 00-Inbox/ 10-Projects/ 20-Areas/ - Language: Python/ - Stack: AWS/ - Domain: Auth/ 30-Resources/ - Libraries/ - Tools/ - Patterns/ 40-Archive/ The key insight: Resources are evergreen, Projects are temporary, Areas are ongoing responsibilities. A note about how JWT works lives in 30-Resources/Domain-Auth/ . A note about implementing JWT for the current sprint lives in 10-Projects/Sprint-42-Auth-Revamp/ . When the sprint is done, the project gets archived. The JWT fundamentals note stays forever. The Templates That Made It Click Architecture Decision Record (ADR) # ADR-042: Use Postgres over DynamoDB for user sessions Status: Accepted | Date: 2026-06-22 ## Context We need session storage that supports complex queries for the audit log feature. ## Decision Postgres with connection pooling via PgBouncer. ## Alternatives Considered - DynamoDB: rejected (query limitations for audit log requirements) - Redis: rejected (not durable enough for complian
AI 资讯
Optimizing Django ORM Queries: A Practical Guide to select_related and prefetch_related
1. Introduction Django's ORM is one of its greatest strengths. It abstracts away raw SQL, lets you express database operations in clean Python, and gets you productive fast. But that convenience comes with a hidden cost: if you're not deliberate about how you fetch related objects, you'll silently generate far more queries than you intend — and you won't notice until your app slows to a crawl in production. The most common culprit is the N+1 query problem : a pattern where fetching a list of N objects triggers an additional query for each one, resulting in N+1 total round-trips to the database. At ten rows it's invisible. At ten thousand rows, it's a disaster. Django provides two tools to fix this: select_related and prefetch_related . This article explains how each one works internally, when to use which, and how to combine them effectively — with before/after examples and real query counts throughout. 2. Understanding the N+1 Problem Consider a simple blog with posts and authors. You want to render a list of posts, showing each post's title and its author's name. Models: # models.py from django.db import models class Author ( models . Model ): name : str = models . CharField ( max_length = 100 ) class Post ( models . Model ): title : " str = models.CharField(max_length=200) " author : Author = models . ForeignKey ( Author , on_delete = models . CASCADE , related_name = " posts " , ) The naive approach: # views.py from django.db import connection from .models import Post def list_posts () -> None : posts = Post . objects . all () # Query 1: fetch all posts for post in posts : print ( f " { post . title } by { post . author . name } " ) # ^^^ Query 2, 3, 4, ... N+1: one per post For 100 posts, this produces 101 queries . Django lazily fetches post.author the first time you access it on each object. Each access hits the database separately. You can verify this with django.db.connection.queries (requires DEBUG = True ): from django.db import connection , reset_queries
AI 资讯
Stop Pasting Sensitive Data into Random Websites: Meet Parsify 🛡️
Hey DEV community! 👋 How many times a day do you need to format a messy JSON string, convert a CSV file, or parse a timestamp? And how many times do you find yourself pasting that data—which might contain API keys, user emails, or proprietary code—into a random website you found on Google? We’ve all done it, but in an era of constant data leaks, it’s a massive security risk. That’s exactly why I built Parsify . What is Parsify? Parsify is an all-in-one data converter and developer toolset designed to handle your daily formatting, parsing, and data manipulation tasks completely offline and client-side. No servers, no tracking, and absolutely no data leaks. Everything happens right inside your browser sandbox. 🚀 Key Features 100% Secure & Offline: Your data never leaves your local machine. Once the page loads, you can literally pull your internet plug and it will still work perfectly. All-in-One Toolkit: No more bookmarking ten different sites for ten different tasks. From JSON formatting and base64 encoding to data conversions, it’s all under one roof. Built for Speed: A clean, lightning-fast UI with batch-processing support to keep your workflow uninterrupted. Privacy by Design: Zero tracking scripts, zero ads, and zero database logging. Why I Built It Most online utilities are bloated with tracking pixels, pop-up ads, and cookies. Worse, you have no idea what happens to the data you paste into their input fields. As a developer, I wanted a tool that felt like a local desktop app but possessed the accessibility of a web app. Parsify is the bridge. It gives you the convenience of a web utility with the strict security boundaries of local execution. Check It Out (It's Free!) If you’re tired of compromising on data privacy for quick utilities, give it a spin: 👉 parsify.tools I’m actively working on adding more tools and converters to the suite. I would absolutely love to get the DEV community's feedback! What converters or formatting utilities do you use daily that you
AI 资讯
Sync and manage contacts across providers: Nylas Contacts API
Contacts are messier than they look. A user's real address book is spread across the people they've saved by hand, the people they've emailed often enough that the provider auto-collected them, and the colleagues in their company directory. Google exposes these through the People API; Microsoft through Graph; both model the data differently and split it across sources you have to query separately. The Nylas Contacts API unifies all of that behind one schema and one grant_id . You read saved contacts, auto-collected contacts, and directory contacts through the same endpoint, create and update entries that sync back to the provider, and organize them into groups. This post walks the contact surface from the HTTP API and the Nylas CLI , which mirrors every operation for terminal use. I work on the CLI, so the terminal commands below are the ones I run when I'm exploring an address book. The contact model and its three sources A contact in Nylas carries the fields you'd expect — given_name , surname , emails , phone_numbers , company_name , job_title , notes — plus richer ones like im_addresses , physical_addresses , and web_pages . The schema is the same across providers, so a Google contact and a Microsoft contact deserialize into one struct. The detail that trips people up is source . Every contact has one of three sources, and they mean very different things: address_book — contacts the user saved deliberately. This is the real address book. inbox — contacts the provider auto-collected because the user emailed them. These were never explicitly saved. domain — contacts from the organization's directory (coworkers). Knowing the source matters because "all contacts" usually isn't what you want. If you're building a contact picker, the inbox source can flood it with one-off recipients the user doesn't think of as contacts. Filter by source deliberately. See the Contacts API overview for the full data model. Before you begin You need a Nylas API key and a connected accou
AI 资讯
Record and transcribe meetings with the Nylas Notetaker API
Meeting notes are the feature everyone wants and nobody wants to build. The hard part isn't the summary — an LLM handles that. The hard part is getting into the meeting: a bot that joins Zoom, Google Meet, and Microsoft Teams, survives each platform's waiting room and admission flow, records cleanly, and produces a transcript you can feed downstream. Each provider has its own join mechanics, and none of them ships a tidy "record this meeting" API. The Nylas Notetaker API is that bot as a service. You point it at a meeting link, it joins on schedule, records, and generates a transcript, and you fetch the recording and transcript through one endpoint. This post walks the Notetaker surface from the HTTP API and the Nylas CLI , which mirrors the whole lifecycle for terminal use and quick testing. I work on the CLI, so the terminal commands below are exactly what I run when I'm testing a notetaker against a live meeting. Two ways to run a notetaker: grant-scoped or standalone Before any code, there's one architectural choice worth understanding, because it changes the endpoint you call. A grant-scoped notetaker is tied to a connected account and lives under /v3/grants/{grant_id}/notetakers . Use it when the bot acts on behalf of a specific user — it can read that user's calendar and join their meetings as them. A standalone notetaker has no grant at all and lives under /v3/notetakers . You hand it a raw meeting link and it joins, no connected account required. This is the one to reach for when you just have a URL and want a recording — a public webinar, a meeting on an account you haven't connected, or a system that deals in links rather than users. Same request body, same lifecycle, same media output; the only difference is whether there's a grant_id in the path. See the Notetaker overview for how both models fit together. Before you begin You need a Nylas API key. If you're using a grant-scoped notetaker you also need a connected account; for standalone, the API key al
AI 资讯
Stop polling: real-time email and calendar webhooks with Nylas
If your integration polls Nylas every minute to check for new email, you're doing too much work and still getting stale data. Polling is a tax: you burn rate limit on requests that mostly return nothing, and a message that arrives at 12:00:05 doesn't reach your app until the next poll. Webhooks flip that around. Nylas pushes a notification to your endpoint the moment something happens — a message arrives, an event changes, a contact is created — and your app reacts in real time. This post walks the webhook surface from both sides: the HTTP API that registers and manages webhooks, and the Nylas CLI , which has genuinely useful tooling for the part everyone gets stuck on — verifying signatures and testing webhooks against local code. I work on the CLI, so the terminal commands below are the ones I run when I'm wiring up a webhook receiver. Triggers and destinations A webhook has two halves: the trigger types it listens for and the destination URL it pushes to. Trigger types are dotted event names like message.created , event.updated , and contact.created , grouped into categories — grant, message, thread, event, contact, calendar, folder, and notetaker. You subscribe one destination to as many triggers as you want. The CLI lists every available trigger so you don't have to guess the names: # All trigger types nylas webhook triggers # Only message-related triggers nylas webhook triggers --category message Webhooks are application-scoped, not grant-scoped: one webhook registered on your application receives notifications for every connected account, identified by the grant_id in each payload. See the notifications overview for the full event model. Before you begin You need a Nylas API key — webhook management is admin-level, so it uses the application's API key rather than a grant. You also need an HTTPS endpoint reachable from the public internet to receive the notifications. The CLI gets the key set up: nylas init # create an account, generate an API key For local de
AI 资讯
One calendar API for Google, Microsoft, and beyond: Nylas Calendar
Scheduling features look simple until you build them. Google Calendar speaks its own REST API with events.insert ; Microsoft 365 wants Graph and POST /me/calendar/events ; Apple and a long tail of providers expect CalDAV. The moment your app needs to read a user's events, drop a meeting on their calendar, or check whether three people are free at 2pm, you're staring down three integrations that disagree on field names, time formats, and recurrence rules. The Nylas Calendar API gives you one interface over all of them. Connect a user's account once, get a grant_id , and read calendars, manage events, send RSVPs, and compute free/busy with the same request shape whether the backing provider is Google or Microsoft. This post walks the calendar surface from both sides: the HTTP API your backend calls, and the Nylas CLI for testing the same operations in a terminal. I work on the CLI, so the terminal snippets below are the commands I actually run when I'm poking at a calendar. Calendars, events, and the calendar_id A connected account has one or more calendars , and every event belongs to exactly one of them. Most operations take a calendar_id , and the special value primary resolves to the account's default calendar — so you don't need to look up an ID to act on the main calendar. One exception: iCloud doesn't support primary , so for iCloud accounts you pass a real calendar ID from nylas calendar list . An event carries a title , a when object holding its start and end times, a list of participants , an optional location , and flags like busy . That schema is identical across providers, which is the whole point: you read a Google event and a Microsoft event into the same struct. See the Calendar API overview for how calendars, events, and availability fit together. Before you begin You need a Nylas API key and a connected account with calendar scopes. The CLI gets you there in two commands: nylas init # create an account, generate an API key nylas auth login # connect
AI 资讯
Building a real-time desktop AI copilot for calls: the hard parts
Half a year ago I asked a simple question: during an online call, could a short, to-the-point hint appear on my screen in a second or two — while the other person is still talking? Not an after-the-fact transcript, but help in the moment. The result is a desktop assistant (macOS + Windows). Below is an honest breakdown of what turned out to be hard, and which solutions worked. Engineering only, no marketing. Architecture in one paragraph On the device there are only two things: audio capture and a thin UI overlay. All the "brains" (provider keys, prompts, model selection) live on the server. The client gets a short-lived per-session token and streams audio; the server returns the transcript and the generated answer. I picked this split not for "security theater" but because otherwise keys and prompts would have to be baked into the binary — and both leak instantly. Hard part #1: system audio, not the microphone The mic only captures you. You need the other party's audio — i.e. the system output. And that's where the platform pain starts: macOS. For a long time there was no native "give me system audio" API; the classic path was a virtual audio device (BlackHole/Soundflower-style) or, in recent versions, ScreenCaptureKit, which can hand you a process's audio. ScreenCaptureKit turned out to be the best option: no kernel extensions for the user to install. Windows. WASAPI loopback saves you — you can grab whatever is going to the output device, without virtual cables. Takeaway: "system audio capture" is not one feature but two different subsystems for two OSes, and most of the early bugs were about permissions and device selection, not about audio itself. Hard part #2: latency is everything A hint that arrives 6 seconds late is useless — the conversation has already moved on. The latency budget has three parts: STT (speech → text). Streaming only. Batch "recognize after the phrase ends" immediately adds 1–2 seconds. The key metrics weren't "overall accuracy on a benchm
AI 资讯
Kinde Is Missing from Mastra's Auth Lineup, So I Built the Provider
If you're building a SaaS AI agent product and you're already on Kinde, you already know the problem. Mastra is the TypeScript-first AI agent framework. It ships with official auth providers for Clerk, Auth0, Supabase, Firebase, WorkOS, and Better Auth. Kinde is not on that list. The obvious question is why not reach for one of those providers, since Auth0 is already there. Most developers who choose Kinde rely on far more than its login. Kinde ships with the organizational structures, permission systems, and monetization tools that products actually need, bringing auth, billing, feature flags, and multi-tenancy together in one platform. If you're building a B2B SaaS product on Kinde, you're using Kinde orgs to segment your customers, Kinde billing to manage subscriptions, and Kinde feature flags to gate features by plan. Switching to Auth0 or Clerk to support a Mastra agent would mean rebuilding all of that elsewhere, which is not a real option. That gap is the problem. You need Kinde to work with Mastra, and until now there was no clean way to connect them. That's why I built mastra-auth-kinde . What Mastra's auth system actually does When you add an auth provider to Mastra, it protects two things at once: all your API routes ( /api/agents/* , /api/workflows/* , and so on) and your Mastra Studio UI. Every request to a protected route goes through your provider before it reaches anything else. You extend Mastra's MastraAuthProvider base class and implement two methods: authenticateToken(token, request) verifies the JWT and returns the decoded user, or null if it fails authorizeUser(user, request) returns true to let the request through, or false for a 403 Mastra handles everything else: extracting the Bearer token from the Authorization header, calling your methods in order, and storing the verified user in the request context so your agents and tools can access it. Why Kinde specifically Beyond the billing and org story above, a few things make Kinde the right fit
AI 资讯
Building Margin: A Privacy-First News Reader Inside Chrome's Side Panel
I built a Chrome extension called Margin — a news reader that lives in the browser's side panel and shows one bite-sized story at a time, instead of an infinite-scroll feed. This is a build log: the decisions, the constraints that pushed back, and a couple of things I had to solve in slightly unusual ways. Why the side panel Chrome shipped chrome.sidePanel in MV3 a while back and most uses I saw were utility tools — note-taking, translation helpers. Nobody was using it for content consumption. News felt like a good fit: a side panel that stays open next to whatever you're working on, where you tap through headlines in a couple of minutes without leaving the page. The reading model is intentionally narrow: one card, one headline, one short summary, tap to read the full article at the source . No infinite scroll, no algorithmic feed. If you've used InShorts, the shape will be familiar. The stack Preact + Vite + @crxjs/vite-plugin . Preact because the side panel is a small UI surface and I didn't want React's weight for what's essentially a card stack and a settings screen. @crxjs/vite-plugin handles the MV3-specific build wiring (manifest generation, service worker loader, HMR for the extension context) that would otherwise be a lot of manual plumbing. The constraint that shaped onboarding chrome.sidePanel.open() requires a user gesture . You cannot call it from a background service worker on install — Chrome will throw. That one constraint shaped the whole first-run experience. My first instinct was "just auto-open the panel on install so people see it immediately." Doesn't work. The fix ended up being two-pronged: On chrome.runtime.onInstalled with reason === 'install' , open a real browser tab with a short walkthrough (find the icon → pin it → open the panel). The button on that page calls sidePanel.open() — valid, because the click is the gesture. The first time the panel itself is opened, show an in-panel welcome screen before onboarding, nudging the user to pin
AI 资讯
Give your AI agent its own inbox: Nylas Agent Accounts via API and CLI
Most "AI email" demos point a model at a human's inbox over OAuth. That's fine until you want the agent to be a participant — to have its own address that people reply to, that calendars invite, and that builds its own sender reputation. Pointing at someone's personal inbox doesn't give you that. Nylas Agent Accounts take the other approach: a real name@yourdomain.com mailbox and calendar that the agent owns end to end. It sends, receives, hosts events, and RSVPs — and to anyone on the other side it's indistinguishable from a human-operated account. It went GA in June 2026. The part I like as an SRE: it's not a new API surface. An Agent Account is just another Nylas grant . It gets a grant_id that works with every endpoint you already use — Messages, Drafts, Threads, Folders, Attachments, Calendars, Events, Webhooks. Nothing new to learn on the data plane. This walkthrough provisions one two ways (CLI and raw API), then sends, receives, RSVPs, and adds guardrails. What you get When you create an Agent Account, Nylas provisions a real mailbox on a domain you've registered (or a Nylas *.nylas.email trial domain). Each account comes with: An email address that sends and receives like any other mailbox Six system folders ( inbox , sent , drafts , trash , junk , archive ), plus any custom ones you create A primary calendar that hosts events and RSVPs over standard iCalendar/ICS A grant_id for all the existing Nylas endpoints Before you begin You need two things: A Nylas API key. The fastest path is the CLI — nylas init creates an account and generates a key in one command. A domain. Either a Nylas-provided *.nylas.email trial subdomain (good for testing in minutes) or your own custom domain with MX + TXT records. Register it under Organization Settings → Domains. Why your own domain? It's what makes the agent a real first-class sender instead of a shared relay address — people reply to it, calendars invite it, and its mail authenticates as coming from you. A new domain b
AI 资讯
BITCOIN HACKATHON
After a full week of intensive Bitcoin programming training, the developers at Zone01 Kisumu moved into the most exciting phase of the bootcamp: building real-world solutions powered by Bitcoin, the Lightning Network, and LND. One thing I learned throughout the experience is that the human mind is truly fascinating. The room was filled with innovative ideas, each attempting to solve a different problem. As the saying goes, no idea is a bad idea—every concept had the potential to make an impact. A total of 17 teams were formed, and each team embarked on a 24-hour hackathon journey to transform their ideas into working products. After an intense day of development came the presentation phase, where we had the privilege of showcasing what we had built. Our team developed Kasi , a WhatsApp chatbot that enables Bitcoin transactions directly through WhatsApp. The goal was to make Bitcoin payments more accessible by leveraging a platform that millions of people already use daily. To build Kasi, we integrated the Twilio API for WhatsApp communication and utilized the Bitnob platform to facilitate Bitcoin transactions. Python was used throughout the development process. The project was brought to life by six developers: Claire, Lamka, Ijay, Dishon, Talo, and myself. Beyond the technical implementation, the hackathon strengthened our understanding of collaborative software development. We practiced Git workflows, team coordination, version control, task management, and effective communication under tight deadlines—skills that are just as valuable as writing code. Although we did not finish at the top of the leaderboard, the experience was incredibly rewarding. Every team brought something unique to the table, and the winners fully deserved their recognition. Congratulations to all the teams that participated and showcased their creativity, determination, and technical skills. One moment from the presentation will stay with me for a long time. As we were demonstrating Kasi to
AI 资讯
Precision Loss and Rounding Exploits in Financial Smart Contracts
A smart contract does not need an overflow, reentrancy bug, or broken access-control check to lose money. Sometimes, the exploit is hidden inside an ordinary division: uint256 result = amount * rate / SCALE; The expression looks harmless. It may even produce the expected answer in every unit test. But financial smart contracts operate with integer arithmetic. Fractions are discarded, rounding direction changes who receives value, and an error of one unit can be repeated across thousands of transactions. In a financial protocol, rounding is not merely a mathematical implementation detail. Rounding is a value-transfer policy. Every division should therefore answer three questions: Which direction does the calculation round? Which party benefits from that direction? Can the rounding advantage be repeated or amplified? This article examines the most dangerous precision problems in Solidity and the engineering patterns used to prevent them. Solidity Does Not Have Native Fixed-Point Arithmetic Most financial formulas use fractions: interest = principal × rate × time fee = amount × fee percentage shares = assets × total shares ÷ total assets collateral value = token amount × oracle price Solidity primarily performs these calculations with integers. For unsigned integers: uint256 result = 5 / 2; The result is: 2 The fractional component is discarded. For positive values, this behaves like rounding down: 2.5 → 2 This appears insignificant until the result represents: vault shares; debt; collateral; protocol fees; interest; rewards; liquidation bonuses; exchange rates; token prices. The lost fraction does not disappear economically. One party receives less value, while another party retains the remainder. Precision Loss Is Not Always Small Consider a protocol calculating a percentage: function calculateFee( uint256 amount, uint256 feeBps ) public pure returns (uint256) { return amount * feeBps / 10_000; } For a 0.3% fee: amount = 100 feeBps = 30 fee = 100 × 30 ÷ 10,000 fee =
AI 资讯
The Imitation Game: Most people think they can spot an AI. Are you sure?
This is a submission for the June Solstice Game Jam What I Built The Imitation Game The Imitation Game is a real-time multiplayer social deduction game inspired by Alan Turing's famous Imitation Game the thought experiment that eventually became known as the Turing Test. Most people believe they can easily tell the difference between an AI and a human. They assume AI is too perfect, too logical, too fast, or too obvious. The Imitation Game challenges that assumption. Players enter a live chat room convinced they'll spot the machine within minutes. Then conversations begin, suspicions form, accusations fly, and certainty starts to disappear. Was that awkward response written by a human, or an AI trying to sound human? Was that emotional story genuine, or generated? Was the player who stayed silent suspicious, or simply distracted? By the end of a match, players often discover that identifying an AI is far harder than they expected. The real question isn't whether the machine can fool people. It's whether people are as good at detecting machines as they think they are. Instead of a single human interrogating a machine, players are placed into a live chat room with other participants and asked a simple question: Can you identify which player is actually an AI? Hidden among the players is a Quanbit , a rogue artificial intelligence from the year 3026 . Its mission is simple: blend in, appear human, avoid suspicion, and survive. The challenge for human players is equally simple, but far more difficult in practice. They must carefully analyze conversations, voting patterns, response timing, and social behavior to determine who among them is secretly the machine. The game currently features two distinct modes, each designed around a different style of deception. Eyefold Eyefold is the purest form of the game's Turing Test experience. Players enter a room where one participant is secretly a Quanbit. Conversations unfold naturally, and everyone is free to discuss any topic.
开源项目
Setting up socket.io
This article covers what I learned or maybe didn't really learn. The Problem With Traditional HTTP Most web applications use HTTP. The flow looks like this: Client → Request → Server Client ← Response ← Server Once the server sends the response, the connection is closed. This works perfectly for: Authentication CRUD operations Fetching data Form submissions But what happens when the server needs to send information without being asked? For example: A new task is assigned Someone comments on a task A project status changes A teammate updates a board With traditional HTTP, the browser would need to keep asking: "Anything new?" "Anything new?" "Anything new?" This technique is called polling, and it's inefficient. That's where Socket.io comes in. What Socket.io Actually Does Socket.io creates a persistent connection between the client and server. Instead of repeatedly opening and closing connections, the connection stays alive. Now communication becomes two-way: Client ↔ Server The client can send data whenever it wants. The server can also send data whenever it wants. This is what makes real-time applications possible. Why Express Alone Isn't Enough One thing that confused me initially was why Socket.io couldn't simply be attached directly to my Express app. The answer lies in how Express works. When you write: app . listen ( 5000 ); Express creates the HTTP server internally. You don't have direct access to it. Socket.io, however, needs access to the raw HTTP server. So instead of: app . listen ( PORT ); The flow becomes: const httpServer = createServer ( app ); Then Socket.io attaches to that server: const io = new Server ( httpServer ); Finally: httpServer . listen ( PORT ); This architecture allows Socket.io and Express to share the same server. Understanding Events Socket.io is event-driven. Everything revolves around two methods: socket . emit () and socket . on () Think of them as: emit = send on = listen For example: Client: socket . emit ( " join-project " ,
开发者
bcrypt and Laravel: 72 Bytes, Not 72 Characters
I expected bcrypt to silently drop characters past 72. I did not expect it to bake in half an emoji. That's what happens with a specific password combination I tested. The original password still works. But strip the emoji (a password manager, a different keyboard, a Unicode normalizer) and you're locked out. Your Laravel validator passed it as valid the whole time. The 72-Byte Rule bcrypt has a hard input limit of 72 bytes. Not characters - bytes. When you call password_hash($password, PASSWORD_BCRYPT) , PHP silently truncates anything past byte 72. Most developers know this in theory. But for ASCII-only apps, it never bites. 72 ASCII characters is already a very long password, and the silent clip is harmless in practice. The trouble starts with multi-byte scripts. How Many Characters Fit? Character set Bytes per char Effective bcrypt limit ASCII 1 72 chars Cyrillic 2 36 chars CJK (Chinese, Japanese, Korean, common block) 3 24 chars Emoji 4 18 chars Past the byte limit, a longer password adds no security at all. A 200-character Cyrillic password hashes identically to its own first 36 characters. Byte 73 and beyond simply do not exist from bcrypt's point of view. So "longer always produces a stronger bcrypt hash" is not true. A Cyrillic user with a 37-character password gets silently truncated at char 36. The hash is still consistent. The user logs in fine, but any variation past character 36 doesn't matter to bcrypt. Annoying from a security standpoint, but it does not break login. The Split-Byte Trap The 72-byte limit cuts at a byte boundary, not a character boundary. If a multi-byte character falls on that cut, bcrypt bakes in an incomplete UTF-8 sequence. // 35 Cyrillic chars = 70 bytes, emoji = 4 bytes, total = 74 bytes $password = str_repeat ( 'А' , 35 ) . '🔑' ; $hash = password_hash ( $password , PASSWORD_BCRYPT ); password_verify ( $password , $hash ); // ? password_verify ( str_repeat ( 'А' , 35 ), $hash ); // ? password_verify ( str_repeat ( 'А' , 36 ), $h
AI 资讯
5 Cookie Tricks for Debugging Auth Issues in Chrome (No More Creating Test Accounts)
Debugging authentication in web apps is painful. You need to test the same flow as five different user types — new visitor, returning user, admin, expired session, logged-out — and the easiest way is to constantly create new accounts or clear all your cookies and start over. There's a faster way. These five techniques use direct cookie manipulation to simulate any auth state without touching your database or creating dummy accounts. I use CookieJar for most of this — a free Chrome extension built natively on MV3 that gives you a proper UI for cookie editing. But I'll show you the underlying Chrome DevTools method too, so you understand what's actually happening. 1. Simulate a Logged-Out State Without Clearing Everything The naive approach: clear all cookies and reload. The problem: you just nuked your dev server session token, your local storage flags, your Stripe test mode cookie, and everything else you carefully set up. The targeted approach : identify and delete only the session/auth cookie. Most session cookies are named session , sid , auth_token , _session_id , or something close. In DevTools: Application → Cookies → [your domain] → find the session cookie → right-click → Delete With CookieJar: open the extension, search session , click the trash icon next to just that cookie. Your dev environment stays intact. The user state resets to logged-out. 2. Test the "Returning User" vs "New User" Path Without a Second Account Session cookies tell the server you're authenticated. But many apps use separate cookies to track whether a user has seen the onboarding flow, completed setup, or visited before. Look for cookies like onboarding_complete , setup_done , first_visit , or custom flags in your app code. To test the new user experience: Export your current cookies (CookieJar → Export → JSON format, or copy from DevTools) Delete the specific onboarding/first-visit flag cookie Reload and test the new user path Re-import or re-set the cookie to restore your state This
AI 资讯
Escaping Generative Monoculture in AI-Assisted Engineering
Originally published on Mohamad Alsabbagh's Blog . AI coding assistants are excellent at compressing known work into fast drafts. That speed is the preface boost : routine implementation arrives almost immediately. The hidden risk is that teams begin treating the model's first plausible answer as architecture. Because LLMs are trained and aligned around historically common patterns, they can pull engineering teams toward Generative Monoculture : less diverse solutions, narrower exploration, and fewer designs shaped by the exceptional constraints of the system in front of them. Give the same prompt to three engineers using the same assistant and you often get the same shape back: a tidy service layer, a familiar API boundary, a conventional retry wrapper, and code that looks clean enough to merge. That answer is useful. It may even be the right answer for ordinary work. The danger is what happens when ordinary work becomes the default posture for extraordinary constraints. Large Language Models are not neutral architecture engines. They are probabilistic systems trained over historical work and tuned toward answers people tend to reward. Used well, that makes them extraordinary accelerators. Used passively, it creates an optimization paradox: teams gain immediate implementation velocity while becoming anchored to a consensus baseline that may be too average for the actual system. 1. The Default Is a Local Optimum Wu, Black, and Chandrasekaran define Generative Monoculture as a narrowing of model output diversity relative to the diversity available in the training data. That matters because software architecture is rarely a search for the most common answer. It is a search for the answer that fits the exact failure modes, latency envelope, team topology, regulatory constraints, and operational reality of a system. The model's default is often a local optimum: a solution that is statistically likely, syntactically polished, and broadly acceptable. That can be excellent
开发者
👾 Server Access Logs with GoAccess
Part 1: Self-hosting on Jetson Orin Nano 👽 Jetson Orin Nano Web Server Follow-up...
AI 资讯
I Got Tired of Paying $99/mo for Options Data — So I Built My Own API tags: python, api, finance, showdev
I build algorithmic trading bots as a side project. Nothing fancy — just small strategies that trade US equity options automatically. The problem I kept running into wasn't the strategy logic. It was the data. Every time I wanted to pull real-time options chains, Greeks, or IV, I had two options: Pay $99+/mo to a data provider Scrape something I probably shouldn't be scraping Neither felt right for a hobbyist project. So I built Market-Options — a simple REST API for US equity options data at $20/mo. What It Does It's a plain REST API. No SDK, no special client library — just HTTP requests and JSON responses. It covers four endpoints: chain — full options chain for a given underlying contract — data for a single contract contracts — batch lookup across multiple contracts contract-overview — Greeks, IV, expiration details Coverage is the top 100 US equity underlyings, which accounts for roughly 95% of actual US options volume. If you're building a bot that trades SPY, QQQ, AAPL, TSLA, or anything in that tier — it's covered. Why Only 100 Underlyings? Because that's what most people actually trade. When I looked at my own bots, and at what most retail algo traders focus on, the top 100 covers everything practical. Exotic underlyings with low volume are also harder to get real data on reliably — so rather than promise coverage I can't deliver, I focused on doing the core well. A Simple Example curl "https://api.market-option.com/chain?symbol=SPY&expiration=2025-01-17" \ -H "Authorization: Bearer YOUR_API_KEY" Response is clean JSON: { "symbol" : "SPY" , "expiration" : "2025-01-17" , "options" : [ { "strike" : 480 , "type" : "call" , "bid" : 3.45 , "ask" : 3.50 , "iv" : 0.182 , "delta" : 0.42 , "gamma" : 0.031 , "theta" : -0.18 , "vega" : 0.29 } ] } No parsing headaches, no weird date formats. Pricing Free tier : 1,000 credits/day — enough to test and build Pro : $20/mo, unlimited within fair use Trial : New accounts get 7 days of Pro, no credit card required Who It's F