Clocks and Time in Distributed Systems

Imagine two servers on opposite sides of a data center. Each timestamps a bank transaction with its own local clock. If one clock runs even a few milliseconds fast, a problem arises. A withdrawal could appear to happen before the deposit that funded it. This happens even though the deposit came first in reality. This is not a hypothetical bug. It is the default behavior of physical clocks in a distributed system. Every machine's clock is an independent piece of hardware. Each one ticks at its own imperfect rate. In a single computer, time is nearly free to trust. There is one crystal oscillator, one operating system clock. There is one consistent notion of "before" and "after." The moment a system spans multiple machines, this assumption collapses. These machines are connected by an unreliable network. Each node has its own clock, and clocks drift apart at different rates. Messages carrying time information take unpredictable amounts of time to arrive. This builds directly on the challenge of Partial Failure and Concurrency. Not only can a message be delayed or lost. Even a message that arrives successfully carries a timestamp whose meaning is already suspect. Physical time synchronization matters enormously in practice. Distributed databases use timestamps to order transactions and resolve conflicts. Financial systems require accurate ordering for regulatory compliance and fraud detection. Distributed logging and monitoring tools rely on timestamps too. They reconstruct the sequence of events across a fleet of machines during an incident. TLS certificates, Kerberos tickets, and OAuth tokens all have expiration times. These must be checked consistently. Google's Spanner database famously built an entire consistency model around this problem. That model, TrueTime, bounds clock uncertainty rather than pretending it away. This article explains what physical clocks are and why they drift. It also covers the classical algorithms used to synchronize them across a network. These include Cristian's algorithm, the Berkeley algorithm, and the Network Time Protocol (NTP). It also explains, carefully, why no amount of clever synchronization can help. Physical clocks cannot become a reliable tool for ordering events in a distributed system. This motivates a completely different idea: Logical Clocks and Lamport Timestamps.

Key takeaways
  • Every machine has its own hardware clock (a crystal oscillator) that drifts from true time at a rate measured in parts-per-million, called clock skew and clock drift.
  • Network delay is asymmetric and variable, so a node cannot simply ask another node "what time is it?" and trust the raw answer.
  • Cristian's algorithm estimates the server's time by measuring round-trip delay and assuming the request and response take equal time.
  • The Berkeley algorithm synchronizes a group of machines to their average time rather than to an external authority, useful when no reliable external time source exists.
  • NTP organizes time servers into a hierarchy of strata, uses statistical filtering across many samples, and can achieve millisecond-to-sub-millisecond accuracy over the internet.
  • Even with perfect synchronization algorithms, clocks have irreducible uncertainty, so physical timestamps alone cannot safely establish a global "happens-before" ordering of events — a gap that logical clocks are designed to close.
The core insight

Physical clocks can be synchronized to within a bounded error, but that error is never zero, so physical timestamps alone cannot be trusted to totally and correctly order events across a distributed system.

The idea

A physical clock is a hardware device — typically a quartz crystal oscillator — that counts oscillations and converts that count into a time-of-day value maintained by the operating system. Because no two crystals are manufactured identically, and because temperature, voltage, and age all affect oscillation frequency, every machine's clock ticks at a slightly different rate from "true" time (as defined by a reference standard such as UTC, Coordinated Universal Time, maintained by atomic clocks). The discrepancy between a clock's rate and the true rate is called clock drift, typically bounded by a drift rate ρ, so that over an interval of real time Δt, a clock's reported time can be off by at most ρ·Δt. Typical quartz oscillators drift at roughly 1–100 parts per million (ppm), meaning an unsynchronized clock can drift by several seconds per day. The instantaneous difference between two clocks' readings at the same real moment is called clock skew. Synchronization is the process of periodically adjusting a clock (or computing a correction offset) to keep skew within an acceptable bound. There are two flavors of synchronization: external synchronization, where nodes synchronize to an authoritative external time source (like a GPS or atomic clock reference), and internal synchronization, where a group of nodes agree with each other, without necessarily matching true external time. External synchronization to within bound D means that for any node's clock C and true time t, |C(t) − t| ≤ D. Internal synchronization to within bound D means that for any two nodes' clocks Ci and Cj, |Ci(t) − Cj(t)| ≤ D, even if both are wrong about the actual UTC time. The fundamental obstacle to synchronization is that clock readings must be communicated over a network, and message delay is variable and largely unknown to the receiver ahead of time. If node A sends its clock reading to node B, by the time B receives it, real time has advanced by the message's transit delay — and B has no direct way to know exactly how large that delay was. All physical clock synchronization algorithms are, at their core, strategies for estimating and compensating for this unknown network delay using statistical or worst-case reasoning.

