AI 资讯
From Joint State-Transition Prediction to Language: A Minimal Predictive Hypothesis of Intelligence
Abstract This paper proposes a minimal hypothesis connecting physical structure, biological intelligence, language, and artificial intelligence. The central claim is that intelligence may not require causality, logic, symbolic reasoning, planning, or explicit object relations as primitive cognitive mechanisms. At its lowest level, intelligence may consist only of predicting transitions between high-dimensional joint states. Reality is minimally assumed to admit local states that can participate in larger joint states and undergo state transitions. A nervous system, itself composed of many simultaneously active units, naturally supports distributed high-dimensional states and can learn to predict how such states change. Language is proposed to emerge from this predictive process rather than from a predesigned symbolic system. During practical interaction with the world, sounds, gestures, perceptions, actions, and bodily states occur together. When sounds become reliably predictive of other states, they acquire symbolic function. Once symbols begin predicting other symbols, prediction can operate in a compressed, recursively composable symbolic state space. On this view, explicit causality, logic, mathematics, planning, and science emerge from increasingly complex language-state prediction rather than from separate underlying cognitive mechanisms. This hypothesis suggests a corresponding direction for artificial intelligence: a unified multimodal latent state space in which perception, language, memory, action, and world dynamics are learned through state-transition prediction. 1. Minimal Reality: Local and Joint States We begin with a deliberately weak assumption about reality. Reality can be represented, for an observer, as states that change. States can also contain distinguishable local structure and participate in larger joint states. Let X_t denote the state accessible to an intelligent system at time t . A state transition can be written simply as: X_t → X_(t+1
AI 资讯
Finding the AI Agents That Actually Matter with Leave-One-Out Ablation
Introduction Modern AI systems rarely rely on a single model anymore. A fraud detection pipeline might combine specialists for: Transaction analysis Identity verification Device fingerprinting Network analysis Similarly, RAG pipelines, LangGraph workflows, and other multi-agent systems often have several AI agents collaborating before producing a final decision. As these systems become more complex, one question becomes surprisingly difficult to answer: Which agent actually influenced the final decision? Running four or five agents doesn't necessarily mean all of them contributed. Sometimes a single specialist completely determines the outcome while the rest simply add latency and compute cost. Most multi-agent frameworks make it easy to build agent workflows—but they don't tell you which agents actually mattered . That question led me to build agent-ablation , a lightweight TypeScript library for performing leave-one-out ablation testing on multi-agent decision systems. Why I built this While experimenting with multi-agent systems, I kept asking myself questions like: Which specialist actually changed the final verdict? Which agents consistently influence decisions? Are some agents effectively redundant? Am I paying for LLM calls that never affect the outcome? Answering those questions usually meant manually removing agents, rerunning experiments, and comparing outputs. That quickly became tedious. I wanted a simple utility that could automate this experiment. Instead of guessing which agents mattered, I wanted to measure their influence. That's why I built agent-ablation . The Idea The core algorithm is intentionally simple. Given a set of agent findings and a deterministic decision function: Compute the baseline decision. Remove one agent's finding. Recompute the decision. Compare the new verdict with the baseline. Repeat for every agent. If removing an agent changes the verdict, that agent is load-bearing . Otherwise, it wasn't necessary for producing that parti
科技前沿
Xiaomi 18 Fold hands-on: An attractive 'mid-size' foldable with powerful specs
Xiaomi's impressive-sounding new foldable arrives on the eve of Apple's big foldable iPhone event.
AI 资讯
Keep a Record of What You Believed Before You Knew
Memory is not a log. It is a story rewritten after you learn how it ended. You will remember being less certain than you were. You will remember seeing the risk you missed. That is not dishonesty. That is how remembering works. Which is why you cannot learn judgment from memory alone. The correction is unglamorous. Before the decision, write down what you expect. Not a plan. A prediction. We are choosing this because we believe that. We think it takes three weeks. We think the load arrives by March. If it does not, we were wrong about the growth, not about the design. Four lines. A date. Somewhere you will find it again. Add the number you least want to write. How sure are you. Seven out of ten is a real answer. Certain is almost never a real answer, and writing it down makes you notice how often you reach for it. Then set a time to come back. The value is not in the writing. It is in the reading, six months on, when the outcome is known and the note is not. You find out something nobody else can tell you. Whether you run early or you run late. Whether your confident calls land better than your hesitant ones. Whether you are wrong about people more often than you are wrong about systems. That is calibration. It is the whole difference between ten years of experience and one year lived ten times. It changes rooms, too. A review where somebody can produce what they actually believed in March is a different meeting from one where everyone remembers agreeing. Hindsight makes us unfair in a peculiar direction. It makes the past look obvious, and the people standing in it look careless. They were not careless. They were standing exactly where you are, with less information and no ending. So write down where you are standing. Your future self will not be able to reconstruct it, and your future self is the one who has to get better. – Serguey Asael Shinder
AI 资讯
Efficient Karatsuba Multiplication Algorithm for Resource-Constrained 8-Bit Computers to Boost Computational Speed
Introduction Implementing the Karatsuba multiplication algorithm on an 8-bit computer isn’t just an academic exercise—it’s a practical solution to a real-world problem. Resource-constrained systems, like the 8-bit TTL computer I’ve been hacking on, face inherent limitations in memory, processing power, and clock speed. These constraints force every operation to be scrutinized for efficiency. Traditional multiplication algorithms, such as the grade-school method, become bottlenecks when dealing with large numbers, as they scale quadratically with input size. Karatsuba, however, offers a theoretical edge: it reduces the number of multiplications required from n² to nlog₂3 ≈ n1.585 , making it significantly faster for sufficiently large inputs. The Challenge: Balancing Theory and Practice Theoretical efficiency is one thing; practical implementation on an 8-bit system is another. The Karatsuba algorithm relies on recursive division and addition, which introduces overhead in memory usage and control flow. On an 8-bit computer, where registers are limited to 8 bits and memory addressing is constrained, this overhead can negate the algorithm’s benefits if not carefully managed. For example, splitting a number into high and low parts requires additional memory accesses, and recursive calls can quickly exhaust the stack. The physical limitation here is the finite number of transistors and clock cycles , which directly impact how much computation can be performed within a given time frame. Why Karatsuba? A Comparative Analysis Other multiplication algorithms, like Toom-Cook or even hardware-specific optimizations, were considered. However, Karatsuba strikes a balance between simplicity and efficiency. Toom-Cook, while more efficient for very large numbers, introduces additional complexity in implementation and requires more memory for intermediate results. Hardware-specific optimizations, such as using lookup tables, are limited by the 8-bit architecture’s address space. Kar
AI 资讯
Posterior Inference: From Joint Distributions to the Inference Bottleneck
A probabilistic model can describe more than the data you observe. It can also include hidden variables that capture structure you cannot observe directly. But defining that model is only the beginning. Once an observation x is available, the practical question changes: Given this x , what does the model imply about the hidden variable z ? That is the central problem of Posterior Inference . The notation is compact, but the computation is not always easy. High-dimensional latent spaces, complex posterior distributions, and interactions among hidden variables can make both the posterior itself and expectations under that posterior difficult to compute. Start with the Joint Distribution Suppose a probabilistic model contains an observed variable x and a hidden or latent variable z . The model does not treat them as unrelated quantities. Instead, it represents their probabilistic relationship through a Joint Distribution : p ( z , x ) This joint distribution describes how the observed data and the hidden variable fit together inside a single probability structure. Once x is observed, however, the question becomes conditional. We are no longer asking only how x and z relate in general. We want to know how the possible values of z are distributed given the particular observation x . That conditional distribution is the posterior. Posterior Distribution: Conditioning on Observed Data The Posterior Distribution is p ( z ∣ x ) = p ( x ) p ( z , x ) The numerator p ( z , x ) contains the probabilistic relationship between the latent variable and the observation. The denominator p ( x ) normalizes those values so that the result becomes a conditional probability distribution over z . The distinction is important: The joint distribution p ( z , x ) describes the probability structure of the model. The posterior distribution p ( z ∣ x ) tells us what that structure implies about z after x has been observed. In that sense, the posterior connects the model with actual data. Pos
AI 资讯
What iOS Build Tools Are Available: From xcodebuild to KXApp Compilation Solutions
The build process for iOS applications involves multiple technical stages, including source code compilation, resource packaging, code signing, and IPA generation. Xcode is the first choice for most iOS developers, but build tools are not limited to Xcode alone; choosing the right tool for different development scenarios can significantly improve efficiency. xcodebuild: The Command-Line Version of Xcode xcodebuild is a command-line build tool bundled with Xcode that compiles and packages without opening Xcode. Common commands include: xcodebuild build to build the project, xcodebuild archive to create an Archive, and xcodebuild -exportArchive to export an IPA. xcodebuild is suitable for integration into CI/CD. CI/CD platforms such as Jenkins, GitHub Actions, and GitLab CI can invoke xcodebuild to perform automated builds. Its downside is that there are many parameters, with over a dozen common parameter combinations, requiring time for initial configuration. Moreover, xcodebuild depends on the Xcode environment and can only be used when Xcode is installed on a Mac. Fastlane: An Automated Build Tool Fastlane, written in Ruby, is an automation toolchain built on top of xcodebuild. It defines the workflows for building, testing, signing, and releasing through a Fastfile configuration file. For instance, lane :release defines a release pipeline that executes operations such as incrementing the version number, compiling, packaging, and uploading to TestFlight in sequence. Fastlane's match feature manages certificates and provisioning profiles, solving the problem of certificate synchronization in team collaboration. gym encapsulates the complex parameters of xcodebuild, allowing an IPA to be generated with a single command. Fastlane also has a rich plugin ecosystem covering push notifications, screenshots, and metadata management. Project Management with CocoaPods and XcodeGen CocoaPods handles the integration of third-party dependencies. Declare the dependent libraries
AI 资讯
Why Compliance Kills Early-Stage Projects and How to Fix It
Compliance itself isn't the villain. The problem is a system designed for large banks being forced onto small teams who measure time in sprints, not fiscal quarters. Innovation was never meant to wait for permission. It's supposed to be fast, chaotic, and full of discovery. But for anyone who has tried to launch a startup especially in Web3, fintech, or any regulated space there is a familiar slowdown that begins the moment compliance enters the conversation. Everything feels alive until the first "verification required" email arrives. That's when the waiting begins. Compliance itself isn't the villain. It protects systems from fraud, builds trust between unknown parties, and ensures accountability. But the way compliance exists today feels like a relic a system designed for large banks, traditional corporations, and legal departments with infinite patience and paperwork. For small teams who measure time in sprints, this system simply doesn't fit. The Repetition Tax Most founders encounter the compliance disconnect the moment they try to grow. After building their MVP and testing their product, they reach the stage where partnerships or investors arrive and suddenly they're asked to complete KYB (Know Your Business) verification again and again. Each time a new partner or service provider comes aboard, the process restarts: upload documents, verify directors, prove legitimacy. It's not that startups resist compliance; they simply don't understand why they must prove the same truth multiple times to different counterparties who have no way to see each other's work. This endless repetition creates what many founders now call the repetition tax. It isn't paid in money but in time and motivation. The same hours that could have gone into improving a product or connecting with users are swallowed by forms, follow-ups, and "under review" messages. And crucially, all this duplicated effort doesn't make the system any safer it just makes it slower. The Security Paradox There
AI 资讯
Inside Tencent EdgeOne Makers: How It Works and What It Offers
Hello everyone! In this article, we will take a technical look at Tencent EdgeOne Makers , a Web and Agent development and deployment platform built on Tencent EdgeOne infrastructure. Rather than following a step-by-step tutorial, we will explore how the platform works behind the scenes and how its different technologies work together to support modern web applications. We will look at the journey from source code and build processes to deployment on the EdgeOne network. We will also explore how edge computing and caching deliver content closer to users, how Edge Functions and Cloud Functions handle server-side workloads, and how EdgeOne Makers supports AI Agents, storage, deployment environments, and developer tools . By understanding how these components interact, we can get a clearer picture of what Tencent EdgeOne Makers offers and how its architecture differs from traditional web hosting. Modern web applications are built from more than a frontend. They may combine APIs, serverless computing, storage, deployment automation, and AI services. Tencent EdgeOne Makers is a Web and Agent development and deployment platform built on Tencent EdgeOne infrastructure. It brings these capabilities into one environment, connecting application development with build processes, deployment, edge delivery, serverless execution, and AI development. EdgeOne Makers evolved from EdgeOne Pages, expanding from frontend hosting to full-stack Web and Agent development. Its architecture connects source code, deployment, and EdgeOne's global edge network. 1. From Source Code to Deployment At the center of Makers is its build and deployment workflow. A project can be connected to a Git repository, allowing Makers to detect common frameworks and apply build configurations. Developers can define parameters such as the root directory, installation command, build command, and output directory. Source Code → Git Repository → Build System → Deployment → EdgeOne Infrastructure → Users A push to
AI 资讯
I Keep Trying to Prove ShrekOS Doesn't Need to Exist
I have no idea what I'm f*cking doing. Something I keep questioning: Why the hell am I building an operating system for this? Seriously. Every couple of weeks I look at ShrekOS, look at the amount of work involved in building an actual Linux distribution, and have basically the same reaction. This is f*cking ridiculous. I wanted a safer way to run AI agents on my computer. Somehow that turned into an immutable Debian system with isolated workloads, capability grants, controlled egress, verified updates, a desktop policy layer, an installer, and enough architecture documents to make me question every decision that led me here. There has to be an easier answer. There has to be some tool I missed. Run the agents in Docker. Use Podman. Use a VM. Use a better agent harness. Install some security middleware. Find a desktop application that manages all of this. Anything other than: Build a f*cking operating system. So I keep trying to prove that ShrekOS does not need to exist. And the annoying part is that every time I do, I eventually end up back at the same problem. I already know containers exist I already wrote the technical version of this question in Why I'm Building ShrekOS When Containers Already Exist . I am not going to repeat that whole argument here. Containers are useful. I use them. The Bench system in ShrekOS literally runs on rootless container technology. I did not invent a magical new isolation primitive because AI showed up. Namespaces exist. Seccomp exists. Landlock exists. Containers exist. Virtual machines exist. Linux already has an absurd number of ways to restrict a process. That is not the thing I keep getting stuck on. The thing I cannot seem to find is the user space around all of it . Not userspace in the kernel terminology sense. I mean the actual space where the human uses the computer. The desktop. The workflow. The place where I can run several autonomous things on my machine and understand, at a glance, what each one is allowed to do. I wa
AI 资讯
DataLens: The Data Tool That Refused to pip install Anything
Somewhere in the DataLens build, my teammate and I hit the wall every "zero-dependency" project eventually hits: the anomaly detector needed a neural net, and the rulebook said no third-party packages. No NumPy. No pandas. No scikit-learn. Just Python 3.14's standard library. Our first reaction was denial. You cannot build an ANN without a matrix library — everyone knows that. numpy.dot() is basically load-bearing infrastructure for machine learning in Python. We spent an embarrassing amount of time trying to convince ourselves some obscure math submodule secretly did vectorized linear algebra. It doesn't. There is no shortcut. If you want matrix multiplication in pure stdlib Python, you write nested for loops and you like it. What we normally would have installed In any other project, this is a two-second decision: pip install numpy , import it, move on with your life. Matrix ops, broadcasting, vectorized activation functions — all free. Neither of us had ever really had to think about how A @ B works under the hood, because neither of us had ever had to write it ourselves. What it actually took to replace it An autoencoder needs: matrix multiplication, transpose, element-wise activation functions (sigmoid, ReLU), and gradient computation for backprop. Without NumPy, every one of those is a hand-rolled function operating on nested Python lists. Matrix multiply becomes three nested loops instead of one line. A forward pass that would be a single .dot() call turns into a small file of helper functions: matmul() , transpose() , add_bias() , sigmoid() , sigmoid_derivative() . We split it — one of us built the forward pass and activation functions, the other took backprop and the training loop — and then spent a good while debugging the seam where the two met. The genuinely hard part wasn't the math — it was performance. Pure Python loops over lists of lists are slow, and profiling a dataset with a few thousand rows through even a small autoencoder made that obvious fas
AI 资讯
Full-Stack Architecture Patterns That Actually Survive Production
Every full-stack tutorial ends the same way: a working app, a happy demo, and zero mention of what happens six months later when your "simple" CRUD app has 40 endpoints, three types of caching, and a frontend team that's afraid to touch the API layer. This post isn't about picking a framework. It's about the architectural decisions that quietly determine whether your app is pleasant to work on in year two — or a slow-motion disaster. 1. Stop treating your API layer as an afterthought A huge number of full-stack apps start with the frontend calling the backend directly, endpoint by endpoint, with no shared contract. It works fine at 5 endpoints. At 50, nobody remembers which fields are optional, which ones changed last sprint, or why the mobile app is still sending the old shape. Two things fix this early: A single source of truth for your API contract. Whether that's OpenAPI, GraphQL SDL, or even just shared TypeScript types in a monorepo package, the goal is the same: one place where "what does this endpoint return" is answered definitively. Generated clients over hand-written fetch calls. If you're writing fetch('/api/users/' + id) by hand in more than one place, you've already created a maintenance liability. Tools like openapi-typescript-codegen or a tRPC setup remove an entire category of bugs. // Instead of this scattered everywhere: const res = await fetch ( `/api/users/ ${ id } ` ); const user = await res . json (); // type: any, hope for the best // This, generated from your contract: const user = await api . users . getById ( id ); // fully typed, autocomplete works 2. Decide where your business logic lives — before you have 30 files that disagree The classic failure mode: business logic scattered across route handlers, database triggers, frontend validation, and a couple of "utils" files nobody wants to open. Every rule ends up implemented two or three times, slightly differently. Pick one layer to own the rules. A common, boring, effective pattern: Contr
AI 资讯
Stratagems #29: Leo Counted 164 Nodes. The AI's Blossoms Had One Root.
Dress a tree in borrowed blossoms, and it looks alive. The roots still tell the truth. — The 36...
AI 资讯
Le Creuset x Star Trek Collection: Prices, availability, release date
Vulcan oven mitts, spaceship baking dishes, and an out-of-this-world communicator grater—you'll need warp speed to Klingon to this limited edition kitchen kit, ideal for perfecting the broth of Khan.
AI 资讯
Security Foundations Behind Reliable AI Systems
Originally published on WordPress on September 27, 2025. When AI systems fail in production, the failure is often blamed on data quality, model drift, or algorithmic limitations. In practice, many of the most damaging failures originate much earlier and much lower in the stack. They come from weak security foundations that allow systems to behave in unintended ways. Reliable AI is not just about accuracy or performance. It is about whether the surrounding infrastructure enforces discipline around access, data handling, and execution paths. Infrastructure as the First Line of AI Security Every AI system depends on infrastructure that controls how compute, storage, and networking are consumed. If that infrastructure is loosely governed, the AI system inherits that weakness. A common example is a shared compute environment where multiple teams run experiments. If isolation is poorly enforced, one workload can access artifacts, logs, or intermediate data from another. The model may be mathematically sound, but the environment allows behavior that violates assumptions about separation and control. From a reliability standpoint, this creates hidden coupling. An AI job might fail or behave inconsistently because another process consumed shared resources or modified shared state. From a security standpoint, the same weakness allows unauthorized access to sensitive datasets or trained models. Strong infrastructure boundaries do not just protect against attackers. They protect teams from each other and from accidental misuse. Access Control Across the AI Lifecycle AI systems have long lifecycles that include data ingestion, preprocessing, training, evaluation, deployment, and monitoring. Each stage introduces different access needs. Problems arise when a single identity or role is allowed to operate across too many of these stages. For example, an engineer might have permission to both modify training data and deploy models. That convenience can quietly undermine trust in the
AI 资讯
Networking Foundations for Modern Edge & IoT Systems
Even though networking fundamentals are often taught at the early stages of a tech career, their relevance becomes far more important when you begin working with distributed IoT and edge-driven architectures. Concepts like subnetting, routing, NAT, DNS, firewalls, and VPNs evolve from simple textbook ideas into core architectural tools that determine how devices communicate, how secure the system remains, and how reliably data moves between the edge and the cloud. This refresher looks at these fundamentals from the perspective of someone building and supporting real IoT and edge environments. The goal is not to re-teach the basics, but to reconnect them with the realities of large-scale, low-power, and cloud-connected systems. 1. Subnetting as the Backbone of IoT Network Segmentation Subnetting plays a much bigger role in IoT and edge-driven environments than most people realize. In traditional networking, subnets help organize traffic and reduce broadcast noise. In IoT, they become a core part of the system architecture. When you’re dealing with sensors, gateways, and edge compute nodes running side by side, the network must be segmented in a way that keeps each function secure and predictable. A typical LoRaWAN setup shows this clearly. The gateway LAN, the packet-forwarder network, and the edge analytics node usually sit in different subnets. This separation allows you to apply strict ACLs around what each component can communicate with, especially because IoT devices often have limited security controls of their own. Subnetting also helps manage traffic flow, ensuring that noisy sensor broadcasts don’t interfere with time-sensitive edge workloads. Beyond security, good subnet design improves fault isolation. If a node misbehaves, the impact is contained within its segment. This structure also supports multi-tenant IoT deployments, where different applications or departments share the same physical infrastructure without touching each other’s data paths. In short
AI 资讯
Audi’s new A2 E-tron is its most affordable and efficient EV yet
When shopping for an electric vehicle, affordability is becoming a more common trait. But affordable and energy efficient is truly a rare breed. Often you have to sacrifice one for the other. Want something affordable? Great, here's a range loser. Want something that goes the distance? Be ready to pay the price. Surprisingly, here comes […]
AI 资讯
Opaque recurrence, and other AI terms that you should probably know
The rise of AI has brought an avalanche of new terms and slang. Here is a glossary with definitions of some of the most important words and phrases you might encounter.
AI 资讯
Enjoying coding again
I Have a Job — I Just Need to Do It A few months ago, I left my last job as a remote Unity developer. Before leaving, I had already started working on a freelance project to build a multi-tenant security and workforce management system . It became a fairly large system involving web applications, mobile apps, real-time tracking, scheduling, reporting, GPS, notifications, and more. The project is now mostly completed, but the client wants to continue adding maintenance, business logic changes, UI modifications, and new development under the same maintenance fee. That doesn't work for me. Maintenance and development are two different things, and when the amount of new development keeps growing while the price stays the same, eventually it stops being sustainable. So I started thinking about what I would do next. The Fear of Not Having a Job For the last few days, I was genuinely worried. I have more than 250,000 BDT in savings , so I'm not in an immediate financial crisis. But money slowly disappears when there is no income. And freelancing isn't exactly comforting right now either. I've been using Upwork, but the experience has become increasingly frustrating. You apply for jobs and often hear nothing. Some clients post a job and never hire anyone. Some jobs get dozens of proposals and disappear quickly. Some invites arrive, but someone else gets hired almost immediately. And every application costs money. After a while, it starts feeling like you're continuously putting money into a machine that promises a job somewhere in the future. You keep applying. You keep waiting. You keep hoping. And eventually, I realized something. What I Was Actually Missing I wasn't missing money. I was missing a job . And there is an important difference. I already have the skills. I already know how to build software. I already have ideas. I already have projects I want to work on. I was simply thinking that a "job" had to come from someone else. Then I thought: I can create my own job
AI 资讯
Zero-Budget Web Dev: Moving from Discord/Drive to Google Sites
Welcome to part one! This is the start of a series where I’ll be posting about my webdev and HTML nightmares. I hope you enjoy the read as much as I hate User Interfaces! Consider this a shared space for learning—I’m sharing what I’ve learned so far, and I’d love to hear your thoughts or better solutions in the comments. To kick things off, let’s talk about how this whole mess started. As a solo developer, you want to spend 99% of your time actually building the things you love. So when it’s time to share builds with early playtesters, I naturally take the path of least resistance... a pinned link in a Discord channel and a shared Google Drive folder. And for a while, it works. Until it suddenly doesn't. The Problem: The "Easy way" Trap Privately, with a small group of alpha testers, Discord is great. You can pin messages, create specific channels, and guide people directly. But as soon as you want to go public, Discord becomes a nightmare for onboarding new users: The "Tutorial" Requirement: If a new user needs a 5-minute guide just to navigate your Discord server to find the launcher or the latest release, you’ve already lost them. Zero Discoverability: Discord is great for community and chat, but terrible as a public storefront or documentation hub. Searching for news, filtering updates, or finding launcher links creates massive friction. Lack of Professionalism: To offer real support, showcase features, and look trustworthy to a public audience, you need a single source of truth—not a maze of text channels lost to the void. I didn't have time to manage an overly complex custom web setup or pay high monthly SaaS fees, but I needed a clean, low-maintenance way to go public. Yes, I spent no more than thirty seconds drawing this on my Bamboo tablet: Why Google? (And the Launcher Evolution) Before even thinking about the website, I had to solve the distribution problem for my launcher. I experimented with several download pipeline prototypes: Git Repos / Diversion (f