500 Lines or Less Experienced Programmers Solve Interesting Problems Michael Dibernardo 2024 Scribd Download
500 Lines or Less Experienced Programmers Solve Interesting Problems Michael Dibernardo 2024 Scribd Download
com
https://textbookfull.com/product/500-lines-or-
less-experienced-programmers-solve-interesting-
problems-michael-dibernardo/
https://textbookfull.com/product/hypernomics-using-hidden-dimensions-
to-solve-unseen-problems-1st-edition-doug-howarth/
textbookfull.com
https://textbookfull.com/product/how-to-solve-real-world-optimization-
problems-from-theory-to-practice-1st-edition-zak/
textbookfull.com
https://textbookfull.com/product/microwave-and-rf-design-
volume-2-transmission-lines-michael-steer/
textbookfull.com
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
https://textbookfull.com/product/fundamentals-of-pathology-medical-
course-and-step-1-review-2017-edition-husain-a-sattar-2/
textbookfull.com
https://textbookfull.com/product/bang-blast-brothers-2-1st-edition-
sabrina-stark-stark-sabrina/
textbookfull.com
https://textbookfull.com/product/electrochemical-reduction-of-carbon-
dioxide-overcoming-the-limitations-of-photosynthesis-1st-edition-
frank-marken/
textbookfull.com
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.
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.
ISBN: 978-1-329-87127-4
Contents
Introduction ix
by Michael DiBernardo
3 Clustering by Consensus 33
by Dustin J. Mitchell
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:
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]
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.
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 .
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).
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.
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.
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.
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.
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/
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.
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 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.
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.
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 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();
}
Most of the rest of the turtle commands can be easily defined in terms of what we’ve built above.
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.
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