├── MANIFEST.in
├── docs
├── source
│ ├── config.rst
│ ├── api.rst
│ ├── index.rst
│ ├── tweet.rst
│ ├── corpus.rst
│ └── conf.py
└── Makefile
├── twitter_markov
├── __init__.py
├── __main__.py
├── checking.py
└── twitter_markov.py
├── tests
├── __init__.py
├── test_cli.py
├── test_markov.py
├── test_markov_methods.py
├── test_checking.py
└── data
│ ├── tweets.txt
│ └── tweets.csv
├── .gitignore
├── .travis.yml
├── README.md
├── Makefile
├── HISTORY.rst
├── bots.yaml
├── setup.py
├── LICENSE
└── corpus.txt
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | # twitter_markov - Create markov chain ("_ebooks") accounts on Twitter
2 | # Copyright 2014-2016 Neil Freeman contact@fakeisthenewreal.org
3 |
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 |
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 |
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 |
17 | include README.md
18 | include README.rst
19 |
--------------------------------------------------------------------------------
/docs/source/config.rst:
--------------------------------------------------------------------------------
1 | Config files
2 | ============
3 |
4 | See the
5 | `bots.yaml `__
6 | file for a full list of settings. Plug your settings in and save the
7 | file as ``bots.yaml`` to your home directory or ``~/bots``. You can also
8 | use JSON, if that's your thing.
9 |
10 | At a minimum, your config file will need to look like this:
11 |
12 | .. code:: yaml
13 |
14 | apps:
15 | example_app_name:
16 | consumer_key: ...
17 | consumer_secret: ...
18 |
19 | users:
20 | example_screen_name:
21 |
22 | key: ...
23 | secret: ...
24 |
25 | app: example_app_name
26 |
27 | # If you want your bot to continue to learn, include this
28 | parent: your_screen_name
29 |
30 | Read up on `dev.twitter.com `__
31 | on obtaining authentication tokens.
32 |
--------------------------------------------------------------------------------
/twitter_markov/__init__.py:
--------------------------------------------------------------------------------
1 | # twitter_markov - Create markov chain ("_ebooks") accounts on Twitter
2 | # Copyright 2014-2016 Neil Freeman contact@fakeisthenewreal.org
3 |
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 |
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 |
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 |
17 | from .twitter_markov import TwitterMarkov
18 | from . import checking
19 |
20 | __version__ = "0.6.0"
21 |
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
1 | # twitter_markov - Create markov chain ("_ebooks") accounts on Twitter
2 | # Copyright 2014-2016 Neil Freeman contact@fakeisthenewreal.org
3 |
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 |
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 |
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 |
17 | from . import test_checking
18 | from . import test_markov
19 | from . import test_markov_methods
20 | from . import test_cli
21 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 |
5 | # C extensions
6 | *.so
7 |
8 | # Distribution / packaging
9 | .Python
10 | env/
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | lib/
17 | lib64/
18 | parts/
19 | sdist/
20 | var/
21 | *.egg-info/
22 | .installed.cfg
23 | *.egg
24 | .eggs
25 |
26 | # PyInstaller
27 | # Usually these files are written by a python script from a template
28 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
29 | *.manifest
30 | *.spec
31 |
32 | # Installer logs
33 | pip-log.txt
34 | pip-delete-this-directory.txt
35 |
36 | # Unit test / coverage reports
37 | htmlcov/
38 | .tox/
39 | .coverage
40 | .cache
41 | nosetests.xml
42 | coverage.xml
43 |
44 | # Translations
45 | *.mo
46 | *.pot
47 |
48 | # Django stuff:
49 | *.log
50 |
51 | # Sphinx documentation
52 | docs/_build/
53 | docs.zip
54 |
55 |
56 | *.brain
57 | *.brain-journal
58 |
59 | README.rst
60 |
--------------------------------------------------------------------------------
/docs/source/api.rst:
--------------------------------------------------------------------------------
1 | API
2 | ===
3 |
4 | Example
5 | +++++++
6 |
7 | This assumes a corpus file (``corpus.txt``) and config file (``config.yaml``).
8 |
9 | .. code:: python
10 |
11 | from twitter_markov import TwitterMarkov
12 |
13 | tm = TwitterMarkov('example_screen_name', 'corpus.txt', config_file='config.yaml')
14 | tweet = tm.compose()
15 |
16 | # do something more with tweet, or use the Tweepy API in a different way
17 |
18 | tm.api.update_status(tweet)
19 |
20 | TwitterMarkov
21 | +++++++++++++
22 |
23 | For commands that generate text, the first corpus in the found corpora (or in the config file) will be the default. When using the class with more than corpus, you can specify a corpus with the `model` keyword argument using the basename of the given file, e.g. "special.txt" for the corpus stored at "dir/special.txt".
24 |
25 | .. autoclass:: twitter_markov.TwitterMarkov
26 | :members:
27 |
28 | Checking
29 | --------
30 |
31 | .. automodule:: twitter_markov.checking
32 | :members:
33 | :undoc-members:
34 |
--------------------------------------------------------------------------------
/docs/source/index.rst:
--------------------------------------------------------------------------------
1 | .. Twitter Markov documentation index file
2 |
3 | Twitter Markov
4 | ==================
5 |
6 | Twitter Markov is a Python library for creating markov chain ("_ebooks") accounts on Twitter.
7 |
8 | The audience for this library is those with at least basic Python experience. Before you set this up, you'll need:
9 |
10 | * A twitter account
11 | * A twitter application (register at `dev.twitter.com `__) with authentication keys for the account (`read more `__)
12 | * A corpus for the bot to learn, which can be a text file or a Twitter archive. Several thousand lines are needed to get decent results, with fewer than 100 or so it won't work at all.
13 |
14 | Install
15 | -------
16 |
17 | Run ``pip install twitter_markov``. Feel free to use a virtualenv, if you're into that.
18 |
19 | Table of contents
20 | -----------------
21 |
22 | .. toctree::
23 | :maxdepth: 2
24 |
25 | corpus
26 | config
27 | tweet
28 | api
29 |
30 | Index
31 | ======
32 |
33 | * :ref:`genindex`
34 | * :ref:`modindex`
35 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | # twitter_markov - Create markov chain ("_ebooks") accounts on Twitter
2 | # Copyright 2014-2017 Neil Freeman contact@fakeisthenewreal.org
3 |
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 |
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 |
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 |
17 | language: python
18 |
19 | python:
20 | - 3.5
21 | - 3.6
22 | - 3.7
23 | - 3.8
24 | - pypy3
25 |
26 | before_install: travis_retry pip install "setuptools>=17.1" "pbr>=0.11,<1.0" mock coverage
27 |
28 | install: travis_retry python setup.py -vvv install
29 |
30 | script: make test
31 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | twitter markov
2 | ==============
3 |
4 | Create markov chain ("_ebooks") accounts on Twitter.
5 | The audience for this library is those with at least basic Python experience. Before you set this up, you'll need:
6 | * A twitter account
7 | * A twitter application (register at [dev.twitter.com](http://dev.twitter.com)) with authentication keys for the account ([read more](https://dev.twitter.com/oauth))
8 | * A text for the bot to learn from, which can be a text file or a Twitter archive. Several thousand lines are needed to get decent results, with fewer than 100 or so it won't work at all.
9 |
10 | ## Install
11 |
12 | Run `pip install twitter_markov`, or download/clone the package and run `python setup.py install`. Feel free to use a virtualenv, if you're into that.
13 |
14 | ## Setting up a bot
15 |
16 | [See the docs](http://pythonhosted.org/twitter_markov) for a complete guide to setting up an ebooks bot. Here are the basics:
17 |
18 | * Create a app and authenticate it with your new Twitter account
19 | * [Create a corpus](http://pythonhosted.org/twitter_markov/corpus.html), a text file with one sentence or text per line
20 | * [Create a `bots.yaml` config file](http://pythonhosted.org/twitter_markov/config.html)
21 | * [Set up a task to tweet and reply](http://pythonhosted.org/twitter_markov/tweet.html)
22 |
23 | ## API
24 |
25 | [See the docs](http://pythonhosted.org/twitter_markov/api.html).
26 |
27 | ## License
28 |
29 | Copyright 2014-2016, Neil Freeman. This software is available under the GPL 3.0. See LICENSE for more information.
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | # twitter_markov - Create markov chain ("_ebooks") accounts on Twitter
2 | # Copyright 2014-2016 Neil Freeman contact@fakeisthenewreal.org
3 |
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 |
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 |
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | .PHONY: all deploy cov test
17 |
18 | all: docs.zip README.rst
19 |
20 | docs.zip: docs/source/conf.py $(wildcard docs/*.rst docs/*/*.rst twitter_markov/*.py)
21 | $(MAKE) -C docs html
22 | cd docs/_build/html; \
23 | zip -qr ../../../$@ . -x '*/.DS_Store' .DS_Store
24 |
25 | deploy: README.rst | clean
26 | python3 setup.py sdist bdist_wheel --universal
27 | twine upload dist/*
28 | git push
29 | git push --tags
30 |
31 | README.rst: README.md
32 | - pandoc $< -o $@
33 | @touch $@
34 | - python setup.py check --restructuredtext --strict
35 |
36 | htmlcov: test
37 | python -m coverage html
38 |
39 | test:
40 | - python -m coverage run --include='build/lib/twitter_markov/*,twitter_markov/*' setup.py -q test
41 | python -m coverage report
42 |
43 | clean:; rm -rf dist build
44 |
45 |
--------------------------------------------------------------------------------
/HISTORY.rst:
--------------------------------------------------------------------------------
1 | 0.6.0
2 | -----
3 | * Remove support for Python 2
4 |
5 | 0.5.0
6 | -----
7 | * Allow for 280-character tweets
8 | * Raise a `RunTimeError` if model fails to compose anything.
9 |
10 | 0.4.6
11 | -----
12 | * refactor TwitterMarkov.compose to use make_short_sentence.
13 | * Add max-len and state-size options to cli.
14 | * change default state size to 2
15 |
16 | 0.4.5
17 | -----
18 | * ignore tweets with blacklisted words when replying
19 | * refactor checking module
20 | * expand docs
21 | * bump required twitter_bot_utils
22 |
23 | 0.4.4
24 | -----
25 | * Remove one per line option
26 | * Expand docs
27 |
28 | 0.4.3
29 | -----
30 | * Add option to create a corpus from a file with one text per line
31 |
32 | 0.4.2
33 | -----
34 | * Fix a double-logging bug
35 |
36 | 0.4.1
37 | -----
38 | * Small update for changed twitter bot utils API
39 |
40 | 0.4
41 | -----
42 | * Replace `cobe` with `markovify`. This simplifies learning, since it's just adding to a text file corpus.
43 | * Also changes `Twitter_markov` API, removing catalyst argument and replacing 'brain' keyword arguments with 'corpus' or 'model'.
44 | * Replace `twittermarkov learn` with `twittermarkov corpus`
45 | * Add checking.generator function
46 | * Restore similarity/blacklist checker for generated text
47 | * rename class from Twitter_markov to TwitterMarkov
48 | * Rework cli tools, renaming twittermarkov learn -> twittermarkov corpus
49 |
50 | 0.3
51 | -----
52 | * Combine two command line tools into one command with subcommands.
53 | * Handle errors in learning more cleanly.
54 |
55 | 0.2.4
56 | -----
57 | * `Twitter_markov` class no longer extends Tweepy.API, so an existing API object can be passed in
58 | * Cleaned up code around brain naming.
59 | * Expanded readme.
60 |
--------------------------------------------------------------------------------
/docs/source/tweet.rst:
--------------------------------------------------------------------------------
1 | Tweeting
2 | ========
3 |
4 | First Tweet
5 | -----------
6 |
7 | Once a corpus is set up, the ``twittermarkov tweet`` command will send
8 | tweets out. If a ``parent`` is specified, this command will send one
9 | tweet and trigger adding recent tweets to the corpus file.
10 |
11 | The learning also won't happen if twittermarkov can't find it's previous
12 | tweets, which might happen if there are problems with the Twitter API,
13 | or your \_ebooks account has never tweeted.
14 |
15 | Since learning depends on the ``_ebooks`` account having an existing
16 | tweet, send a first tweet with the ``--no-learn`` flag.
17 |
18 | .. code:: bash
19 |
20 | twittermarkov tweet --no-learn example_screen_name
21 |
22 | To have your bot reply to mentions, use:
23 |
24 | .. code:: bash
25 |
26 | twittermarkov tweet --reply example_screen_name
27 |
28 | Complete command line options for ``twittermarkov tweet``:
29 |
30 | * ``-c, --config PATH`` bots config file (json or yaml)
31 | * ``-u, --user SCREEN_NAME`` Twitter screen name
32 | * ``-r, --reply`` tweet responses to recent mentions
33 | * ``--corpus corpus`` text file, one sentence per line
34 | * ``--max-len MAX_LEN`` maximum output length. default: 140
35 | * ``--state-size STATE_SIZE`` model state size. default: 2
36 | * ``--no-learn`` skip learning (by default, recent tweets from "parent" account are added to corpus)
37 | * ``-n, --dry-run`` Don't actually do anything
38 | * ``-v, --verbose`` Run talkatively
39 | * ``-q, --quiet`` Run quietly
40 |
41 | Automating
42 | ----------
43 |
44 | On a Unix-based system, set up a cron job like so:
45 |
46 | ::
47 |
48 | 0 10-20 * * * twittermarkov tweet example_screen_name
49 | 15,45 10-20 * * * twittermarkov tweet --reply example_screen_name
50 |
--------------------------------------------------------------------------------
/docs/source/corpus.rst:
--------------------------------------------------------------------------------
1 | Create a corpus
2 | ===============
3 |
4 | The ``twittermarkov corpus`` command will create such a file from a Twitter archive, with options to ignore replies or retweets, and to filter out mentions, urls, media, and/or hashtags.
5 |
6 | "Corpus" is just a fancy-schmancy word for "a bunch of text". `twittermarkov` expects a corpus that's a text file with one tweet per line. Several thousand lines are needed to get decent results, with fewer than 100 or so it won't work at all
7 |
8 | You can turn anything as a corpus. If you're looking for free material, try `Project Gutenberg `__ and the `Internet Archive `__.
9 |
10 | When reading an archive, these arguments use the tweet's metadata to precisely strip the offending content. This may not work well for tweets posted before 2011 or so. For text files or older tweets, a regular expression search is used.
11 |
12 | .. code::bash
13 |
14 | # Usage is twittermarkov corpus archive output
15 | # This creates the file corpus.txt
16 | twittermarkov corpus twitter/archive/path corpus.txt
17 |
18 | twittermarkov corpus --no-retweets --no-replies twitter/archive/path corpus-no-replies.txt
19 | # Teweets like this will be ignored:
20 | # RT @sample I ate a sandwich
21 |
22 | # Tweets like this will be read in without the @ name:
23 | # @example Was it tasty?
24 |
25 |
26 | All the filtering options:
27 |
28 | * ``--no-retweets`` - skip retweets
29 | * ``--no-replies`` - filter out replies (keeps the tweet, just removes the starting username)
30 | * ``--no-mentions`` - filter out mentions
31 | * ``--no-urls`` - filter out urls
32 | * ``--no-media`` - filter out media
33 | * ``--no-hashtags`` - filter out hashtags
34 |
35 | If you're using a Twitter archive, the archive argument should be the tweet.csv file found in the archive folder (which usually has a long name like ``16853453_3f21d17c73166ef3c77d7994c880dd93a8159c88``).
36 |
37 |
--------------------------------------------------------------------------------
/tests/test_cli.py:
--------------------------------------------------------------------------------
1 | # twitter_markov - Create markov chain ("_ebooks") accounts on Twitter
2 | # Copyright 2014-2016 Neil Freeman contact@fakeisthenewreal.org
3 |
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 |
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 |
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | from __future__ import unicode_literals
17 | import unittest
18 | import sys
19 | from os import path, remove
20 | import subprocess
21 | from twitter_markov import __main__ as cli
22 | from twitter_bot_utils import archive
23 |
24 |
25 | class TestMarkovCLI(unittest.TestCase):
26 |
27 | csvpath = path.join(path.dirname(__file__), 'data/tweets.csv')
28 |
29 | def setUp(self):
30 | self.argv = ['twittermarkov', 'corpus', self.csvpath]
31 |
32 | def testcli(self):
33 | target = path.join(path.dirname(self.csvpath), 'tmp.txt')
34 |
35 | sys.argv = self.argv + ['-o', target]
36 |
37 | cli.main()
38 |
39 | result = list(t['text'] for t in archive.read_csv(self.csvpath))
40 |
41 | try:
42 | with open(target) as f:
43 | self.assertEqual(result[0], f.readline().strip())
44 | self.assertEqual(result[1], f.readline().strip())
45 |
46 | finally:
47 | remove(target)
48 |
49 | def testcliStdout(self):
50 | p = subprocess.Popen(self.argv, stdout=subprocess.PIPE)
51 | out, err = p.communicate()
52 |
53 | self.assertIsNone(err, 'err is None')
54 | self.assertIsNotNone(out, 'out is not None')
55 |
56 | sample = 'He could speak a little Spanish, and also a language which nobody understood'
57 |
58 | try:
59 | self.assertIn(sample, out)
60 |
61 | except (TypeError, AssertionError):
62 | self.assertIn(sample, out.decode())
63 |
64 |
65 | if __name__ == '__main__':
66 | unittest.main()
67 |
--------------------------------------------------------------------------------
/bots.yaml:
--------------------------------------------------------------------------------
1 | apps:
2 | example_app_name:
3 |
4 | # From dev.twitter.com
5 | consumer_key: '...'
6 | consumer_secret: '...'
7 |
8 | users:
9 | example_screen_name:
10 | # oauth with twitter to get these
11 | key: '...'
12 | secret: '...'
13 |
14 | # this should match one of the apps above
15 | app: example_app_name
16 |
17 | # If your bot is based on another account, the screen name of that account
18 | parent: screen_name
19 |
20 | # Location of a text file, with one tweet (or other sentence) per line
21 | # This can also be set on the command line.
22 | # This can be a single item or a list
23 | #
24 | corpus: tests/data/tweets.txt
25 |
26 | # How many tweets should we check to make sure we're not repeating something we already tweeted?
27 | checkback: 20
28 |
29 | # This determines how long of a phrase the markov chain be working with.
30 | # Higher values are slower and hew closer to the corpus
31 | # Lower values are faster and more oddball
32 | #
33 | state_size: 3
34 |
35 | # Words to never tweet
36 | # These will be added to a built-in blacklist, taken from https://github.com/dariusk/wordfilter
37 | #
38 | blacklist:
39 | - badword
40 | - evilword
41 |
42 | # With these set to True, we won't tweet these types or learn them from its parent
43 | #
44 | no_retweets: False
45 | no_replies: False
46 |
47 | # With these set, these types of tweets won't be tweeted
48 | # They will still be fed into the corpus, they will just
49 | # be filtered out of results
50 | #
51 | no_hashtags: False
52 | no_urls: False
53 | no_mentions: False
54 | # Symbols are stock ticker abbreviations like $APPL
55 | no_symbols: False
56 |
57 | # With these set, the text will be stripped of these entities before being fed to the brain
58 | # For instance, if filter_hashtags is set,
59 | # "What's Going On #lemonheads" will be fed to the brain as:
60 | # ""What's Going On"
61 | # Take care. Changing the corpus in this way can lead to strange results.
62 | #
63 | filter_hashtags: False
64 | filter_media: False
65 | filter_urls: False
66 | filter_mentions: False
67 | filter_symbols: False
68 |
69 | # By default, wordfilter is applied to the parent's tweets.
70 | filter_parent_badwords: True
71 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # twitter_markov - Create markov chain ("_ebooks") accounts on Twitter
3 | # Copyright 2014-2016 Neil Freeman contact@fakeisthenewreal.org
4 |
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 |
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 |
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
18 | from setuptools import setup
19 |
20 | try:
21 | readme = open('README.rst', 'r').read()
22 | except IOError:
23 | readme = ''
24 |
25 | with open('twitter_markov/__init__.py') as i:
26 | version = next(r for r in i.readlines() if '__version__' in r).split('=')[1].strip('"\' \n')
27 |
28 | setup(
29 | name='twitter_markov',
30 |
31 | version=version,
32 |
33 | description='Create markov chain ("_ebooks") accounts on Twitter',
34 |
35 | long_description=readme,
36 |
37 | author='Neil Freeman',
38 |
39 | author_email='contact@fakeisthenewreal.org',
40 |
41 | url='https://github.com/fitnr/twitter_markov',
42 |
43 | packages=['twitter_markov'],
44 |
45 | license='GPLv3',
46 |
47 | entry_points={
48 | 'console_scripts': [
49 | 'twittermarkov=twitter_markov.__main__:main',
50 | ],
51 | },
52 |
53 | classifiers=[
54 | 'Development Status :: 4 - Beta',
55 | 'Intended Audience :: Developers',
56 | 'License :: OSI Approved :: GNU General Public License v3 (GPLv3)',
57 | 'Programming Language :: Python :: 3.5',
58 | 'Programming Language :: Python :: 3.6',
59 | 'Programming Language :: Python :: 3.7',
60 | 'Programming Language :: Python :: 3.8',
61 | 'Operating System :: OS Independent',
62 | ],
63 |
64 | zip_safe=True,
65 |
66 | install_requires=[
67 | 'twitter_bot_utils>=0.12.0',
68 | 'markovify>=0.2.4,<0.4',
69 | 'python-Levenshtein>=0.12.0, <0.13',
70 | 'wordfilter>=0.1.8',
71 | 'pyyaml>=4.2b1',
72 | 'tweepy',
73 | 'six'
74 | ],
75 |
76 | test_suite='tests',
77 | tests_require=[
78 | 'setuptools>=17.1',
79 | 'pbr>=0.11,<1.0',
80 | 'mock',
81 | ],
82 | )
83 |
--------------------------------------------------------------------------------
/tests/test_markov.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # twitter_markov - Create markov chain ("_ebooks") accounts on Twitter
3 | # Copyright 2014-2016 Neil Freeman contact@fakeisthenewreal.org
4 |
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 |
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 |
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
18 | from __future__ import unicode_literals
19 | import unittest
20 | from os import path
21 | import markovify.text
22 | from twitter_markov import TwitterMarkov
23 |
24 | try:
25 | basestring
26 | except NameError:
27 | basestring = str
28 |
29 |
30 | class tweeter_markov_tests(unittest.TestCase):
31 |
32 | def setUp(self):
33 | self.corpus = path.join(path.dirname(__file__), 'data', 'tweets.txt')
34 | self.configfile = path.join(path.dirname(__file__), '..', 'bots.yaml')
35 |
36 | def testTwitterMarkovAttribs(self):
37 | tm = TwitterMarkov('example_screen_name', self.corpus,
38 | config=self.configfile, dry_run=True, learn=False)
39 | tm.log.setLevel(100)
40 |
41 | assert isinstance(tm, TwitterMarkov)
42 |
43 | assert hasattr(tm, 'screen_name')
44 | assert hasattr(tm, 'api')
45 | assert hasattr(tm, 'config')
46 | assert hasattr(tm, 'wordfilter')
47 | del tm
48 |
49 | def testTwitterMarkovConfigCorpus(self):
50 | tm = TwitterMarkov('example_screen_name', config=self.configfile,
51 | dry_run=True, learn=False)
52 | tm.log.setLevel(100)
53 | del tm
54 |
55 | def testTwitterMarkovListCorpus(self):
56 | tm = TwitterMarkov('example_screen_name', [self.corpus], config=self.configfile,
57 | dry_run=True, learn=False)
58 | assert isinstance(tm, TwitterMarkov)
59 | del tm
60 |
61 | def testTwitterMarkovErrors(self):
62 | self.assertRaises(IOError, TwitterMarkov, 'example_screen_name', 'foo')
63 |
64 | def testTwitterMarkovModel(self, *_):
65 | tm = TwitterMarkov('example_screen_name', self.corpus,
66 | config=self.configfile, dry_run=True, learn=False)
67 | assert isinstance(tm.models['tweets.txt'], markovify.text.Text)
68 |
69 | def testCheck(self):
70 | tm = TwitterMarkov('example_screen_name', [self.corpus], config=self.configfile,
71 | dry_run=True, learn=False)
72 | self.assertFalse(tm.check_tweet('😀' * 141))
73 | self.assertFalse(tm.check_tweet(''))
74 | self.assertFalse(tm.check_tweet('contains the blacklisted word tits'))
75 |
76 | if __name__ == '__main__':
77 | unittest.main()
78 |
--------------------------------------------------------------------------------
/tests/test_markov_methods.py:
--------------------------------------------------------------------------------
1 | # twitter_markov - Create markov chain ("_ebooks") accounts on Twitter
2 | # Copyright 2014-2016 Neil Freeman contact@fakeisthenewreal.org
3 |
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 |
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 |
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 | from __future__ import unicode_literals
17 | import unittest
18 | import os
19 | from os import path
20 | import mock
21 | import tweepy
22 | import markovify.text
23 | from twitter_markov import TwitterMarkov
24 |
25 | try:
26 | basestring
27 | except NameError:
28 | basestring = str
29 |
30 | TIMELINE = [
31 | {
32 | "id": 1235,
33 | "id_str": "1235",
34 | "in_reply_to_user_id": None,
35 | "retweeted": False,
36 | "entities": {},
37 | "user": {"screen_name": "Random"},
38 | "text": "Lorem ipsum dolor sit amet"
39 | },
40 | {
41 | "id": 1234,
42 | "id_str": "1234",
43 | "in_reply_to_user_id": 1,
44 | "retweeted": False,
45 | "entities": {},
46 | "user": {"screen_name": "Random"},
47 | "text": "Quas doloremque velit deleniti unde commodi voluptatum incidunt."
48 | },
49 | {
50 | "id": 1233,
51 | "id_str": "1233",
52 | "retweeted": True,
53 | "in_reply_to_user_id": None,
54 | "entities": {},
55 | "user": {"screen_name": "Random"},
56 | "text": "Sunt, culpa blanditiis, nostrum doloremque illum excepturi quam."
57 | },
58 | ]
59 |
60 |
61 | def fake_timeline():
62 | return [tweepy.Status.parse(tweepy.api, t) for t in TIMELINE]
63 |
64 |
65 | class tweeter_markov_tests(unittest.TestCase):
66 |
67 | @mock.patch.object(tweepy.API, 'user_timeline', return_value=fake_timeline())
68 | def setUp(self, _):
69 | self.corpus = path.join(path.dirname(__file__), 'data', 'tweets.txt')
70 | self.configfile = path.join(path.dirname(__file__), '..', 'bots.yaml')
71 |
72 | self.tm = TwitterMarkov('example_screen_name', [self.corpus], config=self.configfile,
73 | dry_run=True, learn=False)
74 |
75 | self.tm.log.setLevel(100)
76 |
77 | def testCheckModels(self):
78 | for m in self.tm.models.values():
79 | self.assertIsInstance(m, markovify.text.NewlineText)
80 |
81 | @mock.patch.object(tweepy.API, 'user_timeline', return_value=fake_timeline())
82 | def testTwitterMarkovCompose(self, *_):
83 | response = self.tm.compose(tries=150, max_overlap_ratio=2, max_overlap_total=100)
84 |
85 | assert isinstance(response, basestring)
86 | assert len(response) < 140
87 |
88 | @mock.patch.object(tweepy.API, 'mentions_timeline', return_value=fake_timeline())
89 | @mock.patch.object(tweepy.API, 'user_timeline', return_value=fake_timeline())
90 | def testTwitterMarkovReply(self, *_):
91 | r = self.tm.reply_all(tries=75, max_overlap_ratio=2, max_overlap_total=100)
92 |
93 | @mock.patch.object(tweepy.API, 'user_timeline', return_value=fake_timeline())
94 | def testTwitterMarkovRecentlyTweeted(self, _):
95 | recents = self.tm.recently_tweeted
96 | assert recents[0] == TIMELINE[0]['text']
97 |
98 | @mock.patch.object(tweepy.API, 'user_timeline', return_value=fake_timeline())
99 | def testTwitterMarkovCheckTweet(self, _):
100 | assert self.tm.check_tweet('') is False
101 | assert self.tm.check_tweet('badword') is False
102 | assert self.tm.check_tweet('Lorem ipsum dolor sit amet') is False
103 | assert self.tm.check_tweet('Lorem ipsum dolor sit amet!') is False
104 | assert self.tm.check_tweet('Lorem ipsum dolor set namet') is False
105 | assert self.tm.check_tweet('Random Text that should work totally') is True
106 | assert self.tm.check_tweet('@reply Random Text') is True
107 |
108 | @mock.patch.object(tweepy.API, 'user_timeline', return_value=fake_timeline())
109 | def testTwitterMarkovLearn(self, _):
110 | tmp = path.join(path.dirname(__file__), 'data', 'tmp.txt')
111 | self.tm.learn_parent(corpus=tmp)
112 |
113 | try:
114 | with open(tmp) as f:
115 | result = f.read()
116 |
117 | assert TIMELINE[0]['text'] in result
118 | assert TIMELINE[1]['text'] in result
119 | assert TIMELINE[2]['text'] in result
120 |
121 | finally:
122 | os.remove(tmp)
123 |
--------------------------------------------------------------------------------
/twitter_markov/__main__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | # Copyright 2014-2016 Neil Freeman contact@fakeisthenewreal.org
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 |
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 |
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 |
17 | from __future__ import unicode_literals, print_function
18 | import os
19 | import sys
20 | from signal import signal, SIGPIPE, SIG_DFL
21 | import argparse
22 | import twitter_bot_utils as tbu
23 | from . import TwitterMarkov
24 | from . import checking
25 | from . import __version__ as version
26 |
27 |
28 | TWEETER_DESC = 'Post markov chain ("ebooks") tweets to Twitter'
29 | LEARNER_DESC = 'Turn a twitter archive into a twitter_markov-ready text file'
30 |
31 |
32 | def main():
33 | parser = argparse.ArgumentParser(
34 | 'twittermarkov', description='Tweet with a markov bot, or teach it from a twitter archive.')
35 |
36 | tbu.args.add_default_args(parser, version, ())
37 |
38 | subparsers = parser.add_subparsers()
39 |
40 | tweeter = subparsers.add_parser('tweet', description=TWEETER_DESC, usage='%(prog)s [options]')
41 | tbu.args.add_default_args(tweeter, include=('user', 'config', 'dry-run', 'verbose', 'quiet'))
42 | tweeter.add_argument('-r', '--reply', action='store_const', const='reply',
43 | dest='action', help='tweet responses to recent mentions')
44 | tweeter.add_argument('--corpus', dest='corpus', metavar='corpus', type=str,
45 | help='text file, one sentence per line')
46 | tweeter.add_argument('--max-len', type=int, default=140, help='maximum output length. default: 140')
47 | tweeter.add_argument('--state-size', type=int, help='model state size. default: 2')
48 | tweeter.add_argument('--no-learn', dest='learn', action='store_false',
49 | help='skip learning (by default, recent tweets from the "parent" account are added to corpus)')
50 | tweeter.set_defaults(subparser='tweet', func=tweet_func, action='tweet')
51 |
52 | learner = subparsers.add_parser('corpus', description=LEARNER_DESC, usage="%(prog)s [options] archive corpus")
53 | learner.add_argument('-o', type=str, dest='output', metavar='corpus',
54 | help='output text file (defaults to stdout)', default='/dev/stdout')
55 | learner.add_argument('--no-retweets', action='store_true', help='skip retweets')
56 | learner.add_argument('--no-replies', action='store_true', help='filter out replies')
57 | learner.add_argument('--no-mentions', action='store_true', help='filter out mentions')
58 | learner.add_argument('--no-urls', action='store_true', help='filter out urls')
59 | learner.add_argument('--no-media', action='store_true', help='filter out media')
60 | learner.add_argument('--no-hashtags', action='store_true', help='filter out hashtags')
61 | learner.add_argument('-q', '--quiet', action='store_true', help='run quietly')
62 | learner.add_argument('archive', type=str, metavar='archive',
63 | default=os.getcwd(), help='archive csv file (e.g. tweets.csv found in Twitter archive)')
64 |
65 | learner.set_defaults(subparser='learn', func=learn_func, action='learn')
66 |
67 | args = parser.parse_args()
68 | try:
69 | func = args.func
70 | except AttributeError:
71 | parser.parse_args(['--help'])
72 |
73 | argdict = vars(args)
74 | del argdict['func']
75 |
76 | if args.subparser == 'tweet':
77 | func(**argdict)
78 |
79 | elif args.subparser == 'learn':
80 | func(**argdict)
81 |
82 |
83 | def tweet_func(action, max_len=None, **kwargs):
84 | tm = TwitterMarkov(**kwargs)
85 | try:
86 | if action == 'tweet':
87 | tm.log.debug('tweeting')
88 | tm.tweet(max_len=max_len)
89 |
90 | elif action == 'reply':
91 | tm.log.debug('replying')
92 | tm.reply_all(max_len=max_len)
93 |
94 | except RuntimeError:
95 | tm.log.error('model was unable to compose a tweet')
96 | return
97 |
98 |
99 | def learn_func(**kwargs):
100 | if not kwargs['quiet']:
101 | print("Reading " + kwargs['archive'], file=sys.stderr)
102 |
103 | archive = tbu.archive.read_csv(kwargs.get('archive'))
104 | gen = checking.generator(archive, **kwargs)
105 | tweets = (tweet.replace(u'\n', u' ') + '\n' for tweet in gen)
106 |
107 | if kwargs['output'] in ('-', '/dev/stdout'):
108 | signal(SIGPIPE, SIG_DFL)
109 | sys.stdout.writelines(tweets)
110 |
111 | else:
112 | if not kwargs['quiet']:
113 | print("Writing " + kwargs['output'], file=sys.stderr)
114 |
115 | with open(kwargs.get('output'), 'w') as f:
116 | f.writelines(tweets)
117 |
118 | if __name__ == '__main__':
119 | main()
120 |
--------------------------------------------------------------------------------
/tests/test_checking.py:
--------------------------------------------------------------------------------
1 | # twitter_markov - Create markov chain ("_ebooks") accounts on Twitter
2 | # Copyright 2014-2016 Neil Freeman contact@fakeisthenewreal.org
3 |
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 |
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 |
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 |
17 | import unittest
18 | from os import path
19 | from twitter_markov import checking
20 | from twitter_bot_utils import archive
21 |
22 | import tweepy
23 |
24 | try:
25 | basestring
26 | except NameError:
27 | basestring = str
28 |
29 | TWEET = {
30 | "source": "\u003Ca href=\"http:\/\/twitter.com\/download\/iphone\" rel=\"nofollow\"\u003ETwitter for iPhone\u003C\/a\u003E",
31 | "entities": {
32 | "user_mentions": [{
33 | "name": "John Doe",
34 | "screen_name": "twitter",
35 | "indices": [0, 8],
36 | "id_str": "1",
37 | "id": 1
38 | }],
39 | "media": [],
40 | "hashtags": [],
41 | "urls": []
42 | },
43 | "in_reply_to_status_id_str": "318563540590010368",
44 | "id_str": "318565861172600832",
45 | "in_reply_to_user_id": 14155645,
46 | "text": "@twitter example tweet example tweet example tweet",
47 | "id": 318565861172600832,
48 | "in_reply_to_status_id": 318563540590010368,
49 | "in_reply_to_screen_name": "twitter",
50 | "in_reply_to_user_id_str": "14155645",
51 | "retweeted": None,
52 | "user": {
53 | "name": "Neil Freeman",
54 | "screen_name": "fitnr",
55 | "protected": False,
56 | "id_str": "6853512",
57 | "profile_image_url_https": "https:\/\/pbs.twimg.com\/profile_images\/431817496350314496\/VGgzYAE7_normal.jpeg",
58 | "id": 6853512,
59 | "verified": False
60 | }
61 | }
62 |
63 |
64 | class tweeter_markov_tests(unittest.TestCase):
65 |
66 | def setUp(self):
67 | api = tweepy.API()
68 | self.status = tweepy.Status.parse(api, TWEET)
69 |
70 | with open(path.join(path.dirname(__file__), 'data', 'tweets.txt')) as f:
71 | self.txt = f.readlines()
72 |
73 | self.archive = archive.read_csv(path.join(path.dirname(__file__), 'data'))
74 |
75 | def test_mention_filter(self):
76 | mention_filter = checking.construct_tweet_filter(no_mentions=True)
77 | assert mention_filter(self.status) == u' example tweet example tweet example tweet'
78 |
79 | def test_rt_filter(self):
80 | retweet_filter = checking.construct_tweet_checker(no_retweets=True)
81 | assert retweet_filter(self.status)
82 |
83 | def testLinkFilter(self):
84 | link_filter = checking.construct_tweet_filter(no_urls=True)
85 |
86 | assert link_filter('http://happiness.com/ is https://illusory.co') == ' is '
87 |
88 | def testHashFilter(self):
89 | hash_filter = checking.construct_tweet_filter(no_hashtags=True)
90 |
91 | assert hash_filter('#happiness is #illusory') == ' is '
92 |
93 | def test_reply_filter(self):
94 | reply_filter = checking.construct_tweet_checker(no_replies=True)
95 | assert reply_filter(self.status) is False
96 |
97 | def test_reply_filtering_txtfile(self):
98 | generator = checking.generator(self.txt, txt=1, no_replies=1)
99 | self.assertEqual(len(list(generator)), 99)
100 |
101 | def test_reply_filtering_archive(self):
102 | generator = checking.generator(self.archive, no_replies=1)
103 | self.assertEqual(len(list(generator)), 98)
104 |
105 | def test_rt_filtering(self):
106 | generator = checking.generator(self.txt, txt=1, no_retweets=1)
107 | self.assertEqual(len(list(generator)), 99)
108 |
109 | def test_rt_filtering_archive(self):
110 | generator = checking.generator(self.archive, no_retweets=1)
111 | lis = list(generator)
112 | self.assertEqual(len(lis), 98)
113 |
114 | def test_rt_checking(self):
115 | checker = checking.construct_tweet_checker(no_retweets=True)
116 | assert checker('RT @hello There') is False
117 | assert checker('@hello There') is True
118 |
119 | def test_reply_checking(self):
120 | checker = checking.construct_tweet_checker(no_replies=True)
121 | assert checker('RT @hello There') is True
122 | assert checker('@hello There') is False
123 |
124 | lst = list(self.archive)
125 | rt = [t for t in lst if t['tweet_id'] == '651607152713433089'][0]
126 |
127 | assert checker(rt) is True
128 |
129 | def testCheckingReturnStatus(self):
130 | generator = checking.generator([self.status] * 2, return_status=True)
131 | assert isinstance(next(generator), tweepy.Status)
132 |
133 | generator = checking.generator([self.status] * 2, return_status=False)
134 | self.assertTrue(isinstance(next(generator), basestring))
135 |
136 | generator = checking.generator(self.archive, return_status=True)
137 | self.assertTrue(isinstance(next(generator), dict))
138 |
139 |
140 | if __name__ == '__main__':
141 | unittest.main()
142 |
--------------------------------------------------------------------------------
/tests/data/tweets.txt:
--------------------------------------------------------------------------------
1 | @mention hihdfg
2 | tweet with a #hashtag
3 | RT @blah blah blah
4 | Regular old tweet
5 | He could speak a little Spanish, and also a language which nobody understood
6 | He walked down the gallery and across the narrow "bridges"
7 | He stopped before the door of his own cottage, which was the fourth one
8 | Once in a while he withdrew his glance from the newspaper and looked about him.
9 | Both children wanted to follow their father when they saw him starting out.
10 | Her eyebrows were a shade darker than her hair.
11 | Robert rolled a cigarette.
12 | This seemed quite proper and natural on his part.
13 | Robert talked a good deal about himself.
14 | He was spending his summer vacation, as he always did, with his mother at Grand Isle.
15 | He thought it very discouraging that his wife, who was the sole object of his existence, evinced so little interest in things which concerned
16 | He reproached his wife with her inattention, her habitual neglect of the children.
17 | It was then past midnight.
18 | An indescribable oppression, which seemed to generate in some unfamiliar part of her consciousness, filled her whole being with a vague anguish.
19 | The little stinging, buzzing imps succeeded in dispelling a mood which might have held her there in the darkness half a night longer.
20 | The boys were tumbling about, clinging to his legs, imploring that numerous things be brought back to them.
21 | If one of the little Pontellier boys took a tumble whilst at play, he was not apt to rush crying to his mother's arms for comfort;
22 | Many of them were delicious in the role; one of them was the embodiment of every womanly grace and charm.
23 | A green and yellow parrot, which hung in a cage outside the door, kept
24 | "Allez vous-en! Allez vous-en! Sapristi! That's all right!"
25 | He could speak a little Spanish, and also a language which nobody
26 | understood, unless it was the mocking-bird that hung on the other
27 | side of the door, whistling his fluty notes out upon the breeze with
28 | Mr. Pontellier, unable to read his newspaper with any degree of comfort,
29 | arose with an expression and an exclamation of disgust.
30 | He walked down the gallery and across the narrow "bridges" which
31 | connected the Lebrun cottages one with the other. He had been seated
32 | before the door of the main house. The parrot and the mockingbird were
33 | the property of Madame Lebrun, and they had the right to make all the
34 | noise they wished. Mr. Pontellier had the privilege of quitting their
35 | He stopped before the door of his own cottage, which was the fourth one
36 | from the main building and next to the last. Seating himself in a wicker
37 | rocker which was there, he once more applied himself to the task of
38 | reading the newspaper. The day was Sunday; the paper was a day old. The
39 | Sunday papers had not yet reached Grand Isle. He was already acquainted
40 | with the market reports, and he glanced restlessly over the editorials
41 | and bits of news which he had not had time to read before quitting New
42 | Mr. Pontellier wore eye-glasses. He was a man of forty, of medium height
43 | and rather slender build; he stooped a little. His hair was brown and
44 | straight, parted on one side. His beard was neatly and closely trimmed.
45 | Once in a while he withdrew his glance from the newspaper and looked
46 | about him. There was more noise than ever over at the house. The main
47 | building was called "the house," to distinguish it from the cottages.
48 | The chattering and whistling birds were still at it. Two young girls,
49 | the Farival twins, were playing a duet from "Zampa" upon the piano.
50 | Madame Lebrun was bustling in and out, giving orders in a high key to a
51 | yard-boy whenever she got inside the house, and directions in an equally
52 | high voice to a dining-room servant whenever she got outside. She was
53 | a fresh, pretty woman, clad always in white with elbow sleeves. Her
54 | starched skirts crinkled as she came and went. Farther down, before
55 | one of the cottages, a lady in black was walking demurely up and down,
56 | telling her beads. A good many persons of the pension had gone over to
57 | the Cheniere Caminada in Beaudelet's lugger to hear mass. Some young
58 | people were out under the wateroaks playing croquet. Mr. Pontellier's
59 | two children were there--sturdy little fellows of four and five. A
60 | quadroon nurse followed them about with a faraway, meditative air.
61 | Mr. Pontellier finally lit a cigar and began to smoke, letting the paper
62 | drag idly from his hand. He fixed his gaze upon a white sunshade that
63 | was advancing at snail's pace from the beach. He could see it plainly
64 | between the gaunt trunks of the water-oaks and across the stretch of
65 | yellow camomile. The gulf looked far away, melting hazily into the blue
66 | of the horizon. The sunshade continued to approach slowly. Beneath its
67 | pink-lined shelter were his wife, Mrs. Pontellier, and young Robert
68 | Lebrun. When they reached the cottage, the two seated themselves with
69 | some appearance of fatigue upon the upper step of the porch, facing each
70 | "What folly! to bathe at such an hour in such heat!" exclaimed Mr.
71 | Pontellier. He himself had taken a plunge at daylight. That was why the
72 | "You are burnt beyond recognition," he added, looking at his wife as one
73 | looks at a valuable piece of personal property which has suffered some
74 | damage. She held up her hands, strong, shapely hands, and surveyed them
75 | critically, drawing up her fawn sleeves above the wrists. Looking at
76 | them reminded her of her rings, which she had given to her husband
77 | before leaving for the beach. She silently reached out to him, and he,
78 | understanding, took the rings from his vest pocket and dropped them
79 | into her open palm. She slipped them upon her fingers; then clasping
80 | her knees, she looked across at Robert and began to laugh. The rings
81 | sparkled upon her fingers. He sent back an answering smile.
82 | "What is it?" asked Pontellier, looking lazily and amused from one to
83 | the other. It was some utter nonsense; some adventure out there in the
84 | water, and they both tried to relate it at once. It did not seem half
85 | so amusing when told. They realized this, and so did Mr. Pontellier. He
86 | yawned and stretched himself. Then he got up, saying he had half a mind
87 | to go over to Klein's hotel and play a game of billiards.
88 | "Come go along, Lebrun," he proposed to Robert. But Robert admitted
89 | quite frankly that he preferred to stay where he was and talk to Mrs.
90 | "Well, send him about his business when he bores you, Edna," instructed
91 | "Here, take the umbrella," she exclaimed, holding it out to him. He
92 | accepted the sunshade, and lifting it over his head descended the steps
93 | "Coming back to dinner?" his wife called after him. He halted a moment
94 | and shrugged his shoulders. He felt in his vest pocket; there was a
95 | ten-dollar bill there. He did not know; perhaps he would return for the
96 | early dinner and perhaps he would not. It all depended upon the company
97 | which he found over at Klein's and the size of "the game." He did not
98 | say this, but she understood it, and laughed, nodding good-by to him.
99 | Both children wanted to follow their father when they saw him starting
100 | out. He kissed them and promised to bring them back bonbons and peanuts.
101 |
--------------------------------------------------------------------------------
/twitter_markov/checking.py:
--------------------------------------------------------------------------------
1 | # Copyright 2014-2016 Neil Freeman contact@fakeisthenewreal.org
2 | # This program is free software: you can redistribute it and/or modify
3 | # it under the terms of the GNU General Public License as published by
4 | # the Free Software Foundation, either version 3 of the License, or
5 | # (at your option) any later version.
6 |
7 | # This program is distributed in the hope that it will be useful,
8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 | # GNU General Public License for more details.
11 |
12 | # You should have received a copy of the GNU General Public License
13 | # along with this program. If not, see .
14 |
15 | import re
16 | from twitter_bot_utils import helpers
17 | import wordfilter
18 |
19 |
20 | def generator(tweets, return_status=None, **kwargs):
21 | '''
22 | Returns a generator that returned a filtered input iterable of tweets or
23 | tweet-like objects (tweepy.Status objects or dictionaries).
24 |
25 | Args:
26 | tweets (iterable):
27 | return_status (boolean): If true, returns entire status with modified test
28 | no_retweets (boolean): Exclude retweets (e.g. strings beginning RT) (default False)
29 | no_replies (boolean): Exclude replies (e.g. strings beginning @screen_name) (default False)
30 | no_mentions (boolean): Filter out mentions (e.g. strings containing @screen_name) (default False)
31 | no_badwords (boolean): Exclude derogatory terms for people (default True)
32 | no_urls (boolean): filter out exclude urls (default False)
33 | no_hashtags (boolean): filter out hashtags (default False)
34 | no_media (boolean): filter out media (twitter objects only) (default False)
35 | no_symbols (boolean): filter out symbols (twitter objects only) (default False)
36 | '''
37 |
38 | tweet_checker = construct_tweet_checker(
39 | no_retweets=kwargs.get('no_retweets'),
40 | no_replies=kwargs.get('no_replies'),
41 | no_badwords=kwargs.get('no_replies', True)
42 | )
43 |
44 | tweet_filter = construct_tweet_filter(
45 | no_mentions=kwargs.get('no_mentions'),
46 | no_urls=kwargs.get('no_urls'),
47 | no_media=kwargs.get('no_media'),
48 | no_hashtags=kwargs.get('no_hashtags'),
49 | no_symbols=kwargs.get('no_symbols')
50 | )
51 |
52 | for status in tweets:
53 | if not tweet_checker(status):
54 | continue
55 |
56 | text = helpers.format_text(tweet_filter(status))
57 |
58 | if return_status:
59 | try:
60 | status.text = text
61 | except AttributeError:
62 | status['text'] = text
63 |
64 | yield status
65 |
66 | yield text
67 |
68 |
69 | def isreply(tweet):
70 | '''
71 | Checks if a given tweet is a reply.
72 | If tweet is a string, returns True when text starts with '@'.
73 | If tweet is a tweepy.Status object, returns True when ``in_reply_to_status_id`` or
74 | ``in_reply_to_user_id`` is set.
75 |
76 | Args:
77 | tweet (str/tweepy.Status/dict): A string, tweepy.Status object, or Status-like dict.
78 |
79 | Returns:
80 | bool
81 | '''
82 | try:
83 | return bool(tweet.in_reply_to_user_id)
84 |
85 | except AttributeError:
86 | try:
87 | return bool(tweet.get('in_reply_to_user_id') or tweet.get('in_reply_to_status_id'))
88 |
89 | except AttributeError:
90 | try:
91 | return tweet[0] == "@"
92 |
93 | except AttributeError:
94 | pass
95 |
96 | return False
97 |
98 |
99 | def isretweet(tweet):
100 | '''
101 | Checks if a given tweet is a retweet.
102 | If tweet is a string, returns True when text starts with 'RT '.
103 | If tweet is a tweepy.Status object, returns True when ``retweeted_status`` or
104 | ``retweeted_status_id`` is set.
105 |
106 | Args:
107 | tweet (str/tweepy.Status/dict): A string, tweepy.Status object, or Status-like dict.
108 |
109 | Returns:
110 | bool
111 | '''
112 | try:
113 | return bool(tweet.retweeted)
114 |
115 | except AttributeError:
116 | try:
117 | return bool(tweet.get('retweeted_status') or tweet.get('retweeted_status_id'))
118 |
119 | except AttributeError:
120 | try:
121 | return tweet[:3].upper() == 'RT '
122 |
123 | except AttributeError:
124 | pass
125 |
126 | return False
127 |
128 |
129 | def isblacklisted(tweet):
130 | '''
131 | Checks if a given tweet contains a word blacklisted by WordFilter.
132 |
133 | Args:
134 | tweet (str/tweepy.Status/dict): A string, tweepy.Status object, or Status-like dict.
135 |
136 | Returns:
137 | bool
138 | '''
139 | try:
140 | return wordfilter.blacklisted(tweet.text)
141 |
142 | except AttributeError:
143 | try:
144 | return wordfilter.blacklisted(tweet['text'])
145 |
146 | except (KeyError, TypeError):
147 | return wordfilter.blacklisted(tweet)
148 |
149 | return False
150 |
151 |
152 | def construct_tweet_checker(no_retweets=False, no_replies=False, no_badwords=True):
153 | '''
154 | Returns a tweet checker, a function that checks if tweets pass the tests.
155 |
156 | Args:
157 | no_retweets (boolean): Checker filters out retweets (default: False).
158 | no_replies (boolean): Checker filters out replies (default: False).
159 | no_badwords (boolean): Checker filters out blacklisted words (default: True).
160 |
161 | Returns:
162 | function
163 | '''
164 | checks = []
165 |
166 | if no_retweets:
167 | checks.append(isretweet)
168 |
169 | if no_replies:
170 | checks.append(isreply)
171 |
172 | if no_badwords:
173 | checks.append(isblacklisted)
174 |
175 | def checker(tweet):
176 | return not any(isbad(tweet) for isbad in checks)
177 |
178 | return checker
179 |
180 |
181 | def construct_tweet_filter(no_mentions=False, no_urls=False, no_media=False, no_hashtags=False, no_symbols=False):
182 | '''
183 | Returns a filter function for tweet text.
184 |
185 | Args:
186 | no_mentions (boolean): filter out mentions.
187 | no_urls (boolean): filter out urls.
188 | no_media (boolean): filter out media.
189 | no_hashtags (boolean): filter out hashtags.
190 | no_symbols (boolean): filter out symbols.
191 |
192 | Returns:
193 | function
194 | '''
195 | entitytypes = []
196 |
197 | if no_mentions:
198 | entitytypes.append('user_mentions')
199 |
200 | if no_hashtags:
201 | entitytypes.append('hashtags')
202 |
203 | if no_urls:
204 | entitytypes.append('urls')
205 |
206 | if no_media:
207 | entitytypes.append('media')
208 |
209 | if no_symbols:
210 | entitytypes.append('symbols')
211 |
212 | def filterer(tweet):
213 | # ignore strings
214 | try:
215 | text = helpers.remove_entities(tweet, entitytypes)
216 | except AttributeError:
217 | text = tweet
218 |
219 | # Older tweets don't have entities
220 | if no_urls:
221 | # regex stolen from http://stackoverflow.com/questions/6883049/regex-to-find-urls-in-string-in-python
222 | text = re.sub(r"http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+", '', text)
223 |
224 | if no_mentions:
225 | text = re.sub(r'@\w+', '', text)
226 |
227 | if no_hashtags:
228 | text = re.sub(r'#\w+', '', text)
229 |
230 | if no_symbols:
231 | text = re.sub(r'\$[a-zA-Z]+', '', text)
232 |
233 | return text
234 |
235 | return filterer
236 |
--------------------------------------------------------------------------------
/docs/Makefile:
--------------------------------------------------------------------------------
1 | # Makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line.
5 | SPHINXOPTS =
6 | SPHINXBUILD = sphinx-build
7 | PAPER =
8 | BUILDDIR = _build
9 |
10 | # User-friendly check for sphinx-build
11 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
12 | $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
13 | endif
14 |
15 | # Internal variables.
16 | PAPEROPT_a4 = -D latex_paper_size=a4
17 | PAPEROPT_letter = -D latex_paper_size=letter
18 | ALLSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
19 | # the i18n builder cannot share the environment and doctrees with the others
20 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
21 |
22 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext
23 |
24 | help:
25 | @echo "Please use \`make ' where is one of"
26 | @echo " html to make standalone HTML files"
27 | @echo " dirhtml to make HTML files named index.html in directories"
28 | @echo " singlehtml to make a single large HTML file"
29 | @echo " pickle to make pickle files"
30 | @echo " json to make JSON files"
31 | @echo " htmlhelp to make HTML files and a HTML help project"
32 | @echo " qthelp to make HTML files and a qthelp project"
33 | @echo " applehelp to make an Apple Help Book"
34 | @echo " devhelp to make HTML files and a Devhelp project"
35 | @echo " epub to make an epub"
36 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
37 | @echo " latexpdf to make LaTeX files and run them through pdflatex"
38 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
39 | @echo " text to make text files"
40 | @echo " man to make manual pages"
41 | @echo " texinfo to make Texinfo files"
42 | @echo " info to make Texinfo files and run them through makeinfo"
43 | @echo " gettext to make PO message catalogs"
44 | @echo " changes to make an overview of all changed/added/deprecated items"
45 | @echo " xml to make Docutils-native XML files"
46 | @echo " pseudoxml to make pseudoxml-XML files for display purposes"
47 | @echo " linkcheck to check all external links for integrity"
48 | @echo " doctest to run all doctests embedded in the documentation (if enabled)"
49 | @echo " coverage to run coverage check of the documentation (if enabled)"
50 |
51 | clean:
52 | rm -rf $(BUILDDIR)/*
53 |
54 | html:
55 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
56 | @echo
57 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
58 |
59 | dirhtml:
60 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
61 | @echo
62 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
63 |
64 | singlehtml:
65 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
66 | @echo
67 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
68 |
69 | pickle:
70 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
71 | @echo
72 | @echo "Build finished; now you can process the pickle files."
73 |
74 | json:
75 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
76 | @echo
77 | @echo "Build finished; now you can process the JSON files."
78 |
79 | htmlhelp:
80 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
81 | @echo
82 | @echo "Build finished; now you can run HTML Help Workshop with the" \
83 | ".hhp project file in $(BUILDDIR)/htmlhelp."
84 |
85 | qthelp:
86 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
87 | @echo
88 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \
89 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
90 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/TwitterBotUtils.qhcp"
91 | @echo "To view the help file:"
92 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/TwitterBotUtils.qhc"
93 |
94 | applehelp:
95 | $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp
96 | @echo
97 | @echo "Build finished. The help book is in $(BUILDDIR)/applehelp."
98 | @echo "N.B. You won't be able to view it unless you put it in" \
99 | "~/Library/Documentation/Help or install it in your application" \
100 | "bundle."
101 |
102 | devhelp:
103 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
104 | @echo
105 | @echo "Build finished."
106 | @echo "To view the help file:"
107 | @echo "# mkdir -p $$HOME/.local/share/devhelp/TwitterBotUtils"
108 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/TwitterBotUtils"
109 | @echo "# devhelp"
110 |
111 | epub:
112 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
113 | @echo
114 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
115 |
116 | latex:
117 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
118 | @echo
119 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
120 | @echo "Run \`make' in that directory to run these through (pdf)latex" \
121 | "(use \`make latexpdf' here to do that automatically)."
122 |
123 | latexpdf:
124 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
125 | @echo "Running LaTeX files through pdflatex..."
126 | $(MAKE) -C $(BUILDDIR)/latex all-pdf
127 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
128 |
129 | latexpdfja:
130 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
131 | @echo "Running LaTeX files through platex and dvipdfmx..."
132 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
133 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
134 |
135 | text:
136 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
137 | @echo
138 | @echo "Build finished. The text files are in $(BUILDDIR)/text."
139 |
140 | man:
141 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
142 | @echo
143 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
144 |
145 | texinfo:
146 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
147 | @echo
148 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
149 | @echo "Run \`make' in that directory to run these through makeinfo" \
150 | "(use \`make info' here to do that automatically)."
151 |
152 | info:
153 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
154 | @echo "Running Texinfo files through makeinfo..."
155 | make -C $(BUILDDIR)/texinfo info
156 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
157 |
158 | gettext:
159 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
160 | @echo
161 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
162 |
163 | changes:
164 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
165 | @echo
166 | @echo "The overview file is in $(BUILDDIR)/changes."
167 |
168 | linkcheck:
169 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
170 | @echo
171 | @echo "Link check complete; look for any errors in the above output " \
172 | "or in $(BUILDDIR)/linkcheck/output.txt."
173 |
174 | doctest:
175 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
176 | @echo "Testing of doctests in the sources finished, look at the " \
177 | "results in $(BUILDDIR)/doctest/output.txt."
178 |
179 | coverage:
180 | $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage
181 | @echo "Testing of coverage in the sources finished, look at the " \
182 | "results in $(BUILDDIR)/coverage/python.txt."
183 |
184 | xml:
185 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
186 | @echo
187 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml."
188 |
189 | pseudoxml:
190 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
191 | @echo
192 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
193 |
--------------------------------------------------------------------------------
/docs/source/conf.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | #
3 | # Twitter Bot Utils documentation build configuration file, created by
4 | # sphinx-quickstart on Sun Feb 14 17:14:34 2016.
5 | #
6 | # This file is execfile()d with the current directory set to its
7 | # containing dir.
8 | #
9 | # Note that not all possible configuration values are present in this
10 | # autogenerated file.
11 | #
12 | # All configuration values have a default; values that are commented out
13 | # serve to show the default.
14 |
15 | import os
16 |
17 | # If extensions (or modules to document with autodoc) are in another directory,
18 | # add these directories to sys.path here. If the directory is relative to the
19 | # documentation root, use os.path.abspath to make it absolute, like shown here.
20 | #sys.path.insert(0, os.path.abspath('.'))
21 |
22 | # -- General configuration ------------------------------------------------
23 |
24 | # If your documentation needs a minimal Sphinx version, state it here.
25 | #needs_sphinx = '1.0'
26 |
27 | # Add any Sphinx extension module names here, as strings. They can be
28 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
29 | # ones.
30 | extensions = [
31 | 'sphinx.ext.autodoc',
32 | 'sphinx.ext.coverage',
33 | 'sphinx.ext.napoleon',
34 | ]
35 |
36 | # Add any paths that contain templates here, relative to this directory.
37 | templates_path = ['_templates']
38 |
39 | # The suffix(es) of source filenames.
40 | # You can specify multiple suffix as a list of string:
41 | # source_suffix = ['.rst', '.md']
42 | source_suffix = '.rst'
43 |
44 | # The encoding of source files.
45 | #source_encoding = 'utf-8-sig'
46 |
47 | # The master toctree document.
48 | master_doc = 'index'
49 |
50 | # General information about the project.
51 | project = u'Twitter markov'
52 | copyright = u'2016, Neil Freeman'
53 | author = u'Neil Freeman'
54 |
55 | # The version info for the project you're documenting, acts as replacement for
56 | # |version| and |release|, also used in various other places throughout the
57 | # built documents.
58 | #
59 | # The short X.Y version.
60 | with open(os.path.join(os.path.dirname(__file__), '../..', 'twitter_markov/__init__.py')) as i:
61 | version = next(r for r in i.readlines() if '__version__' in r).split('=')[1].strip('"\' \n')
62 |
63 | # The full version, including alpha/beta/rc tags.
64 | release = '0.10.5'
65 |
66 | # The language for content autogenerated by Sphinx. Refer to documentation
67 | # for a list of supported languages.
68 | #
69 | # This is also used if you do content translation via gettext catalogs.
70 | # Usually you set "language" from the command line for these cases.
71 | language = None
72 |
73 | # There are two options for replacing |today|: either, you set today to some
74 | # non-false value, then it is used:
75 | #today = ''
76 | # Else, today_fmt is used as the format for a strftime call.
77 | #today_fmt = '%B %d, %Y'
78 |
79 | intersphinx_mapping = {'tweepy': ('http://docs.tweepy.org/en/v3.5.0', None)}
80 |
81 | # List of patterns, relative to source directory, that match files and
82 | # directories to ignore when looking for source files.
83 | exclude_patterns = []
84 |
85 | # The reST default role (used for this markup: `text`) to use for all
86 | # documents.
87 | #default_role = None
88 |
89 | # If true, '()' will be appended to :func: etc. cross-reference text.
90 | #add_function_parentheses = True
91 |
92 | # If true, the current module name will be prepended to all description
93 | # unit titles (such as .. function::).
94 | #add_module_names = True
95 |
96 | # If true, sectionauthor and moduleauthor directives will be shown in the
97 | # output. They are ignored by default.
98 | #show_authors = False
99 |
100 | # The name of the Pygments (syntax highlighting) style to use.
101 | pygments_style = 'sphinx'
102 |
103 | # A list of ignored prefixes for module index sorting.
104 | #modindex_common_prefix = []
105 |
106 | # If true, keep warnings as "system message" paragraphs in the built documents.
107 | #keep_warnings = False
108 |
109 | # If true, `todo` and `todoList` produce output, else they produce nothing.
110 | todo_include_todos = False
111 |
112 |
113 | # -- Options for HTML output ----------------------------------------------
114 |
115 | # The theme to use for HTML and HTML Help pages. See the documentation for
116 | # a list of builtin themes.
117 | html_theme = 'sphinx_rtd_theme'
118 | nosidebar = True
119 |
120 | # Theme options are theme-specific and customize the look and feel of a theme
121 | # further. For a list of options available for each theme, see the
122 | # documentation.
123 | #html_theme_options = {}
124 |
125 | # Add any paths that contain custom themes here, relative to this directory.
126 | #html_theme_path = []
127 |
128 | # The name for this set of Sphinx documents. If None, it defaults to
129 | # " v documentation".
130 | #html_title = None
131 |
132 | # A shorter title for the navigation bar. Default is the same as html_title.
133 | #html_short_title = None
134 |
135 | # The name of an image file (relative to this directory) to place at the top
136 | # of the sidebar.
137 | #html_logo = None
138 |
139 | # The name of an image file (within the static path) to use as favicon of the
140 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
141 | # pixels large.
142 | #html_favicon = None
143 |
144 | # Add any paths that contain custom static files (such as style sheets) here,
145 | # relative to this directory. They are copied after the builtin static files,
146 | # so a file named "default.css" will overwrite the builtin "default.css".
147 | html_static_path = ['_static']
148 |
149 | # Add any extra paths that contain custom files (such as robots.txt or
150 | # .htaccess) here, relative to this directory. These files are copied
151 | # directly to the root of the documentation.
152 | #html_extra_path = []
153 |
154 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
155 | # using the given strftime format.
156 | #html_last_updated_fmt = '%b %d, %Y'
157 |
158 | # If true, SmartyPants will be used to convert quotes and dashes to
159 | # typographically correct entities.
160 | #html_use_smartypants = True
161 |
162 | # Custom sidebar templates, maps document names to template names.
163 | #html_sidebars = {}
164 |
165 | # Additional templates that should be rendered to pages, maps page names to
166 | # template names.
167 | #html_additional_pages = {}
168 |
169 | # If false, no module index is generated.
170 | #html_domain_indices = True
171 |
172 | # If false, no index is generated.
173 | #html_use_index = True
174 |
175 | # If true, the index is split into individual pages for each letter.
176 | #html_split_index = False
177 |
178 | # If true, links to the reST sources are added to the pages.
179 | html_show_sourcelink = False
180 |
181 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
182 | html_show_sphinx = False
183 |
184 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
185 | #html_show_copyright = True
186 |
187 | # If true, an OpenSearch description file will be output, and all pages will
188 | # contain a tag referring to it. The value of this option must be the
189 | # base URL from which the finished HTML is served.
190 | #html_use_opensearch = ''
191 |
192 | # This is the file name suffix for HTML files (e.g. ".xhtml").
193 | #html_file_suffix = None
194 |
195 | # Language to be used for generating the HTML full-text search index.
196 | # Sphinx supports the following languages:
197 | # 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'
198 | # 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr'
199 | #html_search_language = 'en'
200 |
201 | # A dictionary with options for the search language support, empty by default.
202 | # Now only 'ja' uses this config value
203 | #html_search_options = {'type': 'default'}
204 |
205 | # The name of a javascript file (relative to the configuration directory) that
206 | # implements a search results scorer. If empty, the default will be used.
207 | #html_search_scorer = 'scorer.js'
208 |
209 | # Output file base name for HTML help builder.
210 | htmlhelp_basename = 'TwitterBotUtilsdoc'
211 |
212 |
213 | # -- Options for manual page output ---------------------------------------
214 |
215 | # One entry per manual page. List of tuples
216 | # (source start file, name, description, authors, manual section).
217 | man_pages = [
218 | (master_doc, 'twittermarkov', u'Twitter Markov Documentation',
219 | [author], 1)
220 | ]
221 |
222 | # If true, show URL addresses after external links.
223 | #man_show_urls = False
224 |
225 |
226 |
--------------------------------------------------------------------------------
/tests/data/tweets.csv:
--------------------------------------------------------------------------------
1 | "tweet_id","in_reply_to_status_id","in_reply_to_user_id","timestamp","source","text","retweeted_status_id","retweeted_status_user_id","retweeted_status_timestamp","expanded_urls"
2 | "653986313125953536","","","2015-10-13 17:31:02 +0000","TweetDeck","Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod","","","",""
3 | "653624837043290112","653624251271004161","116332567","2015-10-12 17:34:39 +0000","Twitter for iPhone","@LangeAlexandra @ChappellTracker consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse","","","",""
4 | "651607152713433089","","","2015-10-07 03:57:06 +0000","Twitter for iPhone","RT @ActualPerson084: AT LAST, AN OMNIPRESENT LIGHTNING BOLT IS HERE TO REMIND US ABOUT FANTASY FOOTBALL","651601403501146112","318339237","2015-10-07 03:34:15 +0000",""
5 | "","","","","","He could speak a little Spanish, and also a language which nobody understood"
6 | "","","","","","He walked down the gallery and across the narrow bridges"
7 | "","","","","","He stopped before the door of his own cottage, which was the fourth one"
8 | "","","","","","Once in a while he withdrew his glance from the newspaper and looked about him."
9 | "","","","","","Both children wanted to follow their father when they saw him starting out."
10 | "","","","","","Her eyebrows were a shade darker than her hair."
11 | "","","","","","Robert rolled a cigarette."
12 | "","","","","","This seemed quite proper and natural on his part."
13 | "","","","","","Robert talked a good deal about himself."
14 | "","","","","","He was spending his summer vacation, as he always did, with his mother at Grand Isle."
15 | "","","","","","He thought it very discouraging that his wife, who was the sole object of his existence, evinced so "little interest in things which concerned
16 | "","","","","","He reproached his wife with her inattention, her habitual neglect of the children."
17 | "","","","","","It was then past midnight."
18 | "","","","","","An indescribable oppression, which seemed to generate in some unfamiliar part of her consciousness, "filled her whole being with a vague anguish.
19 | "","","","","","The little stinging, buzzing imps succeeded in dispelling a mood which might have held her there in the "darkness half a night longer.
20 | "","","","","","The boys were tumbling about, clinging to his legs, imploring that numerous things be brought back to "them.
21 | "","","","","","If one of the little Pontellier boys took a tumble whilst at play, he was not apt to rush crying to his "mother's arms for comfort;
22 | "","","","","","Many of them were delicious in the role; one of them was the embodiment of every womanly grace and charm."
23 | "","","","","","A green and yellow parrot, which hung in a cage outside the door, kept"
24 | "","","","","","Allez vous-en! Allez vous-en! Sapristi! That's all right!"
25 | "","","","","","He could speak a little Spanish, and also a language which nobody"
26 | "","","","","","understood, unless it was the mocking-bird that hung on the other"
27 | "","","","","","side of the door, whistling his fluty notes out upon the breeze with"
28 | "","","","","","Mr. Pontellier, unable to read his newspaper with any degree of comfort,"
29 | "","","","","","arose with an expression and an exclamation of disgust."
30 | "","","","","","He walked down the gallery and across the narrow bridges which"
31 | "","","","","","connected the Lebrun cottages one with the other. He had been seated"
32 | "","","","","","before the door of the main house. The parrot and the mockingbird were"
33 | "","","","","","the property of Madame Lebrun, and they had the right to make all the"
34 | "","","","","","noise they wished. Mr. Pontellier had the privilege of quitting their"
35 | "","","","","","He stopped before the door of his own cottage, which was the fourth one"
36 | "","","","","","from the main building and next to the last. Seating himself in a wicker"
37 | "","","","","","rocker which was there, he once more applied himself to the task of"
38 | "","","","","","reading the newspaper. The day was Sunday; the paper was a day old. The"
39 | "","","","","","Sunday papers had not yet reached Grand Isle. He was already acquainted"
40 | "","","","","","with the market reports, and he glanced restlessly over the editorials"
41 | "","","","","","and bits of news which he had not had time to read before quitting New"
42 | "","","","","","Mr. Pontellier wore eye-glasses. He was a man of forty, of medium height"
43 | "","","","","","and rather slender build; he stooped a little. His hair was brown and"
44 | "","","","","","straight, parted on one side. His beard was neatly and closely trimmed."
45 | "","","","","","Once in a while he withdrew his glance from the newspaper and looked"
46 | "","","","","","about him. There was more noise than ever over at the house. The main"
47 | "","","","","","building was called the house, to distinguish it from the cottages."
48 | "","","","","","The chattering and whistling birds were still at it. Two young girls,"
49 | "","","","","","the Farival twins, were playing a duet from Zampa upon the piano."
50 | "","","","","","Madame Lebrun was bustling in and out, giving orders in a high key to a"
51 | "","","","","","yard-boy whenever she got inside the house, and directions in an equally"
52 | "","","","","","high voice to a dining-room servant whenever she got outside. She was"
53 | "","","","","","a fresh, pretty woman, clad always in white with elbow sleeves. Her"
54 | "","","","","","starched skirts crinkled as she came and went. Farther down, before"
55 | "","","","","","one of the cottages, a lady in black was walking demurely up and down,"
56 | "","","","","","telling her beads. A good many persons of the pension had gone over to"
57 | "","","","","","the Cheniere Caminada in Beaudelet's lugger to hear mass. Some young"
58 | "","","","","","people were out under the wateroaks playing croquet. Mr. Pontellier's"
59 | "","","","","","two children were there--sturdy little fellows of four and five. A"
60 | "","","","","","quadroon nurse followed them about with a faraway, meditative air."
61 | "","","","","","Mr. Pontellier finally lit a cigar and began to smoke, letting the paper"
62 | "","","","","","drag idly from his hand. He fixed his gaze upon a white sunshade that"
63 | "","","","","","was advancing at snail's pace from the beach. He could see it plainly"
64 | "","","","","","between the gaunt trunks of the water-oaks and across the stretch of"
65 | "","","","","","yellow camomile. The gulf looked far away, melting hazily into the blue"
66 | "","","","","","of the horizon. The sunshade continued to approach slowly. Beneath its"
67 | "","","","","","pink-lined shelter were his wife, Mrs. Pontellier, and young Robert"
68 | "","","","","","Lebrun. When they reached the cottage, the two seated themselves with"
69 | "","","","","","some appearance of fatigue upon the upper step of the porch, facing each"
70 | "","","","","","What folly! to bathe at such an hour in such heat! exclaimed Mr."
71 | "","","","","","Pontellier. He himself had taken a plunge at daylight. That was why the"
72 | "","","","","","You are burnt beyond recognition, he added, looking at his wife as one"
73 | "","","","","","looks at a valuable piece of personal property which has suffered some"
74 | "","","","","","damage. She held up her hands, strong, shapely hands, and surveyed them"
75 | "","","","","","critically, drawing up her fawn sleeves above the wrists. Looking at"
76 | "","","","","","them reminded her of her rings, which she had given to her husband"
77 | "","","","","","before leaving for the beach. She silently reached out to him, and he,"
78 | "","","","","","understanding, took the rings from his vest pocket and dropped them"
79 | "","","","","","into her open palm. She slipped them upon her fingers; then clasping"
80 | "","","","","","her knees, she looked across at Robert and began to laugh. The rings"
81 | "","","","","","sparkled upon her fingers. He sent back an answering smile."
82 | "","","","","","What is it? asked Pontellier, looking lazily and amused from one to"
83 | "","","","","","the other. It was some utter nonsense; some adventure out there in the"
84 | "","","","","","water, and they both tried to relate it at once. It did not seem half"
85 | "","","","","","so amusing when told. They realized this, and so did Mr. Pontellier. He"
86 | "","","","","","yawned and stretched himself. Then he got up, saying he had half a mind"
87 | "","","","","","to go over to Klein's hotel and play a game of billiards."
88 | "","","","","","Come go along, Lebrun, he proposed to Robert. But Robert admitted"
89 | "","","","","","quite frankly that he preferred to stay where he was and talk to Mrs."
90 | "","","","","","Well, send him about his business when he bores you, Edna, instructed"
91 | "","","","","","Here, take the umbrella, she exclaimed, holding it out to him. He"
92 | "","","","","","accepted the sunshade, and lifting it over his head descended the steps"
93 | "","","","","","Coming back to dinner? his wife called after him. He halted a moment"
94 | "","","","","","and shrugged his shoulders. He felt in his vest pocket; there was a"
95 | "","","","","","ten-dollar bill there. He did not know; perhaps he would return for the"
96 | "","","","","","early dinner and perhaps he would not. It all depended upon the company"
97 | "","","","","","which he found over at Klein's and the size of the game. He did not"
98 | "","","","","","say this, but she understood it, and laughed, nodding good-by to him."
99 | "","","","","","Both children wanted to follow their father when they saw him starting"
100 | "","","","","","out. He kissed them and promised to bring them back bonbons and peanuts."
101 |
--------------------------------------------------------------------------------
/twitter_markov/twitter_markov.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Copyright 2014-2016 Neil Freeman contact@fakeisthenewreal.org
3 | # This program is free software: you can redistribute it and/or modify
4 | # it under the terms of the GNU General Public License as published by
5 | # the Free Software Foundation, either version 3 of the License, or
6 | # (at your option) any later version.
7 |
8 | # This program is distributed in the hope that it will be useful,
9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | # GNU General Public License for more details.
12 |
13 | # You should have received a copy of the GNU General Public License
14 | # along with this program. If not, see .
15 | from __future__ import unicode_literals, print_function
16 | import os
17 | import re
18 | import logging
19 | from collections import Iterable
20 | import Levenshtein
21 | import six
22 | import markovify.text
23 | import twitter_bot_utils as tbu
24 | from wordfilter import Wordfilter
25 | from . import checking
26 |
27 | LEVENSHTEIN_LIMIT = 0.70
28 |
29 |
30 | class TwitterMarkov(object):
31 | """
32 | Posts markov-generated text to twitter
33 |
34 | Args:
35 | screen_name (str): Twitter user account
36 | corpus (str): Text file to read to generate text.
37 | api (:ref:`tweepy.API `): API to use to post tweets.
38 | dry_run (boolean): If set, TwitterMarkov won't actually post tweets.
39 | blacklist (Sequence): A list of words to avoid generating.
40 | """
41 |
42 | default_model = None
43 | _recently_tweeted = []
44 |
45 | def __init__(self, screen_name, corpus=None, **kwargs):
46 | if 'api' in kwargs:
47 | self.api = kwargs.pop('api')
48 | else:
49 | self.api = tbu.API(screen_name=screen_name, **kwargs)
50 |
51 | try:
52 | self.log = self.api.logger
53 | except AttributeError:
54 | self.log = logging.getLogger(screen_name)
55 |
56 | self.screen_name = screen_name
57 | self.config = self.api.config
58 | self.dry_run = kwargs.pop('dry_run', False)
59 |
60 | self.log.debug('screen name: %s', screen_name)
61 | self.log.debug("dry run: %s", self.dry_run)
62 |
63 | try:
64 | corpus = corpus or self.config.get('corpus')
65 |
66 | if isinstance(corpus, six.string_types):
67 | corpora = [corpus]
68 |
69 | elif isinstance(corpus, Iterable):
70 | corpora = corpus
71 |
72 | else:
73 | raise RuntimeError('Unable to find any corpora!')
74 |
75 | self.corpora = [b for b in corpora if b is not None]
76 |
77 | state_size = kwargs.get('state_size', self.config.get('state_size'))
78 |
79 | self.models = self._setup_models(self.corpora, state_size)
80 |
81 | except RuntimeError as e:
82 | self.log.error(e)
83 | raise e
84 |
85 | self.log.debug('models: %s', list(self.models.keys()))
86 |
87 | blacklist = kwargs.get('blacklist') or self.config.get('blacklist', [])
88 | self.wordfilter = Wordfilter()
89 | self.wordfilter.add_words(blacklist)
90 |
91 | self.log.debug('blacklist: %s terms', len(self.wordfilter.blacklist))
92 |
93 | if kwargs.get('learn', True):
94 | self.log.debug('learning...')
95 | self.learn_parent()
96 |
97 | def _setup_models(self, corpora, state_size):
98 | """
99 | Given a list of paths to corpus text files or file-like objects,
100 | set up markovify models for each.
101 | These models are returned in a dict, (with the basename as key).
102 | """
103 | out = dict()
104 | state_size = state_size or 2
105 | self.log.debug('setting up models (state_size=%s)', state_size)
106 |
107 | try:
108 | for pth in corpora:
109 | if isinstance(pth, six.string_types):
110 | corpus_path = os.path.expanduser(pth)
111 | name = os.path.basename(corpus_path)
112 | m = open(corpus_path)
113 |
114 | else:
115 | m = pth
116 | try:
117 | name = m.name
118 | except AttributeError:
119 | name = repr(m)
120 |
121 | try:
122 | out[name] = markovify.text.NewlineText(m.read(), state_size=state_size)
123 |
124 | finally:
125 | m.close()
126 |
127 | except AttributeError as e:
128 | self.log.error(e)
129 | self.log.error("Probably couldn't find the model file.")
130 | raise e
131 |
132 | except IOError as e:
133 | self.log.error(e)
134 | self.log.error('Error reading %s', corpus_path)
135 | raise e
136 |
137 | self.default_model = os.path.basename(corpora[0])
138 |
139 | return out
140 |
141 | @property
142 | def recently_tweeted(self):
143 | '''Returns recent tweets from ``self.screen_name``.'''
144 | if not self._recently_tweeted:
145 | recent_tweets = self.api.user_timeline(self.screen_name, count=self.config.get('checkback', 20))
146 | self._recently_tweeted = [x.text for x in recent_tweets]
147 |
148 | return self._recently_tweeted
149 |
150 | def check_tweet(self, text):
151 | '''Check if a string contains blacklisted words or is similar to a recent tweet.'''
152 | text = text.strip().lower()
153 |
154 | if not text:
155 | self.log.info("Rejected (empty)")
156 | return False
157 |
158 | if self.wordfilter.blacklisted(text):
159 | self.log.info("Rejected (blacklisted)")
160 | return False
161 |
162 | if tbu.helpers.length(text) > 280:
163 | self.log.info("Rejected (too long)")
164 | return False
165 |
166 | for line in self.recently_tweeted:
167 | if text in line.strip().lower():
168 | self.log.info("Rejected (Identical)")
169 | return False
170 |
171 | if Levenshtein.ratio(re.sub(r'\W+', '', text), re.sub(r'\W+', '', line.lower())) >= LEVENSHTEIN_LIMIT:
172 | self.log.info("Rejected (Levenshtein.ratio)")
173 | return False
174 |
175 | return True
176 |
177 | def reply_all(self, model=None, **kwargs):
178 | '''Reply to all mentions since the last time ``self.screen_name`` sent a reply tweet.'''
179 | mentions = self.api.mentions_timeline(since_id=self.api.last_reply)
180 | self.log.info('replying to all...')
181 | self.log.debug('mentions found: %d', len(mentions))
182 |
183 | if not self.dry_run:
184 | for status in mentions:
185 | self.reply(status, model, **kwargs)
186 |
187 | def reply(self, status, model=None, max_len=140, **kwargs):
188 | '''
189 | Compose a reply to the given ``tweepy.Status``.
190 |
191 | Args:
192 | status (tweepy.Status): status to reply to.
193 | model (str): name of model.
194 | max_len (int): maximum length of tweet (default: 140)
195 | '''
196 | self.log.debug('Replying to a mention')
197 |
198 | if status.user.screen_name == self.screen_name:
199 | self.log.debug('Not replying to self')
200 | return
201 |
202 | if self.wordfilter.blacklisted(status.text):
203 | self.log.debug('Not replying to tweet with a blacklisted word (%d)', status.id)
204 | return
205 |
206 | text = self.compose(model, max_len=max_len - 2 - len(status.user.screen_name), **kwargs)
207 | reply = '@{} {}'.format(status.user.screen_name, text)
208 |
209 | self.log.info(reply)
210 | self._update(reply, in_reply=status.id_str)
211 |
212 | def tweet(self, model=None, **kwargs):
213 | '''
214 | Post a tweet composed by "model" (or the default model).
215 | Most of these arguments are passed on to Markovify.
216 |
217 | Args:
218 | model (str): one of self.models
219 | max_len (int): maximum length of the output (default: 140).
220 | init_state (tuple): tuple of words to seed the model
221 | tries (int): (default: 10)
222 | max_overlap_ratio (float): Used for testing output (default: 0.7).
223 | max_overlap_total (int): Used for testing output (default: 15)
224 | '''
225 | model = self.models[model or self.default_model]
226 | text = self.compose(model, **kwargs)
227 | if text:
228 | self._update(text)
229 |
230 | def _update(self, tweet, in_reply=None):
231 | if not self.dry_run:
232 | self.api.update_status(status=tweet, in_reply_to_status_id=in_reply)
233 |
234 | def compose(self, model=None, max_len=140, **kwargs):
235 | '''
236 | Returns a string generated from "model" (or the default model).
237 | Most of these arguments are passed on to Markovify.
238 |
239 | Args:
240 | model (str): one of self.models
241 | max_len (int): maximum length of the output (max: 280, default: 140).
242 | init_state (tuple): tuple of words to seed the model
243 | tries (int): (default: 10)
244 | max_overlap_ratio (float): Used for testing output (default: 0.7).
245 | max_overlap_total (int): Used for testing output (default: 15)
246 |
247 | Returns:
248 | str
249 | '''
250 | model = self.models.get(model or self.default_model)
251 | max_len = min(280, max_len)
252 | self.log.debug('making sentence, max_len=%s, %s', max_len, kwargs)
253 | text = model.make_short_sentence(max_len, **kwargs)
254 |
255 | if text is None:
256 | self.log.error('model failed to generate a sentence')
257 | raise RuntimeError('model failed to generate a sentence')
258 |
259 | # convert to unicode in Python 2
260 | if hasattr(text, 'decode'):
261 | text = text.decode('utf8')
262 |
263 | else:
264 | # Check tweet against blacklist and recent tweets
265 | if not self.check_tweet(text):
266 | # checked out: break and return
267 | text = self.compose(model=model, max_len=max_len, **kwargs)
268 |
269 | self.log.debug('TwitterMarkov: %s', text)
270 |
271 | return text
272 |
273 | def learn_parent(self, corpus=None, parent=None):
274 | '''
275 | Add recent tweets from the parent account (since the last time ``self.screen_name`` tweeted)
276 | to the corpus. This is subject to the filters described in ``bots.yaml``.
277 | '''
278 | parent = parent or self.config.get('parent')
279 | corpus = corpus or self.corpora[0]
280 |
281 | if not parent or not self.api.last_tweet:
282 | self.log.debug('Cannot teach: missing parent or tweets')
283 | return
284 |
285 | tweets = self.api.user_timeline(parent, since_id=self.api.last_tweet)
286 |
287 | try:
288 | gen = checking.generator(tweets,
289 | no_mentions=self.config.get('filter_mentions'),
290 | no_hashtags=self.config.get('filter_hashtags'),
291 | no_urls=self.config.get('filter_urls'),
292 | no_media=self.config.get('filter_media'),
293 | no_symbols=self.config.get('filter_symbols'),
294 | no_badwords=self.config.get('filter_parent_badwords', True),
295 | no_retweets=self.config.get('no_retweets'),
296 | no_replies=self.config.get('no_replies')
297 | )
298 |
299 | self.log.debug('%s is learning', corpus)
300 |
301 | with open(corpus, 'a') as f:
302 | f.writelines(tweet + '\n' for tweet in gen)
303 |
304 | except IOError as e:
305 | self.log.error('Learning failed for %s', corpus)
306 | self.log.error(e)
307 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU General Public License is a free, copyleft license for
11 | software and other kinds of works.
12 |
13 | The licenses for most software and other practical works are designed
14 | to take away your freedom to share and change the works. By contrast,
15 | the GNU General Public License is intended to guarantee your freedom to
16 | share and change all versions of a program--to make sure it remains free
17 | software for all its users. We, the Free Software Foundation, use the
18 | GNU General Public License for most of our software; it applies also to
19 | any other work released this way by its authors. You can apply it to
20 | your programs, too.
21 |
22 | When we speak of free software, we are referring to freedom, not
23 | price. Our General Public Licenses are designed to make sure that you
24 | have the freedom to distribute copies of free software (and charge for
25 | them if you wish), that you receive source code or can get it if you
26 | want it, that you can change the software or use pieces of it in new
27 | free programs, and that you know you can do these things.
28 |
29 | To protect your rights, we need to prevent others from denying you
30 | these rights or asking you to surrender the rights. Therefore, you have
31 | certain responsibilities if you distribute copies of the software, or if
32 | you modify it: responsibilities to respect the freedom of others.
33 |
34 | For example, if you distribute copies of such a program, whether
35 | gratis or for a fee, you must pass on to the recipients the same
36 | freedoms that you received. You must make sure that they, too, receive
37 | or can get the source code. And you must show them these terms so they
38 | know their rights.
39 |
40 | Developers that use the GNU GPL protect your rights with two steps:
41 | (1) assert copyright on the software, and (2) offer you this License
42 | giving you legal permission to copy, distribute and/or modify it.
43 |
44 | For the developers' and authors' protection, the GPL clearly explains
45 | that there is no warranty for this free software. For both users' and
46 | authors' sake, the GPL requires that modified versions be marked as
47 | changed, so that their problems will not be attributed erroneously to
48 | authors of previous versions.
49 |
50 | Some devices are designed to deny users access to install or run
51 | modified versions of the software inside them, although the manufacturer
52 | can do so. This is fundamentally incompatible with the aim of
53 | protecting users' freedom to change the software. The systematic
54 | pattern of such abuse occurs in the area of products for individuals to
55 | use, which is precisely where it is most unacceptable. Therefore, we
56 | have designed this version of the GPL to prohibit the practice for those
57 | products. If such problems arise substantially in other domains, we
58 | stand ready to extend this provision to those domains in future versions
59 | of the GPL, as needed to protect the freedom of users.
60 |
61 | Finally, every program is threatened constantly by software patents.
62 | States should not allow patents to restrict development and use of
63 | software on general-purpose computers, but in those that do, we wish to
64 | avoid the special danger that patents applied to a free program could
65 | make it effectively proprietary. To prevent this, the GPL assures that
66 | patents cannot be used to render the program non-free.
67 |
68 | The precise terms and conditions for copying, distribution and
69 | modification follow.
70 |
71 | TERMS AND CONDITIONS
72 |
73 | 0. Definitions.
74 |
75 | "This License" refers to version 3 of the GNU General Public License.
76 |
77 | "Copyright" also means copyright-like laws that apply to other kinds of
78 | works, such as semiconductor masks.
79 |
80 | "The Program" refers to any copyrightable work licensed under this
81 | License. Each licensee is addressed as "you". "Licensees" and
82 | "recipients" may be individuals or organizations.
83 |
84 | To "modify" a work means to copy from or adapt all or part of the work
85 | in a fashion requiring copyright permission, other than the making of an
86 | exact copy. The resulting work is called a "modified version" of the
87 | earlier work or a work "based on" the earlier work.
88 |
89 | A "covered work" means either the unmodified Program or a work based
90 | on the Program.
91 |
92 | To "propagate" a work means to do anything with it that, without
93 | permission, would make you directly or secondarily liable for
94 | infringement under applicable copyright law, except executing it on a
95 | computer or modifying a private copy. Propagation includes copying,
96 | distribution (with or without modification), making available to the
97 | public, and in some countries other activities as well.
98 |
99 | To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies. Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 |
103 | An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License. If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 |
112 | 1. Source Code.
113 |
114 | The "source code" for a work means the preferred form of the work
115 | for making modifications to it. "Object code" means any non-source
116 | form of a work.
117 |
118 | A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 |
123 | The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form. A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 |
134 | The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities. However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work. For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 |
147 | The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 |
151 | The Corresponding Source for a work in source code form is that
152 | same work.
153 |
154 | 2. Basic Permissions.
155 |
156 | All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met. This License explicitly affirms your unlimited
159 | permission to run the unmodified Program. The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work. This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 |
164 | You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force. You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright. Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 |
175 | Conveying under any other circumstances is permitted solely under
176 | the conditions stated below. Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 |
179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 |
181 | No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 |
187 | When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 |
195 | 4. Conveying Verbatim Copies.
196 |
197 | You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 |
205 | You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 |
208 | 5. Conveying Modified Source Versions.
209 |
210 | You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 |
214 | a) The work must carry prominent notices stating that you modified
215 | it, and giving a relevant date.
216 |
217 | b) The work must carry prominent notices stating that it is
218 | released under this License and any conditions added under section
219 | 7. This requirement modifies the requirement in section 4 to
220 | "keep intact all notices".
221 |
222 | c) You must license the entire work, as a whole, under this
223 | License to anyone who comes into possession of a copy. This
224 | License will therefore apply, along with any applicable section 7
225 | additional terms, to the whole of the work, and all its parts,
226 | regardless of how they are packaged. This License gives no
227 | permission to license the work in any other way, but it does not
228 | invalidate such permission if you have separately received it.
229 |
230 | d) If the work has interactive user interfaces, each must display
231 | Appropriate Legal Notices; however, if the Program has interactive
232 | interfaces that do not display Appropriate Legal Notices, your
233 | work need not make them do so.
234 |
235 | A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit. Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 |
245 | 6. Conveying Non-Source Forms.
246 |
247 | You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 |
252 | a) Convey the object code in, or embodied in, a physical product
253 | (including a physical distribution medium), accompanied by the
254 | Corresponding Source fixed on a durable physical medium
255 | customarily used for software interchange.
256 |
257 | b) Convey the object code in, or embodied in, a physical product
258 | (including a physical distribution medium), accompanied by a
259 | written offer, valid for at least three years and valid for as
260 | long as you offer spare parts or customer support for that product
261 | model, to give anyone who possesses the object code either (1) a
262 | copy of the Corresponding Source for all the software in the
263 | product that is covered by this License, on a durable physical
264 | medium customarily used for software interchange, for a price no
265 | more than your reasonable cost of physically performing this
266 | conveying of source, or (2) access to copy the
267 | Corresponding Source from a network server at no charge.
268 |
269 | c) Convey individual copies of the object code with a copy of the
270 | written offer to provide the Corresponding Source. This
271 | alternative is allowed only occasionally and noncommercially, and
272 | only if you received the object code with such an offer, in accord
273 | with subsection 6b.
274 |
275 | d) Convey the object code by offering access from a designated
276 | place (gratis or for a charge), and offer equivalent access to the
277 | Corresponding Source in the same way through the same place at no
278 | further charge. You need not require recipients to copy the
279 | Corresponding Source along with the object code. If the place to
280 | copy the object code is a network server, the Corresponding Source
281 | may be on a different server (operated by you or a third party)
282 | that supports equivalent copying facilities, provided you maintain
283 | clear directions next to the object code saying where to find the
284 | Corresponding Source. Regardless of what server hosts the
285 | Corresponding Source, you remain obligated to ensure that it is
286 | available for as long as needed to satisfy these requirements.
287 |
288 | e) Convey the object code using peer-to-peer transmission, provided
289 | you inform other peers where the object code and Corresponding
290 | Source of the work are being offered to the general public at no
291 | charge under subsection 6d.
292 |
293 | A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 |
297 | A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling. In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage. For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product. A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 |
310 | "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source. The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 |
318 | If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information. But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 |
329 | The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed. Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 |
337 | Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 |
343 | 7. Additional Terms.
344 |
345 | "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law. If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 |
354 | When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it. (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.) You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 |
361 | Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 |
365 | a) Disclaiming warranty or limiting liability differently from the
366 | terms of sections 15 and 16 of this License; or
367 |
368 | b) Requiring preservation of specified reasonable legal notices or
369 | author attributions in that material or in the Appropriate Legal
370 | Notices displayed by works containing it; or
371 |
372 | c) Prohibiting misrepresentation of the origin of that material, or
373 | requiring that modified versions of such material be marked in
374 | reasonable ways as different from the original version; or
375 |
376 | d) Limiting the use for publicity purposes of names of licensors or
377 | authors of the material; or
378 |
379 | e) Declining to grant rights under trademark law for use of some
380 | trade names, trademarks, or service marks; or
381 |
382 | f) Requiring indemnification of licensors and authors of that
383 | material by anyone who conveys the material (or modified versions of
384 | it) with contractual assumptions of liability to the recipient, for
385 | any liability that these contractual assumptions directly impose on
386 | those licensors and authors.
387 |
388 | All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10. If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term. If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 |
398 | If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 |
403 | Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 |
407 | 8. Termination.
408 |
409 | You may not propagate or modify a covered work except as expressly
410 | provided under this License. Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 |
415 | However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 |
422 | Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 |
429 | Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License. If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 |
435 | 9. Acceptance Not Required for Having Copies.
436 |
437 | You are not required to accept this License in order to receive or
438 | run a copy of the Program. Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance. However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work. These actions infringe copyright if you do
443 | not accept this License. Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 |
446 | 10. Automatic Licensing of Downstream Recipients.
447 |
448 | Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License. You are not responsible
451 | for enforcing compliance by third parties with this License.
452 |
453 | An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations. If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 |
463 | You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License. For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 |
471 | 11. Patents.
472 |
473 | A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based. The
475 | work thus licensed is called the contributor's "contributor version".
476 |
477 | A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version. For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 |
487 | Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 |
492 | In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement). To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 |
499 | If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients. "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 |
513 | If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 |
521 | A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License. You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 |
536 | Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 |
540 | 12. No Surrender of Others' Freedom.
541 |
542 | If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License. If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all. For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 |
552 | 13. Use with the GNU Affero General Public License.
553 |
554 | Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work. The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 |
563 | 14. Revised Versions of this License.
564 |
565 | The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time. Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 |
570 | Each version is given a distinguishing version number. If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation. If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 |
579 | If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 |
584 | Later license versions may give you additional or different
585 | permissions. However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 |
589 | 15. Disclaimer of Warranty.
590 |
591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 |
600 | 16. Limitation of Liability.
601 |
602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 |
612 | 17. Interpretation of Sections 15 and 16.
613 |
614 | If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 |
621 | END OF TERMS AND CONDITIONS
--------------------------------------------------------------------------------
/corpus.txt:
--------------------------------------------------------------------------------
1 | The sea glittered in all directions.
2 | The grassy field, humpy with knolls and lumpy with gray rock, sloped down toward the near-by water.
3 | Bunches of savin and bay and groups of Christmas trees flourished in the fresh June air, and exhilarating balsamic odors assailed Miss Burridge's nostrils as she stood in the doorway viewing the landscape o'er and reflectively picking her teeth with a pin.
4 | "It's an awful sightly place to fail in, anyway," she thought.
5 | Her one boarder came and stood beside her.
6 | She was a young woman with a creamy skin, regular features, dark, dreaming eyes, and a pleasant, slow smile.
7 | "Are you gathering inspiration, Miss Burridge?" she asked, settling a white tam-o'-shanter on her smooth brown locks.
8 | "I hope so, Miss Wilbur.
9 | I need it.
10 | "How could any one help it!" was Diana Wilbur's soft exclamation, as she took a deep breath and gazed at the illimitable be-diamonded blue.
11 | Priscilla Burridge turned her middle-aged gaze upon the enthusiasm of the twentieth year beside her.
12 | "Do you know of any inspiration that would make me able to get the carpenter to come and jack up the saggin' corner of that piazza?" she asked.
13 | "Or get the plumber to mend the broken pipe in the kitchen?" Miss Wilbur's dreaming gaze came back to the bony figure in brown calico.
14 | "It seems almost sacrilege, doesn't it," she said in a voice of awe, "to speak of carpenters and plumbers in a place like this? Such odors, such crystal beauty untouched by the desecrating hand of man.
15 | Miss Priscilla snorted.
16 | "If I don't get hold of the desecrating hand of man pretty soon, you'll be havin' a stream o' water come down on your bed, the first rain.
17 | The girl's attitude of adoration remained unchanged.
18 | "I noticed that little rift," she said slowly.
19 | "As I lay in bed this morning, I looked up at a spot of sapphire that seemed like a day-star full of promise of this transcendent beauty.
20 | Miss Wilbur's pretty lips moved but little when she spoke and her slow utterance gave the effect of a recitation.
21 | Miss Priscilla, for all her harassment, could not forbear a smile.
22 | "I'm certainly glad you're so easily pleased, but you don't know Casco Bay as well as I do, or that day-star would look powerful stormy to you.
23 | When it rains here, all other rains are mere imitations.
24 | It comes down from the sky and up from the ground, and the wind blows it east and west, and the porch furniture turns somersets out into the field, and windows and doors go back on you and give up the fight and let the water in everywhere, while the thunder rolls like the day o' judgment.
25 | The ardent light in the depths of the young girl's eyes glowed deeper.
26 | "I should expect a storm here to be inexorably superb!" she declared.
27 | Miss Priscilla heaved a sigh, half dejection, half exasperation, and turned into the house.
28 | "Drat that plumber!" she said.
29 | "I've only had a few days of it, but I'm sick of luggin' water in from that well.
30 | "Why, Miss Burridge," said her boarder solicitously, "I haven't fully realized--let me bring in a supply.
31 | "No, no, indeed, Miss Wilbur," exclaimed Miss Priscilla, as she moved through the living-room of the house into the kitchen, closely followed by Diana.
32 | "It ain't that I ain't able to do it, but it makes me darned mad when I know there's no need of it.
33 | "But I desire to, Miss Burridge," averred the young girl.
34 | "Any form of movement here cannot fail to be one of joy.
35 | She seized an empty bucket from the sink and went out the back door.
36 | Small groves of evergreen dotted the incline behind the house, and on the right hand soon became a wood-road of stately fir and spruce, which led to a sun-warmed grassy slope which, like every hill of the lovely isle, led down to the jagged rocks that fringed its irregular shore.
37 | "My muscular strength is not excessive," panted Diana, struggling up to the back door with her heavy bucket.
38 | "I'll fill it only half-full next time.
39 | "You ain't goin' to fill it at all," declared Miss Priscilla emphatically, taking the pail from her.
40 | "That'll last me a long time, and when it's gone, I'll get more myself.
41 | 'T ain't that it does me a bit of hurt, but it riles me when I know there ain't any need of it.
42 | She set the pail down beside the sink, filled the kettle from it, and set it on the oil stove while Diana sat down on the back doorstep.
43 | Then she proceeded: "One o' the most disagreeable things about this world is that we do seem to need men.
44 | They're strong and they don't wear skirts to stumble on, and when they're willin' and clever, they certainly do fill a need; but it does seem as if they were created to disappoint women.
45 | They don't know any more about keepin' their promises than they do about the other side o' the moon.
46 | Diana nodded.
47 | "It is observable, I think," she said, "that men's natural regard for ethics is inferior to that of women.
48 | Miss Priscilla sniffed.
49 | "Now it isn't only the plumber and the carpenter.
50 | I came here and saw 'em both over a month ago and explained my needs; explained that I ain't calc'latin' to take in boarders to break their legs on broken piazzas, or drown 'em in their beds.
51 | I explained all this when I rented the house, and when I arrived this week I naturally expected to find those things attended to; and there's Phil Barrison, too.
52 | I've known him most of his life.
53 | He has relatives here on the island, and when I heard he was comin' to stay with 'em on his vacation, I asked him if he wouldn't be a kind of a handy-man to me and he said he would.
54 | He got here before I did, but far as I can make out he's been fishin' ever since.
55 | A lot of help he's been.
56 | Oh, I knew well enough he was a broken reed.
57 | If ever a rapscallion lived, Phil's it.
58 | 'Tain't natural for any young one to be so smart as he was.
59 | Do you believe in school he found out that by openin' and shuttin' his geography real slow, he could set the teacher to yawnin', and, of course, she'd set the rest of 'em off, and Phil just had a beautiful time.
60 | His pranks was always funny ones.
61 | Diana Wilbur gave her slow, rare smile.
62 | "What an interesting bit of hypnosis!" she remarked.
63 | "Hey? Well, when that boy got older, he was real ambitious to study.
64 | He's got one o' those voices that ought to belong to a cherubim instead of a limb like him, and he wanted lessons.
65 | So he got the job of janitor in our church one winter.
66 | I got onto him later.
67 | When he'd oversleep some awful cold mornin' and arrive too late to get the furnace to workin' right, that rascal would drive the mercury up and loosen the bulb of the thermometer so that when the folks came in and went over to it to see just how cold they _was_ goin' to be, they'd see it register over sixty-five and of course they'd take their seats real satisfied.
68 | Miss Wilbur smiled again.
69 | "Your friend certainly showed great resource and ingenuity.
70 | When those traits are joined to lofty principle, they should lift him to heights of success.
71 | Oh,"--the speaker's attitude and voice suddenly changed, and she lifted her finger to impose silence on the cooking utensils which Miss Burridge was dropping into the sink,--"listen!" Mingled with the roulade of a song sparrow on the roof, came the flute of a human voice sounding and approaching through the field.
72 | "Thou'rt like unto a flower, So pure, so sweet, so fair--" The one road of the island swept over a height at some distance behind the house and the singer had left it, and was striding down the incline and through the meadow toward Miss Burridge's.
73 | The still air brought the song while the singer was still hidden, but at last the girl saw him, and the volume of rich tone increased.
74 | At last he came bounding up the slope over which Diana had struggled with her heavy bucket a few minutes before, and then paused at sight of the stranger.
75 | He was a tall, broad-shouldered youth in a dark-blue flannel shirt and nondescript trousers.
76 | He was bareheaded, and locks of his thick blond hair were tumbling over his forehead.
77 | He looked at Diana with curious, unembarrassed blue eyes, and, lips parted, stopped in the act of speaking.
78 | Miss Burridge came to the door.
79 | "Well, at last, Phil," she remarked.
80 | "I only just heard this morning that you had come," he said.
81 | "Here's a peace offering.
82 | He lifted the two mackerel that were hanging from his hand.
83 | "Beauties," vouchsafed Miss Burridge.
84 | "Are they cleaned?" "Well, if you don't look a gift horse--" "Well, now, I ain't goin' to clean 'em," said Miss Burridge doggedly.
85 | "I've been rubbed the wrong way ever since I landed--" Philip laughed.
86 | "And you won't do it to them, eh? Well, I guess I can rub 'em the wrong way for you--" His unabashed eyes were still regarding Diana as impersonally as though they had both been children of five.
87 | "Excuse me, I am obstructing the passage," said the girl, rising.
88 | "This is Miss Diana Wilbur, Phil.
89 | I suppose you're Mr.
90 | Barrison now that you have sung in New York.
91 | The young fellow bowed to the girl who acknowledged the greeting.
92 | "What is the name of those beautiful creatures?" she asked with her usual gentle simplicity of manner.
93 | "These? Oh, these are mackerel.
94 | "Jewels of the deep, surely," she said.
95 | "They are rather dressy," returned Philip.
96 | Diana bathed him in the light of her serene brown gaze.
97 | "I am so ignorant of the names of the denizens of the sea," she said.
98 | "I come from Philadelphia.
99 | Philip returned her look with dancing stars in his eyes.
100 | "I'd have said Boston if you only wore eyeglasses.
101 | "Oh, that _is_ the humorous tradition, is it not?" she returned.
102 | "Now, don't you drip 'em in here," said Miss Burridge, as the young fellow started to enter the kitchen door.
103 | "If you're really goin' to be clever and clean 'em, I'll give you the knife and everything right outdoors.
104 | "Then I think I would better withdraw," said Diana hastily.
105 | "I cannot bear to see the mutilation of such a rich specimen of Nature's handiwork; but, oh, Mr.
106 | Barrison, not without one word concerning the heavenly song that floated across the field as you came.
107 | Miss Burridge calls you Phil;--'Philomel with melody!' _I_ should say.
108 | Au revoir.
109 | I will go down among the pebbles for a while.
110 | She vanished, and Philip regarded Miss Burridge, who returned his gaze.
111 | "_Good night!_" he said at last.
112 | "Sh! Sh!" warned Miss Priscilla, and tiptoed across the kitchen.
113 | When she had looked from a window and seen her boarder's sweater and tam proceeding among the grassy hummocks toward the sea, she returned, bringing out the materials for Philip's operations on the fish.
114 | "I'll bring a rhetoric instead of finny denizens of the deep, the next time I come," he continued, settling to his job.
115 | Miss Priscilla took her boarder's deserted seat on the doorstep.
116 | "Going to open a young ladies' seminary here, and got the teacher all secured?" "Nothing of the kind, Phil, and there's only one explanation of her," declared Miss Priscilla impressively.
117 | "You've been in art galleries and seen these statues of Venus and Apollo and all that tribe?" "I have.
118 | "Well, sir, all I can think of is that one o' their Dianas got down off her perch some dark night, and managed to get hold o' some girl clothes, and came here to this island.
119 | She _says_ she has come to recuperate from unwise vigils caused by vaulting ambition at school.
120 | I said it over to myself till I learned it.
121 | "_I_ should say her trouble might be indigestion from devouring dictionaries," remarked Philip.
122 | "Well, anyway, she's a sweet girl and it's all as natural as breathing to her.
123 | At first I accused her in my own mind of affectation, but, there! she hasn't got an affected bone in her body, and she's willin' and simple as a child.
124 | You'd ought to 'a' seen her luggin' water up the hill for me this mornin'.
125 | That reminds me.
126 | You promised to give me a lift this summer when I needed it.
127 | "At so much a lift," remarked Philip.
128 | "Of course.
129 | Well, the first thing I want you to do is to get the carpenter and the plumber and knock their heads together, and then bring 'em here, one in each hand, so's I can have my house ready when the folks come.
130 | Why, my new stove ain't even put up.
131 | Mr.
132 | Buell, the plumber, promised me faithful he'd come this mornin'.
133 | I'm cookin' on an old kerosene stove there was here and managin' to keep Miss Wilbur from sheer starvation.
134 | "Miss Wilbur? Is that the fair Diana? Where did you get the 'old master'? Did she find you waiting when she got off the pedestal?" "No, I found her waiting.
135 | She came to the island on a misunderstandin'.
136 | There wasn't any one ready so early in the season to make strangers comfortable, and it seems she took a fancy to this place and I found her here sittin' on the steps when I arrived.
137 | She said she had been on the island a week and had walked up to this piazza every pleasant day, and she'd like to live here.
138 | "Did she really say it as plain as that?" "Well--I don't suppose those were her exact words, but she made me understand that she was willin' to come right in for better or for worse just so's she could have a room up there in front where the dawn--yes, she said something about the dawn, I forget whether it was purple or rosy--" "Mottled, perhaps," suggested Philip.
139 | "Well, anyway, I told her the dawn came awful early in the day this part o' the year, and that probably she'd be better satisfied in one o' the back rooms; but she was firm on the _dawn_, so she's got it.
140 | But I draw the line at her gettin' midnight shower-baths, and that's what she will get if that wretch of a Matt Blake don't get here before the next storm and put on the shingles.
141 | "And I have to tell the plumber that you have to 'haul water' too.
142 | Is that it? The well is some little distance.
143 | Rather hard on the statue, wasn't it, to do the hauling? She'll wish she'd stayed in the gallery.
144 | I'll bring in a lot before I go.
145 | "Don't go, Philip," begged Miss Priscilla.
146 | "Supposin' you don't go, not till you can leave me whole-footed.
147 | The men'll come sooner and work better if they know there's a man here.
148 | Your grandma won't care if her visit's interrupted for a little while.
149 | I'll feed you with your own mackerel and you can bet I know how to cook 'em.
150 | "Do you think Matt Blake realizes that I'm a man?" The teeth Philip showed in his smile were an asset for a singer.
151 | "He helped teach me to walk, you know.
152 | "Well, now, you teach _him_" retorted Miss Priscilla.
153 | "Show him how to walk in this direction.
154 | I don't want to make a fizzle of this thing.
155 | I found there wa'n't anybody goin' to run the place this summer, so I thought it might be a good job for me.
156 | I never took a thought that it was goin' to be so hard to get help.
157 | They tell me there ain't any servants any more; and there are enough folks writin' for rooms to fill me up entirely.
158 | I can do the _cookin'_ myself--" "Now, Miss Burridge, you aren't leading up to asking me to put on an apron and wait on table, are you? You must remember I'm recuperating also from a too vaulting ambition.
159 | "Recuperatin', nothin'! You're the huskiest-lookin' thing I ever saw.
160 | No, I ain't goin' to ask you to wait on table; but I've got an idea.
161 | We're too out o' the way here for me to get college boys.
162 | They'd rather go to the mountains and so on--fashionable resorts.
163 | But I've got a niece, if she don't feel too big of herself to do that sort of thing; she might come.
164 | I'm goin' to ask her anyway.
165 | I haven't seen her for years 'cause her mother's been gone a long time and her father went out to Jersey to live, but I've no doubt she's a nice girl.
166 | Her name's Veronica.
167 | Isn't that a beater? I told my sister I couldn't see why she didn't name her Japonica and be done with it.
168 | "It's the name of a saint," remarked Philip.
169 | "Well, I hope she's enough of one to come and help me out.
170 | I'm goin' to ask her.
171 | "Better get Miss Wilbur to write her about the rosy dawn and the jeweled denizens.
172 | I'm afraid you'll be too truthful and tell about the leaks.
173 | With an 'old master' and a saint, you ought to get on swimmingly.
174 | "Well, will you stay with me a few days?" said Miss Priscilla coaxingly.
175 | "If I had a rapscallion to add to the menagerie--" "Do you mean ménage, Miss Burridge?" "I'll call it anything in the world you like, if you'll only stand by me, Phil.
176 | "All right.
177 | The young fellow tossed the second cleaned fish on to the plate.
178 | "Let me wash my hands and I'll go and throw out a line for the plumber.
179 | "You're a good boy," returned Miss Burridge, relieved.
180 | "I do think, Philip, that in the main you are a good boy! Who's that comin' over?" Miss Burridge craned her neck and narrowed her eyes the better to observe a bicycle which appeared across the field.
181 | The apparition of any human being was exciting to one responsible for the comfort of others in this Arcadia, where modern conveniences could only be obtained by effort both spasmodic and continuous.
182 | "Oh, it's Marley Hughes from the post-office.
183 | A youngster of fourteen came wheeling nonchalantly over the bumps of the field, and finally jumped off his machine and came leisurely up the rise among the trees.
184 | "I hoped you might be Matt Blake," said Miss Priscilla.
185 | "He's got as far as to have the shingles here.
186 | "Well, I ain't," remarked Marley in the pleasant, drawling, leisurely, island voice.
187 | "What you got for me?" inquired Miss Burridge.
188 | "Telegram.
189 | The boy brought the store envelope from his pocket.
190 | "Oh, I hate 'em," said Miss Burridge apprehensively.
191 | Marley held it aggravatingly away from Philip's extended hand.
192 | "Take it back if you want me ter," he said with a grin.
193 | "It's ten cents anyway, whether you take it or not.
194 | "Oh, yes, I've got the money right here.
195 | Miss Priscilla turned to a shelf over the sink and took a dime from a purse which lay there.
196 | "Here.
197 | She gave it to Marley, who without more ado jumped on his wheel and coasted down among the trees and off over the soft grass.
198 | "You open it, Phil.
199 | My spectacles ain't here anyway," said Miss Priscilla anxiously.
200 | So Philip tore open the envelope.
201 | The look of amazement which overspread his face as the message greeted him caused Miss Burridge to exclaim fearfully: "Speak out, speak out, Phil.
202 | "They must have taken this down wrong at the store," he said.
203 | Then he read the scrawled words slowly.
204 | "'Look in broiler oven for legs.
205 | " The cryptic sentence appeared to have a magical effect upon Miss Priscilla.
206 | Her face beamed and she threw up her hands in thanksgiving.
207 | "Glory be!" she exclaimed devoutly.
208 | "What am I stumbling on?" said Philip.
209 | "Have you taken to wiring in cipher?" "You _see_" said Miss Priscilla excitedly, reaching for the telegram which Philip yielded, "it _came_ without any _legs_.
210 | Mr.
211 | Buell himself looked it over on the wharf and said he couldn't find 'em anywhere; and, of course, it was a terrible anxiety to me and I wrote to them right off, and I was goin' to get Mr.
212 | Buell to set it up without the legs if necessary and stick somethin' else under.
213 | Come and help me look, Phil.
214 | Miss Burridge seized the young fellow's arm and dragged him into the kitchen, where in one corner reposed the new stove in its shining newness, its parts piled ignominiously lop-sided.
215 | Talking all the time, its owner pulled open one door after another, as Philip disengaged them, and at last she laid hands on the missing treasure.
216 | "Now I'll give you as good a dinner as ever comes off this stove if you'll go and get those men and bring 'em up here," she said.
217 | "Don't leave me till I'm whole-footed, Phil.
218 | "Want feet as well as legs, do you?" he chuckled.
219 | "All right.
220 | See you later if I can get Blake and Buell.
221 | If I can't, I suppose I'd better drown myself.
222 | "No, no, don't do that, Phil.
223 | _You're_ better than nothing, yourself.
224 | For the next few days the right moment for Philip to desert Miss Burridge never seemed to arrive, and by that time the new establishment had come to be in very good running order, which was fortunate, as the expected boarders' dates were drawing near.
225 | Diana approached Philip one morning with a pleased countenance.
226 | He was encouraging the hopeful little sweet peas that stood in a green row below the porch.
227 | She came and sat on the rail above and watched him.
228 | "Miss Burridge is going to allow me to name our domicile," she announced.
229 | "Brave woman!" said Philip, coaxing the brown earth up against the line of green with his trowel.
230 | "Which of us is brave?" asked Diana, smiling,--"Miss Priscilla or myself?" "What are you going to call it? Olympus?" "Why should I?" Diana gave a soft, gurgling laugh.
231 | "I thought perhaps it might bring happy memories and prove a palliation of nostalgia.
232 | "I always have a feeling that you are amusing yourself with me, Mr.
233 | Barrison.
234 | "Have you any objection to my seeing that you are a goddess? What have you done with Apollo, by the way? Couldn't you persuade him to leave the gallery?" "To what gallery do you refer? I do not particularly care for handsome men," was Miss Wilbur's thoughtful response.
235 | "I'm sorry I'm so beautiful, then," said Philip, extending his little earth barricade.
236 | Diana looked down from her balcony on his tumbling blond hair.
237 | "You have a very good presence for your purpose," she said.
238 | "What is my purpose?" "The concert stage, is it not? Perhaps even opera, later?" "Yes, divine huntress, if I ever succeed in making it.
239 | "You will make it unless you are unpardonably dilatory and neglectful.
240 | Every time you utter a musical tone it sends a vibration coursing through my nerves with a pleasant thrill.
241 | Philip looked up at the speaker with his sea-blue, curious gaze, which she received serenely.
242 | "Bully for you, Miss Wilbur.
243 | That's all I can say.
244 | Bully for you.
245 | "I am glad if that encourages you," she said kindly.
246 | "It is quite outside my own volition.
247 | "Then I don't need to thank you, eh?" "Oh, not in the least.
248 | Philip laughed and stooped again to his job.
249 | "Let me see, Apollo--he struck liars and knew how to prescribe for the croup, didn't he, besides being a looker beyond all comers?" Diana smiled.
250 | "You think of everything in terms of humor, do you not?" she rejoined.
251 | "Perhaps--of most things, but not of you.
252 | "Oh, I think of me most of all.
253 | "Far from it," said Philip.
254 | "I wouldn't dare.
255 | If my voice gives you a thrill, yours gives me a chill.
256 | "I can't believe that really," said Diana equably, watching Philip's expert handling of the trowel.
257 | "You are always laughing at me.
258 | I don't in the least understand why, but it doesn't matter at all.
259 | I think it is a quite laudable mission to make people laugh.
260 | What a good gardener you are, Mr.
261 | Barrison.
262 | "Oh, isn't he, though!" exclaimed Miss Priscilla, emerging from the house.
263 | "Think of my luck that Phil really likes to fuss with flowers.
264 | Ox-chains couldn't drag him to do it if he didn't like to.
265 | "Really?" returned Diana.
266 | "Is she not maligning you, Mr.
267 | Barrison? Are you really the slave of caprice?" "I deny it," said Philip.
268 | "It doesn't sound nice.
269 | "It would be a dire thing for you," declared the girl.
270 | "But you do not ask me what I am naming the Inn.
271 | "Oh, it is an Inn, is it?" "Yes," put in Miss Priscilla.
272 | "Since the leaks are mended, both pipes and roof, and the stove's up and the chimney draws, I think we can call it that.
273 | "What is it, then? 'The Dew Drop'?" inquired Philip.
274 | "I particularly dislike puns," said Diana quietly.
275 | "I like 'The Wayside.
276 | Why shouldn't we call it 'The Wayside Inn'?" "You have my permission," said Philip.
277 | "We do not need anything original, but we do need a name that is lovely.
278 | 'The Wayside Inn' is lovely.
279 | "So be it," said Philip.
280 | "And you're not forgettin' what you are goin' to do to-morrow, are you, dear boy?" said Miss Priscilla ingratiatingly.
281 | "Not if it isn't to go again for the plumber," replied Philip.
282 | "His wrenches and hammers are too handy; and I'm sure one more call up here would render him dangerous.
283 | "Mr.
284 | Buell is a very pleasant man," said Diana.
285 | "So is Mr.
286 | Blake, the carpenter.
287 | I have learned such interesting expressions from them.
288 | Mr.
289 | Blake was showing me the fault in one of the gables of this house.
290 | He said the builder had given the roof a 'too quick yank.
291 | Is not that quaint?" "Ha, ha, ha," laughed Philip up into the girl's serious face.
292 | "Bully for Matt.
293 | You may get the vernacular, after all.
294 | "I'm not quick," said Diana.
295 | "I'm afraid I should not prove an apt pupil.
296 | "But, Philip," said Miss Priscilla, "about to-morrow.
297 | You know you'll have to get the early boat to go to meet Veronica.
298 | It's perfectly splendid of you to go, dear boy.
299 | I don't know how I could spare the time.
300 | I've got to get several rooms ready for to-morrow, and the child is such an utter stranger in this part o' the world.
301 | "Oh, yes, I'll go," said Philip carelessly.
302 | "I think the Inn will be relieved that I can get a hair-cut.
303 | My tresses are nearly ready to braid now.
304 | Diana smiled pensively.
305 | "I think you are very amusing, Mr.
306 | Barrison," she said.
307 | Philip vaulted up over the railing and took a seat beside her, regarding his earth-stained hands and then her serene countenance, whose gaze was bent upon him.
308 | He shook his head to toss the blond forelock out of his eyes.
309 | "So my voice gives you a thrill, eh?" "Oh, decidedly," was the devout response.
310 | "That's a good thing.
311 | I thought perhaps you couldn't really be roused from your dreaminess before the fourth of July, but I have some tones that in that case will be warranted to set you and the echoes going at the same time.
312 | Diana clasped her hands.
313 | "Oh, utter them," she begged.
314 | "Can't," laughed Philip, wiping his warm forehead with his shirt-sleeve.
315 | "The stage isn't set.
316 | Diana continued to look imploringly ardent.
317 | "'Drink to me only with thine eyes,'" she suggested.
318 | "That's the only way they'll let you do it nowadays," responded Philip, kicking the heels of his sneakers gently against the railing.
319 | Miss Burridge looked over her spectacles at Diana in her beseeching attitude, and her eyes widened still further as the girl went on slowly with her brown gaze fixed on Philip's quizzical countenance: "How can I bear to leave thee! One parting kiss I give thee--" "Dear me," thought Miss Priscilla.
320 | "I'd never have believed it of her.
321 | And it occurred to her for the first time that Philip Barrison was a handsome man.
322 | "Fare_well_," went on Diana, with soft fervor.
323 | "'Farewell, my own true love--'" "Farewell," sang Philip, falling into the trap and finishing the phrase.
324 | "'Farewe-ell, my own--true--love.
325 | " "Oh," breathed Diana, and the way her clasped hands fell upon her heart caused Miss Priscilla much embarrassment.
326 | "I can scarcely wait," said the girl slowly, "to hear you sing a real song with a real accompaniment.
327 | There is such rare penetrating richness in the quality of your voice.
328 | Miss Burridge cleared her throat.
329 | "I shouldn't wonder if Miss Wilbur was a real help to you, Phil," she said.
330 | "Young folks need encouragement.
331 | "And soap-suds," added Philip, regarding his earthy hands and glancing merrily up at Diana, who was still standing in her attitude of adoration; but there was no answering merriment in those brown orbs.
332 | Her brain might tell her later that Miss Burridge's patronizing remark had been amusing, but she would be obliged to think it over.
333 | Philip jumped off the railing, whistling, and followed Miss Priscilla into the house and to the sink, while Diana, reminiscently humming "The Soldier's Farewell," descended the steps and wandered away.
334 | When, the next day in town, Philip stood in the Union Station waiting for Veronica's train, he wondered how he was to know her, but remembering that Miss Burridge spoke of having instructed her to go the first thing to the transfer office about her trunk, he turned his steps thither as the crowds poured off the train.
335 | All Boston seemed to have decided to come to Maine for the summer.
336 | Soon he saw her--he felt at once it was she--looking about undecidedly as she came.
337 | She was a short, plump girl of seventeen or eighteen, at present bent a little sideways from the weight of the suitcase she was carrying.
338 | Philip strode forward and seized the suitcase with one hand while he lifted his hat with the other.
339 | "Here, you let that alone!" said the girl decidedly, her round eyes snapping.
340 | "Isn't this Miss Trueman?" "Why, yes, it is," she returned, but she still looked suspicious and clung to her suitcase.
341 | Nobody need think she wasn't up to all the tricks.
342 | "Did my aunt send you to meet me?" "She certainly did.
343 | "Then you know her name.
344 | What's her name?" The upward look was so childlike in its shrewdness that it stirred the spirit of mischief.
345 | "Why--let me see, Lucilla, isn't it?" "You give me that suitcase this minute.
346 | The girl pulled on the handle with a muscular little hand.
347 | "Why, Veronica," Philip's smile became a laugh.
348 | "Santa Veronica, what a very unsaintlike voice and expression you're using.
349 | She laughed, too, then, and relinquished her burden.
350 | "You do know me.
351 | Who are you?" "Miss Burridge's man-of-all-work.
352 | Name, Philip Barrison.
353 | "So she gave you such a job as this.
354 | How did you pick me out?" "That wild look around for the transfer office.
355 | They were now moving toward it.
356 | "It wasn't wild.
357 | I didn't need you at all.
358 | Aunt Priscilla needn't have bothered.
359 | I have a tongue in my head and money in my pocket, and Puppa said that's all anybody needs if she has any brains.
360 | "But I have to do what my employer orders, you see," replied Philip.
361 | Veronica looked him over.
362 | Fresh from the barber and in correct summer garb, he was an extremely good-looking object.
363 | "Oh, yes, it isn't your fault," she returned generously, "but is it a swell place Aunt Priscilla's got?" She looked him over again while he stopped at the transfer window and checked her trunk.
364 | "The Wayside Inn," replied Philip with dignity.
365 | "Well, I've come to help her," said the girl.
366 | "But I've never done any serving.
367 | I haven't any uniform or anything like that.
368 | "It isn't necessary.
369 | Look at me.
370 | I don't look like a footman--or a butler--or anything like that, do I?" "No," said Veronica, her round eyes very serious.
371 | "You look like a--like a common--gentleman.
372 | "Thank you, Miss Trueman.
373 | I'll try to deserve your praise.
374 | Philip took her and her suitcase across town in a cab, and aboard the little steamer, and found the best spot he could for them to sit.
375 | "Puppa says this bay is noted for its picturesqueness," said Veronica, when they were settled.
376 | "Quite right," returned Philip, putting in her lap one of the magazines he had bought on the wharf.
377 | "No, thank you," she returned.
378 | "I shan't read.
379 | I'm going to look.
380 | Puppa'll expect me to tell him all about it.
381 | He was delighted at my having a chance to come to the seashore.
382 | He thought it would do my health so much good.
383 | Philip regarded her round cheeks, round eyes, and round, rosy mouth.
384 | "Your health? You look to me as though if you felt any better you'd have to call the doctor.
385 | "Yes, I'm not really ailing--but I freckle.
386 | Isn't it a shame?" She put one hand to her nose which had an upward tilt.
387 | "Oh, that's all right," laughed Philip.
388 | "Call 'em beauty spots.
389 | She sat, pensively continuing to cover her nose with her silk-gloved hand.
390 | "Perhaps you're hungry.
391 | I ought to have bought you some chocolates," said Philip.
392 | "Perhaps there's time still.
393 | He looked at his watch.
394 | Veronica smiled.
395 | It was a pleasant operation to view and disclosed a dimple.
396 | "Did Aunt Priscilla give you money to buy me candy? Don't bother.
397 | I have some gum.
398 | Would you like some?" As she spoke, she opened her handbag.
399 | Philip bent a dreadful frown upon her.
400 | "Do you chew gum?" he asked severely.
401 | "Yes, sometimes, of course.
402 | Everybody does.
403 | "Then you deserve to freckle.
404 | You deserve all the awful things that can befall a girl.
405 | "Well, for a hired man," said Veronica, her hand pausing in its exploration, "you have the most nerve of any one I ever saw.
406 | She seemed quite heated by this condemnation, and instead of the gum drew out a vanity box and, looking in the mirror, powdered her nose deliberately.
407 | Philip opened his magazine.
408 | The whistle blew and the boat began to back out of the slip.
409 | Veronica regarded her companion from time to time out of the tail of her eye, and at a moment when his manner indicated absorption in what he was reading, she replaced the vanity case in her bag and when her hand reappeared, it conveyed something to her mouth.
410 | "I wouldn't," said Philip, without looking up.
411 | She colored hotly.
412 | "Nobody asked you to," she retorted.
413 | Then all was silence while the steamer, getting its direction, began moving toward the islands that dotted the bay.
414 | The girl suddenly started.
415 | "If there aren't those people!" she ejaculated.
416 | "What people?" asked Philip.
417 | "They came on in the same car with me from Boston.
418 | See that dark man over there with a young boy? I couldn't help noticing them on the train.
419 | You see how stupid the boy looks.
420 | He seemed so helpless, and the man just ignored him when he asked questions, and treated him so mean.
421 | I just hate that man.
422 | Philip regarded the couple.
423 | They presented a contrast.
424 | The man was heavily built with a sallow, dark face, his restless eyes and body continually moving with what seemed an habitual impatience.
425 | The boy, perhaps fourteen years of age, had a vacant look, his lips were parted, and his position, slumped down in a camp-chair, indicated a total lack of interest in his surroundings.
426 | "Tell me about Aunt Priscilla," said Veronica suddenly.
427 | "I haven't seen her since I was twelve years old.
428 | My mother died then.
429 | She was Aunt Priscilla's sister and Aunt Pris was willing to take me if Pa wanted her to, but he didn't and we moved away, and I've never seen her since.
430 | Of course, she writes sometimes and so do I.
431 | Has she many boarders?" "Only one so far, but then she's a goddess.
432 | You've read your mythology, haven't you? This is the goddess Diana.
433 | "Say, you're awfully fresh, do you know that?" remarked Veronica.
434 | "You treat me all the time as if I was a baby.
435 | I've graduated from high school and very likely I know just as much as you do.
436 | "I shouldn't doubt that," returned Philip.
437 | "On the level, you'll see when you get to the Inn that I'm telling the truth.
438 | Diana is passing for the present under the title of Miss Wilbur.
439 | "One boarder!" exclaimed Veronica with troubled brow.
440 | "Why, Aunt Priscilla doesn't need two helpers like you and me.
441 | "Oh, there are plenty more boarders coming," said Philip.
442 | "This boat may be full of them for all we know.
443 | She is expecting people to-night.
444 | Let's look around and decide who we'll take up there with us.
445 | "I'll tell you one person I'd choose first of all.
446 | See that woman with her back to us with a blue motor veil around her shoulders? I noticed her just when I was pointing out that devil and the boy to you.
447 | "You use strong language, Miss Trueman.
448 | Couldn't you spare my feelings and call our dark friend Mephisto?" "Sounds too good for him.
449 | I'd like to use me-fist-o on him, I know that.
450 | Veronica giggled, and went on: "Do you see her?" "I do.
451 | My vision is excellent.
452 | "Well, she was on the train, too, and once I saw her smile at that poor shy boy and show him how to get a drink of water.
453 | We were all in a day car.
454 | Chair car crowded.
455 | You can't see her face, but she's the sweetest thing.
456 | Then with a change of voice: "Oh, wouldn't it jar you! There's fuss-tail.
457 | See that dame with the white flower in her hat, looking over the rail? I suppose she's watching to see if the fishes behave themselves.
458 | She was on the train, too, and nothing suited her from Boston to Portland.
459 | She was too hot, or she felt a draught, or she didn't like the fruit the train-boy brought, or something else was wrong, every minute.
460 | "We won't take her, then," said Philip.
461 | "I should say not.
462 | She'd sour the milk.
463 | What's the island like?" "Diana says it resembles Arcadia strikingly, and she ought to know.
464 | "But I never was in Arcadia," objected Veronica.
465 | "Well, it is just a green hill popping right up out of the Atlantic, with plenty of New England rocks in the fields, and drifts of daisies and wild roses for decoration, and huge rocky teeth around the shore that grind the waves into spray and spit it up flying toward the sky.
466 | "What kind of folks? Just folks that come in summer?" "Not at all.
467 | Old families.
468 | New England's aristocracy.
469 | These islands are the only place where there are no aliens, just the simon-pure descendants of Plymouth Rock.
470 | As I say aristocrats.
471 | I was born there.
472 | "You were?" returned Veronica curiously.
473 | "I were.
474 | "Well, I was born in Maine, in Bangor.
475 | I guess that's just about as good.
476 | "No, it's not as good," said Philip gravely.
477 | "Nevertheless, I forgive you.
478 | "Tell me more about the island.
479 | "Well, it has one road.
480 | "Only one street?" "No, no street.
481 | Just one road which has its source in a green field on the south and loses itself in the beach on the north after it has passed the by-path that leads to the haunted farm.
482 | "Oh, go away!" scoffed Veronica.
483 | "I can't.
484 | The walking won't be good for another hour.
485 | "Who lives at the farm?" "The ha'nts.
486 | "Nobody else?" "No, it isn't likely.
487 | It's at the head of Brook Cove where the pirates used to come in at a day when it was laughable to think that passenger boats would ever touch at this island.
488 | Veronica's eyes grew rounder than before.
489 | "Do you suppose there's gold packed in around there if people could only find it?" "I don't, but a great many people thought there might be.
490 | It is much more fun to hunt for pirate gold than to go fishing in squally weather, and it has been hunted for, faithfully.
491 | "And not any found?" said Veronica sympathetically.
492 | "That's the mournful fact.
493 | "But who were the farmers, and why did they stop farming? Was it the ghosts?" "No, I think it was the rocks.
494 | It was found more profitable to farm the sea.
495 | You know abandoned farms are fashionable in New England, anyway, so the ghosts have a rather swell residence at the old Dexter place.
496 | I spent the first eight years of my life on the island.
497 | Then it was an undiscovered Arcadia.
498 | Now--why, you will go up to The Wayside Inn in a motor--that is, if I can get hold of Bill Lindsay before somebody else grabs him.
499 | Lots of people know a good thing when they see it, and lots of people have seen the island.
500 | The wharf was full of people to welcome the little steamer as it drew in, and there was a grand rush of passengers for the coveted motor.
501 | It seemed to Veronica that she heard her aunt's name on many lips, and Philip found himself feeling responsible for the trunk checks of everybody who was seeking Miss Burridge.
502 | The upshot of it all was, by the time he had safeguarded the baggage of the arrivals and sent them on their way, he and Veronica were left to climb the road and pursue the walk toward home.
503 | "Didn't that old hawk-nose say he was going to Aunt Priscilla's?" "It's a very good-looking nose," remarked Philip.
504 | "But so far as I could see, all your friends of the train were bound for the same place.
505 | "He'll be lucky," said Veronica viciously, "if I don't put Paris green in his tea.
506 | Oh, what a beautiful view of the sea!" she exclaimed as they reached the summit of the hill.
507 | They had not walked far when Bill Lindsay's Ford came whirring back over the much-traveled road, and he turned around for them.
508 | "After all," said Philip, as the machine started back up the island, "your lady of the blue veil should set off the affliction of Mephisto's presence.
509 | "Did she come?" asked Veronica delightedly.
510 | "Yes, didn't you see me pack her in with the woman whose halo won't fit? The dull boy sat between them.
511 | "Well," said Veronica, "then there's no great loss without some small gain.
512 | When the motor reached the Inn, Miss Priscilla was pleased with the way Veronica dropped her hat and jacket in the kitchen, and after drinking the one cup of cocoa upon which her aunt insisted, was ready to help her carry in the late supper for the new guests with whom Philip sat down at table.
513 | Veronica, coming and going, tried to make out his status in the house.
514 | "That Mr.
515 | Barrison you sent to meet me," she said to her aunt when the meal was over, "told me he was your man-of-all-work.
516 | He don't act much like it.
517 | "Law, child," Miss Priscilla laughed.
518 | "He has been lately.
519 | Phil's a dear boy when he isn't a wretch, and he's helped me out ever since I came.
520 | I won't ever forget how good he's been.
521 | Now, let's sit down and let me see you eat this fresh omelette and tell me all about yourself.
522 | I see you're just like your mother, handy and capable, and let me tell you, it takes a big load off me, Veronica.
523 | Just as she finished speaking, Diana Wilbur came in from the twilight stroll she had been taking.
524 | "Miss Wilbur, this is my little niece, Veronica Trueman," said Miss Priscilla.
525 | "She has come to help me, and high time, too.
526 | Four people came to-night and there will be more to-morrow.
527 | Diana approached the newcomer and looked down upon her kindly after taking her offered hand.
528 | "You must have had an inspiring ride down the bay, Miss Veronica," she said.
529 | "I have been taking a walk to see the sun set.
530 | It was heavenly to-night.
531 | Such translucent rose-color, and violet that shimmered into turquoise, and robin's-egg blue.
532 | How fortunate for the new people to get that first impression! Well, Miss Burridge," Diana sighed.
533 | "Of course we must be glad to see them, but it has been a very subtle joy to retire and to waken with no human sounds about us.
534 | I shall always remember this last two weeks.
535 | "I'm glad you feel that way," said Miss Priscilla.
536 | "I thought, though, that you'd heard lots o' sounds.
537 | Phil makes enough noise for a regiment when he is dressin' in the mornin'.
538 | "You can scarcely call such melodious tones noise, can you?" replied Miss Wilbur gently.
539 | "His flute is more liquid than that of the hermit thrush.
540 | "I never heard him play the flute.
541 | Miss Priscilla looked surprised.
542 | "I refer to the marvelous, God-bestowed instrument that dwells within him," explained Diana.
543 | "I think myself," said Miss Priscilla, clearing her throat, "that it's kind o' cozy to hear a man whistlin' and shoutin' around in the mornin' while he's dressin'.
544 | I suppose he'll be leavin' us pretty soon now.
545 | I hate to see him go, he's gettin' the plants into such good shape; and wasn't he good about scythin' paths so we wouldn't get wet to our knees every time we left the house? I don't know how you ever had the courage to wade over to this piazza before I came, Miss Wilbur.
546 | "Mr.
547 | Barrison certainly did smooth our paths.
548 | "He told me he was Aunt Priscilla's man-of-all-work," said Veronica, busy with her omelette.
549 | "So he has been," replied Diana seriously: "out of the goodness of his heart and the cleverness of his hands; but he is a great artist, Miss Veronica, or at least he will be.
550 | "Do you mean he paints?" "No, he sings: and it is singing--such as must have sounded when the stars sang together.
551 | "Dear me," said Veronica, "I wish I'd asked him to pipe up when we were on the boat.
552 | Diana let her gaze rest for a moment of silence on the sacrilegious speaker, then she excused herself, saying she would go up to her room.
553 | As soon as the door had closed behind her, Veronica looked up and bestowed upon her aunt a meaning wink.
554 | "She's got it bad, hasn't she?" she said.
555 | Miss Burridge put her finger to her lips warningly.
556 | "Sh!" she breathed.
557 | "Sometimes I think she has: but, law, Phil's nothing but a boy.
558 | "And she's nothing but a girl," said Veronica practically.
559 | "That's the way it usually begins.
560 | Miss Burridge laughed.
561 | "What do you know about it, you child?" "Not so much as I'd like to.
562 | Puppa would never let anybody stay after ten o'clock, and you don't really get warmed up before ten o'clock.
563 | "Why, Veronica Trueman, how you talk!" "Don't speak of how I talk!" said Veronica.
564 | "Hasn't that Miss Wilbur got language! I guess Mr.
565 | Barrison likes her, too.
566 | He told me she was a goddess.
567 | "Oh, Phil's just full of fun.
568 | He always will be a rapscallion at heart, no matter how great he ever gets to be.
569 | "Well, he doesn't want anybody else to stop saying prunes and prisms.
570 | He didn't even want me to chew gum.
571 | Anybody that's as unnatural as that had better marry a goddess.
572 | Now, let's go for those dishes, Aunt Priscilla.
573 | "You good child!" said Miss Burridge appreciatively.
574 | "I can't really ask Genevieve to stay in the evenin'.
575 | She's the little girl who comes every day and prepares vegetables and washes dishes.
576 | Now, one minute, Veronica, while I get the names o' these new people straight.
577 | I've got their letters here.
578 | Miss Priscilla took them down from the chimney-piece.
579 | "There's Mrs.
580 | Lowell, _she_'s alone, and Miss Emerson, _she_'s alone, and Mr.
581 | Nicholas Gayne and his nephew, Herbert Gayne.
582 | I wonder how long I'll remember that.
583 | "I know them all," said Veronica sententiously.
584 | "The whole bunch came on in the same car with me from Boston.
585 | It's my plan to poison Mr.
586 | Gayne.
587 | "Don't talk that way, child.
588 | "You'll agree to it when you see how mean he is to his nephew.
589 | The boy isn't all there.
590 | "What do you mean?" "Has rooms to let in the upper story, you know.
591 | Veronica touched her round forehead.
592 | "Mrs.
593 | Lowell is a queen and Miss Emerson isn't; or else Miss Emerson is a queen and Mrs.
594 | Lowell isn't.
595 | I'll know which is t'other to-morrow.
596 | "You seem to have made up your mind about them all.
597 | "Oh, yes!" said Veronica.
598 | "You don't have to eat a whole jar of butter to find out whether it's good.
599 | All I need is a three-minute taste of anybody, and I had three hours and a half of them.
600 | Now, come on, Aunt Priscilla, let's put some transparent water in the metal bowl, and the snowy foam of soap within it.
601 | She rolled up her naughty eyes as she spoke.
602 | Miss Burridge gave the girl a rebuking look, and then laughed.
603 | "Don't you go to makin' fun of her now," she said.
604 | "She's my star boarder, no matter who else comes, I'm in love with her whether Phil is or not.
605 | She's genuine, that girl is,--genuine.
606 | "And you don't want me to be imitation," giggled Veronica.
607 | "I see.
608 | Then the two went at the clearing-up and dish-washing in high good-humor.
609 | "You, Veronica," said Miss Burridge one morning, looking out of the kitchen window.
610 | "I feel sorry for that young boy.
611 | "I told you you would.
612 | Old Nick should worry what his nephew does with himself all day.
613 | "Veronica!" Miss Priscilla gave the girl a warning wink and motioned with her hand toward the sink where Genevieve, her hair in a tight braid and her slender figure attired in a scanty calico frock, was looking over the bib of an apron much too large for her, and washing the breakfast dishes.
614 | "Excuse me," said Veronica demurely.
615 | "I meant to say Mr.
616 | Gayne.
617 | Genevieve, you must never call Mr.
618 | Gayne 'Old Nick.
619 | Do you hear?" "Veronica!" pleaded Miss Burridge.
620 | "Oh, we all know Mr.
621 | Gayne," said Genevieve, in her piercing, high voice which always seemed designed to be heard through the tumult of a storm at sea.
622 | "He has been here before, then?" asked Miss Burridge.
623 | "Pretty near all last summer.
624 | He comes to paint, you know.
625 | "No, I didn't know he was an artist.
626 | "Oh, yes, he paints somethin' grand, but I never saw any of his pitchers.
627 | "Was his nephew with him last summer?" "No, I don't believe so.
628 | I never saw anybody around with him.
629 | He spent most of his time up to the Dexter farm.
630 | He said he could paint the prettiest pitchers there.
631 | It was him seen the first ghost.
632 | "What are you talking about, Genevieve?" asked Miss Burridge, while Veronica busied herself drying the glass and silver.
633 | "Oh, yes," she put in.
634 | "That is the haunted farm.
635 | Mr.
636 | Barrison was telling me about it.
637 | "Yep," said Genevieve.
638 | "Folks had said so a long time and heard awful queer noises up there, but Mr.
639 | Gayne was the first who really seen the spook.
640 | "I'm not surprised that he had a visitor," said Veronica.
641 | "Dollars to doughnuts, it had horns and hoofs and a tail.
642 | "That's what Uncle Zip said," remarked Genevieve.
643 | "He said 't wa'n't anything but an old stray white cow.
644 | Veronica laughed, and her aunt met her mischievous look with an impressive shake of the head.
645 | "Mind me, now," she said, and Veronica did not pursue the subject.
646 | The long porch across the front of the Inn made, sometimes a sunny, and sometimes a foggy, meeting-place for the members of the family.
647 | It boasted a hammock and some weather-beaten chairs, and Miss Myrna Emerson was not tardy in discovering the one of these which offered the most comfort.
648 | She was a lady of uncertain age and certain ideas.
649 | One of the latter was that it was imperative that she should be comfortable.
650 | "I should think Miss Burridge would have some decent chairs here," she said one morning, dilating her thin nostrils with displeasure as she took possession of the most hopeful of the seats.
651 | The remark was addressed to Diana who was perched on the piazza rail.
652 | "Doubtless they will be added," she said, "should Miss Burridge find that her undertaking proves sufficiently remunerative.
653 | "She charges enough, so far as that goes," declared Miss Emerson curtly, but finding the chair unexpectedly comfortable, she settled back and complained no further.
654 | Philip was out on the grass painting on a long board the words "Ye Wayside Inn.
655 | Herbert Gayne stood watching him listlessly.
656 | His uncle was stretched in the hammock.
657 | Mrs.
658 | Lowell came out upon the porch.
659 | Mr.
660 | Gayne moved reluctantly, but he did arise.
661 | Men usually did exert themselves at the advent of this tall, slender lady with the radiant smile and laughing eyes.
662 | "Perhaps you would like the hammock, Mrs.
663 | Lowell," he said perfunctorily.
664 | "Offer it to me some time later in the day," she responded pleasantly, and he tumbled back into the couch with obvious relief.
665 | Mrs.
666 | Lowell approached the rail and observed Philip's labors.
667 | "Where are you going to hang that sign?" she asked in her charming voice.
668 | "Across the front of the house, I judge.
669 | "Oh, no," replied Philip.
670 | "We can't hope to attract the fish.
671 | I am going to hang it at the back where Bill Lindsay's flivver will feel the lure before it gets here.
672 | "Across the back of the house," cried Miss Emerson in alarm.
673 | "I hope nowhere near my window.
674 | "The sign will depend from iron rings," explained Diana.
675 | "I know they'll squeak," said Miss Emerson positively; "and if they do, Mr.
676 | Barrison, you'll simply have to take it down.
677 | No one replied to this warning.
678 | So Miss Emerson dilated her nostrils again with an air of determination and leaned back in her chair.
679 | The eyes of both Mrs.
680 | Lowell and Diana were upon the young boy whose watching face betrayed no inspiration from the fresh morning.
681 | He had an ungainly, neglected appearance from his rough hair to his worn shoes.
682 | His clothes were partially outgrown and shabby.
683 | "Bert," called his uncle from the hammock.
684 | The boy looked up.
685 | "Come here.
686 | Don't you hear me?" The boy started toward the piazza steps with a shuffling gait.
687 | "You're slower than molasses in January," said Mr.
688 | Gayne lazily.
689 | "Go up to my room and get my field-glasses.
690 | They're on the dresser, I think.
691 | Without a word the boy went into the house and Diana and Mrs.
692 | Lowell exchanged a look.
693 | Each was hoping the messenger would be successful and not draw upon himself a reprimand from the dark, impatient man smoking in the hammock.
694 | The boy returned empty-handed.
695 | "They--they weren't there," he said.
696 | "Weren't where, stu--" Mr.
697 | Gayne encountered Mrs.
698 | Lowell's gaze as he was in the middle of his epithet.
699 | Her eyes were not laughing now, and he restrained himself.
700 | "Weren't on the dresser, do you mean?" he continued in a quieter tone.
701 | "Well, didn't you look about any?" "Yes, sir.
702 | I looked on the--the trunk and on the--the floor.
703 | Mr.
704 | Gayne emitted an inarticulate sound which, but for the presence of the ladies, would evidently have been articulate.
705 | "Oh, well," he groaned, rising to a sitting posture on the side of the hammock, "I suppose I shall have to galvanize my old bones and go after them myself.
706 | His nephew's blank look did not change.
707 | He stood as if awaiting further orders, and his listless eyes met Mrs.
708 | Lowell's kindly gaze.
709 | "It is good fun to look through field-glasses in a place like this, isn't it, Bertie?" she said.
710 | The boy's surprise at being addressed was evident.
711 | "I--I don't know," he replied.
712 | His uncle laughed.
713 | "That's all the answer you'll ever get out of him, Mrs.
714 | Lowell.
715 | He's the champion don't-know-er.
716 | The boy's blank look continued the same.
717 | It was evident that his uncle's description of him was nothing new.
718 | "I don't believe that," said Mrs.
719 | Lowell.
720 | "I think Bertie and I are going to be friends.
721 | I like boys.
722 | The look she was giving the lad as she spoke seemed for a moment to attract his attention.
723 | "You won't--you won't like me," he said in his usual wooden manner.
724 | "Children and fools," laughed his uncle, rising from the hammock.
725 | "Mr.
726 | Gayne!" exclaimed Diana, electrified out of her customary serenity.
727 | The man's restless, dark eyes glanced quickly from the face of one woman to another, even alighting upon Miss Emerson whose countenance only gave its usual indication that the lady had just detected a very unpleasant odor.
728 | He laughed again, good-naturedly, and as he passed his nephew gave him a careless, friendly pat on the shoulder.
729 | The unexpected touch startled the boy and made him cringe.
730 | "Bert believes honesty is the best policy," he said.
731 | "Don't you, Bert?" "Yes, sir," replied the boy automatically.
732 | "Sit down here a minute, won't you, Bertie?" asked Mrs.
733 | Lowell, making a place beside her on the piazza rail.
734 | The boy obeyed.
735 | "Have you ever seen this great ocean before?" "No.
736 | Yes.
737 | I don't know.
738 | "Why, yes, you do know, of course," said Mrs.
739 | Lowell, with a soft little laugh, very intimate and pleasant.
740 | "You know whether you have seen the ocean before.
741 | The boy regarded her, and in the surprise of being really challenged to think, he meditated.
742 | "No," he said, at last.
743 | "I've never been here before.
744 | "Isn't it a beautiful place?" asked Mrs.
745 | Lowell.
746 | "I don't know," returned the boy after a hesitation.
747 | Then he looked down on the grass at Philip.
748 | "Do you want to go back and watch Mr.
749 | Barrison paint?" "Yes.
750 | "All right.
751 | Run along.
752 | We'll talk some other time.
753 | The boy rose and shuffled across the porch and down the steps.
754 | "Mrs.
755 | Lowell, it is heart-breaking!" exclaimed Diana softly.
756 | Her companion nodded.
757 | "The situation is incomprehensible," said Diana.
758 | "It seems as if Mr.
759 | Gayne had some ulterior design which impelled him to stultify any outcropping of intelligence in his nephew.
760 | Have you not observed it from the moment of their arrival?" "Yes, and before we arrived.
761 | I noticed them on the train.
762 | "If there's anything I can't bear to have around, it's an idiot," said Miss Emerson.
763 | "It gives me the creeps.
764 | If he hangs about much, I shall complain to Miss Burridge.
765 | The sweep of the ocean and the rush of the wind made her remark inaudible beyond the piazza.
766 | Mrs.
767 | Lowell turned to her.
768 | "I think we all have a mission right there, perhaps, Miss Emerson.
769 | The boy is not an idiot.
770 | I have observed him closely enough to be convinced of that.
771 | He is a plant in a dark cellar, and I wonder how many years he has been there.
772 | His uncle's methods turn him into an automaton.
773 | If you keep your arm in a sling a few weeks you know it loses its power to act.
774 | The boy's brain seems to have been treated the same way.
775 | His uncle's every word holds the law over him that he cannot think, or reason, and that he is the stupidest creature living.
776 | "That is true," said Diana.
777 | "That is just what he does.
778 | Miss Emerson sniffed.
779 | "Well, I didn't come up to Maine on a mission.
780 | I came to rest, and I don't propose to have that gawk prowling around where I am.
781 | Nicholas Gayne appeared, his binoculars in his hand.
782 | "Would you ladies like to look at the shipping?" he said, approaching.
783 | His manner was ingratiating, and Diana conquered the resentment filling her heart sufficiently to accept the glasses from his hand.
784 | He was conscious that he had not made a good impression.
785 | "The mackerel boats are going out to sea after yesterday's storm," he remarked.
786 | "You will see how wonderfully near you can bring them.
787 | Diana adjusted the glass and exclaimed over its power.
788 | Miss Emerson jumped up from her chair.
789 | "That's something I want to see," she said, and Diana handed her the glass while Nicholas Gayne scowled at the spinster's brown "transformation.
790 | He was not desirous of propitiating Miss Emerson, who, however, pressed him into the service of helping her adjust the screws to suit her eyes, and was effusive in her appreciation of the effect.
791 | "You surely are a benefactor, Mr.
792 | Gayne," she said at last, with enthusiasm.
793 | "Let me be a benefactor to Mrs.
794 | Lowell, too," he returned, and the lady yielded up the glass.
795 | "That is the great Penguin Light beyond Crag Island," he said, as Mrs.
796 | Lowell accepted the binoculars.
797 | "The trees hide it in the daytime, it is so distant, but at night you will see it flash out.
798 | "It is so interesting that you are familiar here, Mr.
799 | Gayne," said Miss Emerson.
800 | "You must tell us all about the island and show us the prettiest places.
801 | The owner of the binoculars stirred restlessly under the appealing smile the lady was bestowing upon him.
802 | "For myself, I just love to walk," she added suggestively.
803 | "I don't do much walking," he returned shortly.
804 | "I come here to sketch.
805 | "Oh, an artist!" exclaimed Miss Emerson, clasping her hands in the extremity of her delight.
806 | "Do you allow any one to watch you work? Such a pleasure as it would be.
807 | "It isn't, though," said Nicholas Gayne with an uncomfortable side-glance at his admirer.
808 | "My daubs aren't worth watching.
809 | "Oh, that will do for you to say," she returned archly.
810 | "I have done some sketching myself.
811 | Perhaps I could persuade you to take a pupil.
812 | "Nothing doing," returned the artist hastily.
813 | "We all come up here to rest, don't we?" he added.
814 | "Oh, I suppose so," sighed Miss Emerson.
815 | "But I do hope you will give me the great pleasure of seeing your work sometime.
816 | She sank back into her chair with a sigh.
817 | "That is a very fine glass," remarked Mrs.
818 | Lowell as she returned it to its owner.
819 | His brow cleared as he received it.
820 | "Well, I must be off," he said.
821 | "I mustn't waste time under these favoring skies.
822 | "Oh, Miss Wilbur," said Miss Emerson, addressing the young girl.
823 | "Wouldn't it be lovely if Mr.
824 | Gayne would let us go with him and watch him sketch?" "I am quite ignorant of his art," returned Diana, rising from her seat.
825 | "And I still have a great deal of exploring to do on my own account.
826 | Nicholas Gayne cast an admiring glance at the statuesque lines of her face and figure.
827 | "Perhaps you will let me make a sketch of you one of these days, Miss Wilbur.
828 | He approached the piazza rail as he spoke and his voice carried down to where Philip was painting under the eyes of the silent, watching boy.
829 | Philip looked up, and, catching the expression with which Gayne seemed to be appraising the young girl, he ruined one of the _n_'s in Inn so that it had to be painted out and done over.
830 | Veronica, her duties finished for the time being, sallied out of doors and approaching Philip looked curiously at his work.
831 | "There's nothing the matter with that," she said encouragingly, and the others came down from the piazza to praise the painter.
832 | Miss Emerson followed, but she looked at the sign doubtfully.
833 | "One can't help being sensitive, can one?" she said to Gayne.
834 | "And the wind blows so hard all the time up here, I'm afraid that sign is going to squeak.
835 | "Show me your window," said Philip good-naturedly, "and I'll see if we can't avoid it.
836 | So they all went around to the back of the house where Philip had his ladder waiting and the sign was finally placed to the satisfaction of everybody except Miss Emerson, who considered it on probation.
837 | Nicholas Gayne was still conscious that he had not made a pleasing impression in his treatment of his nephew and it was no part of his programme to attract attention.
838 | He approached the boy now.
839 | "What are you going to do with yourself, Bert?" "I don't know," was the answer.
840 | "Want to come with me?" "No, sir.
841 | "Well, that's plain enough," said Gayne, laughing and looking around on the company.
842 | "He's a very foolish boy," said Miss Emerson, "when he has an opportunity to watch you sketch.
843 | "Oh, Mr.
844 | Gayne!" cried Veronica.
845 | "Don't go until you tell us about the haunted farm.
846 | "Where did you ever hear about that?" asked the artist, looking with some favor on Veronica's round and dimpled personality.
847 | "I thought you were a stranger here.
848 | "I am, but Genevieve Wilks has just been telling me that you really saw the spook.
849 | Gayne laughed.
850 | "When I came up here last summer, I was told about the haunted farm, and, of course, I was interested in it at once.
851 | There are some particularly good views from there.
852 | So, naturally, I became one of the ha'nts myself and spent a lot of time with them.
853 | "Oh, but tell us what it looked like," persisted Veronica.
854 | "Did you really think you saw one?" "What a subject for this time of a clear, sunny day," said Gayne, lightly.
855 | "Wait until the thunder rolls some stormy night," and, lifting his cap, he hurried away through the field, his sketch-book under his arm.
856 | Diana looked after his receding form.
857 | "It is odd how little like an artist Mr.
858 | Gayne looks," she said.
859 | "You mean he should have long hair and dreamy eyes?" asked Philip.
860 | "I think it is the eyes," replied Diana thoughtfully.
861 | "I cannot picture his looking with concentration and persistence at anything.
862 | "Oh, I've seen him make a pretty good stab at it," said Philip dryly, thinking of the manner in which he had on several occasions seen him stare at Diana.
863 | At this point the dull boy found his tongue.
864 | "I wouldn't go up there," he said haltingly.
865 | "Up where?" asked Mrs.
866 | Lowell encouragingly.
867 | "Up to that farm.
868 | It's full of nettles that sting, and then, when it's dark, ghosts.
869 | The group exchanged glances.
870 | "Who told you that?" asked Philip.
871 | "Uncle Nick.
872 | It did not increase the general admiration of Mr.
873 | Gayne that he should take such means for securing safety from his nephew's companionship.
874 | Mrs.
875 | Lowell took the boy's arm.
876 | "I want to go down to the water," she said.
877 | "Will you go with me?" "Are you afraid to go alone?" he asked.
878 | "I should like it better if you went with me.
879 | He allowed himself to be led around the house, then on among the grassy hummocks and clump of bay and savin and countless blueberry bushes.
880 | "Do you see what quantities of blueberries we are going to have?" asked Mrs.
881 | Lowell.
882 | "Are we?" "Yes.
883 | These are berry bushes.
884 | Do you like blueberries?" "I don't know.
885 | Mrs.
886 | Lowell laughed and shook the arm she was still holding.
887 | "You do know, Bertie," she said.
888 | "You must have eaten lots of blueberries.
889 | Her merry eyes held his dull ones as she spoke.
890 | "I don't like to hear you say you don't know, all the time.
891 | "What difference does it make?" he returned.
892 | "All the difference in the world.
893 | The most important thing in life is for us to _know_.
894 | There are such quantities of beautiful things for us to know.
895 | This day, for instance.
896 | We can know it is beautiful, can't we?" When they reached the stony beach, she released his arm and sat down among the pebbles.
897 | He did not look at them or at the sea; but at her.
898 | She wore a blue dress and her brown hair was ruffling in the wind.
899 | "Do you like stones?" she asked.
900 | "I--" he began.
901 | She lifted her hand and laughed again into his eyes.
902 | "Careful!" she said.
903 | "Don't say you don't know.
904 | The boy's look altered from dullness to perplexity.
905 | "But I don't--" he began slowly.
906 | "Then find out right now," she said, lifting a hand full of the smooth pebbles while the tide seethed and hissed near them.
907 | She held out her hand to him.
908 | "Pick out the prettiest," she said, and he began pulling them over with his forefinger.
909 | "I love stones," she went on.
910 | "See how the ocean has polished them for us.
911 | Years and years of polishing has gone to these, and yet we can pick them up on a bright summer morning and have them for our own if we want them.
912 | "There's one sort of green," said Bertie.
913 | "Green.
914 | That's like me.
915 | Uncle Nick says I'm green.
916 | "Uncle Nick doesn't know everything," said Mrs.
917 | Lowell quietly, as she took the pebble he had chosen and, laying her handkerchief on the beach, placed the green pebble upon it.
918 | "Now, see if we can find some that you can see the light through.
919 | There is one now.
920 | See, that one is almost transparent.
921 | It is translucent.
922 | That is what translucent means.
923 | Isn't it a pretty word--and a pretty stone? Hold it up to your eye.
924 | The boy obeyed, a slight look of interest coming into his face.
925 | Mrs.
926 | Lowell studying him realized what an attractive face his might be.
927 | It was as if the promising bud of a flower had been blighted in mid-opening.
928 | "Let us put all the best pebbles on my handkerchief and take them home with us.
929 | Have you a father and mother, Bertie?" "No.
930 | "Do you remember them?" The boy hesitated and glanced into the kind face bent toward him.
931 | Its expression gave the lonely lad a strange sensation.
932 | A lump came into his throat and moisture suddenly gathered in his eyes.
933 | He swallowed the lump.
934 | "Uncle Nick doesn't want me--to talk about her," he stammered.
935 | "Your mother, do you mean, Bertie?" The tender tone was too much for the boy.
936 | He had to swallow faster and nodded.
937 | In a minute two drops ran down his cheeks.
938 | He ignored them and began throwing pebbles into the water.
939 | The figure that he made in his outgrown trousers and faded old sweater, trying to control himself, moved his companion, and the sign of his emotion encouraged her.
940 | Perhaps he was not so stupid as he seemed.
941 | "I think it would be nice to make a collection of stones while we are here," she said.
942 | "I'm sure Miss Burridge will let us have a glass jar.
943 | See this one.
944 | Bertie dashed the back of his hand across his eyes and turned to look at the small pebble she offered.
945 | "Isn't that a little beauty?" "I--" "Careful!" his companion smiled as she said it and pretended to frown at him in such a merry way that the hint of a smile appeared on his face.
946 | "Uncle Nick likes to have me say I don't know.
947 | He says it's honest.
948 | "Well, no two people could be more different than Uncle Nick and me.
949 | I want you to _know_, and I want you to say so, because it's what we all have a right to.
950 | It is what God wants of us; and, Bertie, if you ever feel like talking about your mother to me, you must do so.
951 | The boy glanced up at her, then down at the pebbles which he pulled over in silence.
952 | "Where do you and your uncle live?" "In Newark.
953 | "Do you go to school there?" "No.
954 | "Where do you go to school?" "Nowhere.
955 | "Where did you learn to read and write then, Bertie?" "In school.
956 | I went when--when _she_ was here.
957 | "Your mother?" "Yes.
958 | "And have you brothers and sisters?" "No.
959 | Just Uncle Nick.
960 | "Does he give you studies to learn?" Mrs.
961 | Lowell's catechism was given in such gentle, interested tones that the answers had come easily up to now.
962 | Now the boy hesitated, and she began to expect the stereotyped answer which he had learned was most pleasing, and the easiest way out with his uncle.
963 | "I--" he began, and caught her look.
964 | "Sometimes," he added.
965 | "But Uncle Nick says it isn't any use--and I don't care anyway, because--she isn't here.
966 | Again Mrs.
967 | Lowell could see the spasm in his throat and face.
968 | It passed and left the usual dull listlessness of expression.
969 | "Your mother was very sweet," said Mrs.
970 | Lowell quietly, and some acknowledgment lighted his eyes as he suddenly looked up at her.
971 | "I know that because she made such a deep impression on the little boy she left.
972 | How old were you, Bertie, in that happy time when she was here?" "I--it was Christmas, and there have been--five Christmases since.
973 | I remember them on my fingers, and one hand is gone.
974 | Mrs.
975 | Lowell met his shifting look with the steady, kind gaze which was so fraught with sympathy that his forlorn, neglected soul turned towards its warmth like a struggling flower to the sun.
976 | "I'll tell you what I think would be beautiful, Bertie," she said.
977 | "And it is for you to do everything you do for her, just as if she were here, or as if you were going to see her to-morrow.
978 | Did she ever talk to you about God?" "Yes.
979 | I said prayers that Christmas--and I got a sled.
980 | "Do you ever say prayers now?" "No.
981 | It--it doesn't do any good if you--if you live with Uncle Nick.
982 | He--he won't let God give you--anything.
983 | "Let me tell you something wonderful, Bertie.
984 | Nobody--not even Uncle Nick--can stand between you and God.
985 | You know the way your mother loved you? God loves you that way, too.
986 | Like a Father and Mother both.
987 | So, whenever you think of your mother's love, think of God's love, too.
988 | It is just as real.
989 | In fact, it was God, you know, who made her love you.
990 | The boy looked up at this.
991 | "Yes.
992 | So, whenever you think of God, remember that 'I don't know' must never come into your thought.
993 | You _do_ know, and you _can_ know better every day.
994 | "Uncle Nick won't like it if I know anything.
995 | "Dear child!" burst from Mrs.
996 | Lowell at this unconscious revelation of blight.
997 | "We will have a secret from Uncle Nick.
998 | I am so glad you have told me about your dear mother, and now you are going to start doing everything in the way you think would make her happy if she were here.
999 | I am sure she loved everything beautiful.
1000 | She loved flowers and birds and this splendid ocean that is going to catch us in a minute if we don't move back.
1001 | What do you say to letting it catch us! Supposing we take off our shoes and stockings and wade.
1002 | Doesn't that foam look tempting?" Color rose in the speaker's cheeks as she finished, and the vitality in her voice was infectious.
1003 | "It's--it'll be cold," said the boy.
1004 | "Let it.
1005 | Come on, it will be fun.
1006 | She was already taking off her shoes and he followed suit.
1007 | It gave her a pang to see the holes in his faded socks, but she caught up her skirts and he pulled up his trousers and shrinkingly followed her.
1008 | The June water was still reminiscent of ice, and she squealed as the foam curled around her ankles, and Bertie hopped up and down until color came into his face, too.
1009 | The incoming tide, noisier and noisier, drove them farther and farther up the beach, until finally they sat down together on a rock at a safe distance from the water, and the sunlight fell hotly on their glistening feet.
1010 | "That was fun!" said Mrs.
1011 | Lowell, laughing and breathing fast.
1012 | "Do you know how to swim, Bertie?" "I--no, I don't.
1013 | "That would be a nice thing to learn while you are here.
1014 | You learn and then teach me.
1015 | "Me? Teach you?" "Of course.
1016 | Why not? There's a cove in the island where they all swim.
1017 | Bertie looked off on the billows.
1018 | "Would my mother like that?" he asked.
1019 | "I'm sure she would, and she would like the collection of stones we are going to make, and she would like you to help Miss Burridge by weeding the garden that they have started.
1020 | There are so many delightful things to do in the world, and you are going to do them all--for her.
1021 | "All for her," echoed Bertie.
1022 | "And not tell Uncle Nick," he added.
1023 | "No.
1024 | You and I will keep the secret.
1025 | Mrs.
1026 | Lowell looked at him with a smile, and the neglected boy, his dull wits stimulated by this amazing experience of comradeship, smiled back at her, the smile of the little child who in that far-away happy Christmas had received a sled.
1027 | "Well, good-bye, Miss Priscilla," said Philip, coming into the kitchen a few mornings afterward.
1028 | "This landlubber life won't do for me any longer.
1029 | Small Genevieve was at the sink washing dishes and Veronica was drying them.
1030 | Miss Burridge slid her last loaf of bread into the oven and then stood up and faced him.
1031 | "Philip Barrison," she said emphatically, "you have been a blessing for these weeks.
1032 | I hate to see you go.
1033 | Now, how much do I owe you for all the good things you've done for me?" Philip laughed and, throwing his arms around her, gave her a hearty smack on the cheek.
1034 | "What do I owe you for popovers and corn fritters?" he rejoined.
1035 | "Just don't let Veronica chew gum, nor let Genevieve flirt with Marley Hughes and we'll call it square.
1036 | Genevieve turned up her little nose and giggled, and Veronica looked scornful.
1037 | "Now, don't you tell me that Puppa liked it," he continued to her.
1038 | "Besides, anybody that lives with your Aunt Pris has so many nicer things to chew there is no excuse.
1039 | Oh, Miss Priscilla, how I hate to say adieu to the waffles!" "Well, you must come real often, Phil.
1040 | I heard you was goin' to give us a concert at the hall sometime this summer.
1041 | Is that so? I do hope you will.
1042 | "I shouldn't wonder.
1043 | My accompanist is coming to-day and we shall do a little work and a lot of fishing.
1044 | "Is he a young feller? You must bring him up to play croquet with the girls.
1045 | "Well, I don't know whether he has any experience as an Alpine climber or not.
1046 | "Why, I don't think it's such an awful bad ground.
1047 | Do you, Veronica?" "Not if he's real nice and hasn't any whiskers," replied the girl.
1048 | "Heaven knows he'll be better than nothing.
1049 | Such a place as this and not a beau! It's a crime.
1050 | "How about me?" inquired Philip modestly.
1051 | Veronica lifted her upper lip disdainfully.
1052 | "Oh, you, with your lectures and your goddesses! What earthly good are you?" "Cr-rushed!" exclaimed Philip.
1053 | "Talked to Mrs.
1054 | Lowell all last evening on the piazza in that lovely moonlight.
1055 | The idea of wasting it on a _Mrs.
1056 | I suppose there's a _Mr.
1057 | to her.
1058 | "Yes, and he's coming before the summer is over.
1059 | The worst of it is she seems to like him.
1060 | "Children, children," said Miss Burridge, and she winked toward the back of Genevieve's head.
1061 | Well she knew the alertness of the ears that were holding back those tight braids of hair.
1062 | "Yes, my accompanist, Barney, is a broth of a boy, but I shall tell him, Veronica, that ten o'clock is the limit, the very extreme limit.
1063 | The girl flushed and laughed.
1064 | "You mind your business now, Mr.
1065 | Barrison, and I'll attend to mine.
1066 | I'm perfectly capable of it.
1067 | "Very well.
1068 | I'll simply keep Puppa's address on my desk, and I won't use it unless I really have to," said Phil, in a conscientious tone which nearly caused Veronica to throw a cup at him.
1069 | "Go along now if you must, Philip," said Miss Priscilla.
1070 | "And I do thank you, dear boy.
1071 | We shall miss you every minute.
1072 | Give my love to your grandmother.
1073 | I wish she could get up as far as this.
1074 | You tell her so.
1075 | "All right, I will.
1076 | Do you know where Miss Wilbur is?" "Aha!" said Veronica softly.
1077 | "I don't want to go without saying good-bye to her.
1078 | "I should hope not," jeered Veronica.
1079 | "I suppose you won't see her again all summer.
1080 | "Oh, yes, I shall, unless Barney Kelly cuts me out.
1081 | "Sure, it's Oirish he is, thin?" "Faith, and he is, and a bit chipped off the original blarney stone at that.
1082 | Trust him not, Veronica.
1083 | "I only hope I'll get the chance, but if you're going to set him on the goddess, what sort of a look-in will I have? I've got five on my nose already.
1084 | "Five what, woman?" "Freckles.
1085 | Can't you see them from there? It will be fulsome flattery if you say you can't.
1086 | Philip squinted up his eyes and came nearer to examine.
1087 | "You remember what I said.
1088 | Tell Barney they're beauty spots--'golden kisses of the sun.
1089 | " "Oh, ain't that pretty!" shouted Genevieve.
1090 | "I'm speckled with 'em jest like a turkey egg, but I don't mind 'em the way Veronica does.
1091 | I've got some powder at home and I powder over 'em.
1092 | "At your age, Genevieve!" exclaimed Philip sternly.
1093 | "What shall I do with the extravagance and artificiality of this generation! Don't you know, Genevieve, that the money you spend for powder should go into the missionary box? You poor, lost, little soul!" Genevieve giggled delightedly, and Miss Burridge, at the window, exclaimed: "There's Miss Wilbur now, Phil, looking at the garden bed.
1094 | "If I were she," said Veronica, "I wouldn't have a word to say to you after the way you wasted last evening.
1095 | "If only she thought so, too!" groaned Philip.
1096 | "But I'm not in it with her astronomy map for June.
1097 | She is a hundred times more interested to know where Jupiter and Venus are than where I am--natural, I suppose--all in the family.
1098 | He threw open the kitchen door and, standing on the step, threw kisses toward the group within.
1099 | "Good-bye, summer!" he sang.
1100 | "_Good-bye, good-bye.
1101 | " The beauty of his voice had its usual effect on Diana, who stood by the strip of green, growing things, looking in his direction, her lips slightly parted over her pretty teeth.
1102 | "You see I'm good-bye-ing," he said, approaching her.
1103 | "Are you leaving us?" she returned, allowing her clasped hands to fall apart.
1104 | "See how well the sweet peas are doing.
1105 | "Yes, I'm leaving you all in good shape.
1106 | Do you think you can go on behaving yourselves without my watchful guardianship and Christian example?" "I think we shall miss you.
1107 | Mr.
1108 | Gayne is not a fair exchange.
1109 | "Thank you.
1110 | Mrs.
1111 | Lowell was talking to me about that outfit last evening.
1112 | She is quite stirred up about the boy.
1113 | "Yes," rejoined Diana.
1114 | "I think she is a wonderful woman.
1115 | She has taken him down to the beach with her again this morning.
1116 | She believes that Mr.
1117 | Gayne is his nephew's enemy rather than his guardian.
1118 | She believes he has some reason for desiring to blight any buddings of intelligence in the boy, and uses an outrageous method of suppression over him all the time.
1119 | It would be so much easier to let it go, and most of us would, I'm sure, rather than spend vacation hours in such insipid company, or have any dealings with that--that impossible uncle; but Mrs.
1120 | Lowell will not relinquish her efforts.
1121 | "Yes, she is a brilliant, fearless sort of woman," said Philip.
1122 | "I shouldn't wonder if she gave Gayne a disagreeable quarter of an hour before she gets through with him.
1123 | "One has to exercise care, however," returned Diana, "lest the man become angered and visit his ill-humor on the boy.
1124 | I am often obliged to constrain myself to civility when I yearn to hurl--" she hesitated.
1125 | "Plates? Oh, do say you long to throw a plate at him!" Diana gave her remote moonbeam smile.
1126 | "I must admit that 'invective' was in my mind.
1127 | A rather strong word for girls to use.
1128 | "A splendid word.
1129 | A good long one, too.
1130 | You might try hurling polysyllables at him some day and see him blink.
1131 | Diana shook her head.
1132 | "That sort of man is a pachyderm.
1133 | He would never flinch at verbal missiles.
1134 | Since you must go, I wish some other agreeable man would join our group and converse with him at table.
1135 | Philip smiled.
1136 | "Surely you have noticed that Miss Emerson is not averse to assuming all responsibility?" "Mr.
1137 | Barrison," said Diana gravely, "I hope when I am--am elderly and unmarried, that I shall not seek to attract men.
1138 | "Miss Wilbur," returned Philip, with a solemnity fitting hers, and regarding the symmetry and grace of her lovely head, "don't spend any time worrying about that; for some inner voice assures me that you will never be elderly and unmarried.
1139 | "The future is on the knees of the gods," she returned serenely.
1140 | "Then I don't need to lose any sleep on account of your posing for one of Mr.
1141 | Gayne's wonderful sketches?" Diana brought the brown velvet of her eyes to bear fully upon him.
1142 | It even seemed hopeful that a spark would glow in them.
1143 | "I loathe the man," she said slowly.
1144 | "Forgive me, divine one.
1145 | Well, I must go now.
1146 | Why won't you take me home? I should like you to meet my grandmother, and think of the pitfalls and mantraps of the island road if I risk myself alone: Bill Lindsay's Ford! Marley Hughes's bicycle! Lou Buell's gray mare taking him to mend somebody's broken pipe! Matt Blake's express wagon! Come and keep my courage up.
1147 | "You have a grandmother on this island?" "I'll prove it if you'll come with me.
1148 | Diana smiled and moved along beside him.
1149 | "It doesn't seem a real, mundane, earthly place to me yet," she said.
1150 | "It must be wonderful to have a solid _pied-à-terre_ here.
1151 | They tell me there are many summer cottages, but they are far from our Inn and I haven't realized them yet.
1152 | I am hoping my parents will consent to purchasing some ground here for me.
1153 | "Where do you usually go in summer?" "Our cottage is at Newport, but I like better Pittsfield, where we go in the autumn.
1154 | Philip looked around at her as she moved along through the field beside him.
1155 | "Is your middle name Biddle?" he asked.
1156 | "No, I have no middle name.
1157 | "I thought in Philadelphia only the descendants of the Biddles had cottages at Newport and Pittsfield.
1158 | Diana smiled.
1159 | "I know that is a stock bit of humor.
1160 | What was that about an Englishman who said he had seen Niagara Falls and almost every other wonder of America except a Biddle? He had not yet seen one.
1161 | "When do you laugh, Miss Wilbur?" asked Philip suddenly.
1162 | "Why, whenever anything amuses me, of course.
1163 | "Yet you like the island, although it has never amused you yet.
1164 | I have lived in the house with you for two weeks and I haven't heard you laugh.
1165 | Diana looked up at him and laughed softly.
1166 | "How amusing!" she said.
1167 | He nodded.
1168 | "It's very good-looking, very.
1169 | Do that again sometime.
1170 | How did you happen to run away from family this season?" "I was tired and almost ill, and some people at home had been here and told me about it.
1171 | So I came, really incontinently.
1172 | I did not wait to perfect arrangements, and when I arrived in a severe rainstorm one evening, I found great kindness at the house my friends had told me of, but no clean towels.
1173 | They were going to have a supply later, but meanwhile I lost my heart to the view from our Inn piazza and Miss Burridge found me there one day and took me in for better or for worse.
1174 | That explains me.
1175 | Now, what explains your having a grandmother here?" "Her daughter marrying my father, I imagine.
1176 | My grandfather was a sea-captain, Cap'n Steve Dorking.
1177 | He had given up the sea by the time I came along.
1178 | "Here? Were you born here?" "Yes.
1179 | "That explains the maritime tints in your eyes.
1180 | Even when they laugh the sparkle is like the sun on the water.
1181 | Continue, please.
1182 | "Well, my father, who came here to fish, met my mother, fell in love, married her, and took her away.
1183 | He was very clever at everything except making money, it seems, so my mother came home within a year to welcome me on to the planet.
1184 | My grandfather had a small farm, and I was his shadow and one of his 'hands' until I was eight years old.
1185 | "Was it a happy life?" "It was.
1186 | I remember especially the smell of Grammy's buttery, sweet-smelling cookies, and gingerbread, and apple pies with cinnamon.
1187 | It smells the same way now.
1188 | Do you wonder I like to come back?" "You stimulate my appetite," said Diana.
1189 | "Oh, she'll give you some.
1190 | There were many jolly things in those days to brighten the life of a country boy.
1191 | The way the soft grass felt to bare feet in the spring, and in the frosty autumn mornings when we went to the yard to milk and would scare up the cows so those same bare feet could stand in the warm place where the cows had lain.
1192 | Then came winter and snowdrifts--making snow huts and coasting down the hills.
1193 | Sliding and skating on the ice-filled hollows.
1194 | It was all great.
1195 | I'm glad I had it.
1196 | "You test my credulity, Mr.
1197 | Barrison, when you speak of ice and snow in this poetic home of summer breezes.
1198 | He looked down at her.
1199 | "We will have a winter house-party at Grammy's sometime and convince you.
1200 | "So at eight years of age you went out into the world?" "Yes, at my dear mother's apron strings.
1201 | My father had spent some time with us every year and at last secured a living salary and took us to town.
1202 | The first thing I did in the glitter of the blinking lamp-posts was to fall in love.
1203 | I prayed every night for a long time that I might marry that girl.
1204 | She had long curls and I reached just to her ear.
1205 | I received her wedding cards a year or so ago.
1206 | I was always praying for something, but only one of my prayers has ever been answered.
1207 | I was always very devout in a thunderstorm, and I prayed that I might not be struck by lightning and I never have been yet.
1208 | "When was your wonderful voice discovered?" "Look here, Miss Wilbur, you are tempting me to a whole biography, and it isn't interesting.
1209 | "Yes, I am interested in--in your mother.
1210 | "My poor mother," said Philip, in a different tone.
1211 | "When I was twelve years old my father was taken ill and soon left us.
1212 | My mother had to struggle and I had to stop school and go to work.
1213 | The first job I got was lathing a house.
1214 | I walked seven miles into the country and put the laths on that house.
1215 | I worked hard for a whole week and received twelve dollars and seventy-five cents.
1216 | It was a ten-dollar gold piece, two silver dollars, fifty cents, and a quarter.
1217 | Diana lifted sympathetic eyes.
1218 | "I bought a suit of clothes and gave up the gold piece.
1219 | The perfect lady clerk failed to give me credit for it and six months afterward the store sent the bill to my mother.
1220 | I put up a heated argument, you may be sure, and before the matter was settled, the perfect lady clerk skipped with another woman's husband.
1221 | So the powers inclined to believe me rather than her.
1222 | "Poor little boy," put in Diana.
1223 | "But your music?" "Yes.
1224 | Well, our minister's wife took an interest in me and gave me lessons on the organ.
1225 | I never would practice, though.
1226 | I would pick out hymns with one finger while I stood on one foot and pumped the pedal with the other.
1227 | It was results I was after; but the cornet allured me, and I learned to play that well enough to join the Sunday-School orchestra.
1228 | "A cousin of my mother's came to our rescue sufficiently to let me go to school, and in all my spare time I did odd jobs, some of them pretty strenuous; but I was a strong youngster, and evidently bore a charmed life, for I challenged fate on trains, on top of buildings, and in engine rooms.
1229 | But I'll spare you the harrowing details.
1230 | At the spring commencement of the high school, I was invited to sing a solo.
1231 | I warbled good old 'Loch Lomond' and forgot the words and was mortified almost to death, but the audience was enthusiastic, I have always believed out of pity.
1232 | "No no," breathed Diana.
1233 | "Well, at any rate, they insisted on an encore, and I was so braced up by the applause and so furious at myself that I gave them 'The Owl and the Pussy Cat.
1234 | ' "Oh.
1235 | "I see you don't know it.
1236 | Well, next day I met a lady on the street who was very musical, it seemed, and she invited me to come to her house and talk over studying music.
1237 | She said I had a great responsibility.
1238 | Oh, you don't want to hear all this!" "I do, I do.
1239 | "My mother passed away soon afterward, and the musical friend in need--good friend she was, and is--told me of a town a hundred miles away where there were vacancies she knew of in choir positions.
1240 | She would give me a letter of introduction and she believed I could qualify for one of them.
1241 | I didn't tell her the slimness of my cash after my dear mother's funeral expenses were paid, and she didn't know.
1242 | So I traveled that hundred miles on a freight train.
1243 | When I first boarded it, I crawled into the fire-box of a new engine that was being transported over that line.
1244 | It grew very cold before we had gone far, and I crawled out and climbed over the coal tender and opened the hole where they put the water in.
1245 | I climbed down into that empty place and lighted a match only to find that there were about twenty bums there ahead of me.
1246 | I didn't stay there long, for I was good and plenty afraid; some of them looked desperate.
1247 | I climbed out again and went along the train till I came to a flat-car loaded with a new threshing machine.
1248 | I saw a brakeman coming along with a lantern, and I knew if he saw me he'd put me off.
1249 | So I climbed into the back of the threshing machine and down into its very depths, and after a while, when I had become chilled to the marrow, the train came to a halt.
1250 | I crawled out and down to the ground and ran around to get warm.
1251 | They were doing some switching and I saw they added two cars to the train.
1252 | One had stock in one end and hay and grain in the other.
1253 | They had to leave the door open to let in air for the stock, and up I climbed and hid under the straw and slept soundly the rest of the journey.
1254 | Oh, I was dirty when I arrived! But my precious letter was safe in an inside pocket, and with the contents of the little bundle I had, and the expenditure of part of my small stock of money, I made myself decent and presented my letter of introduction.
1255 | The organist of one of the churches tried me out.
1256 | He liked my voice so much that he engaged me and was even interested enough to let me live at his house; but three dollars a Sunday was the salary and the voice lessons I engaged would be four dollars a week, so, of course, I had to go to work at once, and I got a job in a big sash and door factory where I worked like a horse ten hours a day.
1257 | "Why, Mr.
1258 | Barrison," sighed Diana, "you are a hero.
1259 | Philip laughed.
1260 | "I had no leisure to think about that.
1261 | Times grew very slack and there began to be great danger that I would lose my job in the factory.
1262 | They said they would have to lay me off unless I would whitewash an old building they had bought to store lumber.
1263 | So I was given a brush and a barrel of lime-water and told to go at it.
1264 | If I lost my job, I wouldn't be able to live.
1265 | So I wrapped my feet in sacks to try to keep warm--it was late November--and went at it: and there were girls, Miss Wilbur, girls! And I couldn't put it over them after Tom Sawyer's fashion.
1266 | Well, I had sung there just thirteen Sundays when the blow fell.
1267 | The committee told me very kindly that they wanted to try another tenor.
1268 | I went home from that talk with a heart heavy as lead.
1269 | I could not sleep, and near midnight I began to cry.
1270 | Yes, I did cry.
1271 | I was twenty-one and I had voted, but I was the most broken-hearted boy in the State.
1272 | I must have cried for two or three hours, pitying myself to the utmost, up three flights of stairs in that little attic room, with the rain pouring on the roof over my head, when all at once I jumped out of bed as dry-eyed as if I'd never shed a tear and, lifting my right hand as high as possible, I made a vow.
1273 | I said--So help me, God, I will become a singer if I have to walk over everybody in the attempt.
1274 | I will learn to sing, and these mutts will listen to me and pay to hear me, too.
1275 | Then I jumped back into bed and fell asleep instantly.
1276 | "Splendid!" said Diana.
1277 | "And how did you keep the vow?" "Well, next morning I began to figure what I must do.
1278 | I knew I hadn't enough education.
1279 | I remembered that three years before I had won a scholarship for twenty weeks' free tuition in a business college in Portland, and I decided that I would need fifty dollars.
1280 | The same cousin who had helped me before to go to school, came across.
1281 | I quit my job, paid my bills, and left for Portland, getting there at Christmas.
1282 | I sang at the Christmas-tree exercises in my home church.
1283 | I went to school as I planned, took care of the furnace for the rent of my room, took care of three horses, got the janitorship of a church--" Diana looked up with a sudden smile.
1284 | "And forced up the thermometer when you overslept.
1285 | Philip burst into a hearty laugh.
1286 | "Did Miss Burridge give me away? I tell you I saved that church lots of coal that winter.
1287 | "Oh, continue.
1288 | I did not mean to interrupt you, for now you are coming to the climax.
1289 | "Nothing very wonderful, Miss Wilbur, but I found I had that to give that people were willing to pay for, and I began going about in country places giving recitals, mixing humorous recitations in with the groups of songs, playing my own accompaniments and sometimes having to shovel a path through the snow to the town hall before my audience could come in.
1290 | I wonder if Caruso ever had to shovel snow away from the Metropolitan Opera House before his friends could get in to hear him! After that I worked my way through two years at college, studying with a good voice teacher.
1291 | Then came the war.
1292 | I got through with little more than a scratch and was in one of the first regiments to be sent home after the armistice was signed.
1293 | The lady who first discovered my voice had influential musical friends in New York.
1294 | She sent me to them, and, to make a long story a little shorter, last winter I was under an excellent management, obtained a church position, and have sung at a good many recitals.
1295 | The coming winter looks hopeful.
1296 | Philip put his hand on his heart and bowed.
1297 | "Thanking you for your kind attention--here we are at Grammy's.
1298 | Their path had led away from the main road across a field toward a buff-colored house set on a rise of ground like a billow in a green sea.
1299 | Where the hill descended beyond, there grew a flourishing apple orchard.
1300 | "Since my grandfather's death, the little farm is overgrown," said Philip.
1301 | "My grandmother gets a neighbor to cut the hay and milk her cow, and so leaves the cares of the world behind her.
1302 | A climbing rosebush nearly covered one side of the cottage, and old-fashioned perennials clung about its base.
1303 | Nothing was yet in bloom; but soon the daisies in the field would lie in white drifts and the wild roses, large and of a deep pink, would soften the ledges of rock cropping out everywhere in the sweet-smelling fields.
1304 | Philip opened the door and ushered his companion into a small hallway covered with oilcloth, then into a sunny living-room, shining clean, with a floor varnished in yellow and strewn with rag rugs.
1305 | An old lady, seated in one of the comfortable rocking-chairs, rose to meet them.
1306 | Her face, the visitor thought, was one of the sweetest she had ever seen.
1307 | "What a pretty girl she must have been!" she reflected.
1308 | Around her neck the old lady wore a string of gold beads, and the thick gray hair growing becomingly around her low forehead was carried back and confined in a black net.
1309 | The simple charm of her welcome to the young girl was the perfection of good manners and her voice was low and pleasant.
1310 | "I'm glad you've brought my boy back, Miss Wilbur, I've been missing him.
1311 | "That's right, Grammy.
1312 | Give me a good character," said Philip hugging her and kissing her cheek.
1313 | "I must have waffles, though.
1314 | I'm spoiled.
1315 | Here a woman appeared at the door of the passageway that led to the kitchen.
1316 | She was very wrinkled and care-worn in appearance, yet sprightly in her movements and manner.
1317 | Many of her teeth were missing and her thin hair was strained back out of the way.
1318 | She wore a large checked apron over her calico dress.
1319 | "Hello, there, Aunt Maria," said Philip.
1320 | "This is Miss Wilbur, one of the guests at Miss Burridge's.
1321 | "Happy to meet you," said Aunt Maria, but casually, in the manner of one who has but slight time for trivial things like social amenities.
1322 | Then she fixed Philip with a severe stare.
1323 | "Is this the day you was expectin' the New York man?" "It is, Aunt Maria.
1324 | Don't tell me you weren't sure and haven't plenty on hand for two man-sized appetites.
1325 | "Well, I thought 'twas.
1326 | I guess I can feed you.
1327 | Aunt Maria's severity lapsed in a semi-toothless smile.
1328 | "How's Priscilla Burridge gettin' along?" "Famously," replied Philip.
1329 | "She's given me waffles every morning.
1330 | "H'm!" grunted Aunt Maria.
1331 | "I guess I can cook anything Priscilla Burridge can, give me the ingregiencies.
1332 | "The principal ingredient is a waffle iron.
1333 | I'll send for one for you.
1334 | Diana had meanwhile been placed in a seat near her hostess, where she faced the line of cheerful red geraniums on the window-sill.
1335 | "Your first visit to the island, Miss Wilbur?" asked the old lady.
1336 | "Yes, Mrs.
1337 | Dorking; but not the last, I assure you.
1338 | "You like it, then?" "I think it is a fairy-tale place.
1339 | "Miss Wilbur has been accustomed to a summer home where the hand of man has been very busy and the foot of man has trodden out nearly all of Nature's earmarks.
1340 | She finds she likes the raw material better," said Philip, leaning against the mantelpiece where odd shells and quaint China objects, half-dog, half-dragon, stood as memorials to Captain Steve Dorking's cruises.
1341 | The swords of two swordfishes, elaborately carved, leaned near him.
1342 | "The island's filling up," said the old lady.
1343 | "A lot of the summer people came yesterday and from now on they'll flock in.
1344 | "Are you glad to see them come?" asked Diana.
1345 | "Yes," returned Mrs.
1346 | Dorking, a rising inflection in her kindly voice.
1347 | "They're most of them good friends of mine.
1348 | "I should say she is glad," remarked Philip.
1349 | "She sits here in state and receives them all, don't you, Grammy?" "I don't know as there's much state about it.
1350 | The old lady smiled, and leaned toward Diana.
1351 | "Miss Wilbur, I guess you've found out already that Philip is the foolishest boy that ever lived.
1352 | We can't afford to mind his talk, can we?" "But his singing, Mrs.
1353 | Dorking," Diana looked up at Philip's tow head towering toward the low ceiling.
1354 | "It doesn't greatly matter how he talks when he can sing as he does.
1355 | "Yes," returned the old lady, again with the moderate rising inflection.
1356 | "I will say Philip's got a real pretty voice.
1357 | "And there is a piano!" said Diana, wistfully looking across the room at the ancient square instrument.
1358 | "That is a very polite name for it," remarked Philip.
1359 | "Oh, Mr.
1360 | Barrison, could you, won't you, sing some song of the sea?" The girl clasped her hands in prospect.
1361 | "I'm your guest, you know.
1362 | It is not quite possible to refuse.
1363 | "Of the sea, eh?" Philip looked at his watch.
1364 | "I think we have time before the boat comes.
1365 | I'll make a bargain with you.
1366 | I'll sing you a song if you will go down to the boat with me and meet my accompanist.
1367 | "Oh, is your accompanist coming?" "Even so.
1368 | But when is an accompanist not an accompanist? Answer: When he comes to the sea to fish.
1369 | I've lured you far from home and dinner, so you come to the boat with me and I'll send you home in Bill Lindsay's chariot.
1370 | "Very well, but--please sing!" "Oh, yes.
1371 | A song of the sea is the order, I understand.
1372 | Meanwhile, I accompany myself on the harp.
1373 | Philip moved over to the piano.
1374 | It was placed so he could look over the case at his listeners.
1375 | He ran his fingers over the yellow keys which gave out a thin, tinkling sound, and then plunged into song: "The owl and the pussy cat went to sea In a beautiful pea-green boat, They took some honey and plenty of money Wrapped up in a five-pound note.
1376 | The owl looked up to the stars above And sang to a small guitar, 'Oh, lovely Pussy, Oh, Pussy, my love, What a beautiful Pussy you are!'"
--------------------------------------------------------------------------------