100% found this document useful (3 votes)
54 views

500 Lines or Less Experienced Programmers Solve Interesting Problems Michael Dibernardo 2024 Scribd Download

Programmers

Uploaded by

mouralawuraa
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
100% found this document useful (3 votes)
54 views

500 Lines or Less Experienced Programmers Solve Interesting Problems Michael Dibernardo 2024 Scribd Download

Programmers

Uploaded by

mouralawuraa
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 62

Download the full version of the textbook now at textbookfull.

com

500 Lines Or Less Experienced Programmers


Solve Interesting Problems Michael Dibernardo

https://textbookfull.com/product/500-lines-or-
less-experienced-programmers-solve-interesting-
problems-michael-dibernardo/

Explore and download more textbook at https://textbookfull.com


Recommended digital products (PDF, EPUB, MOBI) that
you can download immediately if you are interested.

Hypernomics: Using Hidden Dimensions to Solve Unseen


Problems 1st Edition Doug Howarth

https://textbookfull.com/product/hypernomics-using-hidden-dimensions-
to-solve-unseen-problems-1st-edition-doug-howarth/

textbookfull.com

How to Solve Real-world Optimization Problems: From Theory


to Practice 1st Edition Zak

https://textbookfull.com/product/how-to-solve-real-world-optimization-
problems-from-theory-to-practice-1st-edition-zak/

textbookfull.com

Microwave and RF Design Volume 2 Transmission Lines


Michael Steer

https://textbookfull.com/product/microwave-and-rf-design-
volume-2-transmission-lines-michael-steer/

textbookfull.com

Islamic Studies 1st Edition Ayesha Younas

https://textbookfull.com/product/islamic-studies-1st-edition-ayesha-
younas/

textbookfull.com
Operation Crossbow The History of the Allied Bombing
Missions against Nazi Germany s V 2 Rocket Program during
World War II Charles River
https://textbookfull.com/product/operation-crossbow-the-history-of-
the-allied-bombing-missions-against-nazi-germany-s-v-2-rocket-program-
during-world-war-ii-charles-river/
textbookfull.com

Fundamentals of Pathology Medical Course and Step 1 Review


2017 Edition Husain A. Sattar

https://textbookfull.com/product/fundamentals-of-pathology-medical-
course-and-step-1-review-2017-edition-husain-a-sattar-2/

textbookfull.com

Bang Blast Brothers 2 1st Edition Sabrina Stark Stark


Sabrina

https://textbookfull.com/product/bang-blast-brothers-2-1st-edition-
sabrina-stark-stark-sabrina/

textbookfull.com

Electrochemical Reduction of Carbon Dioxide Overcoming the


Limitations of Photosynthesis 1st Edition Frank Marken

https://textbookfull.com/product/electrochemical-reduction-of-carbon-
dioxide-overcoming-the-limitations-of-photosynthesis-1st-edition-
frank-marken/
textbookfull.com

Maternal Child Nursing Care 6th Edition Shannon E. Perry

https://textbookfull.com/product/maternal-child-nursing-care-6th-
edition-shannon-e-perry/

textbookfull.com
Su3 Symmetry in Atomic Nuclei 1st Edition V. K. B. Kota

https://textbookfull.com/product/su3-symmetry-in-atomic-nuclei-1st-
edition-v-k-b-kota/

textbookfull.com
Experienced programmers solve interesting problems
500 Lines or Less
Edited by Michael DiBernardo
This work is licensed under the Creative Commons Attribution 3.0 Unported license (CC BY 3.0). You are free:
• to Share—to copy, distribute and transmit the work
• to Remix—to adapt the work
under the following conditions:
• Attribution—you must attribute the work in the manner specified by the author or licensor (but not in any
way that suggests that they endorse you or your use of the work).
with the understanding that:
• Waiver—Any of the above conditions can be waived if you get permission from the copyright holder.
• Public Domain—Where the work or any of its elements is in the public domain under applicable law,
that status is in no way affected by the license.
• Other Rights—In no way are any of the following rights affected by the license:
– Your fair dealing or fair use rights, or other applicable copyright exceptions and limitations;
– The author’s moral rights;
– Rights other persons may have either in the work itself or in how the work is used, such as publicity
or privacy rights.
• Notice—For any reuse or distribution, you must make clear to others the license terms of this work. The
best way to do this is with a link to http://creativecommons.org/licenses/by/3.0/.
To view a copy of this license, visit http://creativecommons.org/licenses/by/3.0/ or send a letter to
Creative Commons, 444 Castro Street, Suite 900, Mountain View, California, 94041, USA.

The full text of this book is available online at http://www.aosabook.org/.


All royalties from its sale will be donated to Amnesty International.

Product and company names mentioned herein may be the trademarks of their respective owners.

While every precaution has been taken in the preparation of this book, the editors and authors assume no
responsibility for errors or omissions, or for damages resulting from the use of the information contained herein.

Front cover photo ©Kellar Wilson


Copyediting, cover design, and publishing support by Amy Brown: http://amyrbrown.ca

Revision Date: September 9, 2016

ISBN: 978-1-329-87127-4
Contents

Introduction ix
by Michael DiBernardo

1 Blockcode: A visual programming toolkit 1


by Dethe Elza

2 A Continuous Integration System 17


by Malini Das

3 Clustering by Consensus 33
by Dustin J. Mitchell

4 Contingent: A Fully Dynamic Build System 61


by Brandon Rhodes and Daniel Rocco

5 A Web Crawler With asyncio Coroutines 83


by A. Jesse Jiryu Davis and Guido van Rossum

6 Dagoba: an in-memory graph database 109


by Dann Toliver

7 DBDB: Dog Bed Database 141


by Taavi Burns

8 An Event-Driven Web Framework 153


by Leo Zovic

9 A Flow Shop Scheduler 175


by Dr. Christian Muise

10 An Archaeology-Inspired Database 191


by Yoav Rubin

11 Making Your Own Image Filters 215


by Cate Huston

12 A Python Interpreter Written in Python 243


by Allison Kaptur
13 A 3D Modeller 267
by Erick Dransch

14 A Simple Object Model 291


by Carl Friedrich Bolz

15 Optical Character Recognition (OCR) 309


by Marina Samuel

16 A Pedometer in the Real World 323


by Dessy Daskalov

17 The Same-Origin Policy 347


by Eunsuk Kang, Santiago Perez De Rosso, and Daniel Jackson

18 A Rejection Sampler 375


by Jessica B. Hamrick

19 Web Spreadsheet 395


by Audrey Tang

20 Static Analysis 409


by Leah Hanson

21 A Template Engine 431


by Ned Batchelder

22 A Simple Web Server 451


by Greg Wilson

vi CONTENTS
Introduction
Michael DiBernardo

This is the fourth volume in the Architecture of Open Source Applications series, and the first to not
feature the words “open source applications” anywhere in the title.
The first three volumes in the series were about big problems that big programs have to solve.
For an engineer who is early in their career, it may be a challenge to understand and build upon
programs that are much bigger than a few thousand lines of code, so, while big problems can be
interesting to read about, they can also be challenging to learn from.
500 Lines or Less focuses on the design decisions that programmers make in the small when they
are building something new. The programs you will read about in this book were all written from
scratch for this purpose (although several of them were inspired by larger projects that the authors
had worked on previously).
Before reading each chapter, we encourage you to first think about how you might solve the
problem. What design considerations or constraints do you think the author is going to consider
important? What abstractions do you expect to see? How do you think the problem is going to be
decomposed? Then, when reading the chapter, try to identify what surprised you. It is our hope that
you will learn more by doing this than by simply reading through each chapter from beginning to
end.
Writing a useful program in fewer than 500 lines of source code—without resorting to cheap
tricks—is a challenging exercise in itself; writing one to be read for pedagogical purposes when
neatly rendered in a printed book is even tougher. As such, the editors have occasionally taken
liberties with some of the source formatting when porting it into the book. The original source for
each chapter can be found in the code subdirectory of its project folder.
We hope that the experiences of the authors in this book will help you grow out of your comfort
zone in your own programming practice.
— Michael DiBernardo
Contributors
Michael DiBernardo (editorial): Michael DiBernardo is an engineer and director of delivery at
Wave, and a past PyCon Canada chair. He writes at mikedebo.ca.
Amy Brown (editorial): Amy Brown is a freelance editor based in Toronto. She specializes
in science and academic editing, and working with self-publishing authors. She co-edited the
Architecture of Open Source Applications books with Greg Wilson.
Dethe Elza (Blockcode): Dethe is a geek dad, aesthetic programmer, mentor, and creator of the
Waterbear visual programming tool. He co-hosts the Vancouver Maker Education Salons and wants
to fill the world with robotic origami rabbits.
Malini Das (CI): Malini is a software engineer who is passionate about developing quickly (but
safely!), and solving cross-functional problems. She has worked at Mozilla as a tools engineer and is
currently honing her skills at Twitch.
Dustin J. Mitchell (Cluster): Dustin is an open source software developer and release engineer at
Mozilla. He has worked on projects as varied as a host configuration system in Puppet, a Flask-based
web framework, unit tests for firewall configurations, and a continuous integration framework in
Twisted Python.
Daniel Rocco (Contingent): Daniel loves Python, coffee, craft, stout, object and system design,
bourbon, teaching, trees, and Latin guitar. Thrilled that he gets to write Python for a living, he is
always on the lookout for opportunities to learn from others in the community, and to contribute by
sharing knowledge. He is a frequent speaker at PyAtl on introductory topics, testing, design, and
shiny things; he loves seeing the spark of delight in people’s eyes when someone shares a surprising
or beautiful idea. Daniel lives in Atlanta with a microbiologist and four aspiring rocketeers.
Brandon Rhodes (Contingent): Brandon Rhodes started using Python in the late 1990s, and for
17 years has maintained the PyEphem library for amateur astronomers. He works at Dropbox, has
taught Python programming courses for corporate clients, consulted on projects like the New England
Wildflower Society’s “Go Botany” Django site, and will be the chair of the PyCon conference in
2016 and 2017. Brandon believes that well-written code is a form of literature, that beautifully
formatted code is a work of graphic design, and that correct code is one of the most transparent
forms of thought.
A. Jesse Jiryu Davis (Crawler): Jesse is a staff engineer at MongoDB in New York. He wrote
Motor, the async MongoDB Python driver, and he is the lead developer of the MongoDB C Driver and
a member of the PyMongo team. He contributes to asyncio and Tornado. He writes at emptysqua.re.
Guido van Rossum (Crawler): Guido is the creator of Python, one of the major programming
languages on and off the web. The Python community refers to him as the BDFL (Benevolent
Dictator For Life), a title straight from a Monty Python skit.
Dann Toliver (Dagoba): Dann enjoys building things, like programming languages, databases,
distributed systems, communities of smart friendly humans, and pony castles with his two-year-old.
Taavi Burns (DBDB): As the newest bass (and sometimes tenor) in Countermeasure, Taavi strives
to break the mould. . . sometimes just by ignoring its existence. This is certainly true through the
diversity of workplaces in his career: IBM (doing C and Perl), FreshBooks (all the things), Points.com
(doing Python), and now at PagerDuty (doing Scala). Aside from that—when not gliding along
on his Brompton folding bike—you might find him playing Minecraft with his son or engaging in
parkour (or rock climbing, or other adventures) with his wife. He knits continental.
Leo Zovic: Leo (better known online as inaimathi) is a recovering graphic designer who has
professionally written Scheme, Common Lisp, Erlang, Javascript, Haskell, Clojure, Go, Python,

