AI 资讯
Spring Boot For Beginner
🚀 Building a REST API with Java Spring Boot: A Practical Beginner’s Guide If you're coming from Java and want to move into backend development, Spring Boot is one of the best frameworks to learn. It removes a lot of the boilerplate traditionally associated with Spring and makes it surprisingly easy to build production-ready REST APIs. In this article, we'll build a simple Blog REST API using: ☕ Java 🌱 Spring Boot 🌐 Spring Web 🗄️ Spring Data JPA 🐘 PostgreSQL 📦 Maven 🧪 Postman By the end, we'll have an API that can: Create a blog post Get all blog posts Get a post by ID Update a post Delete a post 1. What is Spring Boot? Spring Boot is a framework built on top of the Spring Framework that makes it easier to create Java applications. Without Spring Boot, you often need to configure many things manually. Spring Boot gives us: Auto-configuration Embedded servers Starter dependencies Production-ready features Easy REST API development A simple Spring Boot application can be started with: @SpringBootApplication public class BlogApplication { public static void main ( String [] args ) { SpringApplication . run ( BlogApplication . class , args ); } } That's enough to start our application. 2. Create the Spring Boot Project The easiest way to create a Spring Boot project is through Spring Initializr . Choose: Project: Maven Language: Java Spring Boot: Latest stable version Packaging: Jar Java: 17+ Add these dependencies: Spring Web Spring Data JPA PostgreSQL Driver Validation Lombok Your project structure will look something like: src └── main └── java └── com.example.blog ├── BlogApplication.java ├── controller ├── service ├── repository ├── entity └── dto This separation will become important as our application grows. 3. Create the Blog Entity Let's create a simple BlogPost entity. @Entity @Table ( name = "blog_posts" ) public class BlogPost { @Id @GeneratedValue ( strategy = GenerationType . IDENTITY ) private Long id ; @NotBlank private String title ; @NotBlank @Column (
AI 资讯
Using AI for Job Applications, Honestly
One rule settles nearly every case: a model may help you say what is true about you, and it may not decide what is true about you. Drafting is help. Supplying the content of a claim about your own experience is not. The line, and why it is there An application is a set of representations about a person, made by that person, on which somebody else will rely. That is what makes fabrication in one different in kind from fabrication in an essay: there is a party who acts on it, and there are consequences downstream for colleagues, clients and sometimes patients. So the test is not “did a machine touch this”. It is “does the document assert something the applicant does not know to be true”. A cover letter drafted from your notes and edited by you asserts nothing you did not supply. A cover letter that describes a project you did not run asserts something false regardless of who typed it, and would be equally dishonest written by a friend. Case Description rewriting: fine Rewriting your own bullet points more clearly. Fixing grammar. Translating your industry's jargon into the target industry's. Cutting 900 words to 300. Generating ten possible openings so you can choose one. decoding: fine Asking what a job advert is actually asking for, then checking your own experience against that list yourself. metrics: not fine Letting it fill in achievements, metrics or responsibilities you have not verified. 'Increased conversion by 32%' is a fact about the world; if you do not know the number, it is a fabrication with a number in it. motivation: not fine Any statement of motivation you have not read and would not say out loud. 'I have long admired your work in X' when you have not is a small lie that is very cheap to expose in an interview. assessments: not fine Completing an assessment designed to measure your unaided ability, where the employer has said not to, or where the whole point of the task is the thing you outsourced. What genuinely helps The honest uses are also the ef
AI 资讯
The AI Model Landscape in 2026: who's who and where to start
Let me be upfront about something: this tutorial will age badly. Not the concepts — those hold. But the specific names, the price points, the rankings — the AI model landscape moves fast enough that any comparison table has an expiration date. What's the best model for code today might be second place next quarter. The one that seems expensive now might be the obvious choice by the time you're reading this. That said: the mental model for navigating this landscape doesn't expire. What questions to ask when choosing a model, how API access differs from a subscription, what "context window" actually means on a regular Tuesday — that's stable. With the right map, you can update yourself when things change. And they will. The frontier models: the big three Frontier models are the most capable models at any given moment. In 2026, the competition comes down to three: Claude Sonnet 4.6 (Anthropic) is the model you'll be using throughout this course, and the current benchmark for coding tasks. Together with Opus 4.7, it ships with a 1M token context window at standard pricing — no special headers, no premium plan required. It stands out for sustained reasoning, precise technical writing, and following complex multi-step instructions. Sonnet 4.6 is the speed-quality balance; Opus 4.7 is more powerful but slower and more expensive. GPT-5.4 (OpenAI) — released March 2026 — is the first general-purpose model with native computer use : it can operate desktop interfaces and execute complex workflows across applications. It reaches 1M tokens of context, incorporates the coding capabilities of GPT-5.3-Codex, and comes in multiple variants — Thinking, Pro, mini (free tier), and nano (API-only) — making it the most accessible of the three. Recently, GPT-5.5 has been released, with improvements in speed and reasoning. OpenAI also maintains the Codex family as a separate line: GPT-5.3-Codex is optimized for complex agentic software engineering and leads benchmarks like SWE-Bench Pro; G
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 .
AI 资讯
React useEvent Hook: Stable Callbacks Without Stale Closures (2026)
Every React developer eventually meets the same fork in the road. You write an event handler that reads state, pass it to a child or an effect, and now you must choose: leave it as a plain inline function and watch every render create a new reference — breaking React.memo , re-running effects, re-subscribing listeners — or wrap it in useCallback and start playing dependency-array whack-a-mole, where one forgotten dependency means the handler sees state from three renders ago. That second failure mode has a name — the stale closure — and it's arguably the most common React bug in production code. The fix has a name too: useEvent , proposed in an official React RFC in 2022 , and available today as useEvent in @reactuses/core . It gives you a function whose identity never changes across renders but whose body always sees the latest state and props . Both halves of the fork, no trade-off. This post covers the API, the three-line implementation trick that makes it work, how it compares to useCallback and to React 19.2's built-in useEffectEvent , real patterns, and the one rule you must respect (don't call it during render). TypeScript-first. The Problem in Thirty Seconds Here's the bug factory. A chat component sends a heartbeat with the current draft text: function Composer ({ roomId }: { roomId : string }) { const [ draft , setDraft ] = useState ( '' ); useEffect (() => { const id = setInterval (() => { sendHeartbeat ( roomId , draft ); // ⚠️ which draft? }, 3000 ); return () => clearInterval ( id ); }, [ roomId ]); // draft intentionally omitted — we don't want to reset the timer return < textarea value = { draft } onChange = { e => setDraft ( e . target . value ) } />; } The interval closes over the draft that existed when the effect ran — the empty string. Every heartbeat sends '' forever. Add draft to the dependency array and the closure is fresh, but now the interval tears down and restarts on every keystroke . useCallback doesn't help: it has the exact same depen
AI 资讯
Canonical Cover Explained for Beginners (Introduction & Foundations) — The Interview Guide
If you've started learning DBMS for software engineering interviews, you've probably come across terms like Functional Dependency , Attribute Closure , Candidate Key , Normalization , and Canonical Cover . For many beginners, Canonical Cover feels like another algorithm to memorize. It isn't. Before you ever learn how to compute a Canonical Cover, you should understand why it exists . This article focuses only on the Introduction and Foundations . We intentionally won't discuss the algorithm yet. What Is the Interviewer's Intent? When interviewers ask about Canonical Cover , they are usually not testing your memorization . Instead, they want to know whether you understand: How databases represent business rules Why redundant rules create problems Whether you can simplify complex dependency sets Whether you understand the foundations of normalization In interviews, Canonical Cover often appears before questions on: Normal Forms Dependency Preservation Lossless Decomposition BCNF Schema Design Interviewers are checking your understanding of database design , not your ability to recite definitions. Why Do Interviewers Ask Canonical Cover? Imagine a database contains hundreds of dependency rules. Many of those rules may: Repeat the same information Contain unnecessary attributes Be derivable from other rules A good software engineer should recognize unnecessary complexity. Canonical Cover is essentially about answering one question: "Can we represent exactly the same constraints using fewer and simpler rules?" That's why interviewers ask it. They want to see whether you appreciate: simplicity correctness maintainability efficient schema design Where Does Canonical Cover Fit Inside DBMS? Think of DBMS topics as a learning roadmap. DBMS | -------------------------------- | | Database Design Transactions | | Functional Dependencies | Attribute Closure | Candidate Keys | Canonical Cover | Normalization | 2NF → 3NF → BCNF Canonical Cover belongs to the database design portio
AI 资讯
ASYNCIO.LOCK
Why Does Python Need asyncio.Lock? INTRODUCTION After understanding asyncio.Semaphore , I thought I had learned everything required to control multiple coroutines. A semaphore limits how many coroutines can execute simultaneously. Then another question came to my mind. If Python's event loop executes only one coroutine at a time, why do we even need a Lock? Initially, I assumed a lock was unnecessary because there was only one thread. But after experimenting with shared variables, I realized that even though only one coroutine executes at a particular instant, multiple coroutines can still interfere with each other. In this article, I'll explain the problem that led to asyncio.Lock , how it works, and why almost every backend application uses it. What You Will Learn Why asyncio.Lock exists What is a race condition What is a critical section How Lock works internally Practical examples Real-world backend use cases Prerequisites Before learning asyncio.Lock , you should understand: Coroutines Event Loop await asyncio.Semaphore The Problem Suppose we have a shared variable. counter = 0 Now imagine two coroutines trying to increment it. async def increment (): global counter temp = counter await asyncio . sleep ( 1 ) counter = temp + 1 Initially I expected the final value to become 2 because two coroutines are incrementing the counter. But that wasn't what happened. Let's See What Actually Happens Initially counter = 0 Now Coroutine A starts executing. Read counter ↓ temp = 0 ↓ await The coroutine reaches await . The event loop suspends it and starts another coroutine. Now Coroutine B executes. Read counter ↓ temp = 0 ↓ await Notice something interesting. Both coroutines have already read counter = 0 Now Coroutine A resumes. counter = 1 Then Coroutine B resumes. counter = 1 The final value becomes 1 instead of 2 This is called a Race Condition . Why Did This Happen? Initially I blamed the Event Loop. Later I realized, the Event Loop didn't do anything wrong. Its job is
AI 资讯
Build a Deterministic Multi-Agent Pipeline with A2A in Python
Multi-agent examples often jump straight to models, tools, and production claims. That makes it difficult to see what the protocol is doing. Before adding an LLM, it is useful to watch a small system discover specialists, delegate a task, and return a result that you can inspect. This tutorial uses A2A Orchestration Lab , an open-source Python project by Fernando Paladini. It starts three local agents: an orchestrator, a researcher, and a writer. The researcher and writer are deterministic stubs, so the example isolates the Agent2Agent (A2A) communication flow from model behavior. The result is a runnable research-to-write pipeline that helps explain where A2A fits next to the Model Context Protocol (MCP). TL;DR Install the lab with uv , run its demo command, and inspect the three local Agent Cards and the delegated result. The project is a learning lab, not a production runtime. That is a feature for this tutorial because every moving part remains visible. Prerequisites You need: Python 3.12 or newer. uv for environment and dependency management. A terminal with network access for the initial dependency download. The repository declares version 0.1.0 , requires Python >=3.12 , and depends on the A2A Python SDK, httpx , and uvicorn . It is licensed under MIT. Create and run the lab Clone the public repository and let uv create the environment from the locked dependencies: git clone https://github.com/paladini/a2a-orchestration-lab.git cd a2a-orchestration-lab uv sync Run the bundled end-to-end demo: uv run a2a-lab demo "Explain A2A and how it relates to MCP" The CLI starts the three agents as subprocesses, waits for their Agent Cards, sends a message to the orchestrator, prints the response, and terminates the child processes. The default prompt is the same explanation used by the repository README, but using your own prompt makes the delegation easier to recognize. On a successful run, the output contains sections similar to these: [demo] asking orchestrator: 'Expl
AI 资讯
Add toast messages in Laravel with Wiretoast
Fire toast notifications in Laravel from PHP, Alpine and plain JavaScript with one notify call, plus positioning, auto-dismiss and grouping, and no CSS framework in your bundle Here is a problem I hit on every project. A Livewire action finishes and I need to tell the user it worked, but the toast library I grabbed assumes Tailwind, or ships its own huge runtime, or only works from JavaScript when half my triggers actually live in PHP. Wiretoast is my answer to that, and this post is the fast path to using it. The problem You want to fire a toast from PHP, from Alpine, and from plain JavaScript with the same call, and you do not want to drag a CSS framework into your bundle to get it. How to install Start with Composer, then wire up the assets. I bundle with Vite, so I import the package CSS and JS into my entry files. // resources/js/app.js import ' @wiretoast/js/wiretoast.js ' ; import ' @wiretoast/css/wiretoast.css ' ; That @wiretoast alias is optional, and you set it up by pointing Vite at the vendor resources folder so the imports stay short. // vite.config.js resolve : { alias : { ' @wiretoast ' : path . resolve ( __dirname , ' vendor/edulazaro/wiretoast/resources ' ), }, }, Then the component goes once into your layout, and on the Vite path it injects no tags of its own. <x-wiretoast /> How to use it The fastest possible win is a one-liner in a Livewire component right after something succeeds. The helper is a component macro named notify , registered for you when Livewire is present. $this -> notify ( 'Profile updated' , 'success' ); Under the hood that dispatches a notify browser event, which is exactly what Alpine fires too. So the same toast from a purely front-end button looks like this. <button @ click= "$dispatch('notify', { message: 'Copied', type: 'info' })" > Copy link </button> The five types you can pass are success , error , warning , info and neutral , and a message can be a plain string or an object with a title and a message when you want a he
AI 资讯
How to Convert Images to Buildable Minecraft Pixel Art with Exact Materials
title: How to Convert Images to Buildable Minecraft Pixel Art with Exact Materials published: true tags: minecraft, tutorial, gaming, opensource Originally published at blockartlab.com Disclosure: I built BlockArtLab, the free browser tool used in this guide. Most image-to-pixel-art tools stop at a preview. That is useful for seeing the idea, but it leaves the difficult questions unanswered: How large should the build be? Which real blocks should I collect? How many stacks of each color do I need? This tutorial covers the complete workflow from source image to a blueprint you can construct. 1. Pick an image that survives low resolution Minecraft pixel art works best when the source has one recognizable subject, a clear silhouette, and strong contrast. Logos, flags, game characters, and illustrated portraits usually survive conversion better than photographs with a busy background. Before uploading the image: Crop unused space around the subject Remove distracting background objects Make important features such as eyes or lettering larger Increase contrast if the subject blends into the background ## 2. Choose dimensions by material cost One converted pixel equals one placed block. The total block count is: width × height = total blocks | Size | Total blocks | Best use | |------|-------------|----------| | 16 × 16 | 256 | simple symbols and prototypes | | 32 × 32 | 1,024 | small survival logos and characters | | 64 × 64 | 4,096 | portraits, shading, and medium text | | 128 × 128 | 16,384 | a classic single-map-sized canvas | Doubling both sides multiplies the material count by four. For a first wall build, start between 32 and 64 blocks wide. ## 3. Choose a practical block palette I use three simple palette strategies: Concrete only for logos, flags, cartoons, and saturated colors Survival friendly for accessible concrete, wood, stone, sandstone, moss, and similar materials Full palette when a closer color match matters more than collection cost ## 4. Decide between
AI 资讯
Resize One Image into 6 Social Media Formats Automatically Using Cloudinary Claimable Clouds
Claimable Clouds are temporary Cloudinary environments for AI workflows that let AI Agents safely manage media with no signup required. Imagine you're a busy designer, with many satisfied clients who depend on you to take their images and make them look great across social media. All that manual cropping and scaling, it's enough to make a body cry. On top of that, you know that AI can give you a hand here, but managing the handoff between your AI, your own skilled hands and artistic taste and style, and your always-in-a-hurry client list is another big pain. Enter the concept of the Cloudinary Claimable Cloud, just released today. Take a look at the docs about these new temporary instances available now What we built and why Provision a disposable Cloudinary cloud with no signup, using npx @cloudinary/cloud Auto-detect a dropped image and upload it to that temporary cloud Auto-crop it into 6+ social formats (Instagram, LinkedIn, X, Facebook, Stories) using AI-based smart cropping Generate a side-by-side gallery of results automatically Hand off a Claim URL so a client can make the cloud permanent Now, you can hand off the main pain points to AI - the resizing and reshaping of your images for the various social media platforms, while giving your clients a clean handoff via a temporary Cloud environment that they can use to create a Cloudinary account and start using these assets. One side effect: this also nudges your whole client base toward the same toolset - Cloudinary. The bigger deal is working with an AI agent that makes your life easier but ALSO allows you to keep control of the output. Let's walk through how this works! It all boils down to a new command: npx @cloudinary/cloud Type that into your terminal to kick off the process. I built a small app around this concept to provide this AI agent with a simple harness, so let me show how that looks. The user experience is to drop any image you want resized into the /drop folder. Under the cover, there are a few
AI 资讯
Debugging Node.js Like a Pro
Start with the Built-in Inspector Before reaching for external tools, remember Node.js has a built-in debugger. Run your script with --inspect and open chrome://inspect in Chrome to get a full DevTools experience: breakpoints, step-through, console, and even memory profiling. node --inspect app.js For a quick breakpoint without touching the browser, use --inspect-brk to pause on the first line. This is great for debugging startup issues. Use debugger Statements and Conditional Breakpoints Sometimes you need a breakpoint only when a condition is true. Instead of littering your code with if blocks, set a conditional breakpoint in DevTools. Right-click the line number, choose "Add conditional breakpoint," and enter an expression like user.id === 42 . For quick inline debugging, debugger; works but remember to remove it before committing. I often use it temporarily when I'm too lazy to open the DevTools UI. Log Like a Pro with util.inspect console.log of an object prints [object Object] which is useless. Use util.inspect with depth and colors to see nested structures clearly. const util = require ( ' util ' ); console . log ( util . inspect ( myObject , { showHidden : false , depth : null , colors : true })); Or in modern Node, you can use console.dir with { depth: null } for the same effect. Async Stack Traces: Don't Lose the Context Async errors are painful because stack traces often end at the event loop. Node 12+ gives you better async stack traces by default, but you can improve them further by using Error.captureStackTrace in your own error classes. class MyError extends Error { constructor ( message ) { super ( message ); Error . captureStackTrace ( this , MyError ); } } This makes the stack trace point to the caller, not the constructor. Handle Unhandled Rejections and Exceptions Silent failures are the worst. Set up global handlers to log errors properly and exit gracefully. process . on ( ' unhandledRejection ' , ( reason , promise ) => { console . error ( ' U
AI 资讯
Minimalist LaTeX + VSCode Setup (macOS)
LaTeX is a document preparation system for high-quality typesetting, perfect for academic papers and technical docs. Many people turn to Overleaf as their go-to online editor for LaTeX, but it comes with its own frustrations. If you are tired of Overleaf being costly and always hitting the compile timed out error, this guide is for you! The full MacTeX install weighs in at a massive ~6.4GB, most of which you'll never actually use. Setting up a minimalist LaTeX environment on macOS using BasicTeX and VSCode is a much better alternative that makes your setup ~8 times smaller. It saves storage and makes it much easier to collaborate with your teammates using GitHub as a combo. Install LaTeX via Homebrew We'll use Homebrew to keep things manageable. If you don't have it, grab it at brew.sh . 1. Install LaTeX BasicTeX is the "lean" version of MacTeX. It's only ~140MB initially. brew install --cask basictex 2. Refresh your path and verify Make the TeX binaries available in your current terminal session: eval " $( /usr/libexec/path_helper ) " The default LaTeX compiler pdflatex should be available now. Verify it's working: which pdflatex pdflatex --version 3. Update tlmgr and packages tlmgr is the TeX Live Manager. To update tlmgr and all packages, run the following commands: sudo tlmgr update --self sudo tlmgr update --all 4. Install latexmk (build manager) latexmk is the "build manager" that handles multiple runs of the compiler (necessary for bibliographies and tables of contents). sudo tlmgr install latexmk Verify latexmk version: which latexmk latexmk --version 5. Install essential package collections BasicTeX is too bare-bones for real projects. Since we went minimalist, we need to grab only the packages we actually use. These three collections will cover 90% of your needs while keeping storage down. sudo tlmgr install collection-latexrecommended sudo tlmgr install collection-fontsrecommended sudo tlmgr install collection-latexextra Note: If a build fails due to a mi
AI 资讯
PDF Tamper Detection API for Ruby on Rails: Integration Guide
Originally published at htpbe.tech . The version on htpbe.tech stays in sync with the latest detection algorithm — refer to it for the canonical text. A large share of fintech still ships on Rails. Stripe, Gusto, GitHub, Shopify, Instacart — the generation of companies that defined modern payments and payroll built their backends on Ruby, and the startups following them keep reaching for the same stack. So when a forged bank statement, an altered payslip, or a doctored invoice lands in an underwriting queue, more often than you would guess it lands on a Rails controller. Your KYC provider already confirmed the applicant is a real person with a valid identity. It said nothing about whether the PDF they uploaded was edited after the bank generated it. That structural-tampering layer is invisible to identity verification, and the right place to catch it is at ingress — before your Document model saves, before the row reaches underwriting, before any downstream system trusts the file. This guide walks through integrating the PDF tamper detection API into a Ruby on Rails application: from the first curl command to an idiomatic HtpbeClient service object built on Faraday, a Data -class result struct, configuration-bound credentials, a typed error class, an ActiveJob that analyzes an uploaded document and routes on the verdict, and a request spec that stubs the API with WebMock. The patterns target Rails 7.x and Ruby 3.x, but they map cleanly onto Sinatra, Hanami, or a plain Ruby worker. Treat the code as a reference architecture: it runs the real request flow against the documented error codes, but you should adapt and harden it for your own traffic profile and threat model. If you want the conceptual overview first, start with How to Detect PDF Tampering Programmatically . Integrating from another stack? See the Python , Node.js , Go , Java / Spring Boot , Laravel / PHP , and C# / .NET guides. TL;DR Two API calls, three verdicts: POST /analyze returns a top-level id , th
AI 资讯
Stop Trusting Vibes: A Reproducible Harness for Comparing AI Coding Models on Your Own Codebase
Most comparisons of AI coding models are useless to you. Not because the authors are dishonest, but because they test on their problems: greenfield LeetCode-style prompts, demo TODO apps, or a framework you don't use. Your codebase has different failure modes — a weird build system, a legacy module nobody wants to touch, tests that take 40 minutes. This article is a small, reproducible harness you can run in an afternoon to compare coding models against your own repository, with scoring based on your own test suite instead of vibes. The artifact is ~120 lines of shell and Python, plus a scoring rubric you can adapt. The core idea Instead of asking "which model is best?", ask: on a fixed set of real tasks from my repo, which model produces patches that pass my tests, fastest, with the least hand-holding? That gives you three measurable axes: Correctness — does the resulting diff pass the relevant tests? Edit locality — did the model touch only the files it should have? Iteration cost — how many prompt rounds did it take to get there? Step 1: Build a task set from your own git history The cheapest source of realistic tasks is your own commit log. Find commits that fixed a bug or added a small feature, then check out the parent commit and ask the model to reproduce the fix (without showing it the actual fix). #!/usr/bin/env bash # extract_tasks.sh — mine candidate tasks from git history # Usage: ./extract_tasks.sh <repo_path> <count> set -euo pipefail REPO = " $1 " ; COUNT = " ${ 2 :- 8 } " cd " $REPO " # Small, self-contained commits: <= 3 files, <= 80 changed lines, has a test file touched git log --oneline --no-merges -n 300 | while read -r sha msg ; do files = $( git diff-tree --no-commit-id --name-only -r " $sha " | wc -l ) lines = $( git diff --shortstat " $sha ^" " $sha " | grep -oE '[0-9]+ insertion|[0-9]+ deletion' | grep -oE '[0-9]+' | paste -sd + | bc ) if [ " $files " -le 3 ] && [ " ${ lines :- 999 } " -le 80 ] ; then echo " $sha | $files | $lines | $msg "
AI 资讯
Environment Variables the Safe Way
Environment Variables the Safe Way Environment variables are the standard way to configure applications without hardcoding secrets or environment-specific details. But they're easy to misuse. I've seen API keys committed to repos, configs that crash when a variable is missing, and defaults that silently override production settings. Here's how I handle them safely. Never Commit Secrets The most important rule: never put real secrets in your code or commit them to version control. That includes .env files. Add .env to your .gitignore immediately. If you're using a framework like Laravel or a tool like Vite, the default .env.example is your friend. Commit that, but never the real one. For local development, you can generate a .env from the example and fill in your own values. For production, set variables through your hosting provider's dashboard or a secrets manager like AWS Secrets Manager or HashiCorp Vault. Read Variables Explicitly Don't access process.env directly all over your codebase. Instead, centralize your configuration. Create a config.js (or config.ts ) that reads and validates all the variables you need. // config.js const required = [ ' DATABASE_URL ' , ' JWT_SECRET ' , ' PORT ' ]; const missing = required . filter ( key => ! process . env [ key ]); if ( missing . length ) { throw new Error ( `Missing required environment variables: ${ missing . join ( ' , ' )} ` ); } module . exports = { databaseUrl : process . env . DATABASE_URL , jwtSecret : process . env . JWT_SECRET , port : parseInt ( process . env . PORT , 10 ) || 3000 , }; Now your app imports config and uses config.port . This has several benefits: Fail fast: if a required variable is missing, the app crashes at startup, not later when you try to use it. Type safety: you can parse and validate values once. Easy to mock in tests. Use Defaults Carefully Defaults are convenient, but they can hide problems. For example, if you default PORT to 3000 in production, you might accidentally run on the w
开源项目
Todo el mundo escribe qué reportar. Nadie escribe cómo no perder ninguno
Hay muchísimo escrito sobre qué tiene que reportar una organización: guías de Supersalud, de Supersociedades, de SAGRILAFT, de PTEE, de SST, de reportes ambientales. Todas contestan la misma pregunta — ¿qué me aplica? — y la contestan bien. Casi nadie escribe sobre la pregunta que de verdad hace fallar a las organizaciones: ¿cómo no perder ninguno, todos los años, cuando son treinta? Porque los incumplimientos que he visto de cerca casi nunca vienen de que alguien ignorara la obligación. Vienen de que la obligación se conocía perfectamente y aun así se pasó la fecha. Este artículo va del problema operativo —fechas, evidencia, responsables— no de cuáles normas le aplican a su entidad. Eso es otra conversación, y no es esta. Por qué el archivo de Excel deja de servir Con tres obligaciones, una hoja de cálculo sobra. El dolor no empieza por el número: empieza cuando el calendario hay que derivarlo . 1. Las fechas no son fechas, son reglas. Muchos vencimientos no están escritos como un día del calendario: dependen del último dígito del NIT, de días hábiles, o de un plazo contado desde un hecho. Eso significa que alguien recalcula el calendario entero cada año, a mano . Cada enero se reintroduce la misma oportunidad de equivocarse, y basta con un festivo mal contado. 2. El calendario vive en una persona. Casi siempre hay alguien que "sabe cómo es la cosa". Mientras esté, funciona. Cuando se va de vacaciones —o se va de la empresa— se va con ella el contexto que nunca estuvo escrito. La hoja sobrevive; el criterio para llenarla, no. 3. La hoja dice que se entregó, no lo prueba. La celda en verde es una afirmación de alguien. La evidencia real —el radicado, el archivo exacto que se subió, la hora— está en el correo de alguien. El día que hay que demostrarlo, empieza la arqueología en bandejas de entrada. 4. Los terceros que le reportan a usted. Si recibe información de contratistas, sedes o filiales, ahora administra dos problemas: sus propios vencimientos y los de ellos.
AI 资讯
como encontrar grupos de WhatsApp públicos com segurança
Encontrar grupos de WhatsApp públicos pode ser uma maneira prática de conhecer pessoas, divulgar projetos, trocar experiências e acompanhar assuntos do seu interesse. Existem comunidades sobre estudos, empregos, tecnologia, entretenimento, esportes, promoções, cidades, amizades e diversos outros temas. Porém, antes de entrar em qualquer comunidade, é importante verificar a procedência do convite e adotar alguns cuidados básicos. Afinal, links públicos também podem ser utilizados para divulgar golpes, conteúdos impróprios ou páginas falsas. Neste guia, você vai aprender como encontrar grupos de WhatsApp públicos com segurança e evitar problemas ao participar dessas comunidades. Procure grupos em sites organizados Uma das formas mais simples de encontrar comunidades públicas é utilizar sites especializados em reunir e organizar links por categorias. Em vez de clicar em convites compartilhados aleatoriamente nas redes sociais, procure plataformas que apresentem informações como nome do grupo, descrição, categoria e regras de participação. No site Grupos de WhatsApp , por exemplo, você pode pesquisar comunidades de diferentes assuntos e escolher aquelas que combinam melhor com seus interesses. Mesmo utilizando uma plataforma organizada, continue analisando cada grupo antes de participar. Confira o nome e a descrição do grupo Antes de clicar no botão para entrar, leia com atenção o nome, a descrição e as informações disponíveis sobre a comunidade. Verifique se o conteúdo prometido realmente corresponde ao tema que você procura. Um grupo apresentado como uma comunidade de empregos, por exemplo, não deveria exigir pagamentos, dados bancários ou informações pessoais para liberar supostas vagas. Descrições muito vagas, promessas exageradas e mensagens com urgência artificial merecem atenção. Frases como “ganhe dinheiro imediatamente”, “últimas vagas” ou “lucro garantido” podem ser utilizadas para atrair usuários para golpes. Evite links encurtados ou suspeitos Links oficiais
AI 资讯
Turn Your Routine Into an Assistant: A Practical Guide to Small AI Helpers
AI is not a genie. Treat it like a function. Most people use AI the way they use a search box: type a question, read the answer, move on. That works for one-off curiosity. It is a bad fit for the work you repeat every week, because you re-explain the context every time and never build anything you can trust. A small assistant is different. It is one narrow task, wired up once, with a fixed input and a fixed output shape. You run it, check it, improve it. After a few iterations it stops being a demo and starts pulling real weight. Here is how to build one without drowning in frameworks. Start narrow: one task, one input, one output Do not build "an assistant for my job." Build the thing that turns a messy meeting note into three bullet points. Pick a task that is: Repetitive (you do it weekly or daily) Boring (nobody will miss the manual version) Verifiable (you can look at the output and know if it is wrong) That last one matters most. If you cannot tell good output from bad in ten seconds, you cannot trust the assistant and you cannot improve it. Good starter tasks: drafting reply emails, summarizing documents, normalizing scrappy data, extracting fields from text. Example: an email draft as a function Think of your prompt as a function signature. Inputs go in, a structured draft comes out. def draft_reply ( incoming_email : str , tone : str = " friendly, brief " ) -> str : prompt = f """ You are drafting a reply on my behalf. Do not invent facts. If information is missing, leave a [PLACEHOLDER]. Tone: { tone } Incoming email: --- { incoming_email } --- Write only the reply body. """ return llm ( prompt ) # any model client you like Two lines do the real work: "Do not invent facts" and the [PLACEHOLDER] rule. Together they turn a confident hallucination into a visible gap you can fill. The goal is to make errors loud instead of silent. Example: summaries you can actually trust The failure mode of summaries is a plausible sentence that never appeared in the source.
AI 资讯
How to Make Claude Code and AI Coding Agents Smarter with Spec-Driven Development
A practical guide to writing specs that turn vague AI prompts into production-quality code — from functional requirements to edge cases, with real before-and-after examples. Let me paint a picture you've probably lived. You open Claude Code or OpenCode, type a vague prompt like "add a user dashboard with analytics," and hit enter. The agent spins up, writes a bunch of code — it even looks decent at first glance. Then you realize: the data model is wrong, the API endpoints don't match your existing patterns, there's no error handling, and the "analytics" is just a row of four hardcoded numbers. You spend the next hour correcting, prompting, correcting again. You would have been faster writing it yourself. Now imagine a different scenario. You spend 15 minutes writing a structured specification, paste it into the agent, and it produces exactly what you wanted — following your conventions, handling edge cases, wired into your existing auth and data layer. One shot. That's not luck. That's the difference between treating your AI coding agent like a chatbot and treating it like a senior engineer who needs a clear design document — also known as spec-driven development . The Core Problem: AI Agents Are Powerful but Undirected Claude Code, OpenCode, Cursor Agent — these tools are incredible when pointed at a well-defined task. They can read your entire codebase, understand your conventions, and produce production-quality code. But they share a fundamental limitation: they don't know what you want unless you tell them, precisely and completely. When you give an agent a one-liner prompt, you're leaving an enormous amount of ambiguity. The model will fill in the gaps — but it fills them with its own assumptions, which are often generic, incomplete, or just wrong for your context. A spec closes those gaps. It transforms an open-ended creative writing exercise into a constrained engineering task. What Makes a Spec Actually Work for AI Coding Agents? A spec that works for an AI