How it works

Cristian's algorithm

Cristian's algorithm synchronizes a client to a single, trusted time server, assuming the client can reach the server directly and that round-trip delay is (approximately) symmetric. ``` CristianSync(client, server): T0 <- client.localClock() # time request is sent send REQUEST to server wait for RESPONSE containing T_server T1 <- client.localClock() # time response is received RTT <- T1 - T0

# Assume network delay is symmetric: half of RTT each way estimatedDelay <- RTT / 2 newClientTime <- T_server + estimatedDelay client.setClock(newClientTime) uncertainty <- RTT / 2 # worst-case bound on error return (newClientTime, uncertainty) ``` The reasoning: the server reads its own clock, T_server, at the moment it prepares the response, which occurs somewhere between T0 and T1 in the client's timeline. Cristian's algorithm assumes the request-leg delay equals the response-leg delay, each roughly RTT/2, so it estimates that T_server actually corresponds to client time `T_server + RTT/2`. This estimate is exact only if the network is perfectly symmetric; in practice, the client typically issues several requests and keeps the response with the smallest RTT, since a small RTT bounds the possible asymmetry error more tightly (the true error can be at most RTT/2, so minimizing RTT minimizes the worst-case error bound).

Berkeley algorithm

The Berkeley algorithm was designed for clusters without a reliable external time source. Instead of trusting one authority, an elected time master polls all machines, computes a fault-tolerant average, and tells each machine how to adjust (not overwrite) its clock. ``` BerkeleyMasterSync(master, workers): T_master <- master.localClock() readings <- [ (master, T_master) ] for each worker in workers: T0 <- master.localClock() send TIME_REQUEST to worker wait for TIME_RESPONSE containing T_worker T1 <- master.localClock()

# Estimate worker's time compensated for round-trip delay,

# same idea as Cristian's algorithm (one-way delay ~ RTT/2) adjustedWorkerTime <- T_worker + (T1 - T0) / 2 readings.append( (worker, adjustedWorkerTime) )

# Discard outlier readings (clocks that are wildly off, e.g. faulty) filtered <- discardOutliers(readings) average <- mean( time for (node, time) in filtered ) for each (node, time) in filtered: delta <- average - time # can be negative send ADJUST(delta) to node # node applies delta to its own clock ``` Every participant, including the master, receives a relative adjustment rather than an absolute time. This means the whole cluster converges to a mutually consistent time even if none of them is close to true UTC time — internal synchronization rather than external synchronization. Faulty clocks are excluded from the average using outlier rejection (for example, discarding readings that deviate from the median by more than some threshold), so a single wildly wrong clock cannot drag the entire cluster's time in the wrong direction.

Network Time Protocol (NTP)

NTP is the internet-scale synchronization protocol used almost everywhere. It organizes time sources into a hierarchy of strata:

  • Stratum 0: reference clocks themselves — atomic clocks, GPS receivers — not directly on the network.
  • Stratum 1: servers directly connected to stratum-0 devices.
  • Stratum 2: servers that synchronize with stratum-1 servers, and so on, up to stratum 15.