viii Introduction
PHP and C. He currently blogs about programming, plays board games and works at a Ruby-based
startup in Toronto, Ontario.
Dr. Christian Muise (Flow shop): Dr. Muise is a Research Fellow with the Model-based Embedded
and Robotic Systems group at MIT’s Computer Science and Artificial Intelligence Laboratory. He is
interested in a variety of topics including AI, data-driven projects, mapping, graph theory, and data
visualization, as well as Celtic music, carving, soccer, and coffee.
Yoav Rubin (CircleDB): Yoav is a Senior Software Engineer at Microsoft, and prior to that was
a Research Staff Member and a Master Inventor at IBM Research. He works now in the domain
of data security in the cloud, and in the past his work focused on developing cloud- or web-based
development environments. Yoav holds an MSc in Medical Research in the field of Neuroscience
and BSc in Information Systems Engineering.
Cate Huston (Image filters): Cate is a developer and entrepreneur focused on mobile. She’s lived
and worked in the UK, Australia, Canada, China and the United States, as an engineer at Google, an
Extreme Blue intern at IBM, and a ski instructor. Cate speaks internationally on mobile development,
and her writing has been published on sites as varied as Lifehacker, The Daily Beast, The Eloquent
Woman and Model View Culture. She co-curates Technically Speaking, blogs at Accidentally in
Code and is @catehstn on Twitter.
Allison Kaptur (Interpreter): Allison is an engineer at Dropbox, where she helps maintain one
of the largest networks of Python clients in the world. Before Dropbox, she was a facilitator at the
Recurse Center, a writers’ retreat for programmers in New York. She’s spoken at PyCon North
America about Python internals, and loves weird bugs.
Erick Dransch (Modeller): Erick is a software developer and 2D and 3D computer graphics
enthusiast. He has worked on video games, 3D special effects software, and computer-aided design
tools. If it involves simulating reality, chances are he’d like to learn more about it. You can find him
online at erickdransch.com.
Carl Friedrich Bolz (Object model): Carl is a researcher at King’s College London and is broadly
interested in the implementation and optimization of all kinds of dynamic languages. He is one of
the core authors of PyPy/RPython and has worked on implementations of Prolog, Racket, Smalltalk,
PHP and Ruby.
Marina Samuel (OCR): Marina is an engineer at Mozilla and a current MSc student in Applied
Computing (Artifical Intelligence) at the University of Toronto. She hopes to one day build robots
that will take over the planet.
Dessy Daskalov (Pedometer): Dessy is an engineer by trade, an entrepreneur by passion, and
a developer at heart. She’s currently the CTO and co-founder of Nudge Rewards. When she’s not
busy building product with her team, she can be found teaching others to code, attending or hosting
a Toronto tech event, and online at dessydaskalov.com and @dess_e.
Eunsuk Kang (Same-origin policy): Eunsuk is a PhD candidate and a member of the Software
Design Group at MIT. He received his SM (Master of Science) in Computer Science from MIT
(2010), and a Bachelor of Software Engineering from the University of Waterloo (2007). His research
projects have focused on developing tools and techniques for software modeling and verification,
with applications to security and safety-critical systems.
Santiago Perez (Same-origin policy): Santiago is a PhD student in the Software Design Group at
MIT. He received his SM in Computer Science from MIT (2015), and an undergraduate degree from
ITBA (2011). He used to work at Google, developing frameworks and tools to make engineers more
productive (2012). He currently spends most of his time thinking about design and version control.
Daniel Jackson (Same-origin policy): Daniel is a professor in the Department of Electrical
Engineering and Computer Science at MIT, and leads the Software Design Group in the Computer

Michael DiBernardo ix
Science and Artificial Intelligence Laboratory. He received an MA from Oxford University (1984)
in Physics, and his SM (1988) and PhD (1992) in Computer Science from MIT. He was a software
engineer for Logica UK Ltd. (1984-1986), Assistant Professor of Computer Science at Carnegie
Mellon University (1992-1997), and has been at MIT since 1997. He has broad interests in software
engineering, especially in development methods, design and specification, formal methods, and
safety-critical systems.
Jessica B. Hamrick (Sampler): Jess is a PhD student at UC Berkeley where she studies human
cognition by combining probabilistic models from machine learning with behavioral experiments
from cognitive science. In her spare time, Jess is a core contributor to IPython and Jupyter. She also
holds a BS and MEng in Computer Science from MIT.
Audrey Tang (Spreadsheet): A self-educated programmer and translator, Audrey works with
Apple as an independent contractor on cloud service localization and natural language technologies.
Audrey has previously designed and led the first working Perl 6 implementation, and served in
computer language design committees for Haskell, Perl 5, and Perl 6. Currently Audrey is a full-time
g0v contributor and leads Taiwan’s first e-Rulemaking project.
Leah Hanson (Static analysis): Leah Hanson is a proud alum of Hacker School and loves helping
people learn about Julia. She blogs at blog.leahhanson.us and tweets at @astrieanna.
Ned Batchelder (Template engine): Ned is a software engineer with a long career, currently
working at edX to build open source software to educate the world. He’s the maintainer of coverage.py,
an organizer of Boston Python, and has spoken at many PyCons. He blogs at nedbatchelder.com.
He once had dinner at the White House.
Greg Wilson (Web server): Greg is the founder of Software Carpentry, a crash course in computing
skills for scientists and engineers. He has worked for 30 years in both industry and academia, and is
the author or editor of several books on computing, including the 2008 Jolt Award winner Beautiful
Code and the first two volumes of The Architecture of Open Source Applications. Greg received a
PhD in Computer Science from the University of Edinburgh in 1993.

x Introduction
Visit https://textbookfull.com
now to explore a rich
collection of eBooks, textbook
and enjoy exciting offers!
Acknowledgments
The Architecture of Open Source Applications series would not exist without the hard work of Amy
Brown and Greg Wilson. This particular book would not have been possible without the incredible
efforts of our army of technical reviewers:

Amber Yust Gregory Eric Sanderson Matthias Bussonnier


Andrew Gwozdziewycz James O’Beirne Max Mautner
Andrew Kuchling Jan de Baat Meggin Kearney
Andrew Svetlov Jana Beck Mike Aquino
Andy Shen Jessica McKellar Natalie Black
Anton Beloglazov Jo Van Eyck Nick Presta
Ben Trofatter Joel Crocker Nikhil Almeida
Borys Pierov Johan Thelin Nolan Prescott
Carise Fernandez Johannes Fürmann Paul Martin
Charles Stanhope John Morrissey Piotr Banaszkiewicz
Chris AtLee Joseph Kaptur Preston Holmes
Chris Seaton Josh Crompton Pulkit Sethi
Cyryl Płotnicki-Chudyk Joshua T. Corbin Rail Aliiev
Dan Langer Kevin Huang Ronen Narkis
Dan Shapiro Maggie Zhou Rose Ames
David Pokorny Marc Towler Sina Jahan
Eric Bouwers Marcin Milewski Stefan Turalski
Frederic De Groef Marco Lancini William Lachance
Graham Lee Mark Reid

Chris Seaton, John Morrissey, and Natalie Black deserve extended thanks for going above and beyond
in their technical reviewing. The quantity and depth of their reviews was instrumental in moving the
book forward at several sticking points.
We are very grateful to PagerDuty for their financial support.

Contributing
If you’d like to report errors or translate the content into other languages, please open an issue at
github.com/aosabook/500lines/ or contact us at aosa@aosabook.org.

