Patterns Of Distributed Systems 1st Edition Unmesh Joshi download
Patterns Of Distributed Systems 1st Edition Unmesh Joshi download
https://ebookbell.com/product/patterns-of-distributed-
systems-1st-edition-unmesh-joshi-55578354
https://ebookbell.com/product/patterns-of-distributed-systems-unmesh-
joshi-48497112
https://ebookbell.com/product/agricultural-specialization-and-rural-
patterns-of-development-rural-history-in-europe-annie-antoine-
editor-50329396
https://ebookbell.com/product/remoting-patterns-foundations-of-
enterprise-internet-and-realtime-distributed-object-middleware-markus-
volter-michael-kircher-uwe-zdun-4701206
https://ebookbell.com/product/edge-computing-patterns-for-solution-
architects-learn-methods-and-principles-of-resilient-distributed-
application-architectures-from-hybrid-cloud-to-far-edge-ashok-iyengar-
joseph-pearson-58637174
Patterns Of World History Combined Volume With Sources Sample 2nd
Revised Ed Associate Professor Of History Peter Von Sivers
https://ebookbell.com/product/patterns-of-world-history-combined-
volume-with-sources-sample-2nd-revised-ed-associate-professor-of-
history-peter-von-sivers-44888366
https://ebookbell.com/product/patterns-of-parental-behavior-from-
animal-science-to-comparative-ethology-and-neuroscience-gabriela-
gonzlezmariscal-46462790
https://ebookbell.com/product/patterns-of-exposition-18th-
edition-18th-edition-robert-a-schwegler-48674118
https://ebookbell.com/product/patterns-of-interaction-computational-
design-across-scales-pia-fricker-49114422
https://ebookbell.com/product/patterns-of-christological-
categorisation-oneness-pentecostalism-and-the-renewal-of-jewish-and-
christian-monotheism-marvin-c-sanguinetti-49459098
Patterns of
Distributed Systems
Pearson Addison-Wesley
Signature Series
Unmesh Joshi
Many of the designations used by manufacturers and sellers to distinguish their products
are claimed as trademarks. Where those designations appear in this book, and the publisher
was aware of a trademark claim, the designations have been printed with initial capital
letters or in all capitals.
The author and publisher have taken care in the preparation of this book, but make no
expressed or implied warranty of any kind and assume no responsibility for errors or
omissions. No liability is assumed for incidental or consequential damages in connection
with or arising out of the use of the information or programs contained herein.
For information about buying this title in bulk quantities, or for special sales opportunities
(which may include electronic versions; custom cover designs; and content particular to
your business, training goals, marketing focus, or branding interests), please contact our
corporate sales department at [email protected] or (800) 382-3419.
For questions about sales outside the U.S., please contact [email protected].
All rights reserved. This publication is protected by copyright, and permission must be
obtained from the publisher prior to any prohibited reproduction, storage in a retrieval
system, or transmission in any form or by any means, electronic, mechanical, photocopying,
recording, or likewise. For information regarding permissions, request forms and the
appropriate contacts within the Pearson Education Global Rights & Permissions
Department, please visit www.pearson.com/permissions.
ISBN-13: 978-0-13-822198-0
ISBN-10: 0-13-822198-7
$PrintCode
Pearson’s Commitment to Diversity, Equity, and Inclusion
Pearson is dedicated to creating bias-free content that reflects the diversity of all
learners. We embrace the many dimensions of diversity, including but not limited
to race, ethnicity, gender, socioeconomic status, ability, age, sexual orientation,
and religious or political beliefs.
Education is a powerful force for equity and change in our world. It has the
potential to deliver opportunities that improve lives and enable economic mobil-
ity. As we work with authors to create content for every product and service, we
acknowledge our responsibility to demonstrate inclusivity and incorporate diverse
scholarship so that everyone can achieve their potential through learning. As
the world’s leading learning company, we have a duty to help drive change and
live up to our purpose to help more people create a better life for themselves
and to create a better world.
Our ambition is to purposefully contribute to a world where:
While we work hard to present unbiased content, we want to hear from you
about any concerns or needs with this Pearson product so that we can investigate
and address them.
ix
x Contents
Engineers are often attracted to distributed computing, which promises not only
benefits like scalability and fault tolerance but also the prestige of creating clever,
talk-worthy computer systems. But the reality is that distributed systems are hard.
There are myriads of edge cases, all with subtle interactions and high-dimensional
nuance. Every move you make as a systems designer has n-th degree side effects
which aren’t obvious. You’re Sideshow Bob, surrounded by lawn rakes, and every
step you take results in a rake in the face—until you’ve left the field or expended
all the rakes. (Oh, and even when you’ve left the field, there’s still a rake or two
waiting to be trodden on.)
So how do we avoid, or at least minimize, these pitfalls? The traditional ap-
proach has been to accept that distributed systems theory and practice are both
hard, and to work your way through textbooks and academic papers with confus-
ing or playful titles, studying numerous proofs so that you can carve out small
areas of relative safety and expertise within which to build your system. There’s
a lot of value in that approach for those that can stay the course. Systems profes-
sionals who have grown up that way seem to have a knack for spotting trouble
far down the line, and possess a good deal of technical background for reasoning
about how to solve problems—or at least minimize their likelihood or impact.
However, in other areas of software engineering, this kind of educational hazing
is not so commonplace. Instead of being thrown in at the deep end, we use ab-
stractions to help us gradually learn at greater levels of detail, from higher to
lower levels of abstraction, which often maps neatly onto the way software is
designed and built. Abstractions allow us to reason about behaviors without
getting bogged down in implementation complexity. In a distributed system where
complexity is high, some abstractions can be very useful.
In general software engineering, design patterns are a common abstraction. A
design pattern is a standardized solution to a recurrent problem in software design.
Patterns provide a language that practitioners use to reason about and discuss
problems in a well-understood manner. For example, when someone asks, “How
does this work?” you may hear something like, “It’s just a visitor.” Such exchanges,
xvii
xviii Foreword
xix
xx Preface
logical clocks—but you won’t know how products like MongoDB use them as a
version for the data they store.
I believe that writing code is the best way to test your understanding. Martin
Fowler often says, “Code is like the mathematics of our profession. It’s where we
have to remove the ambiguity.” So, to get a deeper understanding of the building
blocks of distributed systems, I decided to build miniature versions of these
products myself. I started by building a toy version of Kafka. Once I had a rea-
sonable version, I used it to discuss some of the concepts of distributed systems.
That worked well. To verify that explaining concepts through code works effec-
tively, I conducted a few workshops within my company, Thoughtworks. Those
turned out to be very useful. So I extended this to products like Cassandra,
Kubernetes, Akka, Hazelcast, MongoDB, YugabyteDB, CockroachDB, TiKV, and
Docker Swarm. I extracted code snippets to understand the building blocks of
these products. Not surprisingly, there were a lot of similarities in these building
blocks. I happened to discuss this with Martin Fowler a few years back, and he
suggested writing about these as patterns. This book is the outcome of my work
with Martin to document these common building blocks of distributed system
implementations as patterns.
who must build their own distributed systems. I hope the patterns in this book
will give that other group a head start. There are numerous references to design
alternatives used by various products, which might be useful to these readers.
A Note on Examples
I have provided code examples for most of the patterns. The code examples are
based on my own miniature implementations of the various products I studied
while working through these patterns. My choice of language is based on what
I think most readers are likely to be able to read and understand. Java is a good
choice here. The code examples use a minimum of Java language features—mostly
methods and classes, which are available in most programming languages.
Readers familiar with other programming languages should be able to easily un-
derstand these code examples. This book, however, is not intended to be specific
for any particular software platform. Once you understand the code examples,
you will find similarities in code bases in C++, Rust, Go, Scala, or Zig. My hope
is that, once you are familiar with the code examples and the patterns, you will
find it easier to navigate the source code of various open-source products.
Register your copy of Patterns of Distributed Systems on the InformIT site for
convenient access to updates and/or corrections as they become available. To
start the registration process, go to informit.com/register and log in or create an
account. Enter the product ISBN (9780138221980) and click Submit. Look on the
Registered Products tab for an Access Bonus Content link next to this product,
and follow that link to access any available bonus materials. If you would like
to be notified of exclusive offers on new editions and updates, please check the
box to receive email from us.
Acknowledgments
First and foremost, the book was only possible because of encouragement from
Martin Fowler. He guided me to think in terms of patterns. He also helped me
come up with good examples and contributed to the chapters that were very
tricky to write.
I want to thank the Thirty Meter Telescope (TMT) team. Working with that
team was the trigger for much of this work. I had good conversations about many
of these patterns with Mushtaq Ahmed who was leading the TMT project.
Sarthak Makhija validated a lot of these patterns while he worked on building
a distributed key-value store.
I have been publishing these patterns periodically on martinfowler.com. While
working on these patterns, I sent drafts of new material to the Thoughtworks
developer mailing list and asked for feedback. I want to thank the following
people for posting their feedback on the mailing list: Rebecca Parsons, Dave
Elliman, Samir Seth, Prasanna Pendse, Santosh Mahale, James Lewis, Chris Ford,
Kumar Sankara Iyer, Evan Bottcher, Ian Cartwright, and Priyanka Kotwal. Jojo
Swords, Gareth Morgan, and Richard Gall from Thoughtworks helped with
copyediting the earlier versions published on martinfowler.com.
While working on the patterns, I interacted with many people. Professor Indranil
Gupta provided feedback on the Gossip Dissemination pattern. Dahlia Malkhi
helped with questions about Google Spanner. Mikhail Bautin, Karthik Ran-
ganathan, and Piyush Jain from the Yugabyte team answered all my questions
about some of implementation details in YugabyteDB. The CockroachDB team
was very responsive in answering questions about their design choices. Bela Ban,
Patrik Nordwall, and Lalith Suresh provided good feedback on the Emergent
Leader pattern.
Salim Virji and Jim Webber went through the early manuscript and provided
some nice feedback. Richard Sites provided some nice suggestions on the first
chapter. I want to extend my heartfelt thanks to Jim Webber for contributing the
foreword to this book.
One of the great things about being an employee at Thoughtworks is that they
allowed me to spend considerable time on this book. Thanks to the Engineering
xxiii
xxiv Acknowledgments
for Research (E4R) group of Thoughtworks for their support. I want to also thank
Sameer Soman, MD, Thoughtworks India, who always encouraged me.
At Pearson, Greg Doench is my acquisition editor, navigating many issues in
getting a book to publication. I was glad to work with Julie Nahil as my production
editor. It was great to work with Dmitry Kirsanov for copyediting and Alina
Kirsanova for composition and indexing.
My family has been a source of constant support. My mother was always very
hopeful about the book. My wife, Ashwini, is an excellent software developer
herself; she and I had insightful discussions and she provided valuable reviews
of early drafts. My daughter, Rujuta, and son, Advait, were sources of my
motivation.
About the Author
xxv
This page intentionally left blank
Part I
Narratives
1
This page intentionally left blank
Chapter 1
3
4 Chapter 1 The Promise and Perils of Distributed Systems
Likewise, when the CPU or memory limit is reached, requests must wait for
their turn to be processed. When these physical limits are pushed to their capac-
ity, this results in queuing. As more requests pile up, waiting times increase,
negatively impacting the server’s ability to efficiently handle user requests.
The impact of reaching the limits of these resources becomes evident in the
overall throughput of the system, as illustrated in Figure 1.2.
This poses a problem for end users. As the system is expected to accommodate
an increasing user base, its performance actually degrades.
To ensure requests are served effectively, you have to divide and process them
on multiple servers. This enables the utilization of separate CPUs, networks,
memory, and disks to handle user requests. In our example, the workload should
be divided so that each server handles approximately five hundred requests.
This way, most of the application logic executes on the separate server utilizing
a separate network, CPU, memory, and disk. This architecture works particularly
well if most users can be served from caches put at different layers in the archi-
tecture. It makes sure that only a portion of all requests need to reach the database
layer.
As the number of user requests increases, more servers can be added to handle
the stateless business logic. This scalability allows the system to accommodate a
growing user base and ensures that requests can be processed efficiently. In the
event of a server failure, a new server can be introduced to take over the workload
and continue serving user requests seamlessly (Figure 1.4).
6 Chapter 1 The Promise and Perils of Distributed Systems
This approach is effective for many applications. However, there comes a point
when the amount of data stored in stateful databases grows to hundreds of tera-
bytes or even petabytes, or the number of requests to the database layer increases
significantly. As a result, the simplistic architecture described above runs into
limitations stemming from the physical constraints of the four fundamental
resources on the server responsible for managing the data.
Partitioning Data
When a software system runs into hardware’s physical limits, the best approach
to ensure proper request processing is to divide the data and process it on mul-
tiple servers (Figure 1.5). This enables the utilization of separate CPUs, networks,
memory, and disks to handle requests on smaller data portions.
A Look at Failures 7
A Look at Failures
When we utilize multiple machines with their own disk drives, network intercon-
nects, processors, and memory units, the likelihood of failures becomes a signifi-
cant concern. Consider the hard disk failure probability. If a disk has a failure
rate of once in 1000 days, the probability of it failing on any given day is 1/1000,
which may not be a major concern on its own. However, if we have 1000 disks,
the probability of at least one disk failing on a given day becomes 1. If the parti-
tioned data is being served from the disk that fails, it will become unavailable
until the disk is recovered.
To gain insights into the types of failures that can occur look at the failure
statistics from Jeff Dean’s 2009 talk [Dean2009] on Google’s data centers as shown
in Table 1.1. Although these numbers are from 2009, they still provide a valuable
representation of failure patterns.
8 Chapter 1 The Promise and Perils of Distributed Systems
Table 1.1 Failure Events per Year for a Cluster in a Data Center from Jeff Dean’s 2009 Talk
[Dean2009]
Event Details
Router Reloads Takes out DNS and external VIPs for a couple minutes
Process Crash
Software processes can crash unexpectedly due to various reasons. It could be a
result of hardware failures or unhandled exceptions in the code. In containerized
or cloud environments, monitoring software can automatically restart a process
it recognizes as faulty. However, if a user has stored data on the server and re-
ceived a successful response, it becomes crucial for the software to ensure that
the data remains available after the process restarts. Measures need to be in place
to handle process crashes and ensure data integrity and availability.
Network Delay
The TCP/IP network protocol operates asynchronously, meaning it does not
provide a guaranteed upper bound on message delivery delay. This poses a
challenge for software processes that communicate over TCP/IP. They must de-
termine how long to wait for responses from other processes. If a response is
not received within the designated time, they need to decide whether to retry or
consider the other process as failed. This decision-making becomes crucial for
maintaining the reliability and efficiency of communication between processes.
Process Pause
During the execution of a process, it can pause at any given moment. In garbage-
collected languages like Java, execution can be interrupted by garbage collection
pauses. In extreme cases, these pauses can last tens of seconds. As a result, other
processes need to determine whether the paused process has failed. The situation
becomes more complex when the paused process resumes and begins sending
messages to other processes. The other processes then face a dilemma: Should
they ignore the messages or process them, especially if they had previously
10 Chapter 1 The Promise and Perils of Distributed Systems
marked the paused process as failed? Finding the right course of action in these
circumstances is a challenging problem.
Unsynchronized Clocks
The clocks in the servers typically utilize quartz crystals. However, the oscillation
frequency of a quartz crystal can be influenced by factors like temperature changes
or vibrations. This can cause the clocks on different servers to have different
times. Servers typically require a service such as NTP1 that continuously synchro-
nizes their clocks with time sources over the network. However, network faults
can disrupt this service, leading to unsynchronized clocks on servers.2 As a result,
when processes need to order messages or determine the sequence of saved data,
they cannot rely on the system timestamps because clock timings across servers
can be inconsistent.
that help comprehend real code while remaining applicable to a wide range of
systems. The Patterns approach is an excellent tool to fulfill these requirements.
The concept of patterns was initially introduced by architect Christopher
Alexander in his book A Pattern Language [Alexander1977]. This approach gained
popularity in the software industry, thanks to the influential book widely known
as the Gang Of Four [Gamma1994] book.
Patterns, as a methodology, describe particular problems encountered in soft-
ware systems, along with concrete solution structures that can be demonstrated
by real code. One of the key strengths of patterns lies in their descriptive names
and the specific code-level details they provide.
A pattern, by definition, is a “recurring solution” to a problem within a specific
context. Therefore, something is only referred to as a pattern if it is
observed repeatedly in multiple implementations. Generally, The Rule of Three3 is
followed—a pattern should be observed in at least three systems before it can be
recognized as a pattern.
The patterns approach, employed in this book, is rooted in the study of actual
codebases from various open source projects, such as Apache Kafka,4
Apache Cassandra,5 MongoDB,6 Apache Pulsar,7 etcd,8 Apache ZooKeeper,9
CockroachDB,10 YugabyteDB,11 Akka,12 JGroups,13 and others. These patterns
are grounded in practical examples and can be applied to different software sys-
tems. By exploring the insights gained from these codebases, readers can learn
to understand and apply these patterns to solve common software challenges.
Another important aspect of patterns is that they are not used in isolation but
rather in conjunction with other patterns. Understanding how the patterns interlink
makes it much easier to grasp the overall architecture of the system.
The next chapter takes a tour of most of the patterns and shows how they link
together.
3. https://wiki.c2.com/?RuleOfThree
4. https://kafka.apache.org
5. https://cassandra.apache.org
6. https://www.mongodb.com
7. https://pulsar.apache.org
8. https://etcd.io
9. https://zookeeper.apache.org
10. https://www.cockroachlabs.com
11. https://www.yugabyte.com
12. https://akka.io
13. http://www.jgroups.org
This page intentionally left blank
Chapter 2
As discussed in the last chapter, distributing data means at least one of two
things: partitioning and replication. To start our journey through the patterns in
this book, we’ll focus on replication first.
Imagine a very minimal data record that captures how many widgets we have
in four locations (Figure 2.1).
13
14 Chapter 2 Overview of the Patterns
An effective solution to this is Write-Ahead Log (Figure 2.4). With this, the
message handler first writes all the information about the required update to a
log file. This is a single write, so is simple to ensure it’s done atomically. Once the
write is done, the handler can acknowledge to its caller that it has handled
the request. Then the handler, or other component, can read the log entry and
carry out the updates to the underlying files.
Should Neptune crash after updating Boston, the log should contain enough
information for Neptune, when it restarts, to figure out what happened and restore
the data to a consistent state, as shown in Figure 2.5. (In this case it would
store the previous values in the log before any updates are made to the data file.)
The log gives us resilience because, for a known prior state, the linear sequence
of changes determines the state after the log is executed. This property is impor-
tant for resilience in a single node scenario but, as we’ll see, it’s also very valuable
for replication. If multiple nodes start at the same state, and they all play the
same log entries, we know they will end up at the same state too.
Databases use a Write-Ahead Log, as discussed in the above example, to
implement transactions.
Competing Updates
Suppose two different users, Alice and Bob, are connecting to two different
cluster nodes to execute their requests. Alice wants to move 30 widgets from
Boston to London, while Bob wants to move 40 widgets from Boston to Pune
(Figure 2.6).
16 Chapter 2 Overview of the Patterns
How should the cluster resolve this? We can’t have any node just decide to do
an update because we’d quickly run into inconsistency hell as we try to figure
out how to get Boston to store antimatter widgets. One of the most straightforward
approaches is Leader and Followers, where one of the nodes is marked as the
leader, and the others are considered followers. In this situation, the leader
handles all updates and broadcasts those updates to the followers. Let’s say
Neptune is the leader in this cluster. Then, Jupiter will forward Alice’s A1 request
to Neptune (Figure 2.7).
Neptune now gets both update requests, so it has the sole discretion as to how
to deal with them. It can process the first one it receives (Bob’s B1) and reject
A1 (Figure 2.8).
Dealing with the Leader Failing 17
The heartbeat gives us a way to know that Neptune has disconnected, so now
we can turn to the problem of how to deal with Bob’s request. We need to ensure
that once Neptune has confirmed the update to Bob, even if Neptune crashes,
the followers can elect a new leader with B1 applied to their data. But we also
need to deal with more complication than that, as Neptune may have received
multiple messages. Consider the case where there are messages from both Alice
(A1) and Bob (B1) handled by Neptune. Neptune successfully replicates them
both with Jupiter but is unable to contact Saturn before it crashes, as shown in
Figure 2.11.
In this case, how do Jupiter and Saturn deal with the fact that they have different
states?
The answer is essentially the same as discussed earlier for resilience on a single
node. If Neptune writes changes into a Write-Ahead Log and treats replication as
20 Chapter 2 Overview of the Patterns
copying those log entries to its followers, then its followers will be able to figure
out what the correct state is by examining the log entries (Figure 2.12).
When Jupiter and Saturn elect a new leader, they can tell that Jupiter’s log
has later index entries, and Saturn can apply those log entries to itself to gain a
consistent state with Jupiter.
This is also why Neptune can reply to Bob that the update was accepted, even
though it hadn’t heard back from Saturn. As long as a Majority Quorum—that is,
a majority—of the nodes in the cluster have successfully replicated the log mes-
sages, Neptune can be sure that the cluster will maintain consistency even if the
leader disconnects.
Multiple Failures Need a Generation Clock 21
Jupiter is elected as a new leader, and accepts a request from Alice to move
30 widgets from Boston to London. But it also crashes before replicating the
request to other nodes (Figure 2.14).
In a while, Neptune and Jupiter come back, but before they can talk, Saturn
crashes. Neptune is elected as a leader. Neptune checks with itself and Jupiter
for the log entries. It will see two separate requests at index 1, the one from Bob
which it had accepted and the one from Alice that Jupiter has accepted. Neptune
can’t tell which one it should pick (Figure 2.15).
To solve this kind of situation, we use a Generation Clock. This is a number that
increments with each leadership election. It is a key requirement of Leader and
Followers.
Looking at the previous scenario again, Neptune was leader for generation 1.
It adds Bob’s entry in its log marking it with its generation (Figure 2.16).
When Jupiter gets elected as a leader, it increments the generation to 2. So
when it adds Alice’s entry to its log, it’s marked for generation 2 (Figure 2.17).
22 Chapter 2 Overview of the Patterns
The work of this man, who is not a caricaturist, but a student and faithful
representer, bears a strong likeness to things in literature rather than to
things in art. He suggests Dickens, Zola, Tolstoi. Throughout his work is
apparent the broad sympathy of a man of the people who has espoused their
cause and made himself their prophet.
Part of the crowd, elbow to elbow with humanity in the very vortex of
the mass, he has felt the multitude, blood and sinew, around him, until it has
become amalgamated fairly with his inspiration. Then withdrawn to a
fortification, possibly, of his city, in semi-retirement, he lets the turbulent
suggestions take form that he may present them to the world. Thus Steinlen,
so closely of the people, is in reality separated from mankind by virtue of
his talent. And if to the eye demanding agreeable form, beauty seems
sometimes lacking in this artist’s strong, original, profoundly human
creations, it may be said that æsthetics do not abound in the walks of life
which this student of humanity portrays.
FOOTNOTE:
[A] Chez Pelletan.
*** END OF THE PROJECT GUTENBERG EBOOK MODERN FRENCH
MASTERS ***
Updated editions will replace the previous one—the old editions will
be renamed.
1.D. The copyright laws of the place where you are located also
govern what you can do with this work. Copyright laws in most
countries are in a constant state of change. If you are outside the
United States, check the laws of your country in addition to the
terms of this agreement before downloading, copying, displaying,
performing, distributing or creating derivative works based on this
work or any other Project Gutenberg™ work. The Foundation makes
no representations concerning the copyright status of any work in
any country other than the United States.
1.E.6. You may convert to and distribute this work in any binary,
compressed, marked up, nonproprietary or proprietary form,
including any word processing or hypertext form. However, if you
provide access to or distribute copies of a Project Gutenberg™ work
in a format other than “Plain Vanilla ASCII” or other format used in
the official version posted on the official Project Gutenberg™ website
(www.gutenberg.org), you must, at no additional cost, fee or
expense to the user, provide a copy, a means of exporting a copy, or
a means of obtaining a copy upon request, of the work in its original
“Plain Vanilla ASCII” or other form. Any alternate format must
include the full Project Gutenberg™ License as specified in
paragraph 1.E.1.
• You pay a royalty fee of 20% of the gross profits you derive
from the use of Project Gutenberg™ works calculated using the
method you already use to calculate your applicable taxes. The
fee is owed to the owner of the Project Gutenberg™ trademark,
but he has agreed to donate royalties under this paragraph to
the Project Gutenberg Literary Archive Foundation. Royalty
payments must be paid within 60 days following each date on
which you prepare (or are legally required to prepare) your
periodic tax returns. Royalty payments should be clearly marked
as such and sent to the Project Gutenberg Literary Archive
Foundation at the address specified in Section 4, “Information
about donations to the Project Gutenberg Literary Archive
Foundation.”
• You comply with all other terms of this agreement for free
distribution of Project Gutenberg™ works.
1.F.
1.F.4. Except for the limited right of replacement or refund set forth
in paragraph 1.F.3, this work is provided to you ‘AS-IS’, WITH NO
OTHER WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO WARRANTIES OF
MERCHANTABILITY OR FITNESS FOR ANY PURPOSE.
Please check the Project Gutenberg web pages for current donation
methods and addresses. Donations are accepted in a number of
other ways including checks, online payments and credit card
donations. To donate, please visit: www.gutenberg.org/donate.
Most people start at our website which has the main PG search
facility: www.gutenberg.org.
ebookbell.com