Each NTP client exchanges timestamped messages with one or more servers and computes both an offset (the estimated difference between the client's and server's clocks) and a round-trip delay, using four timestamps per exchange. ``` NTPExchange(client, server): T1 <- client.localClock() # client send time send REQUEST(T1) to server

# server receives at T2, replies at T3 (both on server's clock) receive RESPONSE(T1, T2, T3) from server T4 <- client.localClock() # client receive time delay <- (T4 - T1) - (T3 - T2) # total RTT minus server processing time offset <- ((T2 - T1) + (T3 - T4)) / 2 return (offset, delay) ``` The offset formula follows from assuming the outbound delay (T2 − T1, measured against true time) and inbound delay (T4 − T3) are equal. Let the true one-way delay be d for both directions, and let the true clock offset (server minus client) be θ. Then: ``` T2 = T1 + d + θ T4 = T3 + d - θ ``` Adding: T2 + T4 = T1 + T3 + 2d, so d = ((T2 - T1) + (T4 - T3)) / 2, matching the `delay` computed above (rearranged). Subtracting: T2 − T4 = (T1 − T3) + 2θ, so θ = ((T2 − T1) − (T4 − T3)) / 2 = ((T2 − T1) + (T3 − T4)) / 2, exactly the `offset` formula. This derivation is exact only under the symmetric-delay assumption; asymmetric routing (common on the real internet) introduces error proportional to the delay asymmetry. A real NTP client does not act on a single exchange. It gathers samples from multiple servers over time, applies a clock filter (keeps the sample with the lowest delay in a window, since low delay bounds worst-case error), performs intersection and clustering algorithms to discard servers whose offsets disagree with the consensus (falsetickers), and then combines the remaining "truechimers" into a weighted average. The local clock is not reset abruptly (which could make time appear to run backwards, breaking applications); instead NTP slews the clock, temporarily speeding it up or slowing it down until the correction is absorbed, or steps it only for large corrections during startup. ``` NTPClientLoop(client, serverPool): loop forever: samples <- [] for server in serverPool: (offset, delay) <- NTPExchange(client, server) samples.append( (server, offset, delay) ) filtered <- clockFilter(samples) # keep low-delay, consistent samples truechimers <- intersectionAlgorithm(filtered) # reject outlier servers combinedOffset <- weightedAverage(truechimers) # weight by inverse delay/dispersion if abs(combinedOffset) > STEP_THRESHOLD: client.stepClock(combinedOffset) # rare: large jump, e.g. at boot else: client.slewClock(combinedOffset, maxRatePpm = 500) # gradual correction sleep(pollInterval) # pollInterval adapts, typically 64s to 1024s ```

Figure
Architecture of physical clock synchronization: NTP stratum hierarchy and message exchange
NTP Stratum Hierarchy and a Single Exchange GPS Stratum 0 Server A Stratum 1 Server B Stratum 2 Client Host Stratum 3 Single NTP Message Exchange (Client <-> Server B) Client Server B T1 (client send) T2 (server recv), T3 (server send) T4 (client recv) offset = ((T2-T1)+(T3-T4)) / 2 delay = (T4-T1) - (T3-T2)

Complexity & correctness

Message and time complexity. Cristian's algorithm requires one round trip per synchronization (O(1) messages), so its cost is dominated by network latency, not computation. Repeating k times to select the minimum-RTT sample costs O(k) messages and O(k) time to compare RTTs, still trivial compared to real-world polling intervals. The Berkeley algorithm requires the master to poll n workers, giving O(n) messages per round and O(n log n) time if outlier rejection uses sorting (or O(n) with a linear-time median-based filter); this is efficient because the number of machines in a cluster is typically small (tens to low hundreds) relative to polling frequency. NTP's per-exchange cost is O(1) messages, but a client typically polls m servers (commonly 4–8) per cycle, and the filtering/clustering algorithms operate on the last few samples from each server, giving overall per-cycle cost O(m·w) where w is the filter window size (typically 8) — still small and constant relative to m and w, i.e., independent of network size.

Correctness / error bound reasoning. The central correctness claim for Cristian's algorithm is a bound, not an exact value: if the true one-way delays satisfy d_out + d_in = RTT and each is at least 0, then the true server time at the moment of measurement lies within RTT/2 of the estimate `T_server + RTT/2` in the worst case (when delay is maximally asymmetric, e.g. d_out ≈ 0, d_in ≈ RTT, or vice versa). Formally, if we assume min_delay ≤ d_out, d_in and d_out + d_in = RTT, the maximum possible error between the estimate and the true value is RTT/2 − min_delay, which shrinks toward zero only as RTT shrinks toward the true minimum delay — this is why the algorithm is typically run several times and the response with smallest RTT is kept: it directly minimizes the provable error bound. For NTP, the same symmetric-delay assumption underlies the offset formula derived above; the proof that offset = ((T2−T1)+(T3−T4))/2 exactly cancels the unknown one-way delay d only holds when both directions truly share the same delay d. When delay is asymmetric by an amount ε (d_out = d + ε, d_in = d − ε), algebra shows the computed offset differs from the true offset θ by exactly ε — so asymmetric routing directly injects clock error, and no amount of averaging removes this systematic bias, only random jitter is reduced by averaging. This is an honest limitation: NTP's stated accuracy (commonly 1–50 ms over the public internet, sub-millisecond on a well-controlled LAN) is fundamentally bounded by network path symmetry, not by algorithmic cleverness.