xi
[chapter 1]

Blockcode: A visual programming toolkit


Dethe Elza

In block-based programming languages, you write programs by dragging and connecting blocks
that represent parts of the program. Block-based languages differ from conventional programming
languages, in which you type words and symbols.
Learning a programming language can be difficult because they are extremely sensitive to even
the slightest of typos. Most programming languages are case-sensitive, have obscure syntax, and will
refuse to run if you get so much as a semicolon in the wrong place—or worse, leave one out. Further,
most programming languages in use today are based on English and their syntax cannot be localized.
In contrast, a well-done block language can eliminate syntax errors completely. You can still
create a program which does the wrong thing, but you cannot create one with the wrong syntax: the
blocks just won’t fit that way. Block languages are more discoverable: you can see all the constructs
and libraries of the language right in the list of blocks. Further, blocks can be localized into any
human language without changing the meaning of the programming language.

Figure 1.1: The Blockcode IDE in use

Block-based languages have a long history, with some of the prominent ones being Lego Mind-
storms1 , Alice3D2 , StarLogo3 , and especially Scratch4 . There are several tools for block-based
1 http://www.lego.com/en-us/mindstorms/
2 http://www.alice.org/index.php
3 http://education.mit.edu/projects/starlogo-tng
4 http://scratch.mit.edu/
programming on the web as well: Blockly5 , AppInventor6 , Tynker7 , and many more8 .
The code in this chapter is loosely based on the open-source project Waterbear9 , which is not
a language but a tool for wrapping existing languages with a block-based syntax. Advantages of
such a wrapper include the ones noted above: eliminating syntax errors, visual display of available
components, ease of localization. Additionally, visual code can sometimes be easier to read and
debug, and blocks can be used by pre-typing children. (We could even go further and put icons on
the blocks, either in conjunction with the text names or instead of them, to allow pre-literate children
to write programs, but we don’t go that far in this example.)
The choice of turtle graphics for this language goes back to the Logo language, which was created
specifically to teach programming to children. Several of the block-based languages above include
turtle graphics, and it is a small enough domain to be able to capture in a tightly constrained project
such as this.
If you would like to get a feel for what a block-based-language is like, you can experiment with
the program that is built in this chapter from author’s GitHub repository10 .

1.1 Goals and Structure


I want to accomplish a couple of things with this code. First and foremost, I want to implement a
block language for turtle graphics, with which you can write code to create images through simple
dragging-and-dropping of blocks, using as simple a structure of HTML, CSS, and JavaScript as
possible. Second, but still important, I want to show how the blocks themselves can serve as a
framework for other languages besides our mini turtle language.
To do this, we encapsulate everything that is specific to the turtle language into one file
(turtle.js) that we can easily swap with another file. Nothing else should be specific to the turtle
language; the rest should just be about handling the blocks (blocks.js and menu.js) or be generally
useful web utilities (util.js, drag.js, file.js). That is the goal, although to maintain the small
size of the project, some of those utilities are less general-purpose and more specific to their use
with the blocks.
One thing that struck me when writing a block language was that the language is its own IDE.
You can’t just code up blocks in your favourite text editor; the IDE has to be designed and developed
in parallel with the block language. This has some pros and cons. On the plus side, everyone will
use a consistent environment and there is no room for religious wars about what editor to use. On
the downside, it can be a huge distraction from building the block language itself.

The Nature of Scripts


A Blockcode script, like a script in any language (whether block- or text-based), is a sequence of
operations to be followed. In the case of Blockcode the script consists of HTML elements which
are iterated over, and which are each associated with a particular JavaScript function which will be
run when that block’s turn comes. Some blocks can contain (and are responsible for running) other
blocks, and some blocks can contain numeric arguments which are passed to the functions.
5 https://developers.google.com/blockly/
6 http://appinventor.mit.edu/explore/
7 http://www.tynker.com/
8 http://en.wikipedia.org/wiki/Visual_programming_language
9 http://waterbearlang.com/
10 https://dethe.github.io/500lines/blockcode/

2 Blockcode: A visual programming toolkit


In most (text-based) languages, a script goes through several stages: a lexer converts the text
into recognized tokens, a parser organizes the tokens into an abstract syntax tree, then depending on
the language the program may be compiled into machine code or fed into an interpreter. That’s a
simplification; there can be more steps. For Blockcode, the layout of the blocks in the script area
already represents our abstract syntax tree, so we don’t have to go through the lexing and parsing
stages. We use the Visitor pattern to iterate over those blocks and call predefined JavaScript functions
associated with each block to run the program.
There is nothing stopping us from adding additional stages to be more like a traditional language.
Instead of simply calling associated JavaScript functions, we could replace turtle.js with a block
language that emits byte codes for a different virtual machine, or even C++ code for a compiler. Block
languages exist (as part of the Waterbear project) for generating Java robotics code, for programming
Arduino, and for scripting Minecraft running on Raspberry Pi.

Web Applications
In order to make the tool available to the widest possible audience, it is web-native. It’s written in
HTML, CSS, and JavaScript, so it should work in most browsers and platforms.
Modern web browsers are powerful platforms, with a rich set of tools for building great apps. If
something about the implementation became too complex, I took that as a sign that I wasn’t doing it
“the web way” and, where possible, tried to re-think how to better use the browser tools.
An important difference between web applications and traditional desktop or server applications
is the lack of a main() or other entry point. There is no explicit run loop because that is already
built into the browser and implicit on every web page. All our code will be parsed and executed on
load, at which point we can register for events we are interested in for interacting with the user. After
the first run, all further interaction with our code will be through callbacks we set up and register,
whether we register those for events (like mouse movement), timeouts (fired with the periodicity we
specify), or frame handlers (called for each screen redraw, generally 60 frames per second). The
browser does not expose full-featured threads either (only shared-nothing web workers).

1.2 Stepping Through the Code


I’ve tried to follow some conventions and best practices throughout this project. Each JavaScript file
is wrapped in a function to avoid leaking variables into the global environment. If it needs to expose
variables to other files it will define a single global per file, based on the filename, with the exposed
functions in it. This will be near the end of the file, followed by any event handlers set by that file, so
you can always glance at the end of a file to see what events it handles and what functions it exposes.
The code style is procedural, not object-oriented or functional. We could do the same things in
any of these paradigms, but that would require more setup code and wrappers to impose on what
exists already for the DOM. Recent work on Custom Elements11 make it easier to work with the
DOM in an OO way, and there has been a lot of great writing on Functional JavaScript12 , but either
would require a bit of shoe-horning, so it felt simpler to keep it procedural.
There are eight source files in this project, but index.html and blocks.css are basic structure
and style for the app and won’t be discussed. Two of the JavaScript files won’t be discussed in
any detail either: util.js contains some helpers and serves as a bridge between different browser
11 http://webcomponents.org/
12 https://leanpub.com/javascript-allonge/read

Dethe Elza 3
implementations—similar to a library like jQuery but in less than 50 lines of code. file.js is a
similar utility used for loading and saving files and serializing scripts.
These are the remaining files:
• block.js is the abstract representation of a block-based language.
• drag.js implements the key interaction of the language: allowing the user to drag blocks
from a list of available blocks (the “menu”) to assemble them into a program (the “script”).
• menu.js has some helper code and is also responsible for actually running the user’s program.
• turtle.js defines the specifics of our block language (turtle graphics) and initializes its
specific blocks. This is the file that would be replaced in order to create a different block
language.

blocks.jsblocks.js
Each block consists of a few HTML elements, styled with CSS, with some JavaScript event handlers
for dragging-and-dropping and modifying the input argument. The blocks.js file helps to create
and manage these groupings of elements as single objects. When a type of block is added to the
block menu, it is associated with a JavaScript function to implement the language, so each block in
the script has to be able to find its associated function and call it when the script runs.

Figure 1.2: An example block

Blocks have two optional bits of structure. They can have a single numeric parameter (with a
default value), and they can be a container for other blocks. These are hard limits to work with, but
would be relaxed in a larger system. In Waterbear there are also expression blocks which can be
passed in as parameters; multiple parameters of a variety of types are supported. Here in the land of
tight constraints we’ll see what we can do with just one type of parameter.

<!-- The HTML structure of a block -->


<div class="block" draggable="true" data-name="Right">
Right
<input type="number" value="5">
degrees
</div>

It’s important to note that there is no real distinction between blocks in the menu and blocks in
the script. Dragging treats them slightly differently based on where they are being dragged from,
and when we run a script it only looks at the blocks in the script area, but they are fundamentally the
same structures, which means we can clone the blocks when dragging from the menu into the script.
The createBlock(name, value, contents) function returns a block as a DOM element
populated with all internal elements, ready to insert into the document. This can be used to create
blocks for the menu, or for restoring script blocks saved in files or localStorage. While it is flexible
this way, it is built specifically for the Blockcode “language” and makes assumptions about it, so
if there is a value it assumes the value represents a numeric argument and creates an input of type
“number”. Since this is a limitation of the Blockcode, this is fine, but if we were to extend the blocks
to support other types of arguments, or more than one argument, the code would have to change.

4 Blockcode: A visual programming toolkit


function createBlock(name, value, contents){
var item = elem('div',
{'class': 'block', draggable: true, 'data-name': name},
[name]
);
if (value !== undefined && value !== null){
item.appendChild(elem('input', {type: 'number', value: value}));
}
if (Array.isArray(contents)){
item.appendChild(
elem('div', {'class': 'container'}, contents.map(function(block){
return createBlock.apply(null, block);
})));
}else if (typeof contents === 'string'){
// Add units (degrees, etc.) specifier
item.appendChild(document.createTextNode(' ' + contents));
}
return item;
}

