├── .gitignore ├── .travis.yml ├── LICENSE ├── Makefile ├── README.rst ├── assets ├── directory_struc.jpg ├── logo.png └── usage.gif ├── requirements.txt ├── setup.cfg ├── setup.py ├── tests ├── __init__.py ├── inputs.py └── unit_tests.py └── xkcd_dl ├── __init__.py ├── cli.py └── version.py /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | 3 | bin/data/* ## stores the scraped images, you don't want the old crap right ? :D 4 | bin/data/ 5 | bin/xkcd_dict.json 6 | README.md 7 | 8 | ### pypi specific 9 | dist/* 10 | xkcd_dl.egg-info/* 11 | 12 | # Byte-compiled / optimized / DLL files 13 | __pycache__/ 14 | *.py[cod] 15 | 16 | # C extensions 17 | *.so 18 | 19 | # Distribution / packaging 20 | .Python 21 | env/ 22 | build/ 23 | develop-eggs/ 24 | dist/ 25 | downloads/ 26 | eggs/ 27 | lib/ 28 | lib64/ 29 | parts/ 30 | sdist/ 31 | var/ 32 | *.egg-info/ 33 | .installed.cfg 34 | *.egg 35 | 36 | # PyInstaller 37 | # Usually these files are written by a python script from a template 38 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 39 | *.manifest 40 | *.spec 41 | 42 | # Installer logs 43 | pip-log.txt 44 | pip-delete-this-directory.txt 45 | 46 | # Unit test / coverage reports 47 | htmlcov/ 48 | .tox/ 49 | .coverage 50 | .cache 51 | nosetests.xml 52 | coverage.xml 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | 61 | # Sphinx documentation 62 | docs/_build/ 63 | 64 | # PyBuilder 65 | target/ 66 | 67 | 68 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - "3.6" 4 | # command to install dependencies 5 | install: "pip3 install -r requirements.txt" 6 | # command to run tests 7 | script: python3 -m unittest tests.unit_tests 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright © 2015 Tasdik Rahman 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Author: Tasdik Rahman 3 | # @Date: 2016-03-12 4 | # @Last Modified by: Tasdik Rahman 5 | # @Last Modified time: 2016-04-05 16:32:19 6 | # @GPLv3 License 7 | # @http://tasdikrahman.me 8 | # @https://github.com/tasdikrahman/plino 9 | 10 | # virtualenv executables 11 | PIP := $(BIN)/pip 12 | PYTHON := $(BIN)/python 13 | FLAKE8 := $(BIN)/flake8 14 | PEP257 := $(BIN)/pep257 15 | COVERAGE := $(BIN)/coverage 16 | TESTRUN := $(BIN)/py.test 17 | 18 | EGG_INFO := $(subst -,_,$(PROJECT)).egg-info 19 | 20 | 21 | .clean-build: 22 | # @find -name $(PACKAGE).c -delete 23 | @find . -name '*.pyc' -delete 24 | @find . -name '__pycache__' -delete 25 | @rm -rf $(EGG_INFO) 26 | @rm -rf __pycache__ 27 | 28 | 29 | .git-no-changes: 30 | @if git diff --name-only --exit-code; \ 31 | then \ 32 | echo Git working copy is clean...; \ 33 | else \ 34 | echo ERROR: Git working copy is dirty!; \ 35 | echo Commit your changes and try again.; \ 36 | exit -1; \ 37 | fi; 38 | 39 | register: 40 | python setup.py register -r pypi 41 | 42 | dist: test 43 | python setup.py sdist 44 | python setup.py bdist_wheel 45 | 46 | upload: .git-no-changes 47 | python setup.py sdist upload -r pypi 48 | #$(PYTHON) setup.py bdist_wheel upload -r pypi 49 | 50 | 51 | .PHONY: help 52 | help: 53 | @echo "\nPlease call with one of these targets:\n" 54 | @$(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null | awk -v RS= -F:\ 55 | '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}'\ 56 | | sort | egrep -v -e '^[^[:alnum:]]' -e '^$@$$' | xargs | tr ' ' '\n' | awk\ 57 | '{print " - "$$0}' 58 | @echo "\n" 59 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | .. figure:: https://raw.githubusercontent.com/tasdikrahman/xkcd-dl/master/assets/logo.png 2 | :alt: logo 3 | 4 | 5 | |PyPI version| |License| |Travis| 6 | 7 | Download each and every `xkcd `__ comic uploaded! Like ever! 8 | 9 | :Author: Tasdik Rahman 10 | 11 | .. contents:: 12 | :backlinks: none 13 | 14 | .. sectnum:: 15 | 16 | 17 | Features 18 | ========= 19 | 20 | - Can download all the xkcd's uploaded till date(1603 as I am writing 21 | this!). 22 | - Download individual xkcd's and store them 23 | - Download ranges of xkcd's and store them 24 | - Download the latest issue xkcd 25 | - Download the meta text inside each xkcd and store it 26 | - No duplicacy in your XKCD database. 27 | - Stores each xkcd in a separate file named as the ``title`` of the 28 | xkcd at your home directory 29 | - Writes a ``description.txt`` for each xkcd. Storing meta-data like 30 | 31 | - ``date-publised`` 32 | - url value 33 | - a small description of that xkcd 34 | - The alt text on the comic 35 | 36 | - written in uncomplicated ``python``. 37 | 38 | Demo 39 | ==== 40 | 41 | .. figure:: https://raw.githubusercontent.com/tasdikrahman/xkcd-dl/master/assets/usage.gif 42 | :alt: Usage 43 | 44 | Usage 45 | 46 | Each Comic is stored in it's own individual folder with a 47 | ``description.txt`` placed in it. It contains meta-data like - 48 | ``img-link`` - ``title`` - ``date-published`` - ``alt`` 49 | 50 | Here's a little example for the same 51 | 52 | .. figure:: https://raw.githubusercontent.com/tasdikrahman/xkcd-dl/master/assets/directory_struc.jpg 53 | :alt: xkcd\_archive Structure 54 | 55 | xkcd\_archive Structure 56 | 57 | 58 | Usage 59 | ===== 60 | 61 | When running for the first time, do a ``xkcd-dl --update-db`` 62 | 63 | .. code:: bash 64 | 65 | $ xkcd-dl --update-db 66 | XKCD link database updated 67 | Stored it in 'xkcd_dict.json'. You can start downloading your XKCD's! 68 | Run 'xkcd-dl --help' for more options 69 | $ 70 | 71 | ``--help`` 72 | ---------- 73 | 74 | .. code:: bash 75 | 76 | $ xkcd-dl --help 77 | usage: xkcd-dl [-h] [-u] [-l] [-d XKCD_NUM | -a] 78 | [-r [DOWNLOAD_RANGE [DOWNLOAD_RANGE ...]]] [-v] [-P PATH] 79 | [-s XKCD_NUM] 80 | 81 | Run `xkcd-dl --update-db` if running for the first time. 82 | 83 | optional arguments: 84 | -h, --help show this help message and exit 85 | -u, --update-db Update the database 86 | -l, --download-latest 87 | Download most recent comic 88 | -d XKCD_NUM, --download XKCD_NUM 89 | Download specified comic by number 90 | -a, --download-all Download all comics 91 | -r [DOWNLOAD_RANGE [DOWNLOAD_RANGE ...]], --download-range [DOWNLOAD_RANGE [DOWNLOAD_RANGE ...]] 92 | Download specified range 93 | -v, --version show program's version number and exit 94 | -P PATH, --path PATH set path 95 | -s XKCD_NUM, --show XKCD_NUM 96 | Show specified comic by number 97 | 98 | 99 | ``--download-latest`` 100 | --------------------- 101 | 102 | This downloads the last uploaded xkcd comic and stores under the home 103 | directory of the user with a brief description 104 | 105 | .. code:: bash 106 | 107 | $ xkcd-dl --download-latest 108 | Downloading xkcd from 'http://imgs.xkcd.com/comics/flashlights.png' and storing it under '/home/tasdik/xkcd_archive/1603' 109 | $ 110 | 111 | If it has been downloaded, will not do anything 112 | 113 | This command will work even if you have not run --update-db yet. 114 | 115 | ``--download=XKCDNUMBER`` 116 | ------------------------- 117 | 118 | Downloads the particular ``XKCDNUMBER``\ (given that it exists and has 119 | not been downloaded already) and stores it in the home directory 120 | 121 | .. code:: bash 122 | 123 | $ xkcd-dl --download=143 124 | Downloading xkcd from 'http://xkcd.com/143/' and storing it under '/home/tasdik/xkcd_archive/143' 125 | $ xkcd-dl --download=1603 126 | Downloading xkcd from 'http://xkcd.com/1603/' and storing it under '/home/tasdik/xkcd_archive/1603' 127 | xkcd number '1603' has already been downloaded! 128 | $ 129 | 130 | ``--download-range `` 131 | -------------------- 132 | 133 | Will take two number parameters and download all the xkcd's between 134 | the two, inclusive. 135 | 136 | .. code:: bash 137 | 138 | $ xkcd-dl --download-range 32 36 139 | Downloading xkcd from 'http://xkcd.com/32/' and storing it under '/home/tasdik/xkcd_archive/32' 140 | Downloading xkcd from 'http://xkcd.com/33/' and storing it under '/home/tasdik/xkcd_archive/33' 141 | Downloading xkcd from 'http://xkcd.com/34/' and storing it under '/home/tasdik/xkcd_archive/34' 142 | Downloading xkcd from 'http://xkcd.com/35/' and storing it under '/home/tasdik/xkcd_archive/35' 143 | Downloading xkcd from 'http://xkcd.com/36/' and storing it under '/home/tasdik/xkcd_archive/36' 144 | 145 | ``--download-all`` 146 | ------------------ 147 | 148 | As the name suggests, will download all the xkcd's uploaded till date 149 | and store them under the home directory of the user. 150 | 151 | .. code:: bash 152 | 153 | $ xkcd-dl --download-all 154 | Downloading all xkcd's Till date!! 155 | Downloading xkcd from 'http://xkcd.com/1466' and storing it under '/home/tasdik/xkcd_archive/1466' 156 | Downloading xkcd from 'http://xkcd.com/381' and storing it under '/home/tasdik/xkcd_archive/381' 157 | Downloading xkcd from 'http://xkcd.com/198' and storing it under '/home/tasdik/xkcd_archive/198' 158 | Downloading xkcd from 'http://xkcd.com/512' and storing it under '/home/tasdik/xkcd_archive/512' 159 | Downloading xkcd from 'http://xkcd.com/842' and storing it under '/home/tasdik/xkcd_archive/842' 160 | Downloading xkcd from 'http://xkcd.com/920' and storing it under '/home/tasdik/xkcd_archive/920' 161 | .... 162 | .... 163 | 164 | ``--path=PATH`` 165 | --------------- 166 | 167 | To use a custom directory to store your xkcd_archive, you can append 168 | --path=./any/path/here to the end of any download method. Absolute and relative 169 | paths work, but the directory must already exist. 170 | 171 | .. code:: bash 172 | 173 | $ xkcd-dl --download=3 --path=comic 174 | Downloading xkcd from 'http://xkcd.com/3/' and storing it under '/home/tasdik/comic/xkcd_archive/3' 175 | $ xkcd-dl --download-range 54 56 --path=/home/tasdik/xkcd 176 | Downloading xkcd from 'http://xkcd.com/54/' and storing it under '/home/tasdik/xkcd/xkcd_archive/54' 177 | Downloading xkcd from 'http://xkcd.com/55/' and storing it under '/home/tasdik/xkcd/xkcd_archive/55' 178 | Downloading xkcd from 'http://xkcd.com/56/' and storing it under '/home/tasdik/xkcd/xkcd_archive/56' 179 | 180 | ``--show XKCD_NUM`` 181 | ------------------- 182 | 183 | Opens the specified comic. Downloads it, if not downloaded already. Prints the alt text and metadata to stdout. 184 | 185 | .. code:: bash 186 | 187 | $ xkcd-dl --show 32 188 | Downloading xkcd from 'http://xkcd.com/32/' and storing it under '/home/bk/Documents/xkcd-dl/xkcd_dl/xkcd_archive/32' 189 | title : Pillar 190 | date-publised: 2006-1-1 191 | url: http://xkcd.com/32/ 192 | alt: A comic by my brother Doug, redrawn and rewritten by me 193 |   194 | $ xkcd-dl -s 1000 195 | Downloading xkcd from 'http://xkcd.com/1000/' and storing it under '/home/bk/Documents/xkcd-dl/xkcd_dl/xkcd_archive/1000' 196 | xkcd number '1000' has already been downloaded! 197 | title : 1000 Comics 198 | date-publised: 2012-1-6 199 | url: http://xkcd.com/1000/ 200 | alt: Thank you for making me feel less alone. 201 | 202 | 203 | Installation 204 | ============ 205 | 206 | Option 1: installing through `pip `__ (Suggested way) 207 | ------------------------------------------------------------------------------------------- 208 | 209 | `pypi package link `__ 210 | 211 | ``$ pip3 install xkcd-dl`` 212 | 213 | If you are behind a proxy 214 | 215 | ``$ pip3 --proxy [username:password@]domain_name:port install xkcd-dl`` 216 | 217 | **Note:** If you get ``command not found`` then 218 | ``$ sudo apt-get install python3-pip`` should fix that 219 | 220 | Option 2: installing from source 221 | -------------------------------- 222 | 223 | .. code:: bash 224 | 225 | $ git clone https://github.com/tasdikrahman/xkcd-dl.git 226 | $ cd xkcd-dl/ 227 | $ pip3 install -r requirements.txt 228 | $ python3 setup.py install 229 | 230 | Upgrading 231 | --------- 232 | 233 | .. code:: bash 234 | 235 | $ pip3 install -U xkcd-dl 236 | 237 | Uninstalling 238 | ------------ 239 | 240 | ``$ pip3 uninstall xkcd-dl`` 241 | 242 | For ``Arch`` distributions 243 | -------------------------- 244 | 245 | Here is the ``AUR`` link for you 246 | 247 | - `Arch package `__ 248 | 249 | Contributing 250 | ============ 251 | 252 | **I hacked this up in one night, so its a little messy up there.** Feel free to contribute. 253 | 254 | 1. Fork it. 255 | 2. Create your feature branch 256 | (``git checkout -b my-new-awesome-feature``) 257 | 3. Commit your changes (``git commit -am 'Added feature'``) 258 | 4. Push to the branch (``git push origin my-new-awesome-feature``) 259 | 5. Create new Pull Request 260 | 261 | Contributors 262 | ------------ 263 | 264 | Big shout out to 265 | 266 | - `Ian C `__ for fixing issue `#2 `__ which stopped the download if a title of a comic had a special character in it and `BlitzKraft `__ for pointing it out. 267 | - `BlitzKraft `__ for adding the feature to download the `alt-text` from the the xkcd **and** major clean ups! 268 | - `Braden Best `__ for pointing out the issues when installing from source apart from his valuable input. 269 | 270 | To-do 271 | ----- 272 | 273 | - [x] add ``xkcd-dl --download-latest`` 274 | - [x] add ``xkcd-dl --download=XKCDNUMBER`` 275 | - [x] add ``xkcd-dl --download-all`` 276 | - [x] add ``xkcd-dl download-range `` 277 | - [x] add path setting with ``[--path=/path/to/directory]`` option 278 | - [x] add exclude list to easily recognize and ignore dynamic comics 279 | i.e. comics without a default image. 280 | - [x] Remove redundant code in ``download_xkcd_number()``, 281 | ``download_latest()`` and ``download_all()`` (**Refactoring!!**) 282 | - [x] Adding support to open a particular xkcd at the CLI itself. 283 | Implemented using `xdg-open`. Opens using your default image viewer. 284 | - [x] Add tests 285 | 286 | 287 | Known Issues 288 | ------------ 289 | 290 | - There have been issues when installed from source if you are using 291 | ``python 2.*`` as discussed in 292 | `#5 `__. 293 | So using ``python3.*`` is suggested. 294 | - If you get ``command not found`` when installing, it may mean that 295 | you don't have ``pip3`` installed. 296 | ``$ sudo apt-get install python3-pip`` should fix that. To check your 297 | version of pip 298 | - Dynamic comics have to be added manually using the excludeList 299 | 300 | .. code:: bash 301 | 302 | $ pip3 --version 303 | pip 1.5.6 from /usr/lib/python3/dist-packages (python 3.4) 304 | $ 305 | 306 | 307 | Bugs 308 | ---- 309 | 310 | Please report the bugs at the `issue 311 | tracker `__ 312 | 313 | **OR** 314 | 315 | You can tweet me at `@tasdikrahman `__ if you can't get it to work. In fact, you should tweet me anyway. 316 | 317 | Changelog 318 | ========= 319 | 320 | - ``0.1.2``: 321 | bug: fixed relative import error in setup.py 322 | added support for gif files when renaming downloaded image (#38) 323 | 324 | Motivation 325 | ========== 326 | 327 | ``xkcd-dl`` is inspired by an awesome package called `youtube-dl `__ written by `Daniel Bolton `__ (Much respect!) 328 | 329 | How about you get to download all of the xkcd which have been uploaded 330 | till date? This does just that! 331 | 332 | Now I don't know about you, but I just love reading ``xkcd``'s! Had a boring Sunday night looming over, thought why not create something like ``youtube-dl`` but for downloading ``xkcd``'s! 333 | 334 | And hence `xkcd-dl `__ 335 | 336 | Cheers to a crazy night! 337 | 338 | Legal stuff 339 | =========== 340 | 341 | Built with ♥ by `Tasdik Rahman `__ `(@tasdikrahman) `__ and `others `__ released under `MIT License `__ 342 | 343 | You can find a copy of the License at http://prodicus.mit-license.org/ 344 | 345 | Donation 346 | ======== 347 | 348 | If you have found my little bits of software of any use to you, you can help me pay my internet bills :) 349 | 350 | |Paypal badge| 351 | 352 | |Instamojo| 353 | 354 | |gratipay| 355 | 356 | |patreon| 357 | 358 | 359 | .. |PyPI version| image:: https://badge.fury.io/py/xkcd-dl.svg 360 | :target: https://badge.fury.io/py/xkcd-dl 361 | .. |License| image:: https://img.shields.io/pypi/l/xkcd-dl.svg 362 | :target: https://img.shields.io/pypi/l/xkcd-dl.svg 363 | .. |Paypal badge| image:: https://www.paypalobjects.com/webstatic/mktg/logo/AM_mc_vs_dc_ae.jpg 364 | :target: https://www.paypal.me/tasdik 365 | .. |gratipay| image:: https://cdn.rawgit.com/gratipay/gratipay-badge/2.3.0/dist/gratipay.png 366 | :target: https://gratipay.com/tasdikrahman/ 367 | .. |Instamojo| image:: https://www.soldermall.com/images/pic-online-payment.jpg 368 | :target: https://www.instamojo.com/@tasdikrahman 369 | .. |Travis| image:: https://travis-ci.org/tasdikrahman/xkcd-dl.svg?branch=master 370 | :target: https://travis-ci.org/tasdikrahman/xkcd-dl 371 | .. |Travis| image:: https://travis-ci.org/tasdikrahman/xkcd-dl.svg?branch=master 372 | :target: https://travis-ci.org/tasdikrahman/xkcd-dl 373 | .. |patreon| image:: http://i.imgur.com/ICWPFOs.png 374 | :target: https://www.patreon.com/tasdikrahman/ 375 | -------------------------------------------------------------------------------- /assets/directory_struc.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tasdikrahman/xkcd-dl/4e104ddc0d7c10335f08fef2c4554d2df8575a13/assets/directory_struc.jpg -------------------------------------------------------------------------------- /assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tasdikrahman/xkcd-dl/4e104ddc0d7c10335f08fef2c4554d2df8575a13/assets/logo.png -------------------------------------------------------------------------------- /assets/usage.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tasdikrahman/xkcd-dl/4e104ddc0d7c10335f08fef2c4554d2df8575a13/assets/usage.gif -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | beautifulsoup4==4.4.1 2 | python-magic==0.4.10 3 | requests==2.8.1 4 | wheel==0.24.0 5 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | description-file = README.md 3 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | #!/usr/bin/env python 3 | # @Author: Tasdik Rahman 4 | # @Date: 2016-04-19 12:34:46 5 | # @Last Modified by: Tasdik Rahman 6 | # @Last Modified time: 2016-04-19 13:58:00 7 | # @MIT License 8 | # @http://tasdikrahman.me 9 | # @https://github.com/tasdikrahman 10 | 11 | import os 12 | 13 | try: 14 | from setuptools import setup, find_packages 15 | except ImportError: 16 | from distutils.core import setup 17 | 18 | from xkcd_dl.version import VERSION 19 | __version__ = VERSION 20 | 21 | try: 22 | readme = open("README.rst") 23 | long_description = str(readme.read()) 24 | finally: 25 | readme.close() 26 | 27 | setup( 28 | name = 'xkcd-dl', 29 | version = __version__, 30 | author = 'Tasdik Rahman', 31 | author_email = 'prodicus@outlook.com', 32 | description = "Download all the XKCD's uploaded, ever from the command line", 33 | long_description=long_description, 34 | url = 'https://github.com/tasdikrahman/xkcd-dl', 35 | license = 'MIT', 36 | install_requires = [ 37 | "beautifulsoup4==4.4.1", 38 | "python-magic==0.4.10", 39 | "requests==2.8.1", 40 | ], 41 | ### adding package data to it 42 | packages=find_packages(exclude=['contrib', 'docs', 'tests']), 43 | ### 44 | download_url = 'https://github.com/tasdikrahman/xkcd-dl/tarball/'+__version__, 45 | classifiers = [ 46 | 'Intended Audience :: Developers', 47 | 'Topic :: Software Development :: Build Tools', 48 | 'Environment :: Console', 49 | 'Intended Audience :: Developers', 50 | 'License :: OSI Approved :: MIT License', 51 | 'Natural Language :: English', 52 | 'Programming Language :: Python', 53 | 'Programming Language :: Python :: 3', 54 | 'Programming Language :: Python :: 3.4', 55 | ], 56 | keywords = ['xkcd', 'cli', 'commandline','download', 'api', 'comic'], 57 | entry_points = { 58 | 'console_scripts': [ 59 | 'xkcd-dl = xkcd_dl.cli:main' 60 | ], 61 | } 62 | ) -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tasdikrahman/xkcd-dl/4e104ddc0d7c10335f08fef2c4554d2df8575a13/tests/__init__.py -------------------------------------------------------------------------------- /tests/inputs.py: -------------------------------------------------------------------------------- 1 | ARCHIVE_URL_CONTENT="b'\\n\\n\\n\\n\\nxkcd - A webcomic of romance, sarcasm, math, and language - By Randall Munroe\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n
\\n
\\n\\n
\\n
\\n
\\n\"xkcd.com\\nA webcomic of romance,
sarcasm, math, and language.
\\n
\\n
\\nThere are four new shirts in the xkcd store,
\\nalong with posters and lots of other stuff!\\n\\n
\\n
\\n
\\n
\\n
\\n
\\n\\n

Comics:


\\n(Hover mouse over title to view publication date)

\\n\\n\\nAir Force Museum
\\n\\n\\n\\nDecades
\\n\\n\\n\\nGlacial Erratic
\\n\\n\\n\\nDubious Study
\\n\\n\\n\\nDrone Problems
\\n\\n\\n\\nState Word Map
\\n\\n\\n\\nVoting Systems
\\n\\n\\n\\nOpening Crawl
\\n\\n\\n\\nAnti-Drone Eagles
\\n\\n\\n\\nWho?
\\n\\n\\n\\nGenetic Testing Results
\\n\\n\\n\\nDoctor Visit
\\n\\n\\n\\nMachine Learning
\\n\\n\\n\\nRental Car
\\n\\n\\n\\nOkeanos
\\n\\n\\n\\nRandom Obsessions
\\n\\n\\n\\nLunch Order
\\n\\n\\n\\nCode Quality 3
\\n\\n\\n\\nPhoto Library Management
\\n\\n\\n\\nHere to Help
\\n\\n\\n\\nISS Solar Transit 2
\\n\\n\\n\\nGeochronology
\\n\\n\\n\\nISS Solar Transit
\\n\\n\\n\\nSurvivorship Bias
\\n\\n\\n\\nBirdwatching
\\n\\n\\n\\n7 Eleven
\\n\\n\\n\\nIdentification Chart
\\n\\n\\n\\nHottest Editors
\\n\\n\\n\\nExistential Bug Reports
\\n\\n\\n\\nIncinerator
\\n\\n\\n\\nSecurity Advice
\\n\\n\\n\\nSweet 16
\\n\\n\\n\\nRayleigh Scattering
\\n\\n\\n\\nIncognito Mode
\\n\\n\\n\\nMispronunciation
\\n\\n\\n\\nFlag
\\n\\n\\n\\nColor Pattern
\\n\\n\\n\\nVomiting Emoji
\\n\\n\\n\\nOnboarding
\\n\\n\\n\\nBest-Tasting Colors
\\n\\n\\n\\nChat Systems
\\n\\n\\n\\nxkcd Phone 5
\\n\\n\\n\\nHacking
\\n\\n\\n\\nListening
\\n\\n\\n\\nBorrow Your Laptop
\\n\\n\\n\\nUnpublished Discoveries
\\n\\n\\n\\nVideo Content
\\n\\n\\n\\nLocation Reviews
\\n\\n\\n\\nPhone
\\n\\n\\n\\nDecision Paralysis
\\n\\n\\n\\nChess Notation
\\n\\n\\n\\nBad Map Projection: Time Zones
\\n\\n\\n\\nBox Plot
\\n\\n\\n\\nStardew Valley
\\n\\n\\n\\nFocus Knob
\\n\\n\\n\\nAll You Can Eat
\\n\\n\\n\\nFire
\\n\\n\\n\\nSoda Sugar Comparisons
\\n\\n\\n\\nBird/Plane/Superman
\\n\\n\\n\\nTelescopes: Refractor vs Reflector
\\n\\n\\n\\nSad
\\n\\n\\n\\nPhone Numbers
\\n\\n\\n\\nBarge
\\n\\n\\n\\nVoice Commands
\\n\\n\\n\\nTrash
\\n\\n\\n\\nWifi
\\n\\n\\n\\nBad Map Projection: Liquid Resize
\\n\\n\\n\\nEmails
\\n\\n\\n\\nTeam Chat
\\n\\n\\n\\nArtifacts
\\n\\n\\n\\nAppliance Repair
\\n\\n\\n\\n2017
\\n\\n\\n\\nInterest Timescales
\\n\\n\\n\\nDear Diary
\\n\\n\\n\\nReindeer
\\n\\n\\n\\nThings You Learn
\\n\\n\\n\\nAdjective Foods
\\n\\n\\n\\nNegativity
\\n\\n\\n\\nStartup Opportunity
\\n\\n\\n\\nIt Was I
\\n\\n\\n\\nUI Change
\\n\\n\\n\\nNever Seen Star Wars
\\n\\n\\n\\nSettling
\\n\\n\\n\\nUS State Names
\\n\\n\\n\\nApple Spectrum
\\n\\n\\n\\nBaby Post
\\n\\n\\n\\nXKCDE
\\n\\n\\n\\nCatcalling
\\n\\n\\n\\nMoving Boxes
\\n\\n\\n\\nBlame
\\n\\n\\n\\nTV Problems
\\n\\n\\n\\nBritish Map
\\n\\n\\n\\nAstrophysics
\\n\\n\\n\\nNovember 2016
\\n\\n\\n\\nI\\'m With Her
\\n\\n\\n\\nOld Days
\\n\\n\\n\\nTornado Safety Tips
\\n\\n\\n\\nThumb War
\\n\\n\\n\\nInterplanetary Experience
\\n\\n\\n\\nMovie Folder
\\n\\n\\n\\nLife Goals
\\n\\n\\n\\nMushrooms
\\n\\n\\n\\nFuture Archaeology
\\n\\n\\n\\nSpider Paleontology
\\n\\n\\n\\nMaking Friends
\\n\\n\\n\\nRecord Scratch
\\n\\n\\n\\nMetabolism
\\n\\n\\n\\nCoffee
\\n\\n\\n\\nWill It Work
\\n\\n\\n\\nWork
\\n\\n\\n\\nRosetta
\\n\\n\\n\\nFixing Problems
\\n\\n\\n\\nMoon Shapes
\\n\\n\\n\\nDatacenter Scale
\\n\\n\\n\\nManhattan Project
\\n\\n\\n\\nFashion Police and Grammar Police
\\n\\n\\n\\nReductionism
\\n\\n\\n\\nSolar Spectrum
\\n\\n\\n\\nEarth Temperature Timeline
\\n\\n\\n\\nWrong
\\n\\n\\n\\nStarshade
\\n\\n\\n\\nMigrating Geese
\\n\\n\\n\\nCron Mail
\\n\\n\\n\\nNumber of Computers
\\n\\n\\n\\nUnicode
\\n\\n\\n\\nLinear Regression
\\n\\n\\n\\nProofs
\\n\\n\\n\\nMeteorite Identification
\\n\\n\\n\\nDebugging
\\n\\n\\n\\nBusiness Idea
\\n\\n\\n\\nHorses
\\n\\n\\n\\nSuperzoom
\\n\\n\\n\\nBackups
\\n\\n\\n\\nPyramid Honey
\\n\\n\\n\\nTime Travel Thesis
\\n\\n\\n\\nHousehold Tips
\\n\\n\\n\\nVolcano Types
\\n\\n\\n\\n50 ccs
\\n\\n\\n\\nPolitifact
\\n\\n\\n\\nSnapchat
\\n\\n\\n\\nWalking Into Things
\\n\\n\\n\\nInflection
\\n\\n\\n\\nDehydration
\\n\\n\\n\\nxkcd Phone 4
\\n\\n\\n\\nGenetic Testing
\\n\\n\\n\\nPok\\xc3\\xa9mon Go
\\n\\n\\n\\nGnome Ann
\\n\\n\\n\\nJuno
\\n\\n\\n\\nHome Itch Remedies
\\n\\n\\n\\nSpeed and Danger
\\n\\n\\n\\nNew Bug
\\n\\n\\n\\nLocal News
\\n\\n\\n\\nTheft Quadrants
\\n\\n\\n\\nIntervocalic Fortition
\\n\\n\\n\\nAI Research
\\n\\n\\n\\nCode Quality 2
\\n\\n\\n\\nPhishing License
\\n\\n\\n\\nOxidation
\\n\\n\\n\\nMan Page
\\n\\n\\n\\nOptimization
\\n\\n\\n\\nTime-Tracking Software
\\n\\n\\n\\nMy Friend Catherine
\\n\\n\\n\\nMap Age Guide
\\n\\n\\n\\nWorld War III+
\\n\\n\\n\\nFeel Old
\\n\\n\\n\\nPatch
\\n\\n\\n\\nRainbow
\\n\\n\\n\\nDigital Data
\\n\\n\\n\\nBun
\\n\\n\\n\\nLaser Products
\\n\\n\\n\\nBlack Hole
\\n\\n\\n\\nSubstitutions 3
\\n\\n\\n\\nRecent Searches
\\n\\n\\n\\nContrails
\\n\\n\\n\\nFull-Width Justification
\\n\\n\\n\\nMessage in a Bottle
\\n\\n\\n\\nAdult
\\n\\n\\n\\nTimeline of Bicycle Design
\\n\\n\\n\\nWomen on 20s
\\n\\n\\n\\nArcane Bullshit
\\n\\n\\n\\nLaws of Physics
\\n\\n\\n\\nPlanespotting
\\n\\n\\n\\nSingularity
\\n\\n\\n\\nAlgorithms
\\n\\n\\n\\nBrain Upload
\\n\\n\\n\\nCity Talk Pages
\\n\\n\\n\\nMycology
\\n\\n\\n\\nGarden
\\n\\n\\n\\nJack and Jill
\\n\\n\\n\\nPodium
\\n\\n\\n\\nCaptain Speaking
\\n\\n\\n\\nTire Swing
\\n\\n\\n\\nEstimating Time
\\n\\n\\n\\nInsanity
\\n\\n\\n\\nIt Begins
\\n\\n\\n\\nDoomsday Clock
\\n\\n\\n\\nUniversal Install Script
\\n\\n\\n\\nUnited States Map
\\n\\n\\n\\nConditionals
\\n\\n\\n\\nRobotic Garage
\\n\\n\\n\\nBaby
\\n\\n\\n\\nPipelines
\\n\\n\\n\\nFamous Duos
\\n\\n\\n\\nDiacritics
\\n\\n\\n\\nTwitter Bot
\\n\\n\\n\\nToasts
\\n\\n\\n\\nStargazing
\\n\\n\\n\\nDegrees
\\n\\n\\n\\nGravitational Waves
\\n\\n\\n\\nHot Dogs
\\n\\n\\n\\nSuper Bowl Context
\\n\\n\\n\\nTo Taste
\\n\\n\\n\\nBackslashes
\\n\\n\\n\\nSalt Mine
\\n\\n\\n\\nXKCD Stack
\\n\\n\\n\\nBirdsong
\\n\\n\\n\\nIn Case of Emergency
\\n\\n\\n\\nPossible Undiscovered Planets
\\n\\n\\n\\nPalindrome
\\n\\n\\n\\nLonger Than Usual
\\n\\n\\n\\nQuadcopter
\\n\\n\\n\\nTools
\\n\\n\\n\\nMagnus
\\n\\n\\n\\nWoosh
\\n\\n\\n\\nJudgment Day
\\n\\n\\n\\nSubstitutions 2
\\n\\n\\n\\n2016
\\n\\n\\n\\n2016 Conversation Guide
\\n\\n\\n\\nHenge
\\n\\n\\n\\nFixion
\\n\\n\\n\\nChristmas Settings
\\n\\n\\n\\nWatson Medical Algorithm
\\n\\n\\n\\nCold Medicine
\\n\\n\\n\\nTime Capsule
\\n\\n\\n\\nLunch
\\n\\n\\n\\nRed Car
\\n\\n\\n\\nKites
\\n\\n\\n\\nThe Three Laws of Robotics
\\n\\n\\n\\nColds
\\n\\n\\n\\nBaking Soda and Vinegar
\\n\\n\\n\\nFire Ants
\\n\\n\\n\\nFood Combinations
\\n\\n\\n\\nHoverboard
\\n\\n\\n\\nSupreme Court
\\n\\n\\n\\nFive-Day Forecast
\\n\\n\\n\\nDNA
\\n\\n\\n\\nSnakes
\\n\\n\\n\\nFlashlights
\\n\\n\\n\\nLinguistics Club
\\n\\n\\n\\nIsolation
\\n\\n\\n\\nMarketWatch
\\n\\n\\n\\nWater Delivery
\\n\\n\\n\\nSalvage
\\n\\n\\n\\nGit
\\n\\n\\n\\nLaunch Status Check
\\n\\n\\n\\n30 Days Hath September
\\n\\n\\n\\nHuman Subjects
\\n\\n\\n\\nPlay-By-Play
\\n\\n\\n\\nOverthinking
\\n\\n\\n\\nBell\\'s Theorem
\\n\\n\\n\\nThe Source
\\n\\n\\n\\nFrankenstein
\\n\\n\\n\\nHardware Reductionism
\\n\\n\\n\\nFood Rule
\\n\\n\\n\\nKeyboard Problems
\\n\\n\\n\\nSimilarities
\\n\\n\\n\\nMoments of Inspiration
\\n\\n\\n\\nNASA Press Conference
\\n\\n\\n\\nPicture a Grassy Field
\\n\\n\\n\\nBirthday
\\n\\n\\n\\nTravel Ghost
\\n\\n\\n\\nTech Loops
\\n\\n\\n\\nSquirrelphone
\\n\\n\\n\\nAdvent
\\n\\n\\n\\nI Could Care Less
\\n\\n\\n\\nFootprints
\\n\\n\\n\\nTrouble for Science
\\n\\n\\n\\nCyberintelligence
\\n\\n\\n\\nxkcd Survey
\\n\\n\\n\\nCar Model Names
\\n\\n\\n\\nEngineer Syllogism
\\n\\n\\n\\nMagic Tree
\\n\\n\\n\\nSynonym Movies 2
\\n\\n\\n\\nKitchen Tips
\\n\\n\\n\\nBoard Game
\\n\\n\\n\\nBack Seat
\\n\\n\\n\\nEvery Seven Seconds
\\n\\n\\n\\nSynonym Movies
\\n\\n\\n\\nI in Team
\\n\\n\\n\\nWater Phase Diagram
\\n\\n\\n\\nBubblegum
\\n\\n\\n\\nDriving
\\n\\n\\n\\nVet
\\n\\n\\n\\nOzymandias
\\n\\n\\n\\nThe Sky
\\n\\n\\n\\nExoplanet Names 2
\\n\\n\\n\\nSpice Girls
\\n\\n\\n\\nPublic Key
\\n\\n\\n\\nRulebook
\\n\\n\\n\\nPluto
\\n\\n\\n\\nEpisode VII
\\n\\n\\n\\nXKCD Phone 3
\\n\\n\\n\\n90s Kid
\\n\\n\\n\\nSolar System Questions
\\n\\n\\n\\nTamagotchi Hive
\\n\\n\\n\\nStrengths and Weaknesses
\\n\\n\\n\\nMargaret
\\n\\n\\n\\nTeam Effort
\\n\\n\\n\\nScheduling Conflict
\\n\\n\\n\\nVoice
\\n\\n\\n\\nHemingway
\\n\\n\\n\\nPlanning
\\n\\n\\n\\nLyrics
\\n\\n\\n\\nTypes
\\n\\n\\n\\nThe Martian
\\n\\n\\n\\nWords for Pets
\\n\\n\\n\\nBeer
\\n\\n\\n\\nAntique Factory
\\n\\n\\n\\nNew Horizons
\\n\\n\\n\\nThe BDLPSWDKS Effect
\\n\\n\\n\\nKeyboard Mash
\\n\\n\\n\\nBracket
\\n\\n\\n\\nVodka
\\n\\n\\n\\nHumans
\\n\\n\\n\\nPlacebo Blocker
\\n\\n\\n\\nEmojic 8 Ball
\\n\\n\\n\\nDimensions
\\n\\n\\n\\nMicrodrones
\\n\\n\\n\\nAstronomy
\\n\\n\\n\\nSword in the Stone
\\n\\n\\n\\nDegree-Off
\\n\\n\\n\\nVenus
\\n\\n\\n\\nTypical Morning Routine
\\n\\n\\n\\nSpectroscopy
\\n\\n\\n\\nWin by Induction
\\n\\n\\n\\nBasketball Earth
\\n\\n\\n\\nPermaCal
\\n\\n\\n\\nCode Quality
\\n\\n\\n\\nHoroscopes
\\n\\n\\n\\nSpice Girl
\\n\\n\\n\\nNapoleon
\\n\\n\\n\\nScenery Cheat Sheet
\\n\\n\\n\\nOperating Systems
\\n\\n\\n\\nMetaball
\\n\\n\\n\\nxkcloud
\\n\\n\\n\\nOntological Argument
\\n\\n\\n\\nOpportunity
\\n\\n\\n\\nSquirrel Plan
\\n\\n\\n\\nWasted Time
\\n\\n\\n\\nMysteries
\\n\\n\\n\\nUpside-Down Map
\\n\\n\\n\\nArbitrage
\\n\\n\\n\\nTerry Pratchett
\\n\\n\\n\\nNew Products
\\n\\n\\n\\nArt Project
\\n\\n\\n\\nHard Reboot
\\n\\n\\n\\nInsurance
\\n\\n\\n\\nMeeting
\\n\\n\\n\\nDress Color
\\n\\n\\n\\nStories of the Past and Future
\\n\\n\\n\\nAtoms
\\n\\n\\n\\nFundamental Forces
\\n\\n\\n\\nFlowcharts
\\n\\n\\n\\nTornado
\\n\\n\\n\\nVacuum
\\n\\n\\n\\nFriendship
\\n\\n\\n\\nApollo Speeches
\\n\\n\\n\\nQuotative Like
\\n\\n\\n\\n#NowPlaying
\\n\\n\\n\\nAPI
\\n\\n\\n\\nSuper Bowl
\\n\\n\\n\\nTroubleshooting
\\n\\n\\n\\nP-Values
\\n\\n\\n\\nStar Wars
\\n\\n\\n\\nCeres
\\n\\n\\n\\nTechnically
\\n\\n\\n\\nScrews
\\n\\n\\n\\nLocation Sharing
\\n\\n\\n\\nGeography
\\n\\n\\n\\nGut Fauna
\\n\\n\\n\\nKix
\\n\\n\\n\\nUV
\\n\\n\\n\\nWorrying
\\n\\n\\n\\nEmail
\\n\\n\\n\\nPhone Checking
\\n\\n\\n\\nxkcd Phone 2
\\n\\n\\n\\nSanta
\\n\\n\\n\\nAltitude
\\n\\n\\n\\nBlind Trials
\\n\\n\\n\\nPayloads
\\n\\n\\n\\nSMFW
\\n\\n\\n\\nDocuments
\\n\\n\\n\\nSmall Moon
\\n\\n\\n\\nFeedback
\\n\\n\\n\\nOn the Moon
\\n\\n\\n\\nTrolley Problem
\\n\\n\\n\\nDone
\\n\\n\\n\\nfMRI
\\n\\n\\n\\nJurassic World
\\n\\n\\n\\nBackground Screens
\\n\\n\\n\\nAI-Box Experiment
\\n\\n\\n\\nRed Rover
\\n\\n\\n\\nQuestion
\\n\\n\\n\\nMeta-Analysis
\\n\\n\\n\\nLanding
\\n\\n\\n\\nEfficiency
\\n\\n\\n\\nCloud
\\n\\n\\n\\nLanguage Nerd
\\n\\n\\n\\nChemistry
\\n\\n\\n\\nTurnabout
\\n\\n\\n\\nGeese
\\n\\n\\n\\nRack Unit
\\n\\n\\n\\nHouston
\\n\\n\\n\\nHiggs Boson
\\n\\n\\n\\nOrb Hammer
\\n\\n\\n\\nPresidential Alert
\\n\\n\\n\\nWhere Do Birds Go
\\n\\n\\n\\nLightsaber
\\n\\n\\n\\nThe Sake of Argument
\\n\\n\\n\\nMarriage
\\n\\n\\n\\nProteins
\\n\\n\\n\\nData
\\n\\n\\n\\nMove Fast and Break Things
\\n\\n\\n\\niOS Keyboard
\\n\\n\\n\\nReduce Your Payments
\\n\\n\\n\\nTasks
\\n\\n\\n\\nEn Garde
\\n\\n\\n\\nConversation
\\n\\n\\n\\nMy Phone is Dying
\\n\\n\\n\\nFuture Self
\\n\\n\\n\\nWatches
\\n\\n\\n\\nOn the Phone
\\n\\n\\n\\nHorse
\\n\\n\\n\\nSeven
\\n\\n\\n\\nPixels
\\n\\n\\n\\nBallooning
\\n\\n\\n\\nWriting Skills
\\n\\n\\n\\nSuddenly Popular
\\n\\n\\n\\nTeenage Mutant Ninja Turtles
\\n\\n\\n\\nLoop
\\n\\n\\n\\nCalifornia
\\n\\n\\n\\nQuery
\\n\\n\\n\\nMarch of the Penguins
\\n\\n\\n\\nWorst Hurricane
\\n\\n\\n\\nUniversal Converter Box
\\n\\n\\n\\nMeteor
\\n\\n\\n\\nQuantum Vacuum Virtual Plasma
\\n\\n\\n\\nThesis Defense
\\n\\n\\n\\nHarpoons
\\n\\n\\n\\nNew
\\n\\n\\n\\nD.B. Cooper
\\n\\n\\n\\nChaos
\\n\\n\\n\\nSnake Facts
\\n\\n\\n\\nLuke
\\n\\n\\n\\nActors
\\n\\n\\n\\nPower Cord
\\n\\n\\n\\nSuperm*n
\\n\\n\\n\\nTimeghost
\\n\\n\\n\\nDominant Players
\\n\\n\\n\\nDarkness
\\n\\n\\n\\nResearch Ethics
\\n\\n\\n\\nSurface Area
\\n\\n\\n\\nSubduction License
\\n\\n\\n\\nClumsy Foreshadowing
\\n\\n\\n\\nPeople are Stupid
\\n\\n\\n\\nThrowing Rocks
\\n\\n\\n\\nKrypton
\\n\\n\\n\\nMagic Words
\\n\\n\\n\\nRocket Packs
\\n\\n\\n\\nMargin
\\n\\n\\n\\nManual for Civilization
\\n\\n\\n\\n4.5 Degrees
\\n\\n\\n\\nTurbine
\\n\\n\\n\\nFish
\\n\\n\\n\\nJump
\\n\\n\\n\\nAstronaut Vandalism
\\n\\n\\n\\nUrn
\\n\\n\\n\\nScreenshot
\\n\\n\\n\\nSmartwatches
\\n\\n\\n\\nBrightness
\\n\\n\\n\\nPresident
\\n\\n\\n\\nTMI
\\n\\n\\n\\nOne Of The
\\n\\n\\n\\nInstalling
\\n\\n\\n\\nTrain
\\n\\n\\n\\nInflation
\\n\\n\\n\\nLike I\\'m Five
\\n\\n\\n\\nxkcd Phone
\\n\\n\\n\\nMorse Code
\\n\\n\\n\\nGoogle Announcement
\\n\\n\\n\\nOld Files
\\n\\n\\n\\nPhone Alarm
\\n\\n\\n\\nNRO
\\n\\n\\n\\nFree Speech
\\n\\n\\n\\nOrbital Mechanics
\\n\\n\\n\\nAirplane Message
\\n\\n\\n\\nHeartbleed Explanation
\\n\\n\\n\\nHeartbleed
\\n\\n\\n\\nCosmologist on a Tire Swing
\\n\\n\\n\\nMetamaterials
\\n\\n\\n\\nLorenz
\\n\\n\\n\\nShouldn\\'t Be Hard
\\n\\n\\n\\nBefore the Internet
\\n\\n\\n\\nt Distribution
\\n\\n\\n\\nCareer
\\n\\n\\n\\nAnswers
\\n\\n\\n\\nDigits
\\n\\n\\n\\nManuals
\\n\\n\\n\\nAncient Stars
\\n\\n\\n\\nTypes of Editors
\\n\\n\\n\\nUnique Date
\\n\\n\\n\\nWhen You Assume
\\n\\n\\n\\nLand Mammals
\\n\\n\\n\\nHack
\\n\\n\\n\\nTransformers
\\n\\n\\n\\nNow
\\n\\n\\n\\nSecond
\\n\\n\\n\\nFirst Date
\\n\\n\\n\\nSlippery Slope
\\n\\n\\n\\nFrequency
\\n\\n\\n\\nKola Borehole
\\n\\n\\n\\nStanding
\\n\\n\\n\\nUpdate
\\n\\n\\n\\nMobile Marketing
\\n\\n\\n\\nSharks
\\n\\n\\n\\nRejection
\\n\\n\\n\\nWeather
\\n\\n\\n\\nProtocol
\\n\\n\\n\\nWinter
\\n\\n\\n\\nCold
\\n\\n\\n\\nWalmart
\\n\\n\\n\\nAutomation
\\n\\n\\n\\nActually
\\n\\n\\n\\nTheft
\\n\\n\\n\\nInexplicable
\\n\\n\\n\\nQuestions for God
\\n\\n\\n\\nPhotos
\\n\\n\\n\\nRegex Golf
\\n\\n\\n\\nHaskell
\\n\\n\\n\\n2014
\\n\\n\\n\\nGoldbach Conjectures
\\n\\n\\n\\nInfinite Scrolling
\\n\\n\\n\\nChristmas Lights
\\n\\n\\n\\nBuzzfeed Christmas
\\n\\n\\n\\nSigil Cycle
\\n\\n\\n\\nUndocumented Feature
\\n\\n\\n\\nGlass Trolling
\\n\\n\\n\\nProfile Info
\\n\\n\\n\\nYear in Review
\\n\\n\\n\\nFile Extensions
\\n\\n\\n\\nGalilean Moons
\\n\\n\\n\\nI Don\\'t Own a TV
\\n\\n\\n\\nExoplanet Neighborhood
\\n\\n\\n\\nOort Cloud
\\n\\n\\n\\nGit Commit
\\n\\n\\n\\nNew Study
\\n\\n\\n\\nTelescope Names
\\n\\n\\n\\nJob Interview
\\n\\n\\n\\nPi vs. Tau
\\n\\n\\n\\nShoot for the Moon
\\n\\n\\n\\nSyllable Planning
\\n\\n\\n\\nSimple Answers
\\n\\n\\n\\nSubstitutions
\\n\\n\\n\\nPuzzle
\\n\\n\\n\\nEncryptic
\\n\\n\\n\\nThird Way
\\n\\n\\n\\nImproved Keyboard
\\n\\n\\n\\nHeadlines
\\n\\n\\n\\nMonty Hall
\\n\\n\\n\\nMinifigs
\\n\\n\\n\\nMystery News
\\n\\n\\n\\nReverse Identity Theft
\\n\\n\\n\\nGiraffes
\\n\\n\\n\\nAyn Random
\\n\\n\\n\\nAngular Size
\\n\\n\\n\\nint(pi)
\\n\\n\\n\\nOpen Letter
\\n\\n\\n\\nTall Infographics
\\n\\n\\n\\nShadowfacts
\\n\\n\\n\\nHighlighting
\\n\\n\\n\\nFunctional
\\n\\n\\n\\nPrivacy Opinions
\\n\\n\\n\\nAlternate Universe
\\n\\n\\n\\nMess
\\n\\n\\n\\nHalting Problem
\\n\\n\\n\\nJuicer
\\n\\n\\n\\nSlideshow
\\n\\n\\n\\nReassuring
\\n\\n\\n\\nUnquote
\\n\\n\\n\\nShake That
\\n\\n\\n\\nLD50
\\n\\n\\n\\nBee Orchid
\\n\\n\\n\\nFirst
\\n\\n\\n\\nMonster
\\n\\n\\n\\nQuestions
\\n\\n\\n\\nColumbus
\\n\\n\\n\\nPreferred Chat System
\\n\\n\\n\\nExoplanet Names
\\n\\n\\n\\nIncreased Risk
\\n\\n\\n\\nAnti-Glass
\\n\\n\\n\\nOld Accounts
\\n\\n\\n\\nMeteor Showers
\\n\\n\\n\\nSphere
\\n\\n\\n\\nThe Mother of All Suspicious Files
\\n\\n\\n\\nPale Blue Dot
\\n\\n\\n\\n10-Day Forecast
\\n\\n\\n\\nSix Words
\\n\\n\\n\\nSnare
\\n\\n\\n\\nScary Names
\\n\\n\\n\\nAnnoying Ringtone Champion
\\n\\n\\n\\nQuantum Mechanics
\\n\\n\\n\\nSocial Media
\\n\\n\\n\\nEnlightenment
\\n\\n\\n\\nQR Code
\\n\\n\\n\\nSeashell
\\n\\n\\n\\nSettled
\\n\\n\\n\\nDouglas Engelbart (1925-2013)
\\n\\n\\n\\nRelativity
\\n\\n\\n\\nRealistic Criteria
\\n\\n\\n\\nHabitable Zone
\\n\\n\\n\\nPolar/Cartesian
\\n\\n\\n\\nScreensaver
\\n\\n\\n\\nPrometheus
\\n\\n\\n\\nThe Pace of Modern Life
\\n\\n\\n\\nBalloon Internet
\\n\\n\\n\\nIce Sheets
\\n\\n\\n\\nCouncil of 300
\\n\\n\\n\\nDwarf Fortress
\\n\\n\\n\\nPastime
\\n\\n\\n\\nNomenclature
\\n\\n\\n\\nHipsters
\\n\\n\\n\\nReports
\\n\\n\\n\\nDoors of Durin
\\n\\n\\n\\nCells
\\n\\n\\n\\nSticks and Stones
\\n\\n\\n\\nInsight
\\n\\n\\n\\nGeoguessr
\\n\\n\\n\\nCombination Vision Test
\\n\\n\\n\\nInterstellar Memes
\\n\\n\\n\\nBirds and Dinosaurs
\\n\\n\\n\\nI\\'m So Random
\\n\\n\\n\\nEncoding
\\n\\n\\n\\nFootnote Labyrinths
\\n\\n\\n\\nAirAware
\\n\\n\\n\\nEinstein
\\n\\n\\n\\nIs It Worth the Time?
\\n\\n\\n\\nDetail
\\n\\n\\n\\nTime Machines
\\n\\n\\n\\nGirls and Boys
\\n\\n\\n\\nIntegration by Parts
\\n\\n\\n\\nAuthorization
\\n\\n\\n\\nSilence
\\n\\n\\n\\nGeologist
\\n\\n\\n\\nAll Adobe Updates
\\n\\n\\n\\nSubways
\\n\\n\\n\\nFlowchart
\\n\\n\\n\\nStratigraphic Record
\\n\\n\\n\\nExternalities
\\n\\n\\n\\nHumming
\\n\\n\\n\\nThe Past
\\n\\n\\n\\nTime
\\n\\n\\n\\nVoyager 1
\\n\\n\\n\\nBonding
\\n\\n\\n\\nAspect Ratio
\\n\\n\\n\\nBumblebees
\\n\\n\\n\\nIneffective Sorts
\\n\\n\\n\\nCircumference Formula
\\n\\n\\n\\nRose Petals
\\n\\n\\n\\nRembrandt Photo
\\n\\n\\n\\nPGP
\\n\\n\\n\\nVirus Venn Diagram
\\n\\n\\n\\nISO 8601
\\n\\n\\n\\nPickup Artists
\\n\\n\\n\\nTime Robot
\\n\\n\\n\\nThose Not Present
\\n\\n\\n\\nMoving Sidewalks
\\n\\n\\n\\nApp
\\n\\n\\n\\nSteroids
\\n\\n\\n\\nWorkflow
\\n\\n\\n\\nPerl Problems
\\n\\n\\n\\nBridge
\\n\\n\\n\\nExpedition
\\n\\n\\n\\ntar
\\n\\n\\n\\nStar Trek into Darkness
\\n\\n\\n\\nArgument
\\n\\n\\n\\nAmazon
\\n\\n\\n\\nHome Alone
\\n\\n\\n\\nDebugger
\\n\\n\\n\\nLog Scale
\\n\\n\\n\\nHand Sanitizer
\\n\\n\\n\\nDrop Those Pounds
\\n\\n\\n\\nCountdown
\\n\\n\\n\\nRubber Sheet
\\n\\n\\n\\nSick Day
\\n\\n\\n\\nConditioning
\\n\\n\\n\\nKolmogorov Directions
\\n\\n\\n\\nResolution
\\n\\n\\n\\nProof
\\n\\n\\n\\nCommunion
\\n\\n\\n\\nTests
\\n\\n\\n\\nInstagram
\\n\\n\\n\\nBroomstick
\\n\\n\\n\\nNothing to Offer
\\n\\n\\n\\nEvolving
\\n\\n\\n\\nHonest
\\n\\n\\n\\nSky Color
\\n\\n\\n\\nTags
\\n\\n\\n\\nLocation
\\n\\n\\n\\nCoverage
\\n\\n\\n\\nTwo Years
\\n\\n\\n\\nCalendar of Meaningful Dates
\\n\\n\\n\\nRubber and Glue
\\n\\n\\n\\nHeatmap
\\n\\n\\n\\n\\xe2\\x80\\xaeLTR
\\n\\n\\n\\nBroken Mirror
\\n\\n\\n\\nArachnoneurology
\\n\\n\\n\\nLogic Boat
\\n\\n\\n\\nUp Goer Five
\\n\\n\\n\\nFrequentists vs. Bayesians
\\n\\n\\n\\nMath
\\n\\n\\n\\nPoll Watching
\\n\\n\\n\\nCell Number
\\n\\n\\n\\nFifty Shades
\\n\\n\\n\\nCongress
\\n\\n\\n\\nEpsilon and Zeta
\\n\\n\\n\\nObjects In Mirror
\\n\\n\\n\\nLaw of Drama
\\n\\n\\n\\nThe Universal Label
\\n\\n\\n\\nElectoral Precedent
\\n\\n\\n\\nIdentity
\\n\\n\\n\\nBlurring the Line
\\n\\n\\n\\nUndoing
\\n\\n\\n\\nMicrosoft
\\n\\n\\n\\nMy Sky
\\n\\n\\n\\nTraffic Lights
\\n\\n\\n\\nSky
\\n\\n\\n\\nMetallurgy
\\n\\n\\n\\nKilled In Action
\\n\\n\\n\\nThink Logically
\\n\\n\\n\\nPremiere
\\n\\n\\n\\nClick and Drag
\\n\\n\\n\\nRefrigerator
\\n\\n\\n\\nCautionary Ghost
\\n\\n\\n\\nSports Cheat Sheet
\\n\\n\\n\\nADD
\\n\\n\\n\\nLicense Plate
\\n\\n\\n\\nFeathers
\\n\\n\\n\\nNine
\\n\\n\\n\\nFastest-Growing
\\n\\n\\n\\nSketchiness
\\n\\n\\n\\nVows
\\n\\n\\n\\nTuesdays
\\n\\n\\n\\nStar Ratings
\\n\\n\\n\\nA Hypochondriac\\'s Nightmare
\\n\\n\\n\\nClinically Studied Ingredient
\\n\\n\\n\\nCrazy Straws
\\n\\n\\n\\nInterview
\\n\\n\\n\\nForget
\\n\\n\\n\\nMichael Phelps
\\n\\n\\n\\nCuriosity
\\n\\n\\n\\nFormal Languages
\\n\\n\\n\\nInternal Monologue
\\n\\n\\n\\nFive Years
\\n\\n\\n\\nCirith Ungol
\\n\\n\\n\\nEyelash Wish Log
\\n\\n\\n\\nContextBot
\\n\\n\\n\\nServer Problem
\\n\\n\\n\\nWriting Styles
\\n\\n\\n\\nGeology
\\n\\n\\n\\nArgument Victory
\\n\\n\\n\\nVisual Field
\\n\\n\\n\\nUnited Shapes
\\n\\n\\n\\nKnights
\\n\\n\\n\\nHome Organization
\\n\\n\\n\\nGroundhog Day
\\n\\n\\n\\nWarning
\\n\\n\\n\\nMoon Landing
\\n\\n\\n\\nWeekend
\\n\\n\\n\\nSeventies
\\n\\n\\n\\nExoplanets
\\n\\n\\n\\nWords for Small Sets
\\n\\n\\n\\nAlphabet
\\n\\n\\n\\nSwiftkey
\\n\\n\\n\\nPressures
\\n\\n\\n\\nLaundry
\\n\\n\\n\\nShoes
\\n\\n\\n\\nFront Door
\\n\\n\\n\\nKill Hitler
\\n\\n\\n\\nBudget News
\\n\\n\\n\\nEST
\\n\\n\\n\\nCrowdsourcing
\\n\\n\\n\\nBel-Air
\\n\\n\\n\\nOld-Timers
\\n\\n\\n\\nKlout
\\n\\n\\n\\nFelidae
\\n\\n\\n\\nKickstarter
\\n\\n\\n\\nThe\\xe2\\x80\\x89bacon
\\n\\n\\n\\nTen Thousand
\\n\\n\\n\\nEvery Major\\'s Terrible
\\n\\n\\n\\nVisited
\\n\\n\\n\\nForgot Algebra
\\n\\n\\n\\nBookshelf
\\n\\n\\n\\nEmotion
\\n\\n\\n\\nApproximations
\\n\\n\\n\\nSkynet
\\n\\n\\n\\nConstraints
\\n\\n\\n\\nRomney Quiz
\\n\\n\\n\\nAblogalypse
\\n\\n\\n\\nNever
\\n\\n\\n\\nWhites of Their Eyes
\\n\\n\\n\\nLakes and Oceans
\\n\\n\\n\\nRuBisCO
\\n\\n\\n\\nFountain
\\n\\n\\n\\nUmwelt
\\n\\n\\n\\nReviews
\\n\\n\\n\\nCadbury Eggs
\\n\\n\\n\\nShare Buttons
\\n\\n\\n\\nFormal Logic
\\n\\n\\n\\nNetworking
\\n\\n\\n\\ns/keyboard/leopard/
\\n\\n\\n\\nKeyed
\\n\\n\\n\\nDrawing Stars
\\n\\n\\n\\nCommunication
\\n\\n\\n\\nPickup Artist
\\n\\n\\n\\nCompare and Contrast
\\n\\n\\n\\nTumblr
\\n\\n\\n\\nError Code
\\n\\n\\n\\nLate-Night PBS
\\n\\n\\n\\nSo It Has Come To This
\\n\\n\\n\\nBusiness Plan
\\n\\n\\n\\nOrion Nebula
\\n\\n\\n\\nFirst Post
\\n\\n\\n\\nGood Cop, Dadaist Cop
\\n\\n\\n\\nBackward in Time
\\n\\n\\n\\nValentine Dilemma
\\n\\n\\n\\nKerning
\\n\\n\\n\\nCar Problems
\\n\\n\\n\\nWake Up Sheeple
\\n\\n\\n\\nWrong Superhero
\\n\\n\\n\\nBaby Names
\\n\\n\\n\\nEtymology-Man
\\n\\n\\n\\nSigh
\\n\\n\\n\\nSuckville
\\n\\n\\n\\nSustainable
\\n\\n\\n\\nSloppier Than Fiction
\\n\\n\\n\\nSOPA
\\n\\n\\n\\nBatman
\\n\\n\\n\\nAdam and Eve
\\n\\n\\n\\nGame AIs
\\n\\n\\n\\nAAAAAA
\\n\\n\\n\\n1000 Comics
\\n\\n\\n\\nCougars
\\n\\n\\n\\n2012
\\n\\n\\n\\nWait Wait
\\n\\n\\n\\nMaking Things Difficult
\\n\\n\\n\\nCoinstar
\\n\\n\\n\\nAdvent Calendar
\\n\\n\\n\\nBrand Identity
\\n\\n\\n\\nMnemonics
\\n\\n\\n\\nPhantom Menace
\\n\\n\\n\\nPlastic Bags
\\n\\n\\n\\nCryogenics
\\n\\n\\n\\nTradition
\\n\\n\\n\\nPotential
\\n\\n\\n\\nDrinking Fountains
\\n\\n\\n\\nPercentage Points
\\n\\n\\n\\nSpace Launch System
\\n\\n\\n\\nPrivacy
\\n\\n\\n\\nSet Theory
\\n\\n\\n\\nPorn Folder
\\n\\n\\n\\nMoney
\\n\\n\\n\\nWisdom of the Ancients
\\n\\n\\n\\nCitogenesis
\\n\\n\\n\\nMap Projections
\\n\\n\\n\\nSail
\\n\\n\\n\\nOcculting Telescope
\\n\\n\\n\\nThe General Problem
\\n\\n\\n\\nMTV Generation
\\n\\n\\n\\nNovember
\\n\\n\\n\\nAlternative Literature
\\n\\n\\n\\nThe Important Field
\\n\\n\\n\\nDelta-P
\\n\\n\\n\\nEverything
\\n\\n\\n\\nPrairie
\\n\\n\\n\\nJet Fuel
\\n\\n\\n\\nElements
\\n\\n\\n\\nDorm Poster
\\n\\n\\n\\nX11
\\n\\n\\n\\nThe Corliss Resolution
\\n\\n\\n\\nEternal Flame
\\n\\n\\n\\nSubliminal
\\n\\n\\n\\nCaroling
\\n\\n\\n\\nHotels
\\n\\n\\n\\nDevelopment
\\n\\n\\n\\nSharing
\\n\\n\\n\\nNeutrinos
\\n\\n\\n\\nChin-Up Bar
\\n\\n\\n\\n1 to 10
\\n\\n\\n\\nStud Finder
\\n\\n\\n\\nWorking
\\n\\n\\n\\nMystery Solved
\\n\\n\\n\\nFile Transfer
\\n\\n\\n\\nAI
\\n\\n\\n\\nInvesting
\\n\\n\\n\\nFamily Decals
\\n\\n\\n\\nI\\'m Sorry
\\n\\n\\n\\nHurricane Names
\\n\\n\\n\\nEmpirical
\\n\\n\\n\\nJuggling
\\n\\n\\n\\nDepth Perception
\\n\\n\\n\\nOversight
\\n\\n\\n\\nArrow
\\n\\n\\n\\nT-Cells
\\n\\n\\n\\nTornadoGuard
\\n\\n\\n\\nPassword Strength
\\n\\n\\n\\nMissed Connections
\\n\\n\\n\\nMac/PC
\\n\\n\\n\\nTattoo
\\n\\n\\n\\nCIA
\\n\\n\\n\\nLanes
\\n\\n\\n\\nDays of the Week
\\n\\n\\n\\nSpeculation
\\n\\n\\n\\nMimic Octopus
\\n\\n\\n\\nStandards
\\n\\n\\n\\nTime Vulture
\\n\\n\\n\\nCell Phones
\\n\\n\\n\\n3D Printer
\\n\\n\\n\\nStrunk and White
\\n\\n\\n\\nFight Club
\\n\\n\\n\\nDelivery Notification
\\n\\n\\n\\nYouTube Parties
\\n\\n\\n\\nTween Bromance
\\n\\n\\n\\nGoogle+
\\n\\n\\n\\nHofstadter
\\n\\n\\n\\nUnpickable
\\n\\n\\n\\nConnoisseur
\\n\\n\\n\\nIce
\\n\\n\\n\\nCore
\\n\\n\\n\\nManual Override
\\n\\n\\n\\nMagic School Bus
\\n\\n\\n\\nPermanence
\\n\\n\\n\\nWorst-Case Shopping
\\n\\n\\n\\nThe Cloud
\\n\\n\\n\\nAges
\\n\\n\\n\\nAdvertising Discovery
\\n\\n\\n\\nHomeownership
\\n\\n\\n\\nSports
\\n\\n\\n\\nExtended Mind
\\n\\n\\n\\nDarmok and Jalad
\\n\\n\\n\\nTemperature
\\n\\n\\n\\nReligions
\\n\\n\\n\\nNumber Line
\\n\\n\\n\\nChain of Command
\\n\\n\\n\\nElevator Inspection
\\n\\n\\n\\nMarie Curie
\\n\\n\\n\\nTeaching Physics
\\n\\n\\n\\nProgeny
\\n\\n\\n\\n65 Years
\\n\\n\\n\\nNull Hypothesis
\\n\\n\\n\\nMovie Ages
\\n\\n\\n\\nEtymology
\\n\\n\\n\\nTurtles
\\n\\n\\n\\nHeaven
\\n\\n\\n\\nFuture Timeline
\\n\\n\\n\\nCraigslist Apartments
\\n\\n\\n\\nRecycling
\\n\\n\\n\\nRogers St.
\\n\\n\\n\\nPain Rating
\\n\\n\\n\\nSignificant
\\n\\n\\n\\nProbability
\\n\\n\\n\\nHeadache
\\n\\n\\n\\nLamp
\\n\\n\\n\\nModel Rail
\\n\\n\\n\\nBeauty
\\n\\n\\n\\nTrapped
\\n\\n\\n\\n2009 Called
\\n\\n\\n\\nTime Management
\\n\\n\\n\\nFPS Mod
\\n\\n\\n\\nFairy Tales
\\n\\n\\n\\nCharity
\\n\\n\\n\\nAdvertising
\\n\\n\\n\\nServer Attention Span
\\n\\n\\n\\nNolan Chart
\\n\\n\\n\\nHerpetology
\\n\\n\\n\\nCompass and Straightedge
\\n\\n\\n\\nNanobots
\\n\\n\\n\\nFlying Cars
\\n\\n\\n\\nMajor in the Universe
\\n\\n\\n\\nLet Go
\\n\\n\\n\\nWisdom Teeth
\\n\\n\\n\\nNever Do This
\\n\\n\\n\\n(
\\n\\n\\n\\nMilk
\\n\\n\\n\\nArchimedes
\\n\\n\\n\\nTrochee Fixation
\\n\\n\\n\\n1999
\\n\\n\\n\\nLearning to Cook
\\n\\n\\n\\nConsecutive Vowels
\\n\\n\\n\\nLocal g
\\n\\n\\n\\nNa
\\n\\n\\n\\nWorld According to Americans
\\n\\n\\n\\nComplex Conjugate
\\n\\n\\n\\n3D
\\n\\n\\n\\nStingray Nebula
\\n\\n\\n\\nDental Nerve
\\n\\n\\n\\nModern History
\\n\\n\\n\\nGood Code
\\n\\n\\n\\nMisconceptions
\\n\\n\\n\\nMark
\\n\\n\\n\\nAudiophiles
\\n\\n\\n\\nSerious
\\n\\n\\n\\nExplorers
\\n\\n\\n\\nIncident
\\n\\n\\n\\nCoupon Code
\\n\\n\\n\\nSickness
\\n\\n\\n\\nTree
\\n\\n\\n\\nWikileaks
\\n\\n\\n\\nConvincing
\\n\\n\\n\\nTic-Tac-Toe
\\n\\n\\n\\nWeather Radar
\\n\\n\\n\\nGenetic Analysis
\\n\\n\\n\\nArsenic-Based Life
\\n\\n\\n\\nPositive Attitude
\\n\\n\\n\\nMy Business Idea
\\n\\n\\n\\nGuest Week: Zach Weiner (SMBC)
\\n\\n\\n\\nGuest Week: Jeffrey Rowland (Overcompensating)
\\n\\n\\n\\nGuest Week: Bill Amend (FoxTrot)
\\n\\n\\n\\nGuest Week: David Troupes (Buttercup Festival)
\\n\\n\\n\\nGuest Week: Jeph Jacques (Questionable Content)
\\n\\n\\n\\nFive-Minute Comics: Part 3
\\n\\n\\n\\nFive-Minute Comics: Part 2
\\n\\n\\n\\nFive-Minute Comics: Part 1
\\n\\n\\n\\nIllness
\\n\\n\\n\\nMutual
\\n\\n\\n\\nApplied Math
\\n\\n\\n\\nMu
\\n\\n\\n\\nDiode
\\n\\n\\n\\nOne-Liners
\\n\\n\\n\\nGlass
\\n\\n\\n\\nStarlight
\\n\\n\\n\\nConstructive
\\n\\n\\n\\nLos Alamos
\\n\\n\\n\\nThe Economic Argument
\\n\\n\\n\\nConnected
\\n\\n\\n\\nTech Support
\\n\\n\\n\\nParadise City
\\n\\n\\n\\nPumpkin Carving
\\n\\n\\n\\nAirfoil
\\n\\n\\n\\nOnline Communities 2
\\n\\n\\n\\nGolden Hammer
\\n\\n\\n\\nBeautiful Dream
\\n\\n\\n\\nStephen Hawking
\\n\\n\\n\\nAdjectives
\\n\\n\\n\\ndebian-main
\\n\\n\\n\\nBad Ex
\\n\\n\\n\\nConditional Risk
\\n\\n\\n\\nInside Joke
\\n\\n\\n\\nPhysicists
\\n\\n\\n\\nPassword Reuse
\\n\\n\\n\\nLeaving
\\n\\n\\n\\nControl
\\n\\n\\n\\nShowdown
\\n\\n\\n\\nThe Carriage
\\n\\n\\n\\nOrbiter
\\n\\n\\n\\nExoplanets
\\n\\n\\n\\nOpen Mic Night
\\n\\n\\n\\nFalling Asleep
\\n\\n\\n\\nI Don\\'t Want Directions
\\n\\n\\n\\nDesecration
\\n\\n\\n\\nAhead Stop
\\n\\n\\n\\nSample
\\n\\n\\n\\nAnxiety
\\n\\n\\n\\nScheduling
\\n\\n\\n\\nPore Strips
\\n\\n\\n\\nStill No Sleep
\\n\\n\\n\\nSavannah Ancestry
\\n\\n\\n\\nAtheists
\\n\\n\\n\\nUniversity Website
\\n\\n\\n\\nFrogger
\\n\\n\\n\\nPeriod Speech
\\n\\n\\n\\nAll the Girls
\\n\\n\\n\\nWar
\\n\\n\\n\\n1996
\\n\\n\\n\\nTemper
\\n\\n\\n\\nGreen Flash
\\n\\n\\n\\nDilution
\\n\\n\\n\\nOne Two
\\n\\n\\n\\nWorkaround
\\n\\n\\n\\nAnalogies
\\n\\n\\n\\nDFS
\\n\\n\\n\\nMoria
\\n\\n\\n\\n3x9
\\n\\n\\n\\nRaptor Fences
\\n\\n\\n\\nToot
\\n\\n\\n\\nPublic Opinion
\\n\\n\\n\\nInterdisciplinary
\\n\\n\\n\\nDependencies
\\n\\n\\n\\nSouthern Half
\\n\\n\\n\\nPhobia
\\n\\n\\n\\nSwimsuit Issue
\\n\\n\\n\\nBook Burning
\\n\\n\\n\\nStudy
\\n\\n\\n\\nWorst-Case Scenario
\\n\\n\\n\\nGeeks and Nerds
\\n\\n\\n\\nBirth
\\n\\n\\n\\nDyslexics
\\n\\n\\n\\nWalkthrough
\\n\\n\\n\\nInfrastructures
\\n\\n\\n\\nCampfire
\\n\\n\\n\\nBlogging
\\n\\n\\n\\nThe Tell-Tale Beat
\\n\\n\\n\\nMalamanteau
\\n\\n\\n\\nIncision
\\n\\n\\n\\nYogurt
\\n\\n\\n\\nCemetery
\\n\\n\\n\\nFloor
\\n\\n\\n\\nOutbreak
\\n\\n\\n\\nEagle
\\n\\n\\n\\nHDTV
\\n\\n\\n\\nDesert Island
\\n\\n\\n\\nCircuit Diagram
\\n\\n\\n\\nLaser Pointer
\\n\\n\\n\\niPad
\\n\\n\\n\\nTrade Expert
\\n\\n\\n\\nSeat Selection
\\n\\n\\n\\nLiterally
\\n\\n\\n\\nHell
\\n\\n\\n\\nSeismic Waves
\\n\\n\\n\\nComputer Problems
\\n\\n\\n\\nFlatland
\\n\\n\\n\\nRecipes
\\n\\n\\n\\nBrain Worms
\\n\\n\\n\\nThe Flake Equation
\\n\\n\\n\\nFurtive
\\n\\n\\n\\nTime Machine
\\n\\n\\n\\nNumbers
\\n\\n\\n\\nPorn For Women
\\n\\n\\n\\nGeoIP
\\n\\n\\n\\nSingle Ladies
\\n\\n\\n\\nSeismograph
\\n\\n\\n\\nCollatz Conjecture
\\n\\n\\n\\nI Am
\\n\\n\\n\\nSex Dice
\\n\\n\\n\\nJoshing
\\n\\n\\n\\nFreedom
\\n\\n\\n\\nDevotion to Duty
\\n\\n\\n\\nPrinciple of Explosion
\\n\\n\\n\\nHonor Societies
\\n\\n\\n\\nSnow Tracking
\\n\\n\\n\\nScience Valentine
\\n\\n\\n\\nComplexion
\\n\\n\\n\\nTrimester
\\n\\n\\n\\nYou Hang Up First
\\n\\n\\n\\nTensile vs. Shear Strength
\\n\\n\\n\\nStrip Games
\\n\\n\\n\\nSpirit
\\n\\n\\n\\nRetro Virus
\\n\\n\\n\\nChildren\\'s Fantasy
\\n\\n\\n\\nDirty Harry
\\n\\n\\n\\nMicroSD
\\n\\n\\n\\nSemicontrolled Demolition
\\n\\n\\n\\nFIRST Design
\\n\\n\\n\\nSelf-Description
\\n\\n\\n\\nDimensional Analysis
\\n\\n\\n\\nAdmin Mourning
\\n\\n\\n\\nG-Spot
\\n\\n\\n\\nWe Get It
\\n\\n\\n\\nScience Montage
\\n\\n\\n\\nForce
\\n\\n\\n\\nGravity Wells
\\n\\n\\n\\nDecember 25th
\\n\\n\\n\\nChristmas Plans
\\n\\n\\n\\nResearcher Translation
\\n\\n\\n\\nAsshole
\\n\\n\\n\\nAbstraction
\\n\\n\\n\\nRevolutionary
\\n\\n\\n\\nNatural Parenting
\\n\\n\\n\\nThe Sun
\\n\\n\\n\\nSuggestions
\\n\\n\\n\\nStephen and Me
\\n\\n\\n\\nSpinal Tap Amps
\\n\\n\\n\\nExperiment
\\n\\n\\n\\nPandora
\\n\\n\\n\\nSkiFree
\\n\\n\\n\\nSilent Hammer
\\n\\n\\n\\nPrudence
\\n\\n\\n\\nAcademia vs. Business
\\n\\n\\n\\nSagan-Man
\\n\\n\\n\\niPhone or Droid
\\n\\n\\n\\nTwo-Party System
\\n\\n\\n\\nSympathy
\\n\\n\\n\\nLego
\\n\\n\\n\\nOrbitals
\\n\\n\\n\\nMovie Narrative Charts
\\n\\n\\n\\nOctober 30th
\\n\\n\\n\\nClimbing
\\n\\n\\n\\nNachos
\\n\\n\\n\\nSo Bad It\\'s Worse
\\n\\n\\n\\nMore Accurate
\\n\\n\\n\\nBag Check
\\n\\n\\n\\nNowhere
\\n\\n\\n\\nStatic
\\n\\n\\n\\nFall Foliage
\\n\\n\\n\\nScary
\\n\\n\\n\\nConversations
\\n\\n\\n\\nRPS
\\n\\n\\n\\nSurgery
\\n\\n\\n\\nOhm
\\n\\n\\n\\nCreepy
\\n\\n\\n\\nFree
\\n\\n\\n\\nTornado Hunter
\\n\\n\\n\\nLincoln-Douglas
\\n\\n\\n\\nThe Search
\\n\\n\\n\\nScribblenauts
\\n\\n\\n\\nBrontosaurus
\\n\\n\\n\\nLocke and Demosthenes
\\n\\n\\n\\nDate
\\n\\n\\n\\nBlockbuster Mining
\\n\\n\\n\\nSuspicion
\\n\\n\\n\\nAnatomy Text
\\n\\n\\n\\nTime Travel
\\n\\n\\n\\nSkins
\\n\\n\\n\\nPsychic
\\n\\n\\n\\nTech Support Cheat Sheet
\\n\\n\\n\\nNewton and Leibniz
\\n\\n\\n\\nCollections
\\n\\n\\n\\nBranding
\\n\\n\\n\\nOregon
\\n\\n\\n\\nHaiku Proof
\\n\\n\\n\\nSuperlative
\\n\\n\\n\\nWings
\\n\\n\\n\\nSupported Features
\\n\\n\\n\\nAsteroid
\\n\\n\\n\\nUnderstocked
\\n\\n\\n\\nLease
\\n\\n\\n\\nAvoidance
\\n\\n\\n\\nWoodpecker
\\n\\n\\n\\nThreesome
\\n\\n\\n\\nEstimation
\\n\\n\\n\\nDisaster Voyeurism
\\n\\n\\n\\nSheeple
\\n\\n\\n\\nTab Explosion
\\n\\n\\n\\nForm
\\n\\n\\n\\n2038
\\n\\n\\n\\nCutting Edge
\\n\\n\\n\\nExtrapolating
\\n\\n\\n\\nQwertial Aphasia
\\n\\n\\n\\nIdiocracy
\\n\\n\\n\\nOverstimulated
\\n\\n\\n\\nGame Theory
\\n\\n\\n\\nAndroid Boyfriend
\\n\\n\\n\\nApocalypse
\\n\\n\\n\\nPorn
\\n\\n\\n\\nAddiction
\\n\\n\\n\\nLatitude
\\n\\n\\n\\nAndroid Girlfriend
\\n\\n\\n\\nPeriod
\\n\\n\\n\\nVoynich Manuscript
\\n\\n\\n\\nDrama
\\n\\n\\n\\nTroll Slayer
\\n\\n\\n\\nPapyrus
\\n\\n\\n\\nDesignated Drivers
\\n\\n\\n\\nPep Rally
\\n\\n\\n\\nCrime Scene
\\n\\n\\n\\nMission to Culture
\\n\\n\\n\\nOutreach
\\n\\n\\n\\nUnsatisfied
\\n\\n\\n\\nCNR
\\n\\n\\n\\nBrakes
\\n\\n\\n\\nThe Race: Part 5
\\n\\n\\n\\nThe Race: Part 4
\\n\\n\\n\\nThe Race: Part 3
\\n\\n\\n\\nThe Race: Part 2
\\n\\n\\n\\nThe Race: Part 1
\\n\\n\\n\\nPackages
\\n\\n\\n\\nTag Combination
\\n\\n\\n\\nSwine Flu
\\n\\n\\n\\nParental Trolling
\\n\\n\\n\\nTogether
\\n\\n\\n\\nCan\\'t Sleep
\\n\\n\\n\\nNew Car
\\n\\n\\n\\nBorders
\\n\\n\\n\\nWell 2
\\n\\n\\n\\nUrgent Mission
\\n\\n\\n\\nMatrix Revisited
\\n\\n\\n\\nSecurity Question
\\n\\n\\n\\nCrossbows
\\n\\n\\n\\nFermirotica
\\n\\n\\n\\nParking
\\n\\n\\n\\nWell
\\n\\n\\n\\nLithium Batteries
\\n\\n\\n\\nNo Pun Intended
\\n\\n\\n\\n1000 Times
\\n\\n\\n\\nStudents
\\n\\n\\n\\nAlternative Energy Revolution
\\n\\n\\n\\nTwo Mirrors
\\n\\n\\n\\nNot Enough Work
\\n\\n\\n\\nPirate Bay
\\n\\n\\n\\nCorrelation
\\n\\n\\n\\nEtch-a-Sketch
\\n\\n\\n\\nDensity
\\n\\n\\n\\nWestley\\'s a Dick
\\n\\n\\n\\nKindle
\\n\\n\\n\\nSimple
\\n\\n\\n\\nMusic DRM
\\n\\n\\n\\nNeutrality Schmeutrality
\\n\\n\\n\\nPep Talk
\\n\\n\\n\\nSierpinski Valentine
\\n\\n\\n\\nCover-Up
\\n\\n\\n\\nTED Talk
\\n\\n\\n\\nBase System
\\n\\n\\n\\nBoyfriend
\\n\\n\\n\\nSecurity
\\n\\n\\n\\nDucklings
\\n\\n\\n\\nSpace Elevators
\\n\\n\\n\\nIt Might Be Cool
\\n\\n\\n\\nGenetic Algorithms
\\n\\n\\n\\nLaptop Hell
\\n\\n\\n\\nPiano
\\n\\n\\n\\nContingency Plan
\\n\\n\\n\\nI\\'m An Idiot
\\n\\n\\n\\nSledding Discussion
\\n\\n\\n\\nWindows 7
\\n\\n\\n\\nKeynote
\\n\\n\\n\\nConverting to Metric
\\n\\n\\n\\nI Know You\\'re Listening
\\n\\n\\n\\nParty
\\n\\n\\n\\nDecline
\\n\\n\\n\\nGoogle Trends
\\n\\n\\n\\n2008 Christmas Special
\\n\\n\\n\\nCuttlefish
\\n\\n\\n\\n11th Grade
\\n\\n\\n\\nFlow Charts
\\n\\n\\n\\nMarshmallow Gun
\\n\\n\\n\\nWood Chips
\\n\\n\\n\\nNo One Must Know
\\n\\n\\n\\nSimultaneous
\\n\\n\\n\\nFriends
\\n\\n\\n\\nAlternate Currency
\\n\\n\\n\\nSleet
\\n\\n\\n\\nEgg Drop Failure
\\n\\n\\n\\nInduced Current
\\n\\n\\n\\nDrapes
\\n\\n\\n\\nExperimentation
\\n\\n\\n\\nTheft of the Magi
\\n\\n\\n\\nA Bunch of Rocks
\\n\\n\\n\\nLegal Hacks
\\n\\n\\n\\nTerminology
\\n\\n\\n\\nDark Flow
\\n\\n\\n\\nFaust 2.0
\\n\\n\\n\\nElection
\\n\\n\\n\\nScantron
\\n\\n\\n\\nSecretary: Part 5
\\n\\n\\n\\nSecretary: Part 4
\\n\\n\\n\\nSecretary: Part 3
\\n\\n\\n\\nSecretary: Part 2
\\n\\n\\n\\nSecretary: Part 1
\\n\\n\\n\\nActuarial
\\n\\n\\n\\nScrabble
\\n\\n\\n\\nTwitter
\\n\\n\\n\\nMorning Routine
\\n\\n\\n\\nGoing West
\\n\\n\\n\\nSteal This Comic
\\n\\n\\n\\nNumerical Sex Positions
\\n\\n\\n\\nI am Not a Ninja
\\n\\n\\n\\nDepth
\\n\\n\\n\\nFlash Games
\\n\\n\\n\\nFiction Rule of Thumb
\\n\\n\\n\\nHeight
\\n\\n\\n\\nListen to Yourself
\\n\\n\\n\\nSpore
\\n\\n\\n\\nTones
\\n\\n\\n\\nThe Staple Madness
\\n\\n\\n\\nTypewriter
\\n\\n\\n\\nOne-Sided
\\n\\n\\n\\nFurther Boomerang Difficulties
\\n\\n\\n\\nTurn-On
\\n\\n\\n\\nStill Raw
\\n\\n\\n\\nHouse of Pancakes
\\n\\n\\n\\nAversion Fads
\\n\\n\\n\\nThe End is Not for a While
\\n\\n\\n\\nImprovised
\\n\\n\\n\\nFetishes
\\n\\n\\n\\nX Girls Y Cups
\\n\\n\\n\\nMoving
\\n\\n\\n\\nQuantum Teleportation
\\n\\n\\n\\nRBA
\\n\\n\\n\\nVoting Machines
\\n\\n\\n\\nFreemanic Paracusia
\\n\\n\\n\\nGoogle Maps
\\n\\n\\n\\nPaleontology
\\n\\n\\n\\nHoly Ghost
\\n\\n\\n\\nRegrets
\\n\\n\\n\\nFrustration
\\n\\n\\n\\nCautionary
\\n\\n\\n\\nHats
\\n\\n\\n\\nRewiring
\\n\\n\\n\\nUpcoming Hurricanes
\\n\\n\\n\\nMission
\\n\\n\\n\\nImpostor
\\n\\n\\n\\nThe Sea
\\n\\n\\n\\nThings Fall Apart
\\n\\n\\n\\nGood Morning
\\n\\n\\n\\nToo Old For This Shit
\\n\\n\\n\\nIn Popular Culture
\\n\\n\\n\\nI Am Not Good with Boomerangs
\\n\\n\\n\\nMacgyver Gets Lazy
\\n\\n\\n\\nKnow Your Vines
\\n\\n\\n\\nxkcd Loves the Discovery Channel
\\n\\n\\n\\nBabies
\\n\\n\\n\\nRoad Rage
\\n\\n\\n\\nThinking Ahead
\\n\\n\\n\\nInternet Argument
\\n\\n\\n\\nSUV
\\n\\n\\n\\nHow it Happened
\\n\\n\\n\\nPurity
\\n\\n\\n\\nxkcd Goes to the Airport
\\n\\n\\n\\nJournal 5
\\n\\n\\n\\nJournal 4
\\n\\n\\n\\nDelivery
\\n\\n\\n\\nEvery Damn Morning
\\n\\n\\n\\nFantasy
\\n\\n\\n\\nStarwatching
\\n\\n\\n\\nBad Timing
\\n\\n\\n\\nGeohashing
\\n\\n\\n\\nFortune Cookies
\\n\\n\\n\\nSecurity Holes
\\n\\n\\n\\nFinish Line
\\n\\n\\n\\nA Better Idea
\\n\\n\\n\\nMaking Hash Browns
\\n\\n\\n\\nJealousy
\\n\\n\\n\\nForks and Spoons
\\n\\n\\n\\nStove Ownership
\\n\\n\\n\\nThe Man Who Fell Sideways
\\n\\n\\n\\nZealous Autoconfig
\\n\\n\\n\\nRestraining Order
\\n\\n\\n\\nMistranslations
\\n\\n\\n\\nNew Pet
\\n\\n\\n\\nStartled
\\n\\n\\n\\nTechno
\\n\\n\\n\\nMath Paper
\\n\\n\\n\\nElectric Skateboard (Double Comic)
\\n\\n\\n\\nOverqualified
\\n\\n\\n\\nCheap GPS
\\n\\n\\n\\nVenting
\\n\\n\\n\\nJournal 3
\\n\\n\\n\\n\\n\\nConvincing Pickup Line
\\n\\n\\n\\n1,000 Miles North
\\n\\n\\n\\nLarge Hadron Collider
\\n\\n\\n\\nImportant Life Lesson
\\n\\n\\n\\nTravelling Salesman Problem
\\n\\n\\n\\nTap That Ass
\\n\\n\\n\\nUnscientific
\\n\\n\\n\\nThe Ring
\\n\\n\\n\\nMorning
\\n\\n\\n\\nKilobyte
\\n\\n\\n\\nUltimate Game
\\n\\n\\n\\nMaking Rules
\\n\\n\\n\\nAnti-Mindvirus
\\n\\n\\n\\nNightmares
\\n\\n\\n\\nKeeping Time
\\n\\n\\n\\nFuck Grapefruit
\\n\\n\\n\\nAdvanced Technology
\\n\\n\\n\\nDuty Calls
\\n\\n\\n\\nHow it Works
\\n\\n\\n\\nThe Drake Equation
\\n\\n\\n\\nHelping
\\n\\n\\n\\nTrebuchet
\\n\\n\\n\\nMobius Battle
\\n\\n\\n\\nEmoticon
\\n\\n\\n\\nForgetting
\\n\\n\\n\\nReal Programmers
\\n\\n\\n\\nJournal 2
\\n\\n\\n\\nBug
\\n\\n\\n\\nPod Bay Doors
\\n\\n\\n\\nJournal
\\n\\n\\n\\nThe Data So Far
\\n\\n\\n\\nTo Be Wanted
\\n\\n\\n\\nCompiler Complaint
\\n\\n\\n\\nRedwall
\\n\\n\\n\\nDangers
\\n\\n\\n\\nBass
\\n\\n\\n\\nFandom
\\n\\n\\n\\nYour Mom
\\n\\n\\n\\nSlides
\\n\\n\\n\\nResponsible Behavior
\\n\\n\\n\\nReset
\\n\\n\\n\\nBlade Runner
\\n\\n\\n\\nChristmas Back Home
\\n\\n\\n\\nWriters Strike
\\n\\n\\n\\nRock Band
\\n\\n\\n\\nLoud Party
\\n\\n\\n\\nFlies
\\n\\n\\n\\nNerd Sniping
\\n\\n\\n\\nCouple
\\n\\n\\n\\nStartling
\\n\\n\\n\\nPython
\\n\\n\\n\\nFar Away
\\n\\n\\n\\nTrolling
\\n\\n\\n\\nNetwork
\\n\\n\\n\\nSuccess
\\n\\n\\n\\nClose to You
\\n\\n\\n\\nBrick Archway
\\n\\n\\n\\nDiet Coke+Mentos
\\n\\n\\n\\n1337: Part 5
\\n\\n\\n\\n1337: Part 4
\\n\\n\\n\\n1337: Part 3
\\n\\n\\n\\n1337: Part 2
\\n\\n\\n\\n1337: Part 1
\\n\\n\\n\\nFight
\\n\\n\\n\\nClassic
\\n\\n\\n\\nFuture
\\n\\n\\n\\nPost Office Showdown
\\n\\n\\n\\nPriorities
\\n\\n\\n\\nMattress
\\n\\n\\n\\nWasteland
\\n\\n\\n\\nGetting Out of Hand
\\n\\n\\n\\nGyroscopes
\\n\\n\\n\\nPhotoshops
\\n\\n\\n\\nIndecision
\\n\\n\\n\\nTuring Test
\\n\\n\\n\\nEggs
\\n\\n\\n\\nExploits of a Mom
\\n\\n\\n\\nEffect an Effect
\\n\\n\\n\\nA-Minus-Minus
\\n\\n\\n\\nTapping
\\n\\n\\n\\nBallmer Peak
\\n\\n\\n\\nPix Plz
\\n\\n\\n\\nThighs
\\n\\n\\n\\n28-Hour Day
\\n\\n\\n\\nEngineering Hubris
\\n\\n\\n\\nNostalgia
\\n\\n\\n\\nThat Lovin\\' Feelin\\'
\\n\\n\\n\\nLoud Sex
\\n\\n\\n\\nBraille
\\n\\n\\n\\nDating Pools
\\n\\n\\n\\nInsomnia
\\n\\n\\n\\nWith Apologies to Robert Frost
\\n\\n\\n\\nAction Movies
\\n\\n\\n\\nCommitment
\\n\\n\\n\\nShopping Teams
\\n\\n\\n\\nInteresting Life
\\n\\n\\n\\nExcessive Quotation
\\n\\n\\n\\nOrphaned Projects
\\n\\n\\n\\nRule 34
\\n\\n\\n\\nNighttime Stories
\\n\\n\\n\\nCompiling
\\n\\n\\n\\nNames
\\n\\n\\n\\nLimerick
\\n\\n\\n\\nFacebook
\\n\\n\\n\\nAeris Dies
\\n\\n\\n\\nTesla Coil
\\n\\n\\n\\nLisp Cycles
\\n\\n\\n\\nTony Hawk
\\n\\n\\n\\nDNE
\\n\\n\\n\\nBookstore
\\n\\n\\n\\nRTFM
\\n\\n\\n\\ngoto
\\n\\n\\n\\nDignified
\\n\\n\\n\\nFucking Blue Shells
\\n\\n\\n\\nAlone
\\n\\n\\n\\nElevator
\\n\\n\\n\\nNP-Complete
\\n\\n\\n\\nAll Your Base
\\n\\n\\n\\nWikipedian Protester
\\n\\n\\n\\nTape Measure
\\n\\n\\n\\nProjection
\\n\\n\\n\\nOrganic Fuel
\\n\\n\\n\\nOnline Package Tracking
\\n\\n\\n\\nLibrarians
\\n\\n\\n\\nPickup Lines
\\n\\n\\n\\nBlack Hat Support
\\n\\n\\n\\nLong Light
\\n\\n\\n\\nFixed Width
\\n\\n\\n\\nThoughts
\\n\\n\\n\\nWith Apologies to The Who
\\n\\n\\n\\nElectromagnetic Spectrum
\\n\\n\\n\\nLinux User at Best Buy
\\n\\n\\n\\nPowers of One
\\n\\n\\n\\nMerlin
\\n\\n\\n\\nTCMP
\\n\\n\\n\\nChoices: Part 5
\\n\\n\\n\\nChoices: Part 4
\\n\\n\\n\\nChoices: Part 3
\\n\\n\\n\\nChoices: Part 2
\\n\\n\\n\\nChoices: Part 1
\\n\\n\\n\\nCertainty
\\n\\n\\n\\nIN UR REALITY
\\n\\n\\n\\nRegarding Mussolini
\\n\\n\\n\\nThe Glass Necklace
\\n\\n\\n\\nClichéd Exchanges
\\n\\n\\n\\nConspiracy Theories
\\n\\n\\n\\nCode Talkers
\\n\\n\\n\\nOnline Communities
\\n\\n\\n\\nSubjectivity
\\n\\n\\n\\nComic Fragment
\\n\\n\\n\\nHighway Engineer Pranks
\\n\\n\\n\\nEscalators
\\n\\n\\n\\nCD Tray Fight
\\n\\n\\n\\nSnopes
\\n\\n\\n\\nChess Photo
\\n\\n\\n\\nHypotheticals
\\n\\n\\n\\nFactoring the Time
\\n\\n\\n\\nLabyrinth Puzzle
\\n\\n\\n\\nFloor Tiles
\\n\\n\\n\\nTabletop Roleplaying
\\n\\n\\n\\nAppropriate Term
\\n\\n\\n\\nThe Difference
\\n\\n\\n\\nBattle Room
\\n\\n\\n\\nDream Girl
\\n\\n\\n\\nBlagofaire
\\n\\n\\n\\nPet Peeve #114
\\n\\n\\n\\nKeyboards are Disgusting
\\n\\n\\n\\nCollecting Double-Takes
\\n\\n\\n\\nKite
\\n\\n\\n\\nEscape Artist
\\n\\n\\n\\nA New CAPTCHA Approach
\\n\\n\\n\\nChess Enlightenment
\\n\\n\\n\\nCat Proximity
\\n\\n\\n\\nHamiltonian
\\n\\n\\n\\nGraffiti
\\n\\n\\n\\nResonance
\\n\\n\\n\\nColor Codes
\\n\\n\\n\\nSwingset
\\n\\n\\n\\nOpen Source
\\n\\n\\n\\nLisp
\\n\\n\\n\\nValentine\\'s Day
\\n\\n\\n\\nSmall Talk
\\n\\n\\n\\nRandom Number
\\n\\n\\n\\nPhilosophy
\\n\\n\\n\\nBlanket Fort
\\n\\n\\n\\nNintendo Surgeon
\\n\\n\\n\\ne to the pi Minus pi
\\n\\n\\n\\nRomantic Drama Equation
\\n\\n\\n\\nLetting Go
\\n\\n\\n\\nThe Problem with Wikipedia
\\n\\n\\n\\nGhostbusters Marathon
\\n\\n\\n\\nBrain
\\n\\n\\n\\nHamster Ball Heist
\\n\\n\\n\\n90\\'s Flowchart
\\n\\n\\n\\nKayak
\\n\\n\\n\\nRegular Expressions
\\n\\n\\n\\nWhat xkcd Means
\\n\\n\\n\\nReno Rhymes
\\n\\n\\n\\nCandy Button Paper
\\n\\n\\n\\nAmerica
\\n\\n\\n\\nHallucinations
\\n\\n\\n\\nYouTube
\\n\\n\\n\\nChristmas GPS
\\n\\n\\n\\nBill Nye
\\n\\n\\n\\nRight-Hand Rule
\\n\\n\\n\\nPerspective
\\n\\n\\n\\nNinja Turtles
\\n\\n\\n\\nCommand Line Fu
\\n\\n\\n\\nMap of the Internet
\\n\\n\\n\\nPenises
\\n\\n\\n\\nThe Perfect Sound
\\n\\n\\n\\nWorking for Google
\\n\\n\\n\\nLojban
\\n\\n\\n\\nIPoD
\\n\\n\\n\\nExercise
\\n\\n\\n\\nReload
\\n\\n\\n\\nThe Familiar
\\n\\n\\n\\nConsole Lines
\\n\\n\\n\\nWikifriends
\\n\\n\\n\\nMatrix Transform
\\n\\n\\n\\nSnacktime Rules
\\n\\n\\n\\nNash
\\n\\n\\n\\nInterblag
\\n\\n\\n\\nCanada
\\n\\n\\n\\ne to the pi times i
\\n\\n\\n\\nNot Really Into Pokemon
\\n\\n\\n\\nAlice and Bob
\\n\\n\\n\\nBefore Sunrise
\\n\\n\\n\\nAutomatic Doors
\\n\\n\\n\\nThat\\'s What SHE Said
\\n\\n\\n\\nMovie Seating
\\n\\n\\n\\nSkateboarding is Not a Crime
\\n\\n\\n\\nString Theory
\\n\\n\\n\\nTurn Back
\\n\\n\\n\\nWords that End in GRY
\\n\\n\\n\\nReverse Euphemisms
\\n\\n\\n\\nNihilism
\\n\\n\\n\\nMisusing Slang
\\n\\n\\n\\nTurn Signals
\\n\\n\\n\\nPlaying Devil\\'s Advocate to Win
\\n\\n\\n\\nDonald Knuth
\\n\\n\\n\\nAngular Momentum
\\n\\n\\n\\nAccident
\\n\\n\\n\\nPenny Arcade Parody
\\n\\n\\n\\nBoombox
\\n\\n\\n\\nSix Months
\\n\\n\\n\\nFiller Art
\\n\\n\\n\\nCommented
\\n\\n\\n\\nSearch History
\\n\\n\\n\\nBeliefs
\\n\\n\\n\\nCryptography
\\n\\n\\n\\nHamster Ball
\\n\\n\\n\\nMario
\\n\\n\\n\\nGrownups
\\n\\n\\n\\nSandwich
\\n\\n\\n\\nMispronouncing
\\n\\n\\n\\nA Way So Familiar
\\n\\n\\n\\nJoin Myspace
\\n\\n\\n\\nParody Week: Dinosaur Comics
\\n\\n\\n\\nParody Week: A Softer World
\\n\\n\\n\\nParody Week: TFD and Natalie Dee
\\n\\n\\n\\nParody Week: Megatokyo
\\n\\n\\n\\nParody Week: Achewood
\\n\\n\\n\\nDelicious
\\n\\n\\n\\nI Have Owned Two Electric Skateboards
\\n\\n\\n\\nPointers
\\n\\n\\n\\nDreams
\\n\\n\\n\\nScience Fair
\\n\\n\\n\\nSubstitute
\\n\\n\\n\\nMyspace
\\n\\n\\n\\nThe Raven
\\n\\n\\n\\nMusic Knowledge
\\n\\n\\n\\nFans
\\n\\n\\n\\nJulia Stiles
\\n\\n\\n\\nContent Protection
\\n\\n\\n\\ndPain over dt
\\n\\n\\n\\nThe Fast and the Furious
\\n\\n\\n\\nRed Spiders Cometh
\\n\\n\\n\\nMarketing Interview
\\n\\n\\n\\nBlogofractal
\\n\\n\\n\\nCentrifugal Force
\\n\\n\\n\\nQuirky Girls
\\n\\n\\n\\nBalloon
\\n\\n\\n\\nDating Service
\\n\\n\\n\\nWorst Band Name Ever
\\n\\n\\n\\n50 Ways
\\n\\n\\n\\nPong
\\n\\n\\n\\nCity
\\n\\n\\n\\nMeerkat
\\n\\n\\n\\nComputational Linguists
\\n\\n\\n\\nRiemann-Zeta
\\n\\n\\n\\nBaring My Heart
\\n\\n\\n\\nFirefox and Witchcraft - The Connection?
\\n\\n\\n\\nClark Gable
\\n\\n\\n\\nSpoiler Alert
\\n\\n\\n\\nM.C. Hammer Slide
\\n\\n\\n\\nSnakes on a Plane! 2
\\n\\n\\n\\nWright Brothers
\\n\\n\\n\\nParallel Universe
\\n\\n\\n\\nFind You
\\n\\n\\n\\nMoral Relativity
\\n\\n\\n\\nBack to the Future
\\n\\n\\n\\nLaser Scope
\\n\\n\\n\\nFamily Circus
\\n\\n\\n\\nBinary Heart
\\n\\n\\n\\nFall Apart
\\n\\n\\n\\nA Simple Plan
\\n\\n\\n\\nMail
\\n\\n\\n\\nThe Sierpinski Penis Game
\\n\\n\\n\\nProfile Creation Flowchart
\\n\\n\\n\\nJeremy Irons
\\n\\n\\n\\nSunrise
\\n\\n\\n\\nPwned
\\n\\n\\n\\nJacket
\\n\\n\\n\\nGravitational Mass
\\n\\n\\n\\nEscher Bracelet
\\n\\n\\n\\nVelociraptors
\\n\\n\\n\\nDigital Rights Management
\\n\\n\\n\\nPaths
\\n\\n\\n\\nNational Language
\\n\\n\\n\\nKatamari
\\n\\n\\n\\nFrame
\\n\\n\\n\\nAttention, shopper
\\n\\n\\n\\nMy Other Car
\\n\\n\\n\\nIambic Pentameter
\\n\\n\\n\\nGarfield
\\n\\n\\n\\nBored with the Internet
\\n\\n\\n\\nFamiliar
\\n\\n\\n\\nCurse Levels
\\n\\n\\n\\nSu Doku
\\n\\n\\n\\nZeppelin
\\n\\n\\n\\nClasshole
\\n\\n\\n\\nIn the Trees
\\n\\n\\n\\nGuitar Hero
\\n\\n\\n\\nPillow Talk
\\n\\n\\n\\nFive Thirty
\\n\\n\\n\\nNerd Girls
\\n\\n\\n\\nAbusive Astronomy
\\n\\n\\n\\nBanter
\\n\\n\\n\\nSolar Plexus
\\n\\n\\n\\nValentine - Heart
\\n\\n\\n\\nValentine - Karnaugh
\\n\\n\\n\\nStacey\\'s Dad
\\n\\n\\n\\nSuper Bowl
\\n\\n\\n\\nGraduation
\\n\\n\\n\\nWhy Do You Love Me?
\\n\\n\\n\\nWait For Me
\\n\\n\\n\\nThe Cure
\\n\\n\\n\\nUseless
\\n\\n\\n\\nScience
\\n\\n\\n\\nHobby
\\n\\n\\n\\nSecret Worlds
\\n\\n\\n\\nMalaria
\\n\\n\\n\\nPenny Arcade
\\n\\n\\n\\nWant
\\n\\n\\n\\nFound
\\n\\n\\n\\nCounter-Red Spiders
\\n\\n\\n\\nSecrets
\\n\\n\\n\\nSchrodinger
\\n\\n\\n\\nLove
\\n\\n\\n\\nRed Spiders 2
\\n\\n\\n\\nGeico
\\n\\n\\n\\nOld Drawing
\\n\\n\\n\\nLight
\\n\\n\\n\\nBowl
\\n\\n\\n\\nApple Jacks
\\n\\n\\n\\nHyphen
\\n\\n\\n\\nScientists
\\n\\n\\n\\nSheep
\\n\\n\\n\\nFlowers
\\n\\n\\n\\nSelf-reference
\\n\\n\\n\\nPillar
\\n\\n\\n\\nBarrel - Part 5
\\n\\n\\n\\nDonner
\\n\\n\\n\\nHitler
\\n\\n\\n\\nElefino
\\n\\n\\n\\nMeat Cereals
\\n\\n\\n\\nFourier
\\n\\n\\n\\nBarrel - Part 4
\\n\\n\\n\\nGodel, Escher, Kurt Halsey
\\n\\n\\n\\nT-shirts
\\n\\n\\n\\nBarrel - Part 3
\\n\\n\\n\\nKepler
\\n\\n\\n\\nFerret
\\n\\n\\n\\nGeorge Clinton
\\n\\n\\n\\nSnapple
\\n\\n\\n\\nWhat If
\\n\\n\\n\\nMonty Python -- Enough
\\n\\n\\n\\nJust Alerting You
\\n\\n\\n\\nCopyright
\\n\\n\\n\\nCanyon
\\n\\n\\n\\nPoisson
\\n\\n\\n\\nBarrel - Part 2
\\n\\n\\n\\nPi Equals
\\n\\n\\n\\nSerenity is coming out tomorrow
\\n\\n\\n\\nRed spiders
\\n\\n\\n\\nGirl sleeping (Sketch -- 11th grade Spanish class)
\\n\\n\\n\\nIrony
\\n\\n\\n\\nBlown apart
\\n\\n\\n\\nLandscape (sketch)
\\n\\n\\n\\nIsland (sketch)
\\n\\n\\n\\nPetit Trees (sketch)
\\n\\n\\n\\nBarrel - Part 1
\\n\\n\\n
\\n
\\n\"Selected\\n\\n\"Grownups\"/\\n\"Circuit\\n\"Angular\\n\"Self-Description\"/\\n\"Alternative\\n\\n
\\n\\nRSS Feed - Atom Feed\\n
\\n
\\n\\n
\\n
\\nOther things:
\\n Women Also Know Stuff,\\n Tech Solidarity\\n
\\n
\\n
\\n
xkcd.com is best viewed with Netscape Navigator 4.0 or below on a Pentium 3±1 emulated in Javascript on an Apple IIGS at a screen resolution of 1024x1. Please enable your ad blockers, disable high-heat drying, and remove your device from Airplane Mode and set it to Boat Mode. For security reasons, please leave caps lock on while browsing.
\\n
\\n
\\n

\\nThis work is licensed under a\\nCreative Commons Attribution-NonCommercial 2.5 License.\\n

\\nThis means you\\'re free to copy and share these comics (but not to sell them). More details.

\\n
\\n
\\n\\n\\n\\n'" 2 | XKCD_ARCHIVE_JSON="{\"1550\": {\"date-published\": \"2015-7-13\", \"description\": \"Episode VII\"}, \"1654\": {\"date-published\": \"2016-3-11\", \"description\": \"Universal Install Script\"}, \"1230\": {\"date-published\": \"2013-6-26\", \"description\": \"Polar/Cartesian\"}, \"837\": {\"date-published\": \"2010-12-22\", \"description\": \"Coupon Code\"}, \"1160\": {\"date-published\": \"2013-1-14\", \"description\": \"Drop Those Pounds\"}, \"340\": {\"date-published\": \"2007-11-9\", \"description\": \"Fight\"}, \"1374\": {\"date-published\": \"2014-5-28\", \"description\": \"Urn\"}, \"78\": {\"date-published\": \"2006-3-20\", \"description\": \"Garfield\"}, \"514\": {\"date-published\": \"2008-12-8\", \"description\": \"Simultaneous\"}, \"1497\": {\"date-published\": \"2015-3-11\", \"description\": \"New Products\"}, \"403\": {\"date-published\": \"2008-3-31\", \"description\": \"Convincing Pickup Line\"}, \"219\": {\"date-published\": \"2007-2-5\", \"description\": \"Blanket Fort\"}, \"1077\": {\"date-published\": \"2012-7-4\", \"description\": \"Home Organization\"}, \"98\": {\"date-published\": \"2006-5-5\", \"description\": \"Fall Apart\"}, \"1767\": {\"date-published\": \"2016-12-2\", \"description\": \"US State Names\"}, \"981\": {\"date-published\": \"2011-11-23\", \"description\": \"Porn Folder\"}, \"56\": {\"date-published\": \"2006-1-30\", \"description\": \"The Cure\"}, \"1746\": {\"date-published\": \"2016-10-14\", \"description\": \"Making Friends\"}, \"335\": {\"date-published\": \"2007-10-29\", \"description\": \"Mattress\"}, \"1317\": {\"date-published\": \"2014-1-15\", \"description\": \"Theft\"}, \"111\": {\"date-published\": \"2006-6-5\", \"description\": \"Firefox and Witchcraft - The Connection?\"}}" 3 | INFO_URL_DATA={"month": "6", "num": 1851, "link": "", "year": "2017", "news": "", "safe_title": "Magnetohydrodynamics", "transcript": "", "alt": "Magnetohydrodyanmics combines the intuitive nature of Maxwell's equations with the easy solvability of the Navier-Stokes equations. It's so straightforward physicists add \"relativistic\" or \"quantum\" just to keep it from getting boring.", "img": "https://imgs.xkcd.com/comics/magnetohydrodynamics.png", "title": "Magnetohydrodynamics", "day": "16"} 4 | XKCD_ARCHIVE_JSON="{\"1550\": {\"date-published\": \"2015-7-13\", \"description\": \"Episode VII\"}, \"1654\": {\"date-published\": \"2016-3-11\", \"description\": \"Universal Install Script\"}, \"1230\": {\"date-published\": \"2013-6-26\", \"description\": \"Polar/Cartesian\"}, \"837\": {\"date-published\": \"2010-12-22\", \"description\": \"Coupon Code\"}, \"1160\": {\"date-published\": \"2013-1-14\", \"description\": \"Drop Those Pounds\"}, \"340\": {\"date-published\": \"2007-11-9\", \"description\": \"Fight\"}, \"1374\": {\"date-published\": \"2014-5-28\", \"description\": \"Urn\"}, \"78\": {\"date-published\": \"2006-3-20\", \"description\": \"Garfield\"}, \"514\": {\"date-published\": \"2008-12-8\", \"description\": \"Simultaneous\"}, \"1497\": {\"date-published\": \"2015-3-11\", \"description\": \"New Products\"}, \"403\": {\"date-published\": \"2008-3-31\", \"description\": \"Convincing Pickup Line\"}, \"219\": {\"date-published\": \"2007-2-5\", \"description\": \"Blanket Fort\"}, \"1077\": {\"date-published\": \"2012-7-4\", \"description\": \"Home Organization\"}, \"98\": {\"date-published\": \"2006-5-5\", \"description\": \"Fall Apart\"}, \"1767\": {\"date-published\": \"2016-12-2\", \"description\": \"US State Names\"}, \"981\": {\"date-published\": \"2011-11-23\", \"description\": \"Porn Folder\"}, \"56\": {\"date-published\": \"2006-1-30\", \"description\": \"The Cure\"}, \"1746\": {\"date-published\": \"2016-10-14\", \"description\": \"Making Friends\"}, \"335\": {\"date-published\": \"2007-10-29\", \"description\": \"Mattress\"}, \"1317\": {\"date-published\": \"2014-1-15\", \"description\": \"Theft\"}, \"111\": {\"date-published\": \"2006-6-5\", \"description\": \"Firefox and Witchcraft - The Connection?\"}}" 5 | VALID_COMIC_INFO={"month": "7", "num": 1550, "link": "", "year": "2015", "news": "", "safe_title": "Episode VII", "transcript": "[[Movie title: STAR WARS, THE FORCE AWAKENS]]\n\n[[A desolate adobe structure. A sign out front reads TOSCHE STATION]]\n\n[[Hooded jedi & R2D2 walk into the TOSCHE STATION]]\n\nJEDI: I'm here for those power converters.\n\n[[Closing title: Directed by J J Abrams]]\n\n{{Title text: The Lord of the Rings sequel, set years after the Ring hubbub has died down, is just Samwise discreetly creeping back to Bag End to finish dropping the eaves.}}", "alt": "The Lord of the Rings sequel, set years after the Ring hubbub has died down, is just Samwise discreetly creeping back to Bag End to finish dropping the eaves.", "img": "https://imgs.xkcd.com/comics/episode_vii.png", "title": "Episode VII", "day": "13"} 6 | IMAGE_PAGE_CONTENT_1550="b'\\n\\n\\n\\n\\nxkcd: Episode VII\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n
\\n
\\n\\n
\\n
\\n
\\n\"xkcd.com\\nA webcomic of romance,
sarcasm, math, and language.
\\n
\\n
\\nThere are four new shirts in the xkcd store,
\\nalong with posters and lots of other stuff!\\n\\n
\\n
\\n
\\n
\\n
\\n
\\n\\n
Episode VII
\\n\\n
\\n\"Episode\\n
\\n\\n
\\nPermanent link to this comic: https://xkcd.com/1550/
\\nImage URL (for hotlinking/embedding): https://imgs.xkcd.com/comics/episode_vii.png\\n
[[Movie title: STAR WARS, THE FORCE AWAKENS]]\\n\\n[[A desolate adobe structure. A sign out front reads TOSCHE STATION]]\\n\\n[[Hooded jedi & R2D2 walk into the TOSCHE STATION]]\\n\\nJEDI: I'm here for those power converters.\\n\\n[[Closing title: Directed by J J Abrams]]\\n\\n{{Title text: The Lord of the Rings sequel, set years after the Ring hubbub has died down, is just Samwise discreetly creeping back to Bag End to finish dropping the eaves.}}
\\n
\\n
\\n\"Selected\\n\\n\"Grownups\"/\\n\"Circuit\\n\"Angular\\n\"Self-Description\"/\\n\"Alternative\\n\\n
\\n\\nRSS Feed - Atom Feed\\n
\\n
\\n\\n
\\n
\\nOther things:
\\n Women Also Know Stuff,\\n Tech Solidarity\\n
\\n
\\n
\\n
xkcd.com is best viewed with Netscape Navigator 4.0 or below on a Pentium 3±1 emulated in Javascript on an Apple IIGS at a screen resolution of 1024x1. Please enable your ad blockers, disable high-heat drying, and remove your device from Airplane Mode and set it to Boat Mode. For security reasons, please leave caps lock on while browsing.
\\n
\\n
\\n

\\nThis work is licensed under a\\nCreative Commons Attribution-NonCommercial 2.5 License.\\n

\\nThis means you\\'re free to copy and share these comics (but not to sell them). More details.

\\n
\\n
\\n\\n\\n\\n\\n'" 7 | -------------------------------------------------------------------------------- /tests/unit_tests.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import os 3 | import sys 4 | import mock 5 | from xkcd_dl.cli import update_dict, download_all, download_xkcd_range, is_valid_comic, download_one 6 | import xkcd_dl.cli 7 | import json 8 | import tempfile 9 | from io import StringIO 10 | from requests import Response 11 | from requests.packages.urllib3.response import HTTPResponse 12 | from mock import MagicMock 13 | import shutil 14 | 15 | 16 | 17 | def get_fake_xkcd_json_dict(): 18 | from tests.inputs import XKCD_ARCHIVE_JSON 19 | return json.loads(XKCD_ARCHIVE_JSON) 20 | 21 | 22 | def get_info_data(): 23 | from tests.inputs import INFO_URL_DATA 24 | return INFO_URL_DATA 25 | 26 | 27 | def get_comic_info(): 28 | from tests.inputs import VALID_COMIC_INFO 29 | return VALID_COMIC_INFO 30 | 31 | 32 | class Unittests(unittest.TestCase): 33 | def setUp(self): 34 | sys.stdout = StringIO() 35 | 36 | @mock.patch('xkcd_dl.cli.requests.get') 37 | def test_update_dict(self, mock_api_call): 38 | tmp_file = tempfile.NamedTemporaryFile(delete=False) 39 | xkcd_dl.cli.xkcd_dict_location = tmp_file.name 40 | from tests.inputs import ARCHIVE_URL_CONTENT 41 | res = ARCHIVE_URL_CONTENT 42 | 43 | mock_api_call.return_value.status_code = 200 44 | mock_api_call.return_value.content = res 45 | 46 | update_dict() 47 | 48 | with open(tmp_file.name) as json_file: 49 | data = json.load(json_file) 50 | assert len(data) == 1849 51 | os.remove(tmp_file.name) 52 | 53 | @mock.patch('xkcd_dl.cli.read_dict', side_effect=get_fake_xkcd_json_dict) 54 | @mock.patch('xkcd_dl.cli.download_one') 55 | def test_download_all(self, download_one_stub, fake_dict): 56 | download_all() 57 | assert download_one_stub.call_count == 21 58 | 59 | @mock.patch('xkcd_dl.cli.is_valid_comic', return_value=True) 60 | @mock.patch('xkcd_dl.cli.read_dict', side_effect=get_fake_xkcd_json_dict) 61 | @mock.patch('xkcd_dl.cli.download_one') 62 | def test_download_xkcd_range_normal(self, download_one_stub, fake_dict, is_valid_comic_stub): 63 | download_xkcd_range(233, 236) 64 | assert download_one_stub.call_count == 4 65 | 66 | @mock.patch('xkcd_dl.cli.is_valid_comic', return_value=True) 67 | @mock.patch('xkcd_dl.cli.read_dict', side_effect=get_fake_xkcd_json_dict) 68 | @mock.patch('xkcd_dl.cli.download_one') 69 | def test_download_xkcd_range_with_404(self, download_one_stub, fake_dict, is_valid_comic_stub): 70 | download_xkcd_range(400, 405) 71 | assert download_one_stub.call_count == 5 72 | 73 | @mock.patch('xkcd_dl.cli.read_dict', side_effect=get_fake_xkcd_json_dict) 74 | @mock.patch('xkcd_dl.cli.download_one') 75 | def test_download_xkcd_range_wrong_range(self, download_one_stub, fake_dict): 76 | download_xkcd_range(405, 400) 77 | assert sys.stdout.getvalue().strip() == "Start must be smaller than End." 78 | 79 | @mock.patch('xkcd_dl.cli.requests.get') 80 | def test_valid_comic(self, mock_api_call): 81 | from tests.inputs import INFO_URL_DATA 82 | res = INFO_URL_DATA 83 | mock_api_call.return_value.status_code = 200 84 | mock_api_call.return_value.json.return_value = res 85 | assert is_valid_comic(100) == True 86 | 87 | @mock.patch('xkcd_dl.cli.requests.get') 88 | def test_invalid_comic(self, mock_api_call): 89 | from tests.inputs import INFO_URL_DATA 90 | res = INFO_URL_DATA 91 | mock_api_call.return_value.status_code = 200 92 | mock_api_call.return_value.json.return_value = res 93 | assert is_valid_comic(9999999999999999) == False 94 | 95 | @mock.patch('xkcd_dl.cli.shutil.copyfileobj') 96 | @mock.patch('xkcd_dl.cli.requests.get') 97 | def test_download_one(self, mock_call, fake_copyfileobj): 98 | from tests.inputs import VALID_COMIC_INFO 99 | from tests.inputs import IMAGE_PAGE_CONTENT_1550 100 | comic_info = VALID_COMIC_INFO 101 | page_info = IMAGE_PAGE_CONTENT_1550 102 | 103 | mock_info_call = MagicMock(spec=Response) 104 | mock_info_call.json.return_value = get_comic_info() 105 | mock_info_call.return_value.status_code = 200 106 | mock_info_call.return_value = page_info 107 | 108 | mock_image_call = MagicMock(spec=Response) 109 | mock_image_call.status_code = 200 110 | mock_image_call.return_value.json.return_value = comic_info 111 | mock_image_call.content = page_info 112 | 113 | mock_image_content_call = MagicMock(spec=Response) 114 | mock_image_content_call.raw = MagicMock(spec=HTTPResponse) 115 | mock_image_content_call.status_code = 200 116 | 117 | mock_call.side_effect = [mock_info_call, mock_image_call, mock_image_content_call] 118 | xkcd_dl.cli.WORKING_DIRECTORY = tempfile.mkdtemp() 119 | download_one(get_fake_xkcd_json_dict(), 1550) 120 | xkcd_download_folder = xkcd_dl.cli.WORKING_DIRECTORY + "/xkcd_archive/1550/" 121 | files = os.listdir(xkcd_download_folder) 122 | 123 | assert "description.txt" in files 124 | assert 'EpisodeVII.jpg' in files 125 | assert os.path.getsize(xkcd_download_folder + "description.txt") == 238 126 | 127 | shutil.rmtree(xkcd_dl.cli.WORKING_DIRECTORY, ignore_errors=True) 128 | 129 | @mock.patch('xkcd_dl.cli.shutil.copyfileobj') 130 | @mock.patch('xkcd_dl.cli.requests.get') 131 | def test_download_duplicate(self, mock_call, fake_copyfileobj): 132 | from tests.inputs import VALID_COMIC_INFO 133 | from tests.inputs import IMAGE_PAGE_CONTENT_1550 134 | comic_info = VALID_COMIC_INFO 135 | page_info = IMAGE_PAGE_CONTENT_1550 136 | 137 | mock_info_call = MagicMock(spec=Response) 138 | mock_info_call.json.return_value = get_comic_info() 139 | mock_info_call.return_value.status_code = 200 140 | mock_info_call.return_value = page_info 141 | 142 | mock_image_call = MagicMock(spec=Response) 143 | mock_image_call.status_code = 200 144 | mock_image_call.return_value.json.return_value = comic_info 145 | mock_image_call.content = page_info 146 | 147 | mock_image_content_call = MagicMock(spec=Response) 148 | mock_image_content_call.raw = MagicMock(spec=HTTPResponse) 149 | mock_image_content_call.status_code = 200 150 | 151 | mock_call.side_effect = [mock_info_call, mock_image_call, mock_image_content_call, mock_info_call, 152 | mock_image_call, mock_image_content_call] 153 | xkcd_dl.cli.WORKING_DIRECTORY = tempfile.mkdtemp() 154 | download_one(get_fake_xkcd_json_dict(), 1550) 155 | download_one(get_fake_xkcd_json_dict(), 1550) 156 | 157 | assert sys.stdout.getvalue().split('\n')[-2] == "xkcd number '1550' has already been downloaded!" 158 | 159 | shutil.rmtree(xkcd_dl.cli.WORKING_DIRECTORY, ignore_errors=True) 160 | 161 | @mock.patch('xkcd_dl.cli.requests.get') 162 | def test_download_one_invalid(self, mock_api_call): 163 | download_one(get_fake_xkcd_json_dict(), 11) 164 | assert sys.stdout.getvalue().strip() == "11 does not exist! Please try with a different option" 165 | 166 | @mock.patch('xkcd_dl.cli.requests.get') 167 | def test_download_exclusion_list(self, mock_api_call): 168 | download_one(get_fake_xkcd_json_dict(), 1525) 169 | assert "1525 is special. It does not have an image." in sys.stdout.getvalue() 170 | -------------------------------------------------------------------------------- /xkcd_dl/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tasdikrahman/xkcd-dl/4e104ddc0d7c10335f08fef2c4554d2df8575a13/xkcd_dl/__init__.py -------------------------------------------------------------------------------- /xkcd_dl/cli.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # @Author: Tasdik Rahman 3 | # @Date: 2016-04-19 12:29:20 4 | # @Last Modified by: Tasdik Rahman 5 | # @Last Modified time: 2016-04-19 14:03:33 6 | # @MIT License 7 | # @http://tasdikrahman.me 8 | # @https://github.com/tasdikrahman 9 | 10 | import argparse 11 | from subprocess import call 12 | import glob 13 | import shutil 14 | import json 15 | import os 16 | import sys 17 | from os.path import expanduser, join 18 | from os import getcwd 19 | 20 | import magic 21 | import requests 22 | from bs4 import BeautifulSoup as bs4 23 | 24 | from xkcd_dl.version import VERSION 25 | 26 | __author__ = 'Tasdik Rahman' 27 | __email__ = 'prodicus@outlook.com' 28 | __version__ = VERSION 29 | 30 | HOME = expanduser('~') 31 | BASE_URL = 'http://xkcd.com' 32 | ARCHIVE_URL='http://xkcd.com/archive/' 33 | xkcd_dict_filename = '.xkcd_dict.json' 34 | xkcd_dict_location = os.path.join(HOME, xkcd_dict_filename) 35 | SCRIPT_DIRECTORY = os.path.dirname(os.path.abspath(__file__)) 36 | WORKING_DIRECTORY = os.getcwd() 37 | IMAGE_HANDLER = 'open' if sys.platform == 'darwin' else 'xdg-open' 38 | excludeList = ['1350','1416','1525','1608','1416','1506','1446','1663' ] 39 | 40 | def download_all(): 41 | json_content = read_dict() 42 | if json_content: 43 | print("Downloading all xkcd's Till date!!") 44 | all_keys = json_content.keys() 45 | for xkcd_number in all_keys: 46 | download_one(json_content, xkcd_number) 47 | 48 | def download_xkcd_range(*something): 49 | if len(something) != 2: 50 | print('Exactly two values are required for this.') 51 | else: 52 | start, end = something 53 | 54 | json_content = read_dict() 55 | if json_content: 56 | if start > end: 57 | print('Start must be smaller than End.') 58 | return 59 | 60 | if is_valid_comic(start) and is_valid_comic(end): 61 | range_numbers = [x for x in range(start, end+1)] 62 | if start <= 404 <= end: 63 | range_numbers.remove(404) 64 | for number in range_numbers: 65 | download_one(json_content, number) 66 | 67 | def download_latest(): 68 | update_dict() 69 | url = 'https://www.xkcd.com/info.0.json' 70 | response = requests.get(url) 71 | response_content = response.json() 72 | xkcd_number = response_content['num'] 73 | download_one(read_dict(), xkcd_number) 74 | 75 | def make_keyvalue_list(xkcd_dict, xkcd_num, date, description): 76 | xkcd_number = xkcd_num 77 | keyvalue_list = {} 78 | keyvalue_list['date-published'] = date 79 | xkcd_dict[xkcd_number] = keyvalue_list 80 | if xkcd_number == '472': ## Refer [1] 81 | keyvalue_list['description'] = "House of Pancakes" 82 | else: 83 | keyvalue_list['description'] = description 84 | 85 | ''' 86 | [1] the description for XKCD number is 87 | "House". It's hard coded currently 88 | But it works. 89 | ''' 90 | 91 | def update_dict(): 92 | archive_page = requests.get(ARCHIVE_URL) 93 | if archive_page.status_code == 200: 94 | page_content = archive_page.content 95 | archive_soup = bs4(page_content, 'html.parser') 96 | xkcd_dict = dict() 97 | 98 | for data in archive_soup.find_all('div', {'id': 'middleContainer'}): 99 | for alinks in data.find_all('a'): 100 | href = alinks.get('href').strip("/") 101 | date = alinks.get('title') 102 | description = alinks.contents[0] 103 | make_keyvalue_list(xkcd_dict, href, date, description) 104 | 105 | with open(xkcd_dict_location, 'w') as f: 106 | json.dump(xkcd_dict, f) 107 | print("XKCD link database updated\nStored it in '{file}'. You can start downloading your XKCD's!\nRun 'xkcd-dl --help' for more options".format(file=xkcd_dict_location)) 108 | else: 109 | print('Something bad happened!') 110 | 111 | def sanitize_description(desc): 112 | return ''.join([i for i in desc if i.isdigit() or i.isalpha()]) 113 | 114 | def is_valid_comic(num): 115 | url = 'https://www.xkcd.com/info.0.json' 116 | response = requests.get(url) 117 | if response.status_code == 200: 118 | response_content = response.json() 119 | latest_number = response_content["num"] 120 | 121 | if not 0 < num <= latest_number: 122 | print('XKCD is numbered from 0 to {}'.format(latest_number)) 123 | return False 124 | return True 125 | else: 126 | print('There was an internet connection error.') 127 | return False 128 | 129 | def dict_exists(): 130 | if not os.path.isfile(xkcd_dict_location): 131 | print('XKCD list not created! Run the following: \nxkcd-dl --update-db') 132 | return False 133 | return True 134 | 135 | def read_dict(): 136 | if dict_exists(): 137 | with open(xkcd_dict_location, 'r') as f: 138 | file_content = f.readline() 139 | return json.loads(file_content) 140 | else: 141 | return None 142 | 143 | def download_one(xkcd_dict, xkcd_num): 144 | if not xkcd_dict: 145 | return None 146 | 147 | xkcd_number = str(xkcd_num) 148 | if xkcd_number in excludeList: 149 | downloadImage = False 150 | print('{num} is special. It does not have an image.'.format( 151 | num=xkcd_number 152 | ) 153 | ) 154 | ''' 155 | [2] Some comics are special and either don't have an image or have a dynamic one. 156 | The full list is the array excludeList and needs to be manually updated upon the release 157 | of such a comic. 158 | ''' 159 | else: 160 | downloadImage = True 161 | if xkcd_number in xkcd_dict: 162 | date=xkcd_dict[xkcd_number]['date-published'] 163 | description=xkcd_dict[xkcd_number]['description'] 164 | 165 | new_description = sanitize_description(description) 166 | 167 | new_folder = '{current_directory}/xkcd_archive/{name}'.format( 168 | current_directory=WORKING_DIRECTORY, 169 | name=xkcd_number 170 | ) 171 | 172 | to_download_single = "{base}/{xkcd_num}/".format(base=BASE_URL, xkcd_num=xkcd_number) 173 | print("Downloading xkcd from '{img_url}' and storing it under '{path}'".format( 174 | img_url=to_download_single, 175 | path=new_folder 176 | ) 177 | ) 178 | alt=requests.get(to_download_single+'info.0.json').json()['alt'] 179 | if os.path.exists(new_folder): print("xkcd number '{num}' has already been downloaded!".format( 180 | num=xkcd_number) 181 | ) 182 | else: 183 | os.makedirs(new_folder) 184 | os.chdir(new_folder) 185 | with open('description.txt', 'w') as f: 186 | content = """title : {description} 187 | date-published: {date} 188 | url: {url} 189 | alt: {altText} \n""".format(description=description, 190 | date=date, url=to_download_single, altText=alt 191 | ) 192 | f.write(content) 193 | 194 | image_page = requests.get(to_download_single, stream=True) 195 | if downloadImage: 196 | if image_page.status_code == 200: 197 | image_page_content = image_page.content 198 | image_page_content_soup = bs4(image_page_content, 'html.parser') 199 | 200 | for data in image_page_content_soup.find_all("div", {"id": "comic"}): 201 | for img_tag in data.find_all('img'): 202 | img_link = img_tag.get('src') 203 | 204 | complete_img_url = "http:{url}".format(url=img_link) 205 | 206 | file_name = "{description}.jpg".format(description=new_description) 207 | r = requests.get(complete_img_url, stream = True) 208 | if r.status_code == 200: 209 | with open(file_name, 'wb') as f: 210 | r.raw.decode_content = True 211 | shutil.copyfileobj(r.raw, f) 212 | else: 213 | print("Error with connectivity. HTTP error {}".format(r.status_code)) 214 | magic_response = str(magic.from_file(file_name, mime=True)) 215 | if 'png' in magic_response: 216 | os.rename(file_name, "{description}.png".format( 217 | description=new_description) 218 | ) 219 | elif 'jpeg' in magic_response: 220 | os.rename(file_name, "{description}.jpeg".format( 221 | description=new_description) 222 | ) 223 | elif 'gif' in magic_response: 224 | os.rename(file_name, "{description}.gif".format( 225 | description=new_description) 226 | ) 227 | 228 | else: 229 | print("{} does not exist! Please try with a different option".format(xkcd_number)) 230 | 231 | def set_custom_path(custom_path): 232 | path_was_set = False 233 | if custom_path and os.path.isdir(custom_path): 234 | os.chdir(custom_path) 235 | 236 | global WORKING_DIRECTORY 237 | WORKING_DIRECTORY = os.getcwd() 238 | path_was_set = True 239 | print("Path is set to {}".format(WORKING_DIRECTORY)) 240 | else: 241 | print("The path does not exist.") 242 | return path_was_set 243 | 244 | def show_xkcd(num): 245 | download_one(read_dict(), num) 246 | path = '{current_directory}/xkcd_archive/{name}/'.format( 247 | current_directory=WORKING_DIRECTORY, 248 | name=num 249 | ) 250 | call(["cat", path + "description.txt"]) 251 | try: 252 | img_path = glob.glob(path + "*.jpeg")[0] 253 | call([IMAGE_HANDLER, img_path]) 254 | except IndexError: 255 | try: 256 | img_path = glob.glob(path + "*.png")[0] 257 | call([IMAGE_HANDLER, img_path]) 258 | except IndexError: 259 | print('Dynamic comic. Please visit in browser.') 260 | 261 | def main(): 262 | args = parser.parse_args() 263 | if args.update_db: 264 | update_dict() 265 | elif args.download_latest: 266 | download_latest() 267 | elif args.download: 268 | download_one(read_dict(), args.download) 269 | elif args.download_all: 270 | download_all() 271 | elif args.download_range: 272 | download_xkcd_range(*args.download_range) 273 | elif args.show: 274 | show_xkcd(args.show) 275 | elif args.path: 276 | set_custom_path(args.path) 277 | else: 278 | parser.print_usage() 279 | 280 | parser = argparse.ArgumentParser(prog='xkcd-dl', description='Run `xkcd-dl --update-db` if running for the first time.') 281 | parser.add_argument('-u', '--update-db', action='store_true', help='Update the database') 282 | parser.add_argument('-l', '--download-latest', action='store_true', help='Download most recent comic') 283 | group = parser.add_mutually_exclusive_group() 284 | group.add_argument('-d', '--download', help='Download specified comic by number', type=int, metavar='XKCD_NUM') 285 | group.add_argument('-a', '--download-all', action='store_true', help='Download all comics') 286 | parser.add_argument('-r', '--download-range', nargs='*', help='Download specified range', type=int) 287 | parser.add_argument('-v', '--version', action='version', version=__version__) 288 | parser.add_argument('-P', '--path', help='set path') 289 | parser.add_argument('-s', '--show', help='Show specified comic by number', type=int, metavar='XKCD_NUM') 290 | 291 | if __name__ == '__main__': 292 | main() 293 | -------------------------------------------------------------------------------- /xkcd_dl/version.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Author: Tasdik Rahman 3 | # @Date: 2016-04-19 12:26:04 4 | # @Last Modified by: Tasdik Rahman 5 | # @Last Modified time: 2016-04-19 13:58:19 6 | # @GPLv3 License 7 | # @http://tasdikrahman.me 8 | # @https://github.com/tasdikrahman 9 | 10 | VERSION = "0.1.2" --------------------------------------------------------------------------------