Why physical clocks still cannot totally order events. Even a "perfectly" synchronized system, internally consistent to within bound D, still has D > 0 (D = 0 is physically unachievable because message delay is never zero and jitter is never eliminated). Consider two events e1 on node A and e2 on node B that are, in real causal time, separated by less than D — for instance, A sends a message and B receives it and immediately performs an action, with the whole exchange taking less time than the clock uncertainty D. It is entirely possible for B's timestamp on e2 to be numerically smaller than A's timestamp on e1, even though e1 causally preceded e2 (A's message caused B's action). This is not a bug in the synchronization algorithm; it is a mathematical consequence of D being strictly positive. Formally: physical clock synchronization can guarantee |Ci(t) − Cj(t)| ≤ D for all t, but it cannot guarantee that timestamp order matches causal (happens-before) order whenever two causally related events occur within a real-time window smaller than D. This is precisely the gap that motivates purely logical mechanisms — Logical Clocks and Lamport Timestamps — which order events by causality rather than by wall-clock value, sidestepping the synchronization-error problem entirely.

Worked example

Suppose a client synchronizes with an NTP server three times in quick succession, and we want to see how the algorithm behaves, including a case where the naive Cristian-style estimate would be misleading without the minimum-RTT selection rule.

AttemptT1 (client send)T2 (server recv)T3 (server send)T4 (client recv)RTT = T4−T1delay = RTT−(T3−T2)offset
11000.0001000.0501000.0511000.1200.120 s0.119 s+0.0405 s
22000.0002000.0202000.0212000.0450.045 s0.044 s+0.0225 s
33000.0003000.5003000.5013000.5600.560 s0.559 s+0.0295 s