We have some utilities for handling blocks as DOM elements:


• blockContents(block) retrieves the child blocks of a container block. It always returns a
list if called on a container block, and always returns null on a simple block
• blockValue(block) returns the numerical value of the input on a block if the block has an
input field of type number, or null if there is no input element for the block
• blockScript(block) will return a structure suitable for serializing with JSON, to save blocks
in a form they can easily be restored from
• runBlocks(blocks) is a handler that runs each block in an array of blocks
function blockContents(block){
var container = block.querySelector('.container');
return container ? [].slice.call(container.children) : null;
}

function blockValue(block){
var input = block.querySelector('input');
return input ? Number(input.value) : null;
}

function blockUnits(block){
if (block.children.length > 1 &&
block.lastChild.nodeType === Node.TEXT_NODE &&
block.lastChild.textContent){
return block.lastChild.textContent.slice(1);
}
}

function blockScript(block){
var script = [block.dataset.name];
var value = blockValue(block);
if (value !== null){

Dethe Elza 5
script.push(blockValue(block));
}
var contents = blockContents(block);
var units = blockUnits(block);
if (contents){script.push(contents.map(blockScript));}
if (units){script.push(units);}
return script.filter(function(notNull){ return notNull !== null; });
}

function runBlocks(blocks){
blocks.forEach(function(block){ trigger('run', block); });
}

drag.jsdrag.js
The purpose of drag.js is to turn static blocks of HTML into a dynamic programming language
by implementing interactions between the menu section of the view and the script section. The
user builds their program by dragging blocks from the menu into the script, and the system runs the
blocks in the script area.
We’re using HTML5 drag-and-drop; the specific JavaScript event handlers it requires are defined
here. (For more information on using HTML5 drag-and-drop, see Eric Bidleman’s article13 .) While
it is nice to have built-in support for drag-and-drop, it does have some oddities and some pretty major
limitations, like not being implemented in any mobile browser at the time of this writing.
We define some variables at the top of the file. When we’re dragging, we’ll need to reference
these from different stages of the dragging callback dance.

var dragTarget = null; // Block we're dragging


var dragType = null; // Are we dragging from the menu or from the script?
var scriptBlocks = []; // Blocks in the script, sorted by position

Depending on where the drag starts and ends, drop will have different effects:
• If dragging from script to menu, delete dragTarget (remove block from script).
• If dragging from script to script, move dragTarget (move an existing script block).
• If dragging from menu to script, copy dragTarget (insert new block in script).
• If dragging from menu to menu, do nothing.
During the dragStart(evt) handler we start tracking whether the block is being copied from
the menu or moved from (or within) the script. We also grab a list of all the blocks in the script
which are not being dragged, to use later. The evt.dataTransfer.setData call is used for dragging
between the browser and other applications (or the desktop), which we’re not using, but have to call
anyway to work around a bug.

function dragStart(evt){
if (!matches(evt.target, '.block')) return;
if (matches(evt.target, '.menu .block')){
dragType = 'menu';
}else{
dragType = 'script';
13 http://www.html5rocks.com/en/tutorials/dnd/basics/

6 Blockcode: A visual programming toolkit


}
evt.target.classList.add('dragging');
dragTarget = evt.target;
scriptBlocks = [].slice.call(
document.querySelectorAll('.script .block:not(.dragging)'));
// For dragging to take place in Firefox, we have to set this, even if
// we don't use it
evt.dataTransfer.setData('text/html', evt.target.outerHTML);
if (matches(evt.target, '.menu .block')){
evt.dataTransfer.effectAllowed = 'copy';
}else{
evt.dataTransfer.effectAllowed = 'move';
}
}

While we are dragging, the dragenter, dragover, and dragout events give us opportunities to
add visual cues by highlighting valid drop targets, etc. Of these, we only make use of dragover.

function dragOver(evt){
if (!matches(evt.target, '.menu, .menu *, .script, .script *, .content')) {
return;
}
// Necessary. Allows us to drop.
if (evt.preventDefault) { evt.preventDefault(); }
if (dragType === 'menu'){
// See the section on the DataTransfer object.
evt.dataTransfer.dropEffect = 'copy';
}else{
evt.dataTransfer.dropEffect = 'move';
}
return false;
}

When we release the mouse, we get a drop event. This is where the magic happens. We have
to check where we dragged from (set back in dragStart) and where we have dragged to. Then we
either copy the block, move the block, or delete the block as needed. We fire off some custom events
using trigger() (defined in util.js) for our own use in the block logic, so we can refresh the
script when it changes.

function drop(evt){
if (!matches(evt.target, '.menu, .menu *, .script, .script *')) return;
var dropTarget = closest(
evt.target, '.script .container, .script .block, .menu, .script');
var dropType = 'script';
if (matches(dropTarget, '.menu')){ dropType = 'menu'; }
// stops the browser from redirecting.
if (evt.stopPropagation) { evt.stopPropagation(); }
if (dragType === 'script' && dropType === 'menu'){
trigger('blockRemoved', dragTarget.parentElement, dragTarget);
dragTarget.parentElement.removeChild(dragTarget);
}else if (dragType ==='script' && dropType === 'script'){

Dethe Elza 7
if (matches(dropTarget, '.block')){
dropTarget.parentElement.insertBefore(
dragTarget, dropTarget.nextSibling);
}else{
dropTarget.insertBefore(dragTarget, dropTarget.firstChildElement);
}
trigger('blockMoved', dropTarget, dragTarget);
}else if (dragType === 'menu' && dropType === 'script'){
var newNode = dragTarget.cloneNode(true);
newNode.classList.remove('dragging');
if (matches(dropTarget, '.block')){
dropTarget.parentElement.insertBefore(
newNode, dropTarget.nextSibling);
}else{
dropTarget.insertBefore(newNode, dropTarget.firstChildElement);
}
trigger('blockAdded', dropTarget, newNode);
}
}

The dragEnd(evt) is called when we mouse up, but after we handle the drop event. This is
where we can clean up, remove classes from elements, and reset things for the next drag.

function _findAndRemoveClass(klass){
var elem = document.querySelector('.' + klass);
if (elem){ elem.classList.remove(klass); }
}

function dragEnd(evt){
_findAndRemoveClass('dragging');
_findAndRemoveClass('over');
_findAndRemoveClass('next');
}

menu.jsmenu.js
The file menu.js is where blocks are associated with the functions that are called when they run,
and contains the code for actually running the script as the user builds it up. Every time the script is
modified, it is re-run automatically.
“Menu” in this context is not a drop-down (or pop-up) menu, like in most applications, but is the
list of blocks you can choose for your script. This file sets that up, and starts the menu off with a
looping block that is generally useful (and thus not part of the turtle language itself). This is kind of
an odds-and-ends file, for things that may not fit anywhere else.
Having a single file to gather random functions in is useful, especially when an architecture is
under development. My theory of keeping a clean house is to have designated places for clutter, and
that applies to building a program architecture too. One file or module becomes the catch-all for
things that don’t have a clear place to fit in yet. As this file grows it is important to watch for emerging
patterns: several related functions can be spun off into a separate module (or joined together into a
more general function). You don’t want the catch-all to grow indefinitely, but only to be a temporary
holding place until you figure out the right way to organize the code.

8 Blockcode: A visual programming toolkit


Visit https://textbookfull.com
now to explore a rich
collection of eBooks, textbook
and enjoy exciting offers!
We keep around references to menu and script because we use them a lot; no point hunting
through the DOM for them over and over. We’ll also use scriptRegistry, where we store the
scripts of blocks in the menu. We use a very simple name-to-script mapping which does not support
either multiple menu blocks with the same name or renaming blocks. A more complex scripting
environment would need something more robust.
We use scriptDirty to keep track of whether the script has been modified since the last time it
was run, so we don’t keep trying to run it constantly.

var menu = document.querySelector('.menu');


var script = document.querySelector('.script');
var scriptRegistry = {};
var scriptDirty = false;

When we want to notify the system to run the script during the next frame handler, we call
runSoon() which sets the scriptDirty flag to true. The system calls run() on every frame, but
returns immediately unless scriptDirty is set. When scriptDirty is set, it runs all the script
blocks, and also triggers events to let the specific language handle any tasks it needs before and after
the script is run. This decouples the blocks-as-toolkit from the turtle language to make the blocks
re-usable (or the language pluggable, depending how you look at it).
As part of running the script, we iterate over each block, calling runEach(evt) on it, which sets
a class on the block, then finds and executes its associated function. If we slow things down, you
should be able to watch the code execute as each block highlights to show when it is running.
The requestAnimationFrame method below is provided by the browser for animation. It takes
a function which will be called for the next frame to be rendered by the browser (at 60 frames per
second) after the call is made. How many frames we actually get depends on how fast we can get
work done in that call.

function runSoon(){ scriptDirty = true; }

function run(){
if (scriptDirty){
scriptDirty = false;
Block.trigger('beforeRun', script);
var blocks = [].slice.call(
document.querySelectorAll('.script > .block'));
Block.run(blocks);
Block.trigger('afterRun', script);
}else{
Block.trigger('everyFrame', script);
}
requestAnimationFrame(run);
}
requestAnimationFrame(run);

