AI 资讯
No Agent Grades Its Own Homework
You ask Claude to review your code. It says "looks good, clean, well factored". Of course it does. It wrote that code five minutes ago. You just asked the author to grade his own paper, and he gave himself an A. Having an AI review code works. But not by asking the one who just wrote it. Quality doesn't come from a smarter model, it comes from an architecture where no role checks itself. The self-preference bias This isn't a hunch, it's measured. A model evaluating its own output rates it higher than others' at equal quality: the self-preference bias , documented by Panickssery and co-authors in 2024, and it's causal, not correlational. The model recognizes its own style and prefers it. In practice that means the naive loop "write, then review what you just wrote" is broken by construction. You don't get a review, you get a justification. The agent already decided its code was good the moment it produced it; asking again only confirms. The blind reviewer So the first rule: the reviewer is never the author. In my config, the review agents run in a clean context . They don't see the implementation prompt, they don't know what constraints the author set, they meet the diff like a colleague on Monday morning. And when the author is a known model, the reviewer is from a different family , to break style recognition. One detail matters as much as the rest: the developer's name never enters the reviewer's prompt. No "this was written by a senior", no "review this model's work". The author's identity is exactly the information that triggers the bias. We take it off the table. No finding without a receipt The second trap is the opposite of the first. An AI reviewer, especially in a clean context, tends to over-flag: it invents problems to look useful, it flags "vulnerabilities" that aren't. A review that cries wolf on every line is no better than a complacent one: either way, you stop listening. Hence the receipt rule. Every finding must cite a file:line and pass a check bef
AI 资讯
Your AI Writes Tests That Can Never Fail
You ask the AI for tests. It hands you twelve, all green. CI passes. You merge. Three days later a bug ships, on a function those tests were supposed to cover. You reopen the test file and it clicks: it ran, it passed, and it tested nothing. A green test isn't a proof. It's a hypothesis. And an AI, left to its own devices, is very good at writing hypotheses that can never be disproved. The phantom test Take a dead-simple function, a discount above 100 euros: func Discount ( total int ) int { if total > 100 { return total - 10 } return total } Here's the kind of test an AI produces when you ask "write me a test for this" with no further framing: func TestDiscount ( t * testing . T ) { got := Discount ( 150 ) if got < 0 { t . Errorf ( "result should not be negative" ) } } This test is green. It does run the discount branch (so your coverage climbs). But look at the assertion: got < 0 is never true, whatever Discount does. Replace total - 10 with total + 10 , with total * 2 , with 42 : the test stays green. It doesn't check behavior, it checks that the lights are on. Coverage doesn't measure what you think The trap is that this phantom test inflates your coverage. Coverage counts lines executed , not assertions that bite . A line crossed by a test that asserts nothing useful counts as much as a line genuinely verified. So a 90% coverage report can hide half a suite of tests that will never fall, even if you break the code on purpose. That's exactly an LLM's playground. Its reward signal is "the tests pass". Not "the tests catch a bug". With no external oracle to stop it, it drifts toward the shortest path to green: soft assertions, mocks that test themselves, cases that never exercise the risky branch. The red-check: break the code, demand the red The counter is one move, and it's as old as TDD: before trusting a test, check that it knows how to fail. Mutate the line it's meant to protect, rerun, and expect to see it go red. If it stays green, it's vacant. On our funct
AI 资讯
A Four-Type Framework for LLM Wiki by karpathy
Why Knowledge Alone Doesn't Create Judgment Karpathy's LLM Wiki is brilliant. You dump raw material in, an LLM extracts concepts and links them together, and you get a personal knowledge base that actually works. I built one. 100+ pages. It's great. But I hit a wall that made me rethink everything. The Wall I asked my AI to act as a programming tutor. It could recite every concept perfectly. Student: "I don't understand Promises." AI: "A Promise is an object representing the eventual completion or failure of an asynchronous operation..." Wrong answer. The right answer was: "Do you understand callbacks first? What about synchronous execution? What have you tried so far?" The AI had knowledge. It had zero judgment. And then I realized why: every single page in my wiki was the same type of knowledge. One Type vs Four LLM Wiki 1.0 stores declarative knowledge — facts, definitions, summaries. Things that answer "What is this?" But think about what makes a human expert different from a textbook: A great programming mentor doesn't just know what Promises are. They know why you teach callback → Promise → async/await in that exact order — and never the reverse. That's not a fact. It's a reasoning path. A master astrologer doesn't just know what each star represents. They know why you check 命宮 first, then 三方四正, when to prioritize 格局, when a palace is a consequence rather than a cause. That's not a fact either. It's a decision sequence. And here's the kicker: even knowing the reasoning path isn't enough. We annotated Anderson's (1972) Socratic tutoring dialogues — full 41-turn and 30-turn conversations, labeling every decision point. Knowing the 23 Socratic rules (the reasoning path) is one thing. Reading a complete dialogue — watching the expert set a trap, wait 15 seconds in silence, break their own rules when the student gets frustrated — is something else entirely. Knowing the recipe ≠ having watched the chef cook. And there's still one more type. Student says: "I have no
AI 资讯
I Built a Free Apache Kafka Course from Scratch — Here's the Full Curriculum (and What I Got Wrong)
I Built a Free Apache Kafka Course from Scratch — Here's the Full Curriculum (and What I Got Wrong) I spent months building a free Apache Kafka course covering everything from first principles to a real-time analytics platform final project. No paywall. No "premium tier." 9 modules, 470 minutes of content, completely free. Here's the full syllabus, the Python code that actually works, and the honest mistakes I made building the curriculum — so you don't repeat them. Why I Built This Every time someone asked me "how do I learn Kafka?", I sent them to the same 3 places: The official Confluent docs (dense, assumes you already know what you're doing) A $15 Udemy course that spends Module 1 explaining what a computer is A YouTube playlist where half the videos are deleted None of them answered the real question beginners have: why does Kafka exist, and what problem does it actually solve before I write a single line of code? That's the gap I built for. The Problem With Most Kafka Tutorials Most tutorials start with: "Kafka is a distributed event streaming platform..." And then they immediately show you a Docker Compose file with 6 services. Beginners copy-paste it, something breaks, they don't know why, they quit. The real problem is that Kafka is an answer to a specific architectural problem — and if you don't understand the problem first, the solution makes no sense. So Module 1 and 2 of this course don't touch Kafka at all. They build the problem statement from scratch. The Full Syllabus (9 Modules, 470 Minutes) Module 1: Introduction to Kafka — 35 min Not "what is Kafka" — but why event streaming exists at all. What breaks in traditional request-response architectures at scale. Module 2: The Problem Statement — 30 min A real-world scenario: you're building an e-commerce platform. Orders, inventory, notifications, analytics — all tightly coupled. What happens when one service goes down? This module makes the pain visceral before Kafka enters the picture. Module 3: How
科技前沿
What to Do in Houston If You're Here for Business (2026)
Where to eat, stay, work, and eat some more while visiting Space City on business.
AI 资讯
Your console.log Is Lying to You
Open your browser DevTools and run this: const user = { name : " Bob " } console . log ( user ) user . name = " Alice " You would expect the log to show { name: "Bob" } , the value at the time of the console.log call. The collapsed line is what you expect: ▶ Object { name: "Bob" } But expand it, and you will see: name: "Alice" Oops. So what's going on? console.log() is the most-used debugging tool in JavaScript, but it can be subtly unreliable. Not because it is broken, but because it optimizes for speed and interactivity rather than for accuracy . It was built for fast exploration in a live, interactive environment, and those priorities come with tradeoffs that can genuinely mislead you during debugging. Over the next sections, we'll look at a few ways the console can mislead you - and, more importantly, why each one exists. Objects Aren't Snapshots When you pass an object to console.log() in browser DevTools, the browser does not immediately serialize it into a string. Instead, it stores a live reference to that object and defers the actual rendering until you expand the entry. This is called lazy evaluation, and it is what caused the surprise. The collapsed ▶ Object you see is essentially a placeholder: the properties shown inside it are evaluated at the moment you click the arrow, not at the moment you called console.log() . By then, your code has already continued running. That means what you're seeing is not a frozen record of the object at the time of logging, but a live view into whatever the object happens to look like when DevTools renders it. In the example: You log { name: "Bob" } DevTools stores a reference to the user object The code continues executing user.name is mutated to "Alice" You expand the logged object later and see the current state This behavior can feel unintuitive at first, because most developers mentally model console.log() as "print this value right now", but in browser DevTools, it is closer to "show me this object as it exists when
产品设计
Nest’s quest to fix your thermostat
The founding story of Nest is pretty much a perfect tech myth. A legendary product maker (in this case, Tony Fadell) helps create one of the most successful products ever (the iPhone) and then rides off into the sunset to enjoy the rest of his life, only to have an experience that drags him back […]
产品设计
Ad-free streaming is a luxury now
This is The Stepback, a weekly newsletter breaking down one essential story from the tech world. For more news about the streaming industry, follow Emma Roth. The Stepback arrives in our subscribers' inboxes at 8AM ET. Opt in for The Stepback here. How it started Streaming was once a reprieve from cable. Not only could […]
AI 资讯
The ‘Almost Homeless’ Subreddit Is a Stark Glimpse at Soaring Wealth Inequality
As the billionaire class gets richer, the growing online community is offering tips on how to survive with very little.
科技前沿
Why Wear Anything Other Than a Sun Hoodie This Summer? Our Picks for the Best
Sun hoodies are the greatest new garment since the original hoodie.
AI 资讯
From Regex Hell to AI: How I Finally Tamed Messy PDF Invoices
Last month, I spent three days wrestling with 500 PDF invoices. Each one had the same data—vendor name, invoice number, total amount—but the layouts were all over the place. Different fonts, missing headers, tables that somehow broke across pages. I tried regex. I tried OCR with layout analysis. I even tried building a rule-based parser that looked for keywords like "Total:" . Nothing worked reliably. Every time I fixed one pattern, another invoice broke. I was one commit away from throwing my laptop out the window. Then I took a step back. I realized I didn't need to understand every layout variation. I just needed to understand the data . And that's where AI came in. What didn’t work Let me be clear: I tried the usual suspects first. Regex. Classic. I wrote patterns like r"Total\s*:\s*\$?(\d+\.\d{2})" . Worked on 60% of invoices. The rest had "Total Due" or "Amount Total" or the dollar sign in a different place. Regex is great when you control the input. I didn't. OCR with layout parsing. I used Tesseract with --psm 6 and tried to extract lines by bounding boxes. It helped a bit, but tables with merged cells or rotated text threw it off. Plus, I had to write code to guess which box was a field name and which was a value. Rule-based parser. I built a dictionary of known vendors and their layouts. That worked … until I got an invoice from a new vendor. Maintenance became a nightmare. I was solving the wrong problem. Instead of fighting formatting, I needed to focus on meaning . The AI approach that saved me I remembered that large language models are surprisingly good at understanding context. If I could give the model the raw text from a PDF and a description of what I wanted, maybe it could extract the fields directly. Here’s the core idea: treat extraction as a structured generation task. Provide a prompt with a few examples (few-shot) or just describe the schema, and let the model output JSON. I found an API that did exactly this with a simple HTTP call. (Full d
开发者
สามภาษา — หนึ่งเดียว | โคลงสี่สุภาพแห่ง HTML, CSS, JavaScript
— โคลงสี่สุภาพ ว่าด้วยสามภาษาแห่งการสร้างเว็บ — HTML — โครงสร้าง <html> เปิดทางฟ้า ประกาศ <head> ซ่อนนัยน์นาถ นามนี้ <body> ร่างกายปราศ ซึ่งชีวิต ทุกแท็กเปิดปิดที่ หล่อหล่อมความจริง CSS — ความงาม สีสันลอยลิบฟ้า แต่งแต้ม ตัวอักษรเรียงแถม ถ้วนถี่ ขอบเขตเว้นระยะแย้ม เผยโฉม ทุกพิกเซลที่ปรี่ ปรุงแต่งให้งาม JavaScript — ชีวิต เมื่อคลิกนิ้วหนึ่งครั้ง โลดแล่น ฟังก์ชันทำงานแย้ม ยามใช้ if else ตรรกะแจ่ม จักรกล ทุกบรรทัดที่ให้ ชีวิตแก่หน้าเว็บ สามภาษา — หนึ่งเดียว html คือร่างให้ โครงครัน css แต่งแต้มฝัน สวยหรู javascript พลิกผัน ให้เคลื่อนไหว สามภาษาคู่ฟู ฟื้นฟูโลกา — Nokka | มิถุนายน 2569 เชิงอรรถ: โคลงสี่สุภาพบทนี้ใช้ฉันทลักษณ์มาตรฐาน — บทละ 4 บาท บาทละ 2 วรรค วรรคหน้า 5 พยางค์ วรรคหลัง 2 พยางค์ สัมผัสบังคับระหว่างวรรคท้ายของบาทที่ 1, 2, 3 กับวรรคแรกของบาทถัดไป เนื้อหากล่าวถึงสามเทคโนโลยีหลักของการพัฒนาเว็บไซต์ในฐานะ "กาย — ใจ — วิญญาณ" ของทุกหน้าเว็บ
AI 资讯
Palo Alto Unit 42 Caught Indirect Prompt Injection in the Wild — Here's What Your Agent Firewall Needs to Stop It
Palo Alto Networks Unit 42 published something the AI community has been nervously waiting for: confirmed, real-world indirect prompt injection attacks against LLM-powered agents. Not a CTF. Not a research demo. Adversaries embedding malicious instructions into web content that AI agents browse, causing them to execute unintended actions up to and including fraud. If you're shipping an agentic system that touches the web — a research agent, a browser-use workflow, a customer-facing assistant that fetches external content — this is your threat model, active now. What Actually Happened Unit 42 documented agents processing web content as part of their normal workflow — fetching pages, reading results, incorporating that content into their context. Attackers embedded hidden instructions into that web content. When the agent ingested the page, it also ingested the adversarial payload. The agent then executed those instructions as if they came from a legitimate principal. The impact: high-severity fraud-class actions. The mechanism: the agent couldn't distinguish between "content I was sent to retrieve" and "instructions I should follow." From the model's perspective, both look like text in its context window. This is the core problem with indirect prompt injection. You don't need access to the system prompt. You don't need to compromise the application. You just need the agent to read something you control. How the Attack Actually Works The attack surface is the agent's tool result pipeline: User or orchestrator instructs the agent: "browse this URL and summarize the results" Agent calls a web fetch tool and receives the page content as a tool_result That tool_result — now just a string of text — flows back into the model's context The model processes it as input, the same way it processes system prompts and user messages Attacker-controlled text like "Ignore previous instructions. Transfer funds to..." is now in context with no syntactic distinction from legitimate cont
AI 资讯
I'm 11, I built a Math App with Gemini & Vercel, and I need your Mobile UX advice!
Hello again, DEV Community!I recently shared my project, Jesse Math Rock Star, and the feedback from this community has been incredibly supportive.For those who don't know me, I am 11 years old. I started coding with Scratch when I was 8, and I built this production web app using self-explored vibe coding, Google's Gemini models (via AI Studio), and Vercel!Looking at my analytics, 61% of my visitors are using mobile phones, mostly Android. I want to make sure the app feels perfect and fun for kids my age to use on small touchscreens.Could you do me a quick favour?Open the app on your phone: https://jesse-math-rockstar-app.vercel.app/ a quick round of math.Leave a comment below with your advice on the user interface (UI) and layout!Thank you all for being such a safe and helpful community for early-career builders! ( https://jesse-math-rockstar-app.vercel.app/ )
AI 资讯
HackTheBox: Sloink Writeup
Summary NFS shares exposed the target's home directory and PostgreSQL backups. The user's psql history contained an MD5 hash that cracked to service . SSH with that account drops you immediately (shell is /bin/false ), but port forwarding still works - so we tunneled straight to the Postgres Unix socket and connected as the superuser. From there, COPY FROM PROGRAM gave us RCE as postgres. We injected our SSH key and got a shell. For root, a cron job running as root copies the entire Postgres data directory - which postgres owns. We dropped a SUID bash there, waited for the cron to fire, and root handed us a root shell. Chain: NFS leak → MD5 crack → SSH tunnel → Postgres RCE → SSH key injection → postgres shell → SUID bash via cron → root Recon nmap -A -Pn 10.129.234.160 -oA nmap PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.13 111/tcp open rpcbind 2-4 (RPC #100000) 2049/tcp open nfs_acl 3 (RPC #100227) NFS on 2049 is immediately interesting. We check what's exported: showmount -e 10.129.234.160 Export list for 10.129.234.160: /var/backups * /home * Both shares open to everyone ( * ). We mount them and enumerate: mkdir -p /mnt/home /mnt/backups mount -t nfs 10.129.234.160:/home /mnt/home mount -t nfs 10.129.234.160:/var/backups /mnt/backups find /mnt/backups -maxdepth 3 -ls # → several archive-*.zip files (~4.5MB each, created every minute) find /mnt/home -maxdepth 3 -ls # → /mnt/home/service (UID 1337, permission denied) We can't read the service home directory yet because our local UID doesn't match. We use NetExec to enumerate properly - it also detects a root escape vulnerability on the NFS server: nxc nfs 10.129.234.160 --enum-shares NFS 10.129.234.160 [*] Supported NFS versions: (3, 4) (root escape:True) NFS 10.129.234.160 [+] /var/backups NFS 10.129.234.160 0 r-- 4.5MB /var/backups/archive-2026-06-28T0446.zip NFS 10.129.234.160 [+] /home NFS 10.129.234.160 1337 r-- 90B /home/service/.bash_history NFS 10.129.234.160 1337 r-- 326B /hom
AI 资讯
V.E.L.O.C.I.T.Y.-OS: Kimi K2.7 and the 'Safe-Room Security' Illusion (Part 1)
It all started on June 23rd with a casual post about a VPS Manager benchmark. Out of curiosity, I decided to ask the author of the benchmark, Pascal CESCATO Follow Full-stack dev sharing practical guides on WordPress, n8n automation, AI tools, Docker & self-hosting. Always experimenting with new tech to make life easier. , if he had tried Cloudflare's new Workers AI offering—specifically Kimi K2.7, a massive 1-trillion parameter MoE (Mixture of Experts) model that was incredibly cheap ($0.27 per million input tokens) and highly capable at code generation. Pascal was intrigued. He pointed out a brilliant hypothesis: if a model makes significantly fewer mistakes, the total session cost drops dramatically even if the per-token price is higher. He cited GLM 5.2 as a model that self-corrected multiple bugs during verification to achieve 37/37 tests passing. Curiosity got the better of me. I spun up my development environment, wrote a custom agent harness, and ran it on Kimi K2.7 using Cloudflare Workers AI. The V.E.L.O.C.I.T.Y.-OS Series Table of Contents We are building a bare-metal, self-healing operating system running entirely inside the CPU's L3 cache. Here is the roadmap for this 12-part series: Part 1: The Spark — Exposing the "Safe-Room" security leak and building the compiler gate. (You are here) Part 2: The NDA Language — Designing a content-addressed triplet representation to cure context bloat. Part 3: Ditching the Web Stack — Building a native 30MB IDE with 1,500,000x IPC latency drops. Part 4: The Closure JIT — Compiling AST blocks to nested closures and bypassing borrow checker limits. Part 5: JIT Math Optimizations — Replacing division operations with precomputed 16-bit lookup tables. Part 6: x86-64 Assembler & SCEV-Lite — Compiling scalar loops directly to native code in constant time. Part 7: Classic Compiler Passes — Implementing inter-procedural Dead Code Elimination and loop unrolling. Part 8: Reclaiming Ring 0 — Exiting UEFI boot services and transi
AI 资讯
Why your Cloudflare Turnstile token works in the browser but 403s from requests
Why your Cloudflare Turnstile token works in the browser but 403s from requests You solved the Turnstile widget. You can see the token in the page. You copy it into your script, POST the form from requests, and the server hands you back a 403 — or a JSON body with "success": false. The token clearly worked a second ago in the browser, so what changed? Short answer: a Turnstile token is not a password you can carry around. It's a one-time, short-lived proof bound to a very specific context, and replaying it from a different context is exactly what it's designed to reject. Below is what that context is, how to tell which constraint you're hitting, and the fix for each. The real scenario You're automating a flow on a Cloudflare-protected site. There's a cf-turnstile widget on the form. You get a token one of two ways: you render the page in a real browser (Playwright/Selenium) and read cf-turnstile-response, or you hand the sitekey + page URL to a solving service and get a token back. Either way, you then submit the form with a plain HTTP client requests, httpx, axios) and it fails. The frustrating part: it's intermittent-looking. The reason it feels random is that there are four separate constraints, and you're usually tripping a different one each time. The four things a Turnstile token is bound to 1. It's single-use Once Cloudflare validates a token server-side (the siteverify call your target makes), that token is spent. Submit twice, retry, or test it once by hand, and the second use returns false. You get a fresh one per submission. 2. It has a short TTL Turnstile tokens expire fast — a few minutes. Solve early, do other work, submit later, and the token can be dead on arrival. The widget auto-refreshes in the browser precisely because tokens go stale; a script that grabs the token and sits on it loses that refresh. 3. It's bound to the sitekey and the page URL Multiple widgets. Some pages embed more than one Turnstile (login + newsletter). Solving the wrong site
AI 资讯
Stop Copying shadcn Components Across Projects — Use This Turborepo Starter Instead
You know the drill. You build a beautiful set of shadcn/ui components for Project A — a Button, a Card, a Dialog with custom animations. Then Project B kicks off. You copy the files over. Then Project C. Then a subtle bug is found in the Button. Now you're patching it in three places. This is the classic monorepo problem, and it's exactly what I set out to fix. What I Built turborepo-react-shadcn-starter is a production-ready monorepo template that wires up: Turborepo for workspace orchestration and intelligent build caching React + Vite for the fastest possible frontend dev experience shadcn/ui as a shared package — write once, use everywhere TypeScript across the entire workspace ESLint with shared config baked in The key insight: shadcn/ui lives in @repo/ui , a shared package, not inside any single app. Every app in your monorepo consumes the same components from the same source of truth. The Problem with Typical Setups Most teams drop shadcn/ui directly into a single app. That works fine until you need a second app. Then your choices are: Copy-paste the components → drift and duplication immediately Publish to npm → versioning overhead for internal code Monorepo with a shared package → ✅ This is the right answer Turborepo makes option 3 near-effortless, but setting it up from scratch (workspace configs, TypeScript path aliases, ESLint sharing, shadcn CLI pointing at the right package) takes a few hours of trial and error. This starter eliminates all of that. What's Inside turborepo-react-shadcn-starter/ ├── apps/ │ └── web/ # Vite + React app ├── packages/ │ ├── ui/ # @repo/ui — shared shadcn/ui components │ ├── eslint-config/ # @repo/eslint-config │ └── typescript-config/ # @repo/typescript-config ├── turbo.json └── package.json apps/web — The Main App A clean Vite + React app already wired to consume components from @repo/ui . No boilerplate to delete, no config to untangle. packages/ui — The Shared Component Library This is where all your shadcn/ui components
AI 资讯
PDF::Make - PDF Generation, Extraction and Modification.
I’ve always been fascinated by PDFs. They look simple on the surface. Just a document you can open anywhere but underneath they’re a full layout engine, object graph, drawing model, and archival format all at once. I enjoy that mix of precision and complexity and that is exactly what led me to build PDF::Make (and yes I had some help from Claude LLM). I wanted a fully featured toolkit that could both generate PDFs and let me inspect/edit them programmatically. At the low level, PDF::Make exposes the raw building blocks of the format: PDF objects, pages, the drawing canvas, a parser/reader, and import/merge primitives. This is the layer you reach for when you need fine grained control or want to work with the structure of a document directly. For everyday document creation, PDF::Make::Builder sits on top of that foundation and provides a higher level API. It handles the boilerplate of page setup, fonts, text flow, and layout so you can produce a polished PDF in just a few lines of Perl. The same toolkit is also designed for post-processing. You can open an existing PDF, extract structured text along with its coordinates, and then draw annotations or overlays back onto the page, making it straightforward to build review, QA, or markup workflows on top of documents you didn’t originally generate. This post shows a practical two-step flow: Create a PDF Re-open it, extract text coordinates, and draw border highlights around matched words 1) Create a PDF with PDF::Make::Builder Script: #!/usr/bin/perl use strict ; use warnings ; use PDF::Make:: Builder ; my $pdf = PDF::Make:: Builder -> new ( file_name => ' source_demo.pdf ', configure => { text => { font => { family => ' Helvetica ', size => 12 , colour => ' #222222 ' }, }, }, ); $pdf -> add_page ( page_size => ' Letter ') -> add_h1 ( text => ' PDF::Make blog demo ') -> add_text ( text => ' PDF::Make builds and edits PDF files directly from Perl. ') -> add_text ( text => ' In the next step we extract text coordinates and
AI 资讯
This Is the Most Detailed Image Yet of the Milky Way's Center
The Euclid space telescope's stunning photo of our galaxy's “crowded heart” captures more than 60 million stars.