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

标签:#tutorial

找到 692 篇相关文章

AI 资讯

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

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

2026-08-18 原文 →
AI 资讯

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

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

2026-08-18 原文 →
AI 资讯

How to Turn Latitude and Longitude into an Address with JavaScript

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

2026-08-18 原文 →
开发者

Software Testing for Beginners: A Simple Guide to Getting Started

What Is Software Testing? 🧪 Software testing is the process of checking software to make sure it works correctly and does what it is supposed to do. For example, when we use a login page, we can test: Correct username and password Wrong password Empty username Empty password Forgot password option The goal is to find bugs and problems before the software is used by customers. Why Is Testing Important? Testing helps developers and companies: Find bugs Improve software quality Provide a better user experience Prevent problems after release Even a small bug can sometimes cause a big problem, so testing is an important part of software development. Manual Testing In manual testing, a tester checks the application manually without using automation scripts. For example, a tester can open a website, enter different inputs, click buttons, and check whether the expected result appears. Automation Testing In automation testing, we use tools and programming to test software automatically. Some popular tools are: Selenium Playwright Cypress Automation is useful when the same tests need to be performed many times. Conclusion Software testing is an important part of creating reliable software. If you are a beginner, you can start with manual testing , then learn SQL, API testing, and automation testing .

2026-08-18 原文 →
AI 资讯

Why Your Generated Tone Clicks, and How an Envelope Fixes It

If you have generated a pure tone in code and played it back, you may have noticed a small click at the start, the end, or both. The tone itself is clean, but the edges are not. That click is not a bug in your sine wave. It is a real and well understood artifact, and the fix is a technique you will reuse in every sound you ever synthesize: an envelope. This piece builds directly on generating a basic tone from scratch . We take a tone that clicks, look at the actual sample values to see why, and apply an envelope to smooth it. Everything is plain C++ with no libraries, and every number here is captured from a real run of the code. Where the click comes from A tone is a list of samples tracing a sine wave. A speaker turns those samples into sound by physically moving: the sample value sets the position of the speaker cone at each instant, where 0 is its resting position and larger values push it further forward or pull it back. Playing the tone moves the cone in and out 44,100 times a second to recreate the wave. When playback starts, the cone is at rest, at position 0. But the first sample of the tone is usually not 0. It is wherever the wave happens to be at that instant, and if that value is far from zero, the cone has to move from rest to that position in a single sample step, about 22 microseconds at this sample rate. That near instant movement is the click. A cone moving gradually pushes the air smoothly and produces a smooth sound. A cone forced to a distant position in one sample makes a sharp, abrupt movement of the air, which your ear hears as a click or pop. You can see it directly in the numbers. Here are the first six samples of a plain 440 Hz tone at half amplitude: n=0 raw=0 n=1 raw=1026 n=2 raw=2048 n=3 raw=3063 n=4 raw=4065 n=5 raw=5051 The wave leaves zero and climbs fast. Between the silence before playback and sample 1, the signal jumps by 1026 in one step. The same thing happens at the end: if the tone stops while the wave is partway through a cy

2026-08-17 原文 →
AI 资讯

Faire tourner Qwen 3.8–27B en local avec Unsloth et DeepSeek Harness sur une RTX 3090 (24 Go) sous Windows 11.