function runEach(evt){
var elem = evt.target;
if (!matches(elem, '.script .block')) return;
if (elem.dataset.name === 'Define block') return;
elem.classList.add('running');
scriptRegistry[elem.dataset.name](elem);

Dethe Elza 9
elem.classList.remove('running');
}

We add blocks to the menu using menuItem(name, fn, value, contents) which takes a
normal block, associates it with a function, and puts in the menu column.

function menuItem(name, fn, value, units){


var item = Block.create(name, value, units);
scriptRegistry[name] = fn;
menu.appendChild(item);
return item;
}

We define repeat(block) here, outside of the turtle language, because it is generally useful in
different languages. If we had blocks for conditionals and reading and writing variables they could
also go here, or into a separate trans-language module, but right now we only have one of these
general-purpose blocks defined.

function repeat(block){
var count = Block.value(block);
var children = Block.contents(block);
for (var i = 0; i < count; i++){
Block.run(children);
}
}
menuItem('Repeat', repeat, 10, []);

turtle.jsturtle.js
turtle.js is the implementation of the turtle block language. It exposes no functions to the rest of
the code, so nothing else can depend on it. This way we can swap out the one file to create a new
block language and know nothing in the core will break.
Turtle programming is a style of graphics programming, first popularized by Logo, where you
have an imaginary turtle carrying a pen walking on the screen. You can tell the turtle to pick up
the pen (stop drawing, but still move), put the pen down (leaving a line everywhere it goes), move
forward a number of steps, or turn a number of degrees. Just those commands, combined with
looping, can create amazingly intricate images.
In this version of turtle graphics we have a few extra blocks. Technically we don’t need both
turn right and turn left because you can have one and get the other with negative numbers.
Likewise move back can be done with move forward and negative numbers. In this case it felt
more balanced to have both.
The image above was formed by putting two loops inside another loop and adding a move
forward and turn right to each loop, then playing with the parameters interactively until I liked
the image that resulted.

var PIXEL_RATIO = window.devicePixelRatio || 1;


var canvasPlaceholder = document.querySelector('.canvas-placeholder');
var canvas = document.querySelector('.canvas');
var script = document.querySelector('.script');
var ctx = canvas.getContext('2d');

10 Blockcode: A visual programming toolkit


Figure 1.3: Example of Turtle code running

var cos = Math.cos, sin = Math.sin, sqrt = Math.sqrt, PI = Math.PI;


var DEGREE = PI / 180;
var WIDTH, HEIGHT, position, direction, visible, pen, color;

The reset() function clears all the state variables to their defaults. If we were to support multiple
turtles, these variables would be encapsulated in an object. We also have a utility, deg2rad(deg),
because we work in degrees in the UI, but we draw in radians. Finally, drawTurtle() draws the
turtle itself. The default turtle is simply a triangle, but you could override this to draw a more
aesthetically-pleasing turtle.
Note that drawTurtle uses the same primitive operations that we define to implement the turtle
drawing. Sometimes you don’t want to reuse code at different abstraction layers, but when the
meaning is clear it can be a big win for code size and performance.

function reset(){
recenter();
direction = deg2rad(90); // facing "up"
visible = true;
pen = true; // when pen is true we draw, otherwise we move without drawing
color = 'black';
}

function deg2rad(degrees){ return DEGREE * degrees; }

function drawTurtle(){
var userPen = pen; // save pen state
if (visible){
penUp(); _moveForward(5); penDown();
_turn(-150); _moveForward(12);

Dethe Elza 11
_turn(-120); _moveForward(12);
_turn(-120); _moveForward(12);
_turn(30);
penUp(); _moveForward(-5);
if (userPen){
penDown(); // restore pen state
}
}
}

We have a special block to draw a circle with a given radius at the current mouse position. We
special-case drawCircle because, while you can certainly draw a circle by repeating MOVE 1 RIGHT
1 360 times, controlling the size of the circle is very difficult that way.
function drawCircle(radius){
// Math for this is from http://www.mathopenref.com/polygonradius.html
var userPen = pen; // save pen state
if (visible){
penUp(); _moveForward(-radius); penDown();
_turn(-90);
var steps = Math.min(Math.max(6, Math.floor(radius / 2)), 360);
var theta = 360 / steps;
var side = radius * 2 * Math.sin(Math.PI / steps);
_moveForward(side / 2);
for (var i = 1; i < steps; i++){
_turn(theta); _moveForward(side);
}
_turn(theta); _moveForward(side / 2);
_turn(90);
penUp(); _moveForward(radius); penDown();
if (userPen){
penDown(); // restore pen state
}
}
}

Our main primitive is moveForward, which has to handle some elementary trigonometry and
check whether the pen is up or down.
function _moveForward(distance){
var start = position;
position = {
x: cos(direction) * distance * PIXEL_RATIO + start.x,
y: -sin(direction) * distance * PIXEL_RATIO + start.y
};
if (pen){
ctx.lineStyle = color;
ctx.beginPath();
ctx.moveTo(start.x, start.y);
ctx.lineTo(position.x, position.y);
ctx.stroke();
}

12 Blockcode: A visual programming toolkit


}

Most of the rest of the turtle commands can be easily defined in terms of what we’ve built above.

function penUp(){ pen = false; }


function penDown(){ pen = true; }
function hideTurtle(){ visible = false; }
function showTurtle(){ visible = true; }
function forward(block){ _moveForward(Block.value(block)); }
function back(block){ _moveForward(-Block.value(block)); }
function circle(block){ drawCircle(Block.value(block)); }
function _turn(degrees){ direction += deg2rad(degrees); }
function left(block){ _turn(Block.value(block)); }
function right(block){ _turn(-Block.value(block)); }
function recenter(){ position = {x: WIDTH/2, y: HEIGHT/2}; }

When we want a fresh slate, the clear function restores everything back to where we started.

function clear(){
ctx.save();
ctx.fillStyle = 'white';
ctx.fillRect(0,0,WIDTH,HEIGHT);
ctx.restore();
reset();
ctx.moveTo(position.x, position.y);
}

When this script first loads and runs, we use our reset and clear to initialize everything and
draw the turtle.

onResize();
clear();
drawTurtle();

Now we can use the functions above, with the Menu.item function from menu.js, to make blocks
for the user to build scripts from. These are dragged into place to make the user’s programs.

Menu.item('Left', left, 5, 'degrees');


Menu.item('Right', right, 5, 'degrees');
Menu.item('Forward', forward, 10, 'steps');
Menu.item('Back', back, 10, 'steps');
Menu.item('Circle', circle, 20, 'radius');
Menu.item('Pen up', penUp);
Menu.item('Pen down', penDown);
Menu.item('Back to center', recenter);
Menu.item('Hide turtle', hideTurtle);
Menu.item('Show turtle', showTurtle);

Dethe Elza 13
Random documents with unrelated
content Scribd suggests to you:
“We detectives are employed to do deeds of mercy as well as those
of justice and duty. I bid you good day, Mr. Prescott.”
He had nothing more to say.
The man was not one to argue with, and having made up his mind
all the powers of heaven and earth could not change it.
This Eric read on his face, and saw in his manner—Prescott was as
stubborn as a mule in all he undertook, which perhaps in a measure
accounted for his success.
The detective was disappointed.
He had hoped for much and gained nothing, since the other was so
set in his ways as to be defiant.
As Darrell had said there was nothing left now but to let matters run
their course.
The puzzle had become deeper than ever to him, and he now
accepted it without any very strong attempt at solving the enigma.
He could not understand how Lillian could love such a man as
Prescott in preference to her husband, except on the theory that the
artist possessed some terrible power over her which she was
incapable of resisting.
Sadly he left the building.
The game must go on now to the inevitable conclusion—some one
would get hurt, but that was to be expected.
What he regretted most of all was the shock to poor Joe.
Strange how such an honest, good fellow, making a husband beyond
all reproach, should be thus afflicted.
It often happens in life. Then men who deserve little are given
wives a thousand times too good for them.
All are not mated who are married, any more with regard to their
character than in their stature—we often see a little man and a tall
woman going along arm in arm and smile as we think how
incongruous it seems, never reflecting that their natures may be
more in harmony than the well-mated pair ahead.
The detective believed that the guilty couple had some plan
matured, and that they meant to make their flight that night.
Indications pointed to it.
He resolved then, to checkmate them, and make the thing a failure.
Under no condition should Lillian be allowed to go forth.
Eric endeavored to picture Joe’s wife in her confusion, when the
mask was torn off.
Would she prove a firebrand?
He did not believe it. It seemed utterly impossible for a sweet, mild-
mannered little woman like Lillian to develop into a fury.
No doubt, when she found that her secret was known, she would
collapse in a heap at the feet of her husband, and he—well, Eric
believed Joe was fool enough to take her in his arms and forgive her.
How could he learn what their plans were?
He was thus pondering when he saw a figure in front of him that he
thought he recognized. It was the trim maid who had given Prescott
the note before.
Of course Eric might be mistaken—there were many other like maids
besides Mrs. Leslie’s particular, but having the subject in his mind he
jumped to the conclusion that this must be the same party he had
seen before.
She was walking along slowly, looking up at the numbers of the
great buildings as if searching for a particular one.
Undoubtedly she was looking for the building in which the artist had
his studio.
Quick as a flash a plan came into the detective’s mind.
What should she be looking for Prescott for but to deliver a note?
He intercepted her.
When he saw her face he discovered that she was an exceedingly
youthful looking person to be about thirty years of age, as Joe had
declared—had he been asked to guess it he would have said
seventeen.
Appearances are deceitful, however, especially when women are
concerned.
As he came face to face with the girl, he smiled—she did not look
offended.
“I beg your pardon, but are you looking for the office of Paul
Prescott?”
She seemed surprised.
“How did you know, sir?”
“Because I am a friend of his with authority to receive the note you
have and keep it for him. I presume it is from the same party as the
one you gave him last evening.”
“You know about that, too?”
“Of course—I saw it. Give me the note and tell the lady Paul has it,
as he will in half an hour.”
“But—I—”
“The note, girl.”
She met his eyes, placed a note in his hand and turning sped away,
while the detective chuckled to think what a cunning little god
Fortune was after all.
CHAPTER XVIII
FORTUNE’S FAVORS