(All times in seconds, using a hypothetical "true" clock timeline for illustration; the server clock genuinely runs 0.025 s ahead of the client's clock in this example, and network jitter varies attempt to attempt.) Applying the offset formula to attempt 1: offset = ((1000.050 − 1000.000) + (1000.051 − 1000.120)) / 2 = (0.050 − 0.069) / 2 = −0.0095 — wait, let's recompute carefully using the actual numbers: (T2 − T1) = 0.050, (T3 − T4) = 1000.051 − 1000.120 = −0.069. Sum = −0.019, divided by 2 = −0.0095 s. This illustrates a key point: attempt 1's large asymmetric delay (a slow return trip) badly distorts the offset estimate, even though it "looks like" a normal exchange. Redo attempt 2: (T2 − T1) = 0.020, (T3 − T4) = 2000.021 − 2000.045 = −0.024. Sum = −0.004, offset = −0.002 s. Much closer to the true value. Redo attempt 3: (T2 − T1) = 0.500, (T3 − T4) = 3000.501 − 3000.560 = −0.059. Sum = 0.441, offset = +0.2205 s — wildly wrong, driven by a huge, asymmetric network delay spike (a queuing delay burst on the return path). An NTP client's clock filter would examine the delay column (0.120, 0.045, 0.560) and retain the sample with the smallest delay, attempt 2 (delay = 0.044 s), because low delay bounds the worst-case asymmetry error most tightly. It would discard attempts 1 and 3 as unreliable, even though all three "succeeded" at the transport level. This demonstrates why NTP never trusts a single exchange, and why minimum-delay selection — not averaging all samples blindly — is the statistically sound approach: averaging attempt 1, 2, and 3's offsets naively would give (−0.0095 + −0.002 + 0.2205)/3 ≈ +0.0697 s, a badly biased result compared to trusting attempt 2's −0.002 s, which is much closer to reasonable expectations for a well-behaved link.

Common pitfalls & traps

PitfallWhy it happensConsequence
Assuming symmetric network delay always holdsAsymmetric routing, one-way congestion, or asymmetric last-mile links (e.g. asymmetric DSL/cable) violate the core assumptionSystematic (not random) clock offset error that averaging cannot fix
Stepping the clock abruptly on every correctionSimplicity; ignore side effectsTimestamps can appear to go backwards, breaking log ordering, file modification times, and lock leases
Trusting a single time server with no quorum or outlier checkSeems sufficient for a small deploymentOne misconfigured or compromised server can silently poison the whole fleet's clock
Using wall-clock timestamps to order events across machines for correctness-critical logic (e.g. "last write wins")Physical timestamps look intuitively like a total orderCausality violations: an earlier cause can get a later timestamp than its effect, corrupting application state
Ignoring clock drift between synchronization roundsAssuming synchronization is a one-time setup stepClocks silently re-diverge between polls, especially on VMs where the virtual clock can lag under CPU contention
Comparing timestamps across systems with different epoch or leap-second handlingOverlooking subtle timekeeping standards (UTC vs. TAI, leap seconds)Off-by-one-second bugs, especially around leap second events

Pioneers & history

The problem of synchronizing distributed clocks became formally important as computer networks grew beyond single machines in the 1970s and 1980s, but its intellectual roots trace to the deeper realization that "simultaneity" is not absolute — an idea most famously associated with relativity, later reinterpreted for the very different setting of message-passing computer networks.

Origins · 1 minLeslie Lamport and how this was discovered
LL
Leslie Lamport
born 1941 · Formalized the notion that physical time is insufficient to order distributed events and introduced logical clocks in his 1978 paper "Time, Clocks, and the Ordering of Events in a Distributed System," directly motivating the topic that follows this one.

FC
Flaviu Cristian
1945–1999 · Computer scientist who formalized the round-trip-delay-based client-server clock synchronization technique now known as Cristian's algorithm, emphasizing probabilistic guarantees on synchronization error in asynchronous networks.

DL
David L. Mills
1938–2024 · Designed and championed the Network Time Protocol starting in the early 1980s, building the stratum hierarchy, clock filtering, and selection algorithms that still synchronize most of the internet's clocks today.

History
1981
— David Mills begins development of what becomes the Network Time Protocol for ARPANET.
1985
— Flaviu Cristian formalizes probabilistic clock synchronization via round-trip time estimation.
1989
— The Berkeley algorithm is described for internal clock synchronization in networks of workstations without reliable external time sources.
1991
— NTP version 3 (RFC 1305) formalizes the modern stratum model and statistical filtering algorithms.
2010
s — Google's Spanner introduces TrueTime, using GPS and atomic clock hardware to bound clock uncertainty explicitly rather than assume it away, enabling globally consistent transaction ordering.

Where this matters

Nearly every large-scale distributed system depends on some form of physical time synchronization, even when it also uses logical mechanisms for correctness-critical ordering. Operating systems ship with NTP or its successor, chrony, running as a background daemon to keep the local clock aligned with public time servers. Financial exchanges use highly precise time synchronization — often via Precision Time Protocol (PTP), a refinement of NTP-style ideas for sub-microsecond accuracy — because regulations require verifiable, accurate ordering of trades across matching engines. Distributed tracing and observability tools (used to debug Partial Failure scenarios in microservice architectures) stitch together spans from many machines using timestamps, and inaccurate clocks directly translate into misleading trace visualizations. Certificate validation (TLS), Kerberos authentication, and OAuth token expiry all silently assume that clocks across communicating parties are reasonably close, and clock skew is a frequent, hard-to-diagnose cause of authentication failures in real production incidents. Google's Spanner database uses a system called TrueTime, which does not report a single timestamp but an interval [earliest, latest] guaranteed to contain the true time, explicitly encoding the uncertainty this article describes, and it waits out that uncertainty window before committing certain transactions to guarantee external consistency. Distributed databases such as CockroachDB adopt similar "commit-wait" strategies inspired directly by Spanner's approach. Understanding physical clock synchronization is thus a prerequisite for understanding both the practical operation of nearly all networked infrastructure and the theoretical motivation for logical clocks, vector clocks, and hybrid logical clocks that layer causal reasoning on top of (or instead of) wall-clock time.

Ask the tutor: How does Google's TrueTime system use explicit clock uncertainty intervals to guarantee transaction ordering in Spanner?

Why do physical clocks drift at all — isn't a quartz crystal precise?

Quartz crystals are precise in the sense of being highly consistent, but "consistent" is not the same as "exactly matching an external standard." Each crystal has manufacturing variations in its exact cut and shape, and its oscillation frequency also depends on temperature, supply voltage, and age, none of which are identical across machines. A crystal rated for 20 parts-per-million drift can be off by 20 microseconds every second, which compounds to roughly 1.7 seconds per day if left completely uncorrected. This is why every operating system runs a background synchronization daemon: without one, clocks would visibly diverge within hours, breaking anything that depends on cross-machine time comparisons, from log correlation to TLS certificate validation.

What's the practical difference between external and internal synchronization?

External synchronization ties every node's clock to an outside reference, typically UTC via GPS or a stratum-1 NTP server, so that |C(t) − t| stays within a bound for the true time t. Internal synchronization only guarantees that nodes agree with each other, |Ci(t) − Cj(t)| ≤ D, without necessarily being close to true UTC time at all. The Berkeley algorithm is a classic internal synchronization technique, useful in isolated clusters without internet access or a trusted external time source. Most production systems want both: internal agreement so application logic behaves consistently, and external accuracy so timestamps are meaningful when compared against real-world events like log timestamps from other organizations.

Does using NTP make it safe to use wall-clock timestamps to decide the order of events in my distributed application?

Not in general, and this is one of the most important cautions in the article. NTP reduces clock skew to a bound, often single-digit milliseconds on a LAN, but that bound is never zero, and network jitter can occasionally spike well beyond typical values. If two causally related events (one clearly happened because of the other) occur within a real-time gap smaller than the current synchronization error, their timestamps can appear in the wrong order. Systems that must get ordering exactly right — like database transaction ordering or distributed locks — should use techniques designed around this problem, such as logical clocks, vector clocks, or an explicit uncertainty interval like Google's TrueTime, rather than raw timestamp comparison.

Why does NTP slew the clock instead of just setting it to the correct time immediately?

If NTP simply overwrote the clock value every time it received a correction, the local clock could visibly jump backward whenever the estimated true time was earlier than the current reading. A clock moving backward can break assumptions baked into filesystems (modification timestamps), build systems (which rely on "newer than" comparisons), TLS session validity windows, and any code that computes elapsed time by subtracting two readings, potentially producing negative durations. Slewing avoids this by gradually speeding up or slowing down the rate at which the clock advances — for example, running 500 parts-per-million faster than normal — until the discrepancy is absorbed, so time as observed by applications always moves forward monotonically, just at a slightly adjusted rate for a while.

How does Cristian's algorithm handle the case where the network is congested and RTT is very large?

A large RTT directly widens the worst-case error bound, since the algorithm can only guarantee the true server time lies within RTT/2 of its estimate. It does not silently produce a wrong answer with false confidence; the error bound it reports scales honestly with the measured RTT. The standard mitigation is to repeat the request several times and keep only the response with the smallest observed RTT, since a smaller RTT provably tightens the worst-case error bound, assuming at least one attempt manages to avoid unusually heavy queuing delay. If all attempts see high RTT (e.g., a genuinely congested link), the algorithm's honest answer is that synchronization confidence is currently low, which real systems can use to widen application-level tolerance windows.

Is the Network Time Protocol still used today, or has it been replaced?

NTP remains extremely widely deployed; it is the default time synchronization mechanism built into virtually every major operating system, either directly or through a modernized implementation like chrony or systemd-timesyncd, both of which are protocol-compatible with NTP. For applications needing much tighter precision — sub-microsecond, such as high-frequency trading or telecom synchronization — the Precision Time Protocol (PTP, IEEE 1588) is used instead, applying similar statistical ideas but with hardware timestamping to eliminate most software-induced jitter. Large cloud providers also layer specialized systems, such as Amazon's Time Sync Service or Google's TrueTime, on top of GPS and atomic clock hardware, but these still rely on NTP-like exchange and filtering principles underneath.

How does this topic connect to logical clocks, which come next?

Physical clock synchronization tries to make wall-clock readings across machines agree as closely as possible, but this article shows that agreement can never be perfect, and near-simultaneous causally related events can still get out-of-order timestamps. Logical clocks abandon the goal of tracking real time altogether and instead track only relative causal order — did event A happen before event B, based on message-passing evidence, regardless of what any physical clock says. This reframing, introduced by Leslie Lamport, sidesteps network delay uncertainty entirely, because logical clocks only need to observe the order in which messages are sent and received, not measure how long they took.

Before this

Where this leads