Par Jacques Gariépy • Guide technique, retour d'expérience, dépannage Windows pas-à-pas et utilisation Web & CLI. Table des Matières Introduction & Architecture Globale Pourquoi ce Setup ? (RTX 3090 24 Go + UD-Q4_K_XL) Comment Obtenir & Générer vos Clés d'Accès Dépannage & Installation d'Unsloth Studio : Le Bug SSLKEYLOGFILE Installation & Compilation de DeepSeek Harness Démarrage du Serveur Local Haute Performance (llama.cpp CUDA 13) Configuration Automatique & Fichier .env Utilisation : Interface Web & Mode CLI (Style Claude Code) Résolution des Pièges & Erreurs Courantes sous Windows Benchmarks Réels sur RTX 3090 Résumé des Commandes & Scripts Clés 1. Introduction & Architecture Globale Faire tourner un agent autonome d'ingénierie logicielle directement sur sa machine locale (100% privé, sans frais d'API et à latence minimale) est devenu une réalité grâce à la convergence de trois briques technologiques de pointe : DeepSeek Harness ( dsh ) : Le framework open-source d'agents de DeepSeek conçu pour orchestrer des workflows complexes de développement logiciel (gestion de sessions, modes Plan/Exécution, sandbox système, sous-agents, exécution de terminaux et édition de code). Unsloth Engine ( llama.cpp CUDA 13) : Le moteur d'inférence C++/CUDA ultra-optimisé intégrant FlashAttention-2 et la quantisation dynamique du cache KV. Qwen 3.8-27B en Quantisation Dynamique ( UD-Q4_K_XL ) : Les modèles de code open-source les plus performants, optimisés par Unsloth pour offrir une précision équivalente au 5-bit avec l'empreinte mémoire d'un 4-bit. Diagramme d'Architecture ┌──────────────────────────────────────────────────────────────────────────────┐ │ INTERFACES UTILISATEUR │ ├──────────────────────────────────────┬───────────────────────────────────────┤ │ Interface Web (Navigateur) │ Interface Console (CLI) │ │ http://127.0.0.1:3080 │ Style Claude Code │ └──────────────────┬───────────────────┴───────────────────┬───────────────────┘ │ │ │ (WebSocket / HTTP) │ (Console I/

2026-08-17 原文 →
AI 资讯

How to Choose the Right Chart: One Question About Your Data

By the end of this page you can pick the right chart in about five seconds, by asking one question: what comparison must the reader make? The four possible answers each map to one chart, and you will also know the two miscasts that cause most bad charts, the axis rules that keep bars honest, and the escape hatch for when one chart holds too much. It is about twenty minutes. Here is what to actually do with it today. Open the last chart you made. Say out loud what the reader is supposed to compare in it. If the chart type does not match that comparison in the table below, remake it. It is usually a two-minute fix. The short version: comparison across categories takes a bar. Change over time takes a line. Relationship between two measures takes a scatter. Part of a whole takes a bar too, once you pass a few slices. One picture carries the fork, so it comes first. The original carries a diagram here. In words: A decision fork. On the left, a single rounded node contains the question: compare what? Four lines branch from it to four small chart pictures on the right, stacked vertically. The first branch, labelled categories, leads to a miniature bar chart with four vertical bars of different heights. The second branch, labelled time, leads to a miniature line chart with a single rising line over an axis. The third branch, labelled relationship, leads to a miniature scatter plot of dots drifting upward to the right. The fourth branch, labelled parts, leads to a miniature horizontal stacked bar divided into segments, drawn next to a small crossed-out pie, meaning that for part-of-whole comparisons a bar is preferred over a pie. The picture says that the single question of what the reader must compare selects one of four chart types. Every number on this page is computed. The example tables are shown in full, and every total, percentage, and correlation was verified by running the arithmetic in Python before it went on the page. 1. The one question, and the decision table B

2026-08-17 原文 →
AI 资讯

Budget vs Actual Variance Analysis: The Sign Trap and the Percent Trap

By the end of this page you can read a budget vs actual table without being fooled by it, and build one in Excel that does not fool anyone else. You will know the variance formula, why analysts write F and U instead of trusting plus and minus, the two ways percent variance lies, and how to say the whole table in one sentence. It is about twenty minutes. Here is what to actually do today. Open the last variance table you were sent and find its biggest percentage. Then find its biggest dollar amount. If they are different rows, and they usually are, you now know which row deserved the attention, and it is probably not the one that got it. The short version: variance is actual minus budget. On a revenue line, positive is good. On a cost line, positive is bad. So analysts label every line F for favorable or U for unfavorable, rank by dollars, and flag by percent. The sign flip is the trap people fall into first, so it gets the picture. The original carries a diagram here. In words: Two panels, each showing a pair of vertical bars rising from a shared baseline. In the left panel, labeled revenue, a shorter bar marked budget stands next to a taller bar marked actual. The extra height of the actual bar above the budget level is shaded in the accent color and marked with the letter F and a check mark, because collecting more revenue than budgeted is favorable. In the right panel, labeled cost, the bars have the same shapes: a shorter budget bar next to a taller actual bar. But here the extra height above budget is shaded in the warning color and marked with the letter U and a cross, because spending more than budgeted is unfavorable. A dashed horizontal line runs across each panel at the budget height. The two panels are geometrically identical, and only the meaning of the line decides whether the overshoot is good or bad. That is why the sign of a variance cannot be read without knowing the line type. Every number on this page is verified. The worked example is a small dep

2026-08-17 原文 →
AI 资讯

Operations Analytics, Start to Finish

By the end of this page you can say, out loud and in your own words, what every core operations number does. What the unit of work is. Throughput, and why a count on its own answers nothing. Cycle time, and the rule that ties it to how much work is sitting open. Backlog. Utilization, and why aiming for 100 percent makes everything slower. Error rate, rework and first pass yield. Service levels, and why the average hides the customers you are failing. That list is most of what an operations analyst job, a technical screen, and a first real dataset will ask of you. Here is what to actually do with it. Go through once end to end without stopping, just for the shape. Then come back to the retrieval sheet near the bottom, cover the right-hand column, and try to say each answer before you read it. That second pass is where the learning happens, and there is measured evidence for it further down. The short version: operations analytics is the study of how work moves through a process. Every number in it is either how much, how fast, how much is stuck, or how much was wrong. One idea decides more of your operations work than any other, so it gets the picture. Work arrives, waits, gets done, and leaves. How much is in progress and how long each item takes are two different spans over that same picture, and they are locked to each other. The original carries a diagram here. In words: A left-to-right process diagram. On the far left an arrow labelled "arriving" points into a row of three small stacked boxes labelled "waiting", representing a queue. An arrow leads from the queue into a single larger rounded box labelled "working", representing the person or machine doing the job. A final arrow leads out of that box to the right and is labelled "done". Above the queue and the working box, a bracket in a strong accent colour spans both and is labelled "in progress", showing that work in progress includes everything waiting as well as everything actively being worked on. Below, a

2026-08-17 原文 →
AI 资讯

Build a Risk Index That Colors Itself

When this workbook is finished, you can change one number and watch the whole thing follow. Move a cut-off from 65 to 70 and every row re-bands, every fill recolors, every count updates, and the legend still matches the map. Nobody can color a cell by hand, because no cell has a color of its own. That is the whole trick, and it takes about twenty minutes to build. The example here is a security risk index across twenty sites. The same shape works for vendor scoring, lead scoring, incident triage, or any list where a number has to turn into a label and a color. The fault, and where it actually comes from You have met this file. A scored list, colored by hand, that nobody quite trusts any more. Look closely and the same faults turn up every time: Two rows score 61.4. One is amber, one is yellow. The same band is drawn in two shades, because two people picked from the palette on two different days. A row sits below the cut-off and is colored red anyway, because somebody knew that site was a problem. A score lands exactly on 65, which appears in two bands, so the answer depends on who typed it. One row has no band at all. It quietly drops out of every count. These look like five separate mistakes. They are one mistake, five times. The rule lives in the formatting instead of in a column. A color is not a value you can test. You cannot write a formula that asks "is this row the right shade of amber," so nothing checks it, and it drifts. The test: can you sort by band? If the band is only a color, you cannot sort it, count it, or filter it, and neither can anybody else. That is the tell. The chain: score, then band, then color Everything below is one idea applied three times. Each thing is derived from the thing before it, and only the first one is typed. Layer Where it lives Who decides it Sub-scores Four columns, one per category Your source data. Typed once. Composite score A formula, from the sub-scores and the weights The weights row Band A formula, from the score The

2026-08-17 原文 →
AI 资讯

web page hosting

How to Host a Website Using GitLab Pages If you have a website made with HTML and CSS, you can host it for free using GitLab Pages . GitLab Pages takes the files from your GitLab repository and publishes them as a website. For this, you need to create a .gitlab-ci.yml file. This file tells GitLab how to deploy your website. After pushing the file to your repository, GitLab creates a pipeline. When the pipeline finishes successfully, GitLab Pages gives you a URL which you can open in a browser to see your live website. Understanding the Pipeline A pipeline is the process GitLab uses to run the instructions written in .gitlab-ci.yml . If the pipeline fails, the website will not be deployed correctly. Sometimes the pipeline can fail because of an invalid YAML file, incorrect indentation, or a problem in the deployment commands. Another common problem is trying to create a public folder when the folder already exists. For a simple HTML and CSS website, the important thing is that the public folder contains your website files and index.html should be directly inside it. For example, the structure should look like this: public/ ├── index.html ├── style.css └── images/ The index.html file is important because it is the main page GitLab Pages looks for when someone opens the website. Hosting More Than One Website You can host multiple websites using GitLab Pages, but if the websites are completely different projects, it is better to create a separate GitLab project for each website . For example, you can have one project called youtube-clone and another project called portfolio . Each project can have its own HTML, CSS, .gitlab-ci.yml , pipeline and Pages deployment. This makes the projects easier to manage and prevents one website from affecting another website. So, GitLab is not only a place to store your code. With GitLab Pages and CI/CD pipelines, you can also use it to turn your HTML and CSS project into a live website that can be accessed through the internet.

2026-08-17 原文 →
开发者

i18n sin gettext: traducciones en JSON con claves de punto

Quieres que tu app hable español e inglés. Buscas cómo, y el ecosistema te empuja a gettext o Babel: ficheros .po , un paso de compilación a .mo , herramientas de extracción. Potente, sí. Pero para una app pequeña o mediana es un peaje que no querías pagar — solo necesitabas un t() honesto. Lo resolví tantas veces que lo empaqueté: dotkey-i18n , Python puro, sin dependencias. Tus traducciones son JSON que cualquiera puede editar: // locales/es.json { "login" : { "welcome" : "Hola, {name}" , "submit" : "Entrar" }, "menu" : { "reports" : "Informes" , "settings" : "Ajustes" } } from dotkey_i18n import Translator tr = Translator ( " locales " , default_lang = " es " ) tr . t ( " login.welcome " , name = " Juan " ) # "Hola, Juan" tr . t ( " menu.reports " , lang = " en " ) # "Reports" Tres detalles que marcan la diferencia Claves con notación de punto. t("login.submit") navega el JSON anidado. Agrupas las cadenas por pantalla o módulo sin claves planas kilométricas. Fallback al idioma por defecto. Si una clave falta en el idioma pedido, se busca en el idioma por defecto antes de rendirse. Tus traducciones pueden ir incompletas —la vida real— sin dejar huecos en blanco en la interfaz. Nunca revienta la interfaz. Una clave que no existe devuelve la propia clave (un marcador visible, no una excepción a mitad de render). Una interpolación con un campo que falta devuelve el texto sin formatear. Un JSON corrupto se trata como vacío. Nada de esto tumba la pantalla. Agnóstico del framework El idioma actual entra por un lang_getter inyectable, así el mismo Translator sirve en NiceGUI, Flask, FastAPI o un script suelto: # NiceGUI: idioma desde la sesión del usuario tr = Translator ( " locales " , default_lang = " es " , lang_getter = lambda : app . storage . user . get ( " idioma " )) # Flask tr = Translator ( " locales " , lang_getter = lambda : session . get ( " lang " )) La prioridad es clara: lang= explícito → lang_getter() → idioma por defecto. De dónde viene Salió del servic

2026-08-17 原文 →
AI 资讯

Build a POS receipt printer in Node.js

Disclosure: I build Receiptful, the printing API used in this tutorial. The Node and Express parts apply whatever you print with. You have orders coming into your point of sale, and you want each one to print on the thermal printer at the counter. This is a complete walkthrough of a small Node service that does exactly that. By the end you will have an endpoint you can POST an order to and watch paper come out. There is nothing to install next to the printer for this tutorial to work, and no ESC/POS to write by hand. You send HTML, Receiptful prints it. Before you start You need two things from the console : A paired printer, which gives you a printer ID . If you have not done this yet, the getting started guide walks through it in a couple of minutes. An API key (the rf_live_… value), created under API keys and shown only once. On the code side you need Node 18 or newer, so that fetch is available globally with no extra dependency. We will use TypeScript, but the same code works in plain JavaScript if you drop the types. Put your credentials in the environment rather than in the source: export RECEIPTFUL_API_KEY = "rf_live_3f9c…" export RECEIPTFUL_PRINTER_ID = "42" Step 1: model the order Start with the shape of an order. Yours will have more fields, but this is enough to print a useful receipt: interface LineItem { name : string ; quantity : number ; unitPrice : number ; // in cents, to avoid float rounding } interface Order { id : number ; items : LineItem []; placedAt : Date ; } Keeping money in cents and formatting only at the edges saves you from the classic floating point rounding bugs that show up as a receipt total that is one cent off. Step 2: render the order as HTML This is the part that decides how the receipt looks. Receiptful converts the HTML you send into ESC/POS for your specific printer, so you get to lay a receipt out with tags you already know instead of byte codes. function money ( cents : number ): string { return " $ " + ( cents / 100 ). toFi

2026-08-16 原文 →
开发者

Cómo solucionar `docker run` con `Exited (1)` en Raspberry Pi

Cómo solucionar docker run con Exited (1) en Raspberry Pi ¿Por qué ocurre este error? El código de salida 1 indica que el proceso principal del contenedor terminó con un error genérico. En Raspberry Pi, los casos más comunes son: Arquitectura incompatible : La imagen fue construida para amd64 (x86_64), pero Raspberry Pi usa arm32v7 o arm64v8 . Falta de binarios compatibles : El ENTRYPOINT o CMD del contenedor intenta ejecutar un binario compilado para otra arquitectura. Problemas de permisos o dependencias faltantes en el entorno embebido (especialmente en Raspberry Pi OS Lite sin GUI). Uso incorrecto de --net=host : En algunas versiones de Docker en Raspberry Pi, el flag --net=host puede causar fallos si el sistema no lo soporta correctamente. 🔍 Nota crítica : En tu comando original docker run --net = host -d -t myimage , hay un error de sintaxis: --net = host tiene espacios alrededor del = . Docker lo interpreta como un nombre de red literal " = host" , lo que probablemente falla. Pasos para solucionarlo Paso 1: Corrige la sintaxis del comando # ❌ Incorrecto (con espacios en `--net`) docker run --net = host -d -t myimage # ✅ Correcto (sin espacios) docker run --net host -d -t myimage ⚠️ Importante : En Docker CLI, los flags con valores no deben tener espacios entre el = . Usa --net=host o --net host , pero nunca --net = host . Paso 2: Verifica la arquitectura de la imagen Ejecuta en tu Raspberry Pi: docker inspect myimage --format '{{.Architecture}}' Si el resultado es amd64 , la imagen no es compatible con Raspberry Pi . Solución: Reconstruir la imagen para ARM Si tienes el Dockerfile , usa multi-arch build: # Al inicio del Dockerfile (antes de FROM) # syntax=docker/dockerfile:1 FROM --platform=$BUILDPLATFORM golang:1.21-alpine AS builder ... O construye explícitamente para ARM: # En tu máquina de desarrollo (x86_64) docker buildx create --use docker buildx build --platform linux/arm/v7 -t myimage:armv7 . --push # o para Pi 4 (64-bit): docker buildx build --platf

2026-08-16 原文 →
AI 资讯

How to Catch a Pine Script Repaint Bug Before It Costs You Real Money

I've watched too many TradingView strategies look great in the Strategy Tester and then fall apart the moment real money went live. Almost every time, the code compiled fine. The bug wasn't syntax. It was repainting, the script quietly using information it shouldn't have had yet. Repainting doesn't throw an error. It just quietly makes your backtest better than your live trading will ever be. Here are the four places it actually comes from, and how to catch each one before you trust a strategy. 1. request.security() with the wrong lookahead If you pull a higher-timeframe value with request.security() and don't handle the offset correctly, the current, still-forming HTF bar can leak into your calculation. The fix is barmerge.lookahead_off combined with offsetting the source by one bar, e.g. close[1]. lookahead_on is only safe when you've already offset the source yourself. Using it directly on a live value is the single most common repaint source in Pine scripts posted online. 2. Signals computed before the bar closes If your entry logic runs on close or ta.crossover() without a barstate.isconfirmed guard, the signal can appear, then disappear, then reappear as the candle's still-forming close price changes. What you saw fire in real time is not always what the finished bar actually did. Guard any entry/exit logic that matters with barstate.isconfirmed if you're evaluating it intrabar. 3. Same-bar stop/target ambiguity When your stop and your target could both have been hit inside the same bar's high-low range, the Strategy Tester has to guess which one happened first. It doesn't always tell you which assumption it made, and that one hidden assumption can flatter your win rate without you ever seeing it happen. 4. Bar Replay is the real manual test TradingView's Bar Replay tool is the closest thing to a repaint detector you already have. Step through history bar by bar and watch whether a signal that appeared in the past matches what you originally saw. If a signal m

2026-08-16 原文 →
AI 资讯

Who am I ??

Hello Guys!!! I am Kuldeep Gade. A final-year Computer Engineering student with a specialization in Cybersecurity. Currently, I am working on home lab automation so that it will help to encounter alerts (false positives). For practice, I have created a controlled environment for performing attacks and detecting them, such that the outside doesn't get affected. Working on projects which will enhance my cybersecurity skills. But I wasn't that obsessed with cybersecurity from the starting. I am a person who experimented with lots of domains by myself. When I was in the first year, I completed Full-Stack in MERN. For 1–1.5 years, I did that, but after some time, AI got so much power that within 3–4 months of the launch, they were able to create such stunning websites that needed a team of skilled people. And I thought it could be useless to go deep into MERN more, because if AI can do such things within months, then what is going to happen at the time of my graduation? And that's the reason I tried other things. So I realised that it could be better to gain the fundamental knowledge in the core of Domains that will automatcally get to implementation level with the help of the AI tools. So I started to learn Data Science and Machine Learning. Soon, I realised that I cannot keep up with it. Then I started with cybersecurity. And currently, I am going deep into it. As a result, I got my answer, and now I am a bit focused towards the cybersecurity domain. It was a tremendous feeling about knowing the root of the system on which we are working. How to troubleshoot the errors and problems. And I am loving it now. Gaining experience in this field is not just learning and watching tutorials. We have to perform hands-on practice. We have to learn by doing things, breaking systems, understanding workflows, rebuilding them. I am going to share my experience in the field as we go in upcoming blogs. Recently, I started my new goal to "read the books". And did some research on books.

2026-08-16 原文 →
产品设计

Why 'WHERE x = NULL' Never Works in SQL (And What to Use Instead)

Adapted from the SQL Essentials Companion Guide . You write a query to find every customer with no phone number on file. WHERE phone = NULL looks obviously correct — and it returns zero rows, even though you can see NULL sitting right there in the column. Nothing crashes. No error. The query just quietly lies to you about what's in the table. This isn't SQL being broken. It's SQL being consistent about something most languages don't force you to think about: NULL doesn't mean "nothing," it means "unknown." And you can't compare something to unknown with = and expect a real answer. What's actually happening Take this table: -- customers | id | name | phone | | ----|-------------|------------| | 1 | Jordan Lee | 555 - 0142 | | 2 | Sam Rivera | NULL | | 3 | Alex Chen | 555 - 0198 | SELECT name FROM customers WHERE phone = NULL ; -- returns 0 rows SQL doesn't evaluate conditions as just true or false — it has a third result: unknown . phone = NULL asks "does this unknown value equal this other unknown value?" There's no way to answer that, so SQL returns UNKNOWN for every single row, including Sam Rivera's. And WHERE only keeps rows where the condition is TRUE . UNKNOWN doesn't qualify, so the row gets filtered out — the exact same as if it had evaluated to FALSE . This is true even for the row that "should" match. NULL = NULL isn't TRUE — it's also UNKNOWN . NULL never equals anything, not even another NULL . That's the whole rule, and it applies uniformly, which is why = can't be patched into working here — it's not almost right, it's answering a different question than the one you're asking. The fix, step by step Recognize the symptom : a query that runs cleanly but returns fewer rows than it should — especially zero rows when you can see matching data — with a NULL column somewhere in the WHERE clause. Swap = for IS NULL (or != for IS NOT NULL ). These are dedicated operators built specifically to test for absence, not comparison operators being asked to do somethin

2026-08-16 原文 →
AI 资讯

How I Built a WhatsApp AI Bot That Runs for $0/Month on Windows

I wanted a simple WhatsApp AI bot without paying every month for cloud hosting or an AI API. So I built one that runs on a Windows PC I already have running 24/7. The result: WhatsApp integration with Node.js Optional local AI using Ollama No VPS or cloud server required No paid AI API required Runs on Windows 10/11 Can restart automatically after a reboot «The "$0/month" refers to additional software, hosting, and AI API costs. It assumes you already have the PC, internet connection, and electricity.» The basic architecture The setup is intentionally simple: WhatsApp → Node.js bot → Local AI → WhatsApp reply The Node.js application handles incoming WhatsApp messages and decides how to respond. For AI responses, the bot can send the user's message to a locally running Ollama model and return the generated answer back to WhatsApp. That gives us: WhatsApp → Node.js → Ollama on localhost → Node.js → WhatsApp No cloud AI API is required. What you need For the basic setup: Windows 10 or Windows 11 Node.js LTS A WhatsApp account Ollama if you want local AI A computer that can stay powered on You don't need Kubernetes. You don't need AWS. You don't need Docker. And you don't need to rent a VPS. Connecting WhatsApp For this project I used "whatsapp-web.js". The first time the application starts, it displays a QR code. You scan the QR code with WhatsApp, similar to connecting WhatsApp Web. After authentication, the application can listen for incoming messages and send replies. A simplified example looks like this: const { Client, LocalAuth } = require('whatsapp-web.js'); const client = new Client({ authStrategy: new LocalAuth() }); client.on('qr', (qr) => { console.log('Scan the QR code to connect WhatsApp'); }); client.on('ready', () => { console.log('WhatsApp bot is ready'); }); client.on('message', async (message) => { if (message.body.toLowerCase() === 'hello') { await message.reply('Hello from the bot!'); } }); client.initialize(); "LocalAuth" stores the authenticated W

2026-08-16 原文 →
AI 资讯

Notificar a varios canales sin que un fallo tumbe al resto

Quieres mandar la misma notificación a varios sitios: Slack, Discord, un webhook, un email. La primera versión es un for de tres líneas: for canal in canales : canal ( mensaje ) Y funciona en las demos. Hasta que un día Discord devuelve un 500, canal(mensaje) lanza, y el email y el Slack que iban detrás nunca salen . Peor: te enteras por el usuario que no recibió la alerta, no por un log. Dos cosas fallan en ese for : No aísla. La primera excepción corta el reparto entero. No reporta. O cada canal se traga su error en un try/except disperso, o el fallo se pierde. La forma correcta Aísla cada canal y recoge el resultado. Lo empaqueté como fanout-broadcast —Python puro, sin dependencias— porque lo reescribía en cada proyecto: from fanout_broadcast import Broadcaster bc = Broadcaster () bc . add ( " discord " , a_discord ) bc . add ( " telegram " , a_telegram ) bc . add ( " email " , a_email , enabled = False ) # apagado por ahora report = bc . broadcast ( " ¡Nueva versión publicada! " ) if not report . ok : for o in report . failed : log . error ( " %s falló: %s " , o . name , o . error ) broadcast llama a todos los canales habilitados, captura la excepción de cada uno por separado , y sigue con el siguiente. Un Discord caído ya no impide que salga el email. Al final tienes un reporte: report . ok # ¿ningún canal falló? report . delivered # los que entregaron report . failed # los que lanzaron (cada uno con su .error) report . skipped # los que estaban deshabilitados Encender y apagar sin ramificar el código Cada canal tiene un interruptor, en runtime o por variable de entorno: from fanout_broadcast import env_enabled bc . add ( " discord " , a_discord , enabled = env_enabled ( " discord " )) # mira DISCORD_ENABLED Esto importa más de lo que parece: separa qué canales existen de cuáles están activos hoy , sin comentar código ni meter if por todos lados. Apagas un canal problemático con una variable de entorno, no con un despliegue. Escalar, pero después de intentarlo

2026-08-16 原文 →