At least luck favored him and Eric could not say anything against the
sudden whirl of the wheel that had left him in such an advantageous
position.
He was naturally anxious to scan the note he held and learn its
contents.
Looking around he saw a candy and ice cream saloon near by, where
many ladies and few gentlemen passed in.
He believed, as the fall day was warm, that he could enjoy a plate of
cream, so he entered, selecting a table in a corner that was isolated.
Here he gave his order, and while enjoying his cream opened the
note.
It was sealed in the envelope, but the gum had stuck poorly, and he
could easily open it with his knife blade.
Once the contents lay open before him he read: “To-night then it
shall be. We are to have company at our house. I cannot get my
trunk out without arousing his suspicions so I have sent everything
to the place you named in packages by my maid. Have the carriage
around the corner. I will slip out while the gayety is at its height,
meet you at the door and in a minute we will be beyond his reach.
He has been cruel to me, I fear him, and yet I love you, Paul, and
will be yours forever.”
This time no signature.
The writer was learning caution.
Even initials might be dangerous.
As for Eric, he read this note over again with the deepest pain and
surprise.
“She means to leave him—there is no doubt of that, but what can
she have reference to when she speaks of his cruelty? Joe cruel—
Joe, the kindest, mildest, dearest fellow, I ever knew. He could only
be cruel by kindness. Either he has done too much for her, or else
she is not in her right mind. If that man is cruel then Prescott is a
devil, I’m sure. I would that the writer of this could find out the
truth—it would serve her well if we let her go on and reap as she
has sown but for the sake of my poor friend she must be saved.”
He took out an old envelope and with a pencil copied the note
verbatim.
Then he enclosed the original in the envelope, sealed it up, saw that
the address was correct, and was ready to have it delivered.
When he issued forth from the confectionary, he looked about him
until he saw a bright appearing district messenger boy sauntering
along in the manner peculiar to his kind.
This youth he beckoned to his side.
“Can you spare five minutes, boy?”
The other grinned and nodded.
“Make it up later, mister.”
“All right. Here is a note, it is to be taken to the top floor of this
number and delivered into the hands of Mr. Prescott, the artist. You
can take the elevator up.”
“All right, boss.”
“You are to tell him a girl dressed in black and wearing a little maid’s
cap on her head gave you the note.”
“Fine looking’ maid you are, mister.”
“Never mind—do as I say. Here’s fifteen cents. If you come and
report to me the result, I have a quarter more for you.”
“Hey! I’m off like the limited express.”
So saying he took note and money and plunged into the building
with hot haste, determined to win the prize offered.
Eric waited patiently.
He knew he would see the boy again.
That silver quarter would serve as a magnet to draw him back to the
spot.
Eric had not studied human nature thus long without being able to
guess certain things, and in this instance his surmise proved correct.
Before the ten minutes had elapsed he saw the messenger boy
come flying along in a way that must have amazed any person who
had grown accustomed to the usual methods of these lads.
“Here you are, sir. Right side up with care. Found him in, and
delivered the note.”
The grin on the boy’s face declared also that he had been paid for
his work by the artist, but this was none of Eric’s business.
He took out a quarter.
“See here now, boy, I want you to prove what you say. What did
you do?”
“Knocked on the door—a cove opened it—asked him if Paul Prescott
was in—said as how he was the same—handed him the letter—he
opened it, grinned, and gave me a shiner. Then I vamosed the
ranch and came to you.”
“Did he ask you where you got it?”
“I told him the girl in black racket, which was really the worst I ever
heard, but the fellow seemed to swallow it without question.”
“Describe the gentleman.”
This was the crucial test.
The boy obeyed without hesitation, and speedily proved that he
must have seen and conversed with the artist himself.
After that Eric had no good reason for longer withholding the
promised reward, which was quickly stowed away in the lad’s
pocket.
The artist’s interview had not resulted in all that he expected, but he
could not say it had been barren of profit. Then again what followed
had made up in a measure for his defeat.
He knew the enemy’s plans.
Thus it would not be such a tremendous job to defeat them. Should
Joe know?
He believed it would be policy to put him on his guard, and in that
way the plotting of the enemy would prove less profitable. So it was
to end to-night.
A carriage was to be in waiting at the corner, and while Joe’s
attention was taken up with entertaining his guests, his wife would
slip out and meet her lover.
Here was a chance for a little diplomacy.
For instance, perhaps it could be arranged that the real Prescott be
kidnapped or otherwise kept out of the way, while Joe dressed
himself up to resemble the other.
Then he could carry off his own wife, and at the proper time reveal
his identity, and teach her a terrible lesson.
That would all be decidedly picturesque and highly dramatic, but
there were a number of obstacles to it that would have to be
overcome ere they could accomplish the best result.
These difficulties were of such a nature that it seemed as though
they could not be overcome.
Darrell cast around him to see whether there was not some other
means handy.
How would it do to have the artist arrested on some charge when on
the way to the place of meeting?
He decided against this on the spot, for it was very apt to make the
whole affair public gossip for the newspapers, something Joe would
rather cut off his right hand than have occur.
Next in order he thought that Lillian might be given something to
make her sleepy or have such a headache that she could never carry
out her part of the arrangement; but this was offensive to his official
taste—he felt as though it was retreating before the attack, and it
was not his intention to do this.
Finally he decided to see Joe—perhaps the other would suggest
something that might open up a plausible scheme—some little hint
dropped in conversation would give Eric the clew he was looking for.
Joe was still in his office.
He looked surprised to see his friend, and yet made no remark.
In spite of his effort to appear cheerful, the keen eye of the
detective could see the traces of acute suffering in his face.
“I’ve been to see that man, Joe,” he said.
“You have?”
“Yes, I thought it might be best for all concerned if I could shame
him into giving up his design.”
“That was too bad, Eric, I would have forbidden it had I known your
intention.”
“I know it. The thought came to me after I had seen you. I am
sorry now I went.”
“You failed?”
“I did indeed.”
“Well, don’t be afraid to tell me. You see I’m calm and collected.”
Eric could not but notice this, but he did not like it.
In his mind it seemed like the awful stillness that precedes the
hurricane.
He had no excuse for withholding anything so he told Joe what had
occurred. “That man is an accomplished scoundrel,” the other said,
quietly.
“I believe that myself, but don’t be afraid of our not mastering him.
I discovered one of his weak points after leaving him.”
“Trust you for that—what was it?”
Eric proceeded to tell of his adventure. “Show me the duplicate,”
said Joe, trembling with emotion.
When he had hastily read the copy Darrell had made, he uttered a
low cry of despair. “Yes, it is so,” he muttered.
“What?”
“We are to have company to-night. It is my birthday, as I told you,
and my wife said she had invited a few relatives and friends in to
spend the evening—an informal affair with a little supper of coffee,
cakes and ice cream. Yes, it is all a deep-laid scheme—and on my
birthday too. Oh! Lillian, my wife, how could you!”
His arms lay upon the table, and he let his head fall heavily upon
them.
Eric turned to the window and smoked his cigar in silence.
He had the deepest respect for the grief of his friend—it was the
keenest misery a human soul can meet here below—death causes
many pangs, but not the bitter blank that comes when one is
betrayed by the individual he or she had been ready to die for.
Yes, from the hour the base Judas betrayed his loving Master, human
misery has never known a lower depth than this.
For five minutes Joe fought his battle all alone, and then he looked
up.
His face was set and calm, as though he had conquered again.
It was a bitter struggle and wearing upon him but he must go
through to the end.
“Eric, I am ready to converse again. Pardon my weakness, old
friend, but this is a cruel business. I did not think I was such a
baby.
“Baby! Great heavens! man, you bear it twice as well as I could.
Such a thing would have murdered me outright.”
They began talking again.
Eric spoke of his unformed plans, and between them they began to
patch up a scheme by means of which the end they sought would be
attained without publicity.
What it was we shall not disclose just now, leaving that for the
proper time.
At any rate it seemed to give poor Joe some satisfaction to think he
was able to circumvent the villain who had destroyed his peace of
mind.
“After all, it might be better for me to challenge that man, and kill
him,” he said moodily.
“Yes, or leave Lillian a widow, at the mercy of any adventurer.
Besides, in that way the whole dreadful story would get into the
papers, and you could not live in New York even if that artist failed
to murder you. No, you will find that the plan we have arranged is
the best after all.”
“You are undoubtedly right, Eric—consider it settled, and prepare to
carry it out. We will end this agony this night and that devil shall
learn what he risks in attempting to steal another man’s treasure.”
“You will not fail me, Joe?”
“It shall be the effort of my life, Darrell, to succeed. Have no fears
of me—my pride has been aroused. It is not the weak lover but the
outraged husband who speaks now.”
CHAPTER XIX
THE TIME DRAWS NEAR

For once Joe Leslie was thoroughly aroused, and the detective knew
he need have no fears of him again.
Whatever he was given to do he would carry out to the letter.
So they noted with something of satisfaction that the day was
drawing to a close, and the night coming on, for their hour could not
be reached until darkness had for some time settled down over the
great city.
Both were anxious to have the thing over.
It did not give them much pleasure, and all their satisfaction arose in
the thought that justice and right would triumph when the man who
had plotted against the peace of a home went down among his idols
of clay.
In these modern days men have to do strange things when the
sanctity of their house has been invaded by a human serpent.
Sometimes the stern arm of the law is called upon for assistance.
Now and then, however, we read of some outraged husband going
back to old time principles and being a law unto himself on such an
occasion.
Long ago they had a means of avenging such wrongs by meeting in
the lists with lance or sword—in short, fighting a duel.
The modern way is perhaps the best if least chivalric since it is all in
favor of the man who has been wronged, and does not risk his life.
We have seen that Joe was not modern in his ways.
The last thing he desired on earth was to make his misery public.
His love for his wife was wonderful—he only blamed the man who
had gained such power over her mind as to make her irresponsible.
Just as though there were wizards to-day—the times of Salem
witchcraft have not returned to haunt us again, thank heaven.
Joe really did believe—and the shrewd detective allowed the same
idea to permeate his own mind to a certain extent—that it was a
case where a weak mind was dominated by a masterful one. He
had known such cases, and seen examples of hypnotism that had
astonished him.
Thus he excused Lillian.
While Eric did not go that far, he believed there were extenuating
circumstances connected with the case, and was willing to look upon
it all in a most lenient way.
Probably he would have acted in a different manner had it been his
own wife who was concerned in the affair.
That was a matter that brought the business down to mere
speculation, and when it reached this point it became unprofitable.
When the detective left his friend he had everything arranged.
As far as human sight could see beyond, all was ready for the
business in hand.
Should Paul Prescott attempt to put his little game into practice he
would find himself brought up rather suddenly.
There was an hour or so of daylight left, and this Eric put to good
advantage, as he had a number of little things to do.
One cannot engage to carry out a scheme like this without many
accessories being needed, and the wise man looks for these before
the time arrives for their use.
Gradually the day gave way to evening. Darrell believed all was
arranged.
He felt satisfied that before another day came around, Joe’s
condition would be changed—this night was the crisis—either his
spirits must go down or else rise suddenly.
All depended on one person.
This was Lillian.
To him she was the one object that could affect his future—the
lodestone that drew him on.
When he had made his preparations and eaten a light supper down
town, Eric started for the scene of the coming comedy.
He could not pierce the future any more than any other human, and
hence knew not whether it would remain such or prove to be a
tragedy.
Coming events may often cast their shadows before, but there are
times when the sun is so nearly in the zenith that this shadow does
not amount to very much.
Besides, what does a shadow amount to anyhow—it is not tangible,
and presents no opportunity for solution.
For once at least in his life the detective confessed himself unable to
insure the future.
He knew certain facts, and that others would coalesce, but what the
result would be he did not pretend to be chemist enough to decide.
Time alone would tell.
That was the physician who could be depended upon to bind up
broken hearts, to solve the deepest mysteries and set everything
right.
Given time, nothing was impossible.
As the shades of evening descended, Darrell brought up in the
neighborhood of the building on Fourteenth Street where the artist’s
studio was located.
He was passing slowly by when a hack drove up and stopped at the
curb.
“Engaged?” he asked the driver.
“Sorry, sir, but I am,” returned that worthy. A jehu always hates to
lose a fare.
“Can’t accommodate me up town?”
“Right away?”
“Yes.”
“Where to?”
“About Eighty-fourth and Third Avenue.”
The man’s face lighted up—Darrell was answered—he saw a chance
of doubling his fare. “I reckon the other’d make no objection. Pay
me first, and I’ll tell him I was taken by you.”
“How much?”
“One, fifty.”
Without a murmur the detective handed over the amount,
submitting to be robbed in order to carry out his point.
Of course he was disguised.
No one would for a moment imagine that this old gentleman was the
same athletic individual who had visited Prescott in his studio, and
argued with him over a revolver.
The clocks were striking seven as he entered the hack and made
himself comfortable.
Along the wide pavement hundreds were still hurrying, although the
swarms from all the great stores had long since passed by.
Presently from out the building the artist came. He looked worried,
and well he might.
When a man sets out to steal another man’s wife he risks a great
deal.
It must weigh upon his mind, even the personal danger involved,
though his conscience be free.
Darrell recognized this fact, and did not wonder at the look of
anxiety he saw upon the countenance of the artist.
The latter looked up and down the street ere catching sight of the
hack at the curb. Then a smile came upon his face.
He walked up to the driver, spoke a few words, frowned when the
other mentioned having another passenger, saw no other vehicle in
sight that he could engage, glanced in at the seeming old man, and
then, grumbling, entered.
“I trust I have not inconvenienced you, sir,” remarked the old
gentleman, anxiously.
“Not at all, not at all,” replied the artist courteously, though his
manner had belied his words.
They rumbled along.
Block after block was left behind.
It is a long distance from Fourteenth Street up to the point where
they were bound, and when half an hour had gone by they had not
yet reached their destination.
Indeed, it was not far from eight o’clock when the driver pulled up at
the corner.
The old gentleman got out slowly.
He bade his traveling companion good night and turning walked
away, his cane beating a lively tattoo upon the stone pavement.
Darrell was satisfied with his investment thus far—he had been
carried up town, had seen the artist well upon his way, and knew
both driver and vehicle by sight.
There could not very well be any mistake after this—he believed
things were well laid out, and that all they needed was a chance to
execute their plan.
He again changed his looks, so that in case the artist saw him he
would not realize that he had met him before.
With the facilities at his command it was not a difficult thing for him
to do this, and by means of a few deft turns he completely altered
his character, and might defy recognition, even were keener eyes
concerned than those of Paul Prescott, the artist.
When this had been done Darrell walked up the avenue, and soon
came to the corner where, as he expected, he found the vehicle.
Prescott was not in sight.
Some two hours must elapse before the time arranged would pass.
The driver had also vanished, no doubt being in a liquor store near
by, where he could wet his whistle, lounge at his ease and watch his
team at the same time.
His horses would have a good chance to rest before they were
needed again, and this was probably one reason why the artist had
him on hand at such an early hour.
When young Lochinvar carried off his bride he managed to have a
good steed, knowing that everything depended on the swiftness of
his flight, as pursuit would be sudden and furious.
So Paul Prescott, with an eye to possible emergencies, had chosen a
vehicle that was drawn by a good team of animals.
He showed his wisdom here.
In case of pursuit it might be his salvation.
When the detective sauntered past the house upon which his
interest was centered he saw that it was lighted up.
Company was expected.
Lillian had invited a few particular friends in to see them, on account
of its being Joe’s birthday.
As yet they had not begun to arrive, but would soon appear upon
the scene.
Darrell heard a vehicle coming, and stopped in a dark spot near by.
“The first of the guests,” he muttered.
As the carriage stopped in front of the house he gave a start.
“Jupiter! guests with trunks—that’s odd.” There was a trunk up
beside the driver, who at once leaped to the ground.
As he opened the door a vision of jaunty wraps and bonnets sprang
out and flew up the steps to ring the bell, while Darrell held his
breath as he guessed the truth.
The door opened.
“Marian!”
A flutter of feminine apparel, a little shriek of girlish delight, and the
sisters were locked in each others’ arms, to the wonderment of the
man who watched below.
Then the jehu carried in the trunk, the door closed, the carriage
rumbled away and the street resumed its wonted appearance.
Eric was puzzled.
He had not counted on this.
Had any of the others?
What effect would it have on the anticipated elopement, he
wondered.
Here was the lover with his vehicle on hand, and such a nature as
Paul Prescott’s would not brook interference.
The affair became more complicated.
Darrell would have given something to have had the next two hours
over.
As it was he had to possess his soul in patience and wait.
Things that he did not dream of were fated to turn up in that time,
and he was bound to have his hands full.
Guests soon began to arrive. Several came in carriages, while
others were not far enough away to bother with vehicles.
It was no fashionable gathering, but one of warm friends, of whom
Joe Leslie had many.
His business and social life was such that he drew people to him,
making many friends and few enemies, which is after all the only
true way to go through this world.
CHAPTER XX
FOR PLUNDER

At about a quarter to nine Darrell once more sauntered past the


house.
He could see into the parlor, as the inside shutters were turned, and
with a number of others he was attracted by the bright scene.
Although perhaps he would not confess it, the bachelor detective
was eagerly hoping for even a fleeting glimpse of Marian.
He got it too.
After having seen the photograph Lillian had shown him, he knew he
could not be mistaken.
The girl stood for half a minute in direct focus from his place of
observation, and the gas-light fell full upon her face and figure.
Darrell drew in a long breath.
“That settles it,” he muttered, “I’ll try—unless this other affair takes
the heart out of me.”
He had lived between thirty-five and forty years without ever having
a serious love scrape; but an inward monitor told him his time had
come at last.
The little god plays all manner of pranks with his victims, and
although Eric Darrell had eluded his sway so long, it would all be
made up to him presently.
As Marian stood there she was joined by a second figure.
This was Joe.
Eric scanned his face eagerly, as best he could under the
circumstances.
“Thank heaven! Joe is calm. He has aroused his energies. No
danger of his giving out when the crucial test comes,” he muttered.
Joe Leslie did appear self-possessed, but it was easy to be seen that
he was not himself this evening.
His wife accounted for it to the friends about her by stating that Joe
had been overworking himself lately, and that morning he
complained of a severe headache.
She did not seem to suspect that she had given him cause for his
breakdown.
None are so blind as those who refuse to see. It might be this or
innocence that caused her to ignore the truth.
Eric, with a sigh, passed on.
He had seen Lillian join the others, and the trio gave him a strange
feeling.
“So fair, and yet so false. How can a man trust a woman when he
has such a terrible example before his eyes—and her sister too.”
He soon forgot all this. Something else attracted his attention, and
he found that there was need of his care. A couple of sinister-
looking men passed the house and looked in.
He saw them conversing eagerly together a minute or two later just
beyond.
At first an idea sprang into his head that they might be men hired by
Prescott to create a disturbance and delay pursuit after the latter
had succeeded in reaching his carriage with Lillian.
If this were so, he must take them into his calculations and watch
them closely. That their conversation concerned the house where
the little gathering was taking place was beyond all doubt, for their
motions attested this.
Then they moved off.
Eric did not believe they had gone, and he followed them with his
eyes.
They slipped into a vacant lot near by, and the detective began to
get a new idea.
Perhaps these fellows were not in the employ of the artist after all,
but skirmishing around on their own hook.
That meant knavery.
He was aroused.
To follow them was his first thought.
Stealing down to the vacant lot he too vanished amid its blackness.
At first he could see and hear nothing, but in a few minutes he
caught a clew, and found that the two men had gone to the fence
separating the vacant lot from Joe’s back yard.
Some old wagons and drays were scattered here and there about
the place, for it presented an admirable wagon yard.
Such is cosmopolitan New York.
The palace often touches the hovel.
Some of the aristocrats up town can look out from their magnificent
houses, and survey the shanty of the squatter built on the rocks,
where the agile goat browses on old shoes and empty cans.
Some day this will not be, but it is so now, and a source of wonder
to foreigners.
Darrell began to pick his way through the wagon yard, careful to
proceed without noise, for when men are bent upon an unlawful
errand it does not take much of a sound to cause palpitation of the
heart, and he did not want to have their death on his hands—just
yet.
They seemed to be surveying the scene from the rear.
It was undoubtedly their intention to make some sort of a haul here.
The silver might be lying around loose, or even some jewelry in the
upper rooms—men of their trade do not discriminate, so long as
what they seize upon has a specific value.
First, last and all the time, what they want is the cold cash.
It was certain that they must be frightened away, and that at once.
His other business was too important to allow him the pleasure of
playing with these fellows, much as he might have enjoyed it.
Under these circumstances he worked his way close to where they
crouched.
He could hear them working with a chisel or burglar’s tool of some
sort—they were prying off a board from the fence, so that they
might easily pass through when they desired.
It would be a good route for flight, also, after their object was
attained.
So interested were they in the task that they did not have the
faintest suspicion of the presence of any one.
Darrell could hear their low words.
“Bill, this here promises to be a lucky strike,” said one, in a low tone.
Bill muttered a reply.
“Well, I’m of the opinion, Bill, as we’ll have a good whack at some
valuables. Ye see, the guests are all in there—if we can deceive the
gal below and slip upstairs there ought to be fat pickings for fellers
of our size.”
“Softly, partner, softly—there’s another in this here game you ain’t
counted on.”
As these words reached their ears, the two men muttered
exclamations of dismay.
“Who the deuce is it?”
“Where in thunder is he?”
“I’m right here. You fellows are treading on my corns. This is my
pasture—get out.”
“Not much we won’t. We’ll slit your wizen first, I reckon. We’re in
this here game now for keeps,” growled the man named Bill.
“Then you must go snacks. I’ll furnish the information, and you do
the work—an equalization of labor—ain’t that fair?”
“What d’ye know, critter?”
“Where the silver is kept—it ain’t been brought out yet awhile, and
by a little bold work the hull of it can be spirited away.”
At this the two men can hardly restrain their delight.
“Lead us to it, and the third is yourn.”
“You’re on the steal, then?”
“Ready to take anything that counts.”
“This is the steel I deal in.”
One of the men, the fellow nearest him, felt something like a piece
of ice pressed against his left temple.
He put up his hand.
The investigation did not afford him any particular pleasure, for what
he touched sent a shiver through his whole frame.
It was a cold revolver.
“Move a hand or a foot and you are a dead man. And you also,” to
the other fellow.
The board had just come off in this latter chap’s arms, and light from
the house poured through the opening in a stream that was strong
enough to show him the situation.
He dared not drop the board, and he was also prevented from
attacking the unknown.
Eric was master of the situation.
“Now see here, men, listen to me.”
“Go ahead!” growled one.
“In mercy’s name don’t press that trigger,” groaned the other.
Darrell had to smile at the sudden termination to which
circumstances had brought the bold raid of the two sneak thieves.
They had come after plunder, but found something more awaiting
them.
The little scheme, concocted on the spur of the moment, had been
driven into obscurity.
“I am a detective, watching this house.”
Both men groaned.
“Fools we was.”
“And although I’m going to let you go this time, if I see either of you
here again you’ll make a bee-line for the Tombs.”
“Don’t worry, mister—if we get off this time we’ll make ourselves
scarce. It gives me a chill to think of Sing Sing.”
“You ought to get the chill before you start on such an expedition,
and not after you are caught. You know that when ‘the devil was
sick, the devil a monk would be; but when the devil got well, the
devil a monk was he’.”
“Kin we go, mister?”
“Yes—pass out the front door, gentlemen, just as you came in. And,
remember, once goes a long way with me—if you show up here
again, down you go to Centre Street.”
“Thank ye, boss.”
The men crept quickly away—indeed, their haste was really
ludicrous, for they seemed to have a deep-rooted fear lest he might
be tempted to change his mind.
But under the circumstances Eric was quite satisfied to see them
safely off the premises.
His other work would take up his attention, and he could not expect
to amuse himself with such side-shows as these.
He once more made his way to the street.
As before a little knot of curious people stood in front of the house
gazing in. The glimpses they caught of beautiful women and brave
men were a revelation to them. It was like looking into Paradise.
Otherwise the street was quiet.
A train boomed past on the elevated road below. Eric looked at his
watch. It was a quarter past nine.
Three-quarters of an hour still remained, and then would come the
grand climax.
He began to breathe easier, for time was passing, and he felt sure
their plans would come out all right.
Sauntering to the corner he saw the hack still there as he had left it.
The driver was sitting inside now.
He knew his orders and only waited for the proper time to arrive.
Where was Prescott?
Eric had expected to see him scouting around the Leslie mansion,
but if the artist was there he had kept his person well concealed.
Not yet had Eric doubted the motives that brought the other here.
Everything seemed to fit as snugly as though it had been made for it
—when a carpenter makes a neat job he dove-tails the corners, and
Darrell looked upon the many little things that connected so
wonderfully, as the finishing touches of the joiner.
If a thunder cloud burst upon him it would certainly take him
unawares, while the cool rain might be very acceptable.
He began to count the minutes.
Seldom had this man ever felt any such thing as nervousness in his
life, but just now he certainly experienced a spell of it. The minutes
seemed hours.
People walked along the street—he scrutinized every one as though
he expected to see a ghost appear.
In reality he was looking for Prescott.
It worried him to know that the man was somewhere around and
yet out of sight, though he did not doubt but what he would be on
hand when needed.
CHAPTER XXI
THE COTTAGE BEYOND THE HARLEM

Sometimes things do not run quite as smoothly as we hope for.


The best laid plans of mice and men often go wrong—there’s many a
slip ‘twixt the cup and the lip.
So it happened on the present occasion.
It was all owing to a certain clock which had taken a notion to get
ahead of its fellows and was some ten minutes fast.
A lamp set Chicago on fire.
So this unlucky clock upset the beautiful plans of the wily detective,
as he believed, and came near leaving him in the lurch.
By chance he was down near the corner when suddenly he saw a
female hurrying that way.
A long cloak concealed her figure, but a handsome dress of white
silk peeped below—a heavy veil had been snatched up to hide her
face and serve in lieu of a hat at the same time.
Where she came from he hardly knew, but a terrible fear almost
palsied him.
It was Lillian!
She had come ahead of time—Joe would not be ready, and as a
result confusion must ensue.
Luckily the detective was a man able to grasp an emergency.
He never yet had seen the time when he was so taken by surprise
that his mind refused to do its work.
Just then there was need of quick thought, and action must follow
on its heels.
Hardly had the woman paused upon the corner than a dark figure
sprang out of the shadows near by.
“Paul!” she whispered.
“Good heavens! you are ten minutes ahead of time, darling. I would
have met you at the place appointed had—” the rush of a train
drowned what else he said.
Then the detective saw him assist the now shrinking figure toward
the carriage.
“He will be furious,” he heard her say, as she looked apprehensively
around, as though anticipating the appearance of an enraged
husband on the scene.
If these were her sensations now, what of the future—remorse must
soon kill her.
“He had better keep his hands off, or I will teach him a lesson! The
cowardly cur, to bully you so. Enter, darling—you are safe with me.”
Eric’s first impulse was for blood.
He felt strongly inclined to spring forward and grapple with this
boaster, who breathed such lies of Joe in his wife’s ears.
Then another thought came.
Such a public scene would immediately collect a crowd at the corner,
and Lillian’s name would be dragged in the dust.

You might also like