{ "cells": [ { "cell_type": "markdown", "metadata": { "button": false, "new_sheet": false, "run_control": { "read_only": false }, "slideshow": { "slide_type": "slide" } }, "source": [ "# Where the Bugs are\n", "\n", "Every time a bug is fixed, developers leave a trace – in the _version database_ when they commit the fix, or in the _bug database_ when they close the bug. In this chapter, we learn how to _mine these repositories_ for past changes and bugs, and how to _map_ them to individual modules and functions, highlighting those project components that have seen most changes and fixes over time." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "slideshow": { "slide_type": "skip" } }, "outputs": [], "source": [ "from bookutils import YouTubeVideo\n", "# YouTubeVideo(\"w4u5gCgPlmg\")" ] }, { "cell_type": "markdown", "metadata": { "button": false, "new_sheet": false, "run_control": { "read_only": false }, "slideshow": { "slide_type": "subslide" } }, "source": [ "**Prerequisites**\n", "\n", "* You should have read [the chapter on tracking bugs](Tracking.ipynb)." ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "button": false, "new_sheet": false, "run_control": { "read_only": false }, "slideshow": { "slide_type": "skip" } }, "outputs": [], "source": [ "import bookutils" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "slideshow": { "slide_type": "skip" } }, "outputs": [], "source": [ "import Tracking" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "skip" } }, "source": [ "## Synopsis\n", "\n", "\n", "To [use the code provided in this chapter](Importing.ipynb), write\n", "\n", "```python\n", ">>> from debuggingbook.ChangeExplorer import \n", "```\n", "\n", "and then make use of the following features.\n", "\n", "\n", "This chapter provides two classes `ChangeCounter` and `FineChangeCounter` that allow to mine and visualize the distribution of changes in a given `git` repository.\n", "\n", "`ChangeCounter` is initialized as\n", "\n", "```python\n", "change_counter = ChangeCounter(repository)\n", "```\n", "where `repository` is either \n", "\n", "* a _directory_ containing a `git` clone (i.e., it contains a `.git` directory)\n", "* the URL of a `git` repository.\n", "\n", "Additional arguments are being passed to the underlying `RepositoryMining` class from the [PyDriller](https://pydriller.readthedocs.io/) Python package. A `filter` keyword argument, if given, is a predicate that takes a modification (from PyDriller) and returns True if it should be included.\n", "\n", "In a change counter, all elements in the repository are represented as _nodes_ – tuples $(f_1, f_2, ..., f_n)$ that denote a _hierarchy_: Each $f_i$ is a directory holding $f_{i+1}$, with $f_n$ being the actual file.\n", "\n", "A `change_counter` provides a number of attributes. `changes` is a mapping of nodes to the number of changes in that node:\n", "\n", "```python\n", ">>> change_counter.changes[('README.md',)]\n", "\n", "7\n", "```\n", "The `messages` attribute holds all commit messages related to that node:\n", "\n", "```python\n", ">>> change_counter.messages[('README.md',)]\n", "\n", "['first commit',\n", " 'Adjusted to debuggingbook',\n", " 'New Twitter handle: @Debugging_Book',\n", " 'Doc update',\n", " 'Doc update',\n", " 'Doc update',\n", " 'Doc update']\n", "```\n", "The `sizes` attribute holds the (last) size of the respective element:\n", "\n", "```python\n", ">>> change_counter.sizes[('README.md',)]\n", "\n", "10701\n", "```\n", "`FineChangeCounter` acts like `ChangeCounter`, but also retrieves statistics for elements _within_ the respective files; it has been tested for C, Python, and Jupyter Notebooks and should provide sufficient results for programming languages with similar syntax.\n", "\n", "The `map()` method of `ChangeCounter` and `FineChangeCounter` produces an interactive tree map that allows to explore the elements of a repository. The redder (darker) a rectangle, the more changes it has seen; the larger a rectangle, the larger its size in bytes.\n", "\n", "```python\n", ">>> fine_change_counter.map()\n", "```\n", "\n", "
\n", "\n", "Subclassing offers several ways to customize what to mine and how to visualize it. See the chapter for details.\n", "\n", "Here are all the classes defined in this chapter:\n", "\n", "\n", "![](PICS/ChangeExplorer-synopsis-1.svg)\n", "\n" ] }, { "cell_type": "markdown", "metadata": { "button": false, "new_sheet": false, "run_control": { "read_only": false }, "slideshow": { "slide_type": "slide" } }, "source": [ "## Mining Change Histories\n", "\n", "The history of any software project is a history of change. Any nontrivial project thus comes with a _version database_ to organize and track changes; and possibly also with an [issue database](Tracking.ipynb) to organize and track issues.\n", "\n", "Over time, these databases hold plenty of information about the project: _Who changed what, when, and why?_ This information can be _mined_ from existing databases and _analyzed_ to answer questions such as\n", "\n", "* Which parts in my project were most frequently or recently changed?\n", "* How many files does the average change touch?\n", "* Where in my project were the most bugs fixed?" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "To answer such questions, we can _mine_ change and bug histories for past changes and fixes. This involves digging through version databases such as `git` and [issue trackers such as RedMine or Bugzilla](Tracking.ipynb) and extracting all their information. Fortunately for us, there is ready-made infrastructure for some of this. " ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Mining with PyDriller" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "[PyDriller](https://pydriller.readthedocs.io/) is a Python package for mining change histories. Its `RepositoryMining` class takes a `git` version repository and allows to access all the individual changes (\"modifications\"), together with committers, affected files, commit messages, and more." ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "slideshow": { "slide_type": "skip" } }, "outputs": [], "source": [ "from pydriller import RepositoryMining # https://pydriller.readthedocs.io/" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "To use `RepositoryMining`, we need to pass it \n", "* the URL of a `git` repository; or\n", "* the directory name where a cloned `git` repository can be found.\n", "\n", "In general, cloning a `git` repository locally (with `git clone URL`) and then analyzing it locally will be faster and require less network resources." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Let us apply `RepositoryMining` on the repository of this book. The function `current_repo()` returns the directory in which a `.git` subdirectory is stored – that is, the root of a cloned `git` repository." ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "slideshow": { "slide_type": "skip" } }, "outputs": [], "source": [ "import os" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "def current_repo():\n", " path = os.getcwd()\n", " while True:\n", " if os.path.exists(os.path.join(path, '.git')):\n", " return os.path.normpath(path)\n", " \n", " # Go one level up\n", " new_path = os.path.normpath(os.path.join(path, '..'))\n", " if new_path != path:\n", " path = new_path\n", " else:\n", " return None\n", " \n", " return None " ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/plain": [ "'/Users/zeller/Projects/debuggingbook'" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "current_repo()" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "This gives us a repository miner for the book:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "book_miner = RepositoryMining(current_repo())" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "`traverse_commits()` is a generator that returns one commit after another. Let us fetch the very first commit made to the book:" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "book_commits = book_miner.traverse_commits()\n", "book_first_commit = next(book_commits)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Each commit has a number of attributes telling us more about the commit." ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/plain": [ "['author',\n", " 'author_date',\n", " 'author_timezone',\n", " 'branches',\n", " 'committer',\n", " 'committer_date',\n", " 'committer_timezone',\n", " 'dmm_unit_complexity',\n", " 'dmm_unit_interfacing',\n", " 'dmm_unit_size',\n", " 'hash',\n", " 'in_main_branch',\n", " 'merge',\n", " 'modifications',\n", " 'msg',\n", " 'parents',\n", " 'project_name',\n", " 'project_path']" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "[attr for attr in dir(book_first_commit) if not attr.startswith('_')]" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "For instance, the `msg` attribute lets us know about the commit message:" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "'first commit'" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "book_first_commit.msg" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "whereas the `author` attribute gets us the name and email of the person who made the commit:" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "['email', 'name']" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "[attr for attr in dir(book_first_commit.author) if not attr.startswith('_')]" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "('Andreas Zeller', 'zeller@cispa.saarland')" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "book_first_commit.author.name, book_first_commit.author.email" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "A commit consists of multiple _modifications_ to possibly multiple files. The commit `modifications` attribute returns a list of modifications." ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "[]" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "book_first_commit.modifications" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "For each modification, we can retrieve the files involved as well as several statistics:" ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/plain": [ "['added',\n", " 'change_type',\n", " 'changed_methods',\n", " 'complexity',\n", " 'diff',\n", " 'diff_parsed',\n", " 'filename',\n", " 'language_supported',\n", " 'methods',\n", " 'methods_before',\n", " 'new_path',\n", " 'nloc',\n", " 'old_path',\n", " 'removed',\n", " 'source_code',\n", " 'source_code_before',\n", " 'token_count']" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "[attr for attr in dir(book_first_commit.modifications[0]) if not attr.startswith('_')]" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Let us see which file was created with this modification:" ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "'README.md'" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "book_first_commit.modifications[0].new_path" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "The `source_code` attribute holds the entire file contents after the modification." ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "# debuggingbook\n", "\n" ] } ], "source": [ "print(book_first_commit.modifications[0].source_code)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "We see that the `debuggingbook` project started with a very simple commit, namely the addition of an (almost empty) `README.md` file." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "The attribute `source_code_before` holds the previous source code. We see that it is `None` – the file was just created." ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "None\n" ] } ], "source": [ "print(book_first_commit.modifications[0].source_code_before)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Let us have a look at the _second_ commit. We see that it is much more substantial already." ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "book_second_commit = next(book_commits)" ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/plain": [ "['Chapters.makefile',\n", " 'LICENSE.md',\n", " 'Makefile',\n", " 'README.md',\n", " 'debuggingbook.bib',\n", " 'ipypublish',\n", " 'ipypublish_plugins',\n", " 'notebooks/.ipynb_checkpoints/index-checkpoint.ipynb',\n", " 'notebooks/index.ipynb',\n", " 'utils']" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "[m.new_path for m in book_second_commit.modifications]" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "We fetch the modification for the `README.md` file:" ] }, { "cell_type": "code", "execution_count": 21, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "readme_modification = [m for m in book_second_commit.modifications if m.new_path == 'README.md'][0]" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "The `source_code_before` attribute holds the previous version (which we already have seen):" ] }, { "cell_type": "code", "execution_count": 22, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "# debuggingbook\n", "\n" ] } ], "source": [ "print(readme_modification.source_code_before)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "The `source_code` attribute holds the new version – now a complete \"README\" file. (Compare this first version to the [current README text](index.ipynb).)" ] }, { "cell_type": "code", "execution_count": 23, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "# About this Book\n", "\n", "__Welcome to \"The Debugging Book\"!__ \n", "\n", "Software has bugs, and finding bugs can involve lots of effort. This book addresses this problem by _automating_ software debugging, specifically by _locating errors and their causes automatically_. Recent years have seen the development of novel techniques that lead to dramatic improvements in test generation and software testing. They\n" ] } ], "source": [ "print(readme_modification.source_code[:400])" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "The `diff` attribute holds the differences between the old and the new version." ] }, { "cell_type": "code", "execution_count": 24, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "@@ -1 +1,157 @@\n", "-# debuggingbook\n", "+\n", "+# About this Book\n", "+\n", "+__Welcome to \"The Debugging Book\"!__ \n", "+\n", "+So\n" ] } ], "source": [ "print(readme_modification.diff[:100])" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "The `diff_parsed` attribute even lists added and deleted lines:" ] }, { "cell_type": "code", "execution_count": 25, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/plain": [ "[(1, ''),\n", " (2, '# About this Book'),\n", " (3, ''),\n", " (4, '__Welcome to \"The Debugging Book\"!__'),\n", " (5, ''),\n", " (6,\n", " 'Software has bugs, and finding bugs can involve lots of effort. This book addresses this problem by _automating_ software debugging, specifically by _locating errors and their causes automatically_. Recent years have seen the development of novel techniques that lead to dramatic improvements in test generation and software testing. They now are mature enough to be assembled in a book – even with executable code.'),\n", " (7, ''),\n", " (8, ''),\n", " (9, ''),\n", " (10, '## A Textbook for Paper, Screen, and Keyboard')]" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "readme_modification.diff_parsed['added'][:10]" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "With all this information, we can track all commits and modifications and establish statistics over which files were changed (and possibly even fixed) most. This is what we will do in the next section." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Counting Changes\n", "\n", "We start with a simple `ChangeCounter` class that, given a repository, counts for each file how frequently it was changed." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "The constructor takes the repository to be analyzed and sets the internal counters:" ] }, { "cell_type": "code", "execution_count": 26, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "class ChangeCounter:\n", " \"\"\"Count the number of changes for a repository.\"\"\"\n", " \n", " def __init__(self, repo, filter=None, log=False, **kwargs):\n", " \"\"\"Constructor. `repo` is a git repository (as URL or directory).\n", "`filter` is a predicate that takes a modification and returns True \n", " if it should be considered (default: consider all).\n", "`log` turns on logging if set.\n", "`kwargs` are passed to the `RepositoryMining()` constructor.\"\"\"\n", " self.repo = repo\n", " self.log = log\n", "\n", " if filter is None:\n", " filter = lambda m: True\n", " self.filter = filter\n", "\n", " # A node is an tuple (f_1, f_2, f_3, ..., f_n) denoting\n", " # a folder f_1 holding a folder f_2 ... holding a file f_n\n", " self.changes = {} # Mapping node -> #of changes\n", " self.messages = {} # Mapping node -> list of commit messages\n", " self.sizes = {} # Mapping node -> last size seen\n", " self.hashes = set() # All hashes already considered\n", "\n", " self.mine(**kwargs)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "The method `mine()` does all the heavy lifting of mining. It retrieves all commits and all modifications from the repository, passing the modifications through the `update_stats()` method." ] }, { "cell_type": "code", "execution_count": 27, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "class ChangeCounter(ChangeCounter):\n", " def mine(self, **kwargs):\n", " \"\"\"Gather data from repository. To be extended in subclasses.\"\"\"\n", " miner = RepositoryMining(self.repo, **kwargs)\n", "\n", " for commit in miner.traverse_commits():\n", " for m in commit.modifications:\n", " m.hash = commit.hash\n", " m.committer = commit.committer\n", " m.committer_date = commit.committer_date\n", " m.msg = commit.msg\n", "\n", " if self.include(m):\n", " self.update_stats(m)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "The `include()` method allows to filter modifications. For simplicity, we copy the most relevant attributes of the commit over to the modification, such that the filter can access them, too." ] }, { "cell_type": "code", "execution_count": 28, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "class ChangeCounter(ChangeCounter):\n", " def include(self, m):\n", " \"\"\"Return True if the modification `m` should be included\n", "(default: the `filter` predicate given to the constructor).\n", "To be overloaded in subclasses.\"\"\"\n", " return self.filter(m)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "The `update_stats()` method is the method that does the counting. It takes a modification converts the file name into a _node_ – a tuple $(f_1, f_2, ..., f_n)$ that denotes a _hierarchy_: Each $f_i$ is a directory holding $f_{i+1}$, with $f_n$ being the actual file. Here is what this notebook looks as a node:" ] }, { "cell_type": "code", "execution_count": 29, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/plain": [ "('debuggingbook', 'notebooks', 'ChangeExplorer.ipynb')" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tuple('debuggingbook/notebooks/ChangeExplorer.ipynb'.split('/'))" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "For each such node, `update_stats()` then invokes `update_size()`, `update_changes()`, and `update_elems()`." ] }, { "cell_type": "code", "execution_count": 30, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "class ChangeCounter(ChangeCounter):\n", " def update_stats(self, m):\n", " \"\"\"Update counters with modification `m`. Can be extended in subclasses.\"\"\"\n", " if not m.new_path:\n", " return\n", "\n", " node = tuple(m.new_path.split('/'))\n", "\n", " if m.hash not in self.hashes:\n", " self.hashes.add(m.hash)\n", " self.update_size(node, len(m.source_code) if m.source_code else 0)\n", " self.update_changes(node, m.msg)\n", "\n", " self.update_elems(node, m)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "`update_size()` simply saves the last size of the item being modified. Since we progress from first to last commit, this reflects the size of the newest version." ] }, { "cell_type": "code", "execution_count": 31, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "class ChangeCounter(ChangeCounter):\n", " def update_size(self, node, size):\n", " \"\"\"Update counters for `node` with `size`. Can be extended in subclasses.\"\"\"\n", " self.sizes[node] = size" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "`update_changes()` increases the counter `changes` for the given node `node`, and adds the current commit message `commit_msg` to its list. This makes\n", "\n", "* `size` a mapping of nodes to their size\n", "* `changes` a mapping of nodes to the number of changes they have seen\n", "* `commit_msg` a mapping of nodes to the list of commit messages that have affected them." ] }, { "cell_type": "code", "execution_count": 32, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "class ChangeCounter(ChangeCounter):\n", " def update_changes(self, node, commit_msg):\n", " \"\"\"Update stats for `node` changed with `commit_msg`.\n", "Can be extended in subclasses.\"\"\"\n", " self.changes.setdefault(node, 0)\n", " self.changes[node] += 1\n", "\n", " self.messages.setdefault(node, [])\n", " self.messages[node].append(commit_msg)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "The `update_elems()` method is reserved for later use, when we go and count fine-grained changes." ] }, { "cell_type": "code", "execution_count": 33, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "class ChangeCounter(ChangeCounter):\n", " def update_elems(self, node, m):\n", " \"\"\"Update counters for subelements of `node` with modification `m`.\n", "To be defined in subclasses.\"\"\"\n", " pass" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Let us put `ChangeCounter` to action – on the current (debuggingbook) repository." ] }, { "cell_type": "code", "execution_count": 34, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "DEBUGGINGBOOK_REPO = current_repo()" ] }, { "cell_type": "code", "execution_count": 35, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "'/Users/zeller/Projects/debuggingbook'" ] }, "execution_count": 35, "metadata": {}, "output_type": "execute_result" } ], "source": [ "DEBUGGINGBOOK_REPO" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "You can also specify a URL instead, but this will access the repository via the network and generally be much slower." ] }, { "cell_type": "code", "execution_count": 36, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "# DEBUGGINGBOOK_REPO = 'https://github.com/uds-se/debuggingbook.git'" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "The function `debuggingbook_change_counter` instantiates a `ChangeCounter` class (or any subclass) with the debuggingbook repository, mining all the counters as listed above." ] }, { "cell_type": "code", "execution_count": 37, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "def debuggingbook_change_counter(cls):\n", " \"\"\"Instantiate a ChangeCounter (sub)class `cls` with the debuggingbook repo\"\"\"\n", " \n", " def filter(m):\n", " \"\"\"Do not include the `docs/` directory; it only holds Web pages\"\"\"\n", " return m.new_path and not m.new_path.startswith('docs/')\n", "\n", " return cls(DEBUGGINGBOOK_REPO, filter=filter)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Let us set `change_counter` to this `ChangeCounter` instance. This can take a few minutes." ] }, { "cell_type": "code", "execution_count": 38, "metadata": { "slideshow": { "slide_type": "skip" } }, "outputs": [], "source": [ "from Timer import Timer" ] }, { "cell_type": "code", "execution_count": 39, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/plain": [ "103.36603598899092" ] }, "execution_count": 39, "metadata": {}, "output_type": "execute_result" } ], "source": [ "with Timer() as t:\n", " change_counter = debuggingbook_change_counter(ChangeCounter)\n", "\n", "t.elapsed_time()" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "The attribute `changes` of our `ChangeCounter` now is a mapping of nodes to the respective number of changes. Here are the first 10 entries:" ] }, { "cell_type": "code", "execution_count": 40, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/plain": [ "[('README.md',),\n", " ('Chapters.makefile',),\n", " ('.gitignore',),\n", " ('full_notebooks', 'index.ipynb~'),\n", " ('binder', 'README.md'),\n", " ('notebooks', '99_Appendices.ipynb'),\n", " ('beta', 'html', 'PICS'),\n", " ('notebooks', '01_Intro.ipynb'),\n", " ('html', 'custom.css'),\n", " ('notebooks', '404.ipynb')]" ] }, "execution_count": 40, "metadata": {}, "output_type": "execute_result" } ], "source": [ "list(change_counter.changes.keys())[:10]" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "This is the number of changes to the `Chapters.makefile` file which lists the book chapters:" ] }, { "cell_type": "code", "execution_count": 41, "metadata": { "slideshow": { "slide_type": "fragment" }, "tags": [ "outputPrepend" ] }, "outputs": [ { "data": { "text/plain": [ "29" ] }, "execution_count": 41, "metadata": {}, "output_type": "execute_result" } ], "source": [ "change_counter.changes[('Chapters.makefile',)]" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "The `messages` attribute holds all the messages:" ] }, { "cell_type": "code", "execution_count": 42, "metadata": { "slideshow": { "slide_type": "subslide" }, "tags": [ "outputPrepend" ] }, "outputs": [ { "data": { "text/plain": [ "['Initial import',\n", " 'First notebooks',\n", " 'New: make booktitle, authors configurable in Chapters.makefile',\n", " 'Doc fix',\n", " 'Doc fix',\n", " 'New: Tracer',\n", " 'Fix: \"Tracer\" is ready',\n", " 'New chapter structure',\n", " 'New: added Debugger to chapters',\n", " 'New: depend on shared files, not links',\n", " 'Update',\n", " 'New: ClassDiagram',\n", " 'New chapter',\n", " \"Renamed 'Invariants' to 'Assertions'\",\n", " 'Added Time Travel Debugger project',\n", " 'Updated synopsis',\n", " 'New: ChangeDebugger',\n", " 'New: Project 2',\n", " 'New: Slicer',\n", " 'Moved Slicing before Statistical Debugging',\n", " 'New: leaders for missing parts',\n", " 'New: Tracking (very early stage)',\n", " 'Renumbered parts',\n", " 'Need more time for ChangeExplorer',\n", " 'New: bug tracking',\n", " 'Rmeoved appendices not needed',\n", " 'New: dynamic invariants (as import from fuzzingbook)',\n", " 'New: project 3',\n", " 'Reorganized chapters']" ] }, "execution_count": 42, "metadata": {}, "output_type": "execute_result" } ], "source": [ "change_counter.messages[('Chapters.makefile',)]" ] }, { "cell_type": "code", "execution_count": 43, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "for node in change_counter.changes:\n", " assert len(change_counter.messages[node]) == change_counter.changes[node]" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "The `sizes` attribute holds the final size:" ] }, { "cell_type": "code", "execution_count": 44, "metadata": { "slideshow": { "slide_type": "fragment" }, "tags": [ "outputPrepend" ] }, "outputs": [ { "data": { "text/plain": [ "3299" ] }, "execution_count": 44, "metadata": {}, "output_type": "execute_result" } ], "source": [ "change_counter.sizes[('Chapters.makefile',)]" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Visualizing Past Changes" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "To explore the number of changes across all project files, we visualize them as a _tree map_. A tree map visualizes hierarchical data using nested rectangles. In our visualization, each directory is shown as a rectangle containing smaller rectangles. The _size_ of a rectangle is relative to its size (in bytes); and the _color_ of a rectangle is relative to the number of changes it has seen." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "We use the [easyplotly](https://github.com/mwouts/easyplotly) package to easily create a treemap." ] }, { "cell_type": "code", "execution_count": 45, "metadata": { "slideshow": { "slide_type": "skip" } }, "outputs": [], "source": [ "import easyplotly as ep\n", "import plotly.graph_objects as go" ] }, { "cell_type": "code", "execution_count": 46, "metadata": { "slideshow": { "slide_type": "skip" } }, "outputs": [], "source": [ "import math" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "The method `map_node_sizes()` returns a size for the node – any number will do. By default, we use a logarithmic scale, such that smaller files are not totally visually eclipsed by larger files." ] }, { "cell_type": "code", "execution_count": 47, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "class ChangeCounter(ChangeCounter):\n", " def map_node_sizes(self):\n", " \"\"\"Return a mapping of nodes to sizes. Can be overloaded in subclasses.\"\"\"\n", " # Default: use log scale\n", " return {node: math.log(self.sizes[node]) if self.sizes[node] else 0\n", " for node in self.sizes}\n", "\n", " # Alternative: use sqrt size\n", " return {node: math.sqrt(self.sizes[node]) for node in self.sizes}\n", "\n", " # Alternative: use absolute size\n", " return self.sizes" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "The method `map_node_color()` returns a color for the node – again, as a number. The smallest and largest numbers returned indicate beginning and end in the given color scale, respectively." ] }, { "cell_type": "code", "execution_count": 48, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "class ChangeCounter(ChangeCounter):\n", " def map_node_color(self, node):\n", " \"\"\"Return a color of the node, as a number. Can be overloaded in subclasses.\"\"\"\n", " if node and node in self.changes:\n", " return self.changes[node]\n", " return None" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "The method `map_node_text()` shows a text to be displayed in the rectangle; we set this to the number of changes." ] }, { "cell_type": "code", "execution_count": 49, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "class ChangeCounter(ChangeCounter):\n", " def map_node_text(self, node):\n", " \"\"\"Return the text to be shown for the node (default: #changes). \n", "Can be overloaded in subclasses.\"\"\"\n", " if node and node in self.changes:\n", " return self.changes[node]\n", " return None" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "The methods `map_hoverinfo()` and `map_colorscale()` set additional map parameters. For details, see the [easyplotly](https://github.com/mwouts/easyplotly) documentation." ] }, { "cell_type": "code", "execution_count": 50, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "class ChangeCounter(ChangeCounter):\n", " def map_hoverinfo(self):\n", " \"\"\"Return the text to be shown when hovering over a node.\n", "To be overloaded in subclasses.\"\"\"\n", " return 'label+text'\n", "\n", " def map_colorscale(self):\n", " \"\"\"Return the colorscale for the map. To be overloaded in subclasses.\"\"\"\n", " return 'YlOrRd'" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "With all this, the `map()` function creates a tree map of the repository, using the [easyplotly](https://github.com/mwouts/easyplotly) `Treemap` constructor." ] }, { "cell_type": "code", "execution_count": 51, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "class ChangeCounter(ChangeCounter):\n", " def map(self):\n", " \"\"\"Produce an interactive tree map of the repository.\"\"\"\n", " treemap = ep.Treemap(\n", " self.map_node_sizes(),\n", " text=self.map_node_text,\n", " hoverinfo=self.map_hoverinfo(),\n", " marker_colors=self.map_node_color,\n", " marker_colorscale=self.map_colorscale(),\n", " root_label=self.repo,\n", " branchvalues='total'\n", " )\n", "\n", " fig = go.Figure(treemap)\n", " fig.update_layout(margin=dict(l=0, r=0, t=30, b=0))\n", "\n", " return fig" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "This is what the tree map for `debuggingbook` looks like. \n", "\n", "* Click on any rectangle to enlarge it.\n", "* Click outside of the rectangle to return to a wider view.\n", "* Hover over a rectangle to get further information." ] }, { "cell_type": "code", "execution_count": 52, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "change_counter = debuggingbook_change_counter(ChangeCounter)" ] }, { "cell_type": "code", "execution_count": 53, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/html": [ " \n", " " ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.plotly.v1+json": { "config": { "plotlyServerURL": "https://plot.ly" }, "data": [ { "branchvalues": "total", "hoverinfo": "label+text", "ids": [ "/README.md", "/Chapters.makefile", "/.gitignore", "/full_notebooks/index.ipynb~", "/binder/README.md", "/notebooks/99_Appendices.ipynb", "/beta/html/PICS", "/notebooks/01_Intro.ipynb", "/html/custom.css", "/notebooks/404.ipynb", "/beta/code/LICENSE.md", "/notebooks/index.ipynb", "/binder/postBuild", "/beta/code/bookutils", "/code/setup.py.in", "/PICS", "/pdf/PICS", "/.gitmodules", "/notebooks/ReleaseNotes.ipynb", "/notebooks/00_Table_of_Contents.ipynb", "/notebooks/Guide_for_Authors.ipynb", "/notebooks/Intro_Debugging.ipynb", "/notebooks/Chapters.ipynb", "/ipypublish_plugins/README.md", "/beta/slides/reveal.js", "/html/favicon/android-chrome-144x144.png", "/notebooks/Debugger.ipynb", "/notebooks/Tracer.ipynb", "/notebooks/03_Observing.ipynb", "/notebooks/Importing.ipynb", "/notebooks/StatisticalDebugger.ipynb", "/notebooks/.ipynb_checkpoints/index-checkpoint.ipynb", "/code/requirements.txt", "/notebooks/Template.ipynb", "/notebooks/PICS/ClassDiagram-synopsis-1.png", "/notebooks/ClassDiagram.ipynb", "/notebooks/Invariants.ipynb", "/notebooks/PICS/StatisticalDebugger-synopsis-1.png", "/binder/requirements.txt", "/binder/apt.txt", "/.gitattributes", "/binder/postBuild.template", "/notebooks/Assertions.ipynb", "/notebooks/PICS/timetravel_debugger_gui_demo.gif", "/notebooks/Time_Travel_Debugger.ipynb", "/notebooks/Reducer.ipynb", "/notebooks/DeltaDebugger.ipynb", "/notebooks/ChangeDebugger.ipynb", "/notebooks/diff_match_patch/__init__.py", "/notebooks/Draft_Second_Project.ipynb", "/notebooks/Slicer.ipynb", "/notebooks/Reducing_Code.ipynb", "/notebooks/PICS/Slicer-synopsis-1.png", "/notebooks/PICS/ChangeDebugger-synopsis-1.png", "/notebooks/PICS/Debugger-synopsis-1.png", "/html/favicon/android-chrome-192x192.png", "/notebooks/PICS/DeltaDebugger-synopsis-1.png", "/notebooks/PICS/Tracer-synopsis-1.png", "/notebooks/Repairer.ipynb", "/code/pycodestyle.cfg", "/notebooks/PICS/Repairer-synopsis-1.png", "/notebooks/Tours.ipynb", "/notebooks/Tracking.ipynb", "/notebooks/PICS/Tracking-synopsis-1.png", "/notebooks/02_Observing.ipynb", "/notebooks/ChangeExplorer.ipynb", "/notebooks/PICS/ChangeExplorer-synopsis-1.png", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DDSet.ipynb", "/", "/full_notebooks", "/binder", "/notebooks", "/beta/html", "/beta", "/html", "/beta/code", "/code", "/pdf", "/ipypublish_plugins", "/beta/slides", "/html/favicon", "/notebooks/.ipynb_checkpoints", "/notebooks/PICS", "/notebooks/diff_match_patch" ], "labels": [ "README.md", "Chapters.makefile", ".gitignore", "index.ipynb~", "README.md", "99_Appendices.ipynb", "PICS", "01_Intro.ipynb", "custom.css", "404.ipynb", "LICENSE.md", "index.ipynb", "postBuild", "bookutils", "setup.py.in", "PICS", "PICS", ".gitmodules", "ReleaseNotes.ipynb", "00_Table_of_Contents.ipynb", "Guide_for_Authors.ipynb", "Intro_Debugging.ipynb", "Chapters.ipynb", "README.md", "reveal.js", "android-chrome-144x144.png", "Debugger.ipynb", "Tracer.ipynb", "03_Observing.ipynb", "Importing.ipynb", "StatisticalDebugger.ipynb", "index-checkpoint.ipynb", "requirements.txt", "Template.ipynb", "ClassDiagram-synopsis-1.png", "ClassDiagram.ipynb", "Invariants.ipynb", "StatisticalDebugger-synopsis-1.png", "requirements.txt", "apt.txt", ".gitattributes", "postBuild.template", "Assertions.ipynb", "timetravel_debugger_gui_demo.gif", "Time_Travel_Debugger.ipynb", "Reducer.ipynb", "DeltaDebugger.ipynb", "ChangeDebugger.ipynb", "__init__.py", "Draft_Second_Project.ipynb", "Slicer.ipynb", "Reducing_Code.ipynb", "Slicer-synopsis-1.png", "ChangeDebugger-synopsis-1.png", "Debugger-synopsis-1.png", "android-chrome-192x192.png", "DeltaDebugger-synopsis-1.png", "Tracer-synopsis-1.png", "Repairer.ipynb", "pycodestyle.cfg", "Repairer-synopsis-1.png", "Tours.ipynb", "Tracking.ipynb", "Tracking-synopsis-1.png", "02_Observing.ipynb", "ChangeExplorer.ipynb", "ChangeExplorer-synopsis-1.png", "DynamicInvariants.ipynb", "DDSet.ipynb", "/Users/zeller/Projects/debuggingbook", "full_notebooks", "binder", "notebooks", "html", "beta", "html", "code", "code", "pdf", "ipypublish_plugins", "slides", "favicon", ".ipynb_checkpoints", "PICS", "diff_match_patch" ], "marker": { "colors": [ 7, 29, 1, 1, 1, 2, 2, 3, 9, 1, 1, 5, 7, 1, 2, 1, 1, 1, 1, 1, 6, 31, 3, 1, 1, 1, 21, 24, 1, 2, 38, 1, 1, 2, 16, 2, 6, 176, 1, 2, 1, 1, 11, 1, 10, 1, 40, 16, 1, 1, 109, 6, 183, 49, 26, 1, 50, 57, 66, 1, 73, 1, 25, 1, 1, 8, 44, 9, 1, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null ], "colorscale": [ [ 0.0, "rgb(255,255,204)" ], [ 0.125, "rgb(255,237,160)" ], [ 0.25, "rgb(254,217,118)" ], [ 0.375, "rgb(254,178,76)" ], [ 0.5, "rgb(253,141,60)" ], [ 0.625, "rgb(252,78,42)" ], [ 0.75, "rgb(227,26,28)" ], [ 0.875, "rgb(189,0,38)" ], [ 1.0, "rgb(128,0,38)" ] ] }, "parents": [ "/", "/", "/", "/full_notebooks", "/binder", "/notebooks", "/beta/html", "/notebooks", "/html", "/notebooks", "/beta/code", "/notebooks", "/binder", "/beta/code", "/code", "/", "/pdf", "/", "/notebooks", "/notebooks", "/notebooks", "/notebooks", "/notebooks", "/ipypublish_plugins", "/beta/slides", "/html/favicon", "/notebooks", "/notebooks", "/notebooks", "/notebooks", "/notebooks", "/notebooks/.ipynb_checkpoints", "/code", "/notebooks", "/notebooks/PICS", "/notebooks", "/notebooks", "/notebooks/PICS", "/binder", "/binder", "/", "/binder", "/notebooks", "/notebooks/PICS", "/notebooks", "/notebooks", "/notebooks", "/notebooks", "/notebooks/diff_match_patch", "/notebooks", "/notebooks", "/notebooks", "/notebooks/PICS", "/notebooks/PICS", "/notebooks/PICS", "/html/favicon", "/notebooks/PICS", "/notebooks/PICS", "/notebooks", "/code", "/notebooks/PICS", "/notebooks", "/notebooks", "/notebooks/PICS", "/notebooks", "/notebooks", "/notebooks/PICS", "/notebooks", "/notebooks", null, "/", "/", "/", "/beta", "/", "/", "/beta", "/", "/", "/", "/beta", "/html", "/notebooks", "/notebooks", "/notebooks" ], "text": [ 7, 29, 1, 1, 1, 2, 2, 3, 9, 1, 1, 5, 7, 1, 2, 1, 1, 1, 1, 1, 6, 31, 3, 1, 1, 1, 21, 24, 1, 2, 38, 1, 1, 2, 16, 2, 6, 176, 1, 2, 1, 1, 11, 1, 10, 1, 40, 16, 1, 1, 109, 6, 183, 49, 26, 1, 50, 57, 66, 1, 73, 1, 25, 1, 1, 8, 44, 9, 1, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null ], "type": "treemap", "values": [ 9.278092474027002, 8.101374671228582, 3.2188758248682006, 0, 6.171700597410915, 7.2640301428995295, 2.70805020110221, 7.346010209913293, 9.567175303116281, 8.233503140233994, 3.044522437723423, 9.614604759507829, 9.644198554585564, 3.2188758248682006, 7.142827401161621, 2.6390573296152584, 2.833213344056216, 5.384495062789089, 7.0630481633881725, 3.8918202981106265, 10.905368652244466, 11.42411610894823, 8.31115254800169, 5.003946305945459, 5.53338948872752, 0, 10.83089625014413, 10.979189389621132, 7.335633981927201, 8.619027497297505, 11.57362537806985, 9.629576884168266, 5.056245805348308, 9.219002745054835, 8.21878715560148, 3.828641396489095, 11.459429747027478, 9.796681548218318, 4.532599493153256, 6.056784013228625, 4.68213122712422, 7.038783541388542, 11.497639223432527, 14.227734771764943, 10.427268887462334, 11.218473864211628, 11.706846157607535, 11.30010346272789, 4.07753744390572, 9.958496435566927, 12.102105602982014, 10.718520452336056, 9.104201775914515, 11.555659230890438, 8.624791202014256, 8.698180525197055, 9.093357016490364, 8.177515823846075, 11.807175918300041, 3.6375861597263857, 9.641148287756142, 8.381373468273702, 11.117361181539327, 11.348923082759187, 0, 10.983511476392884, 11.68596238595356, 11.854335490621065, 9.248599084093273, 548.5948933101026, 0, 33.444066199766944, 425.40278772370993, 2.708050201102213, 14.504837952421383, 18.265355828313364, 6.263398262591631, 15.836659366236331, 2.8332133440562193, 5.0039463059454645, 5.533389488727527, 8.698180525197063, 9.629576884168277, 111.4747622812094, 4.077537443905724 ] } ], "layout": { "margin": { "b": 0, "l": 0, "r": 0, "t": 30 }, "template": { "data": { "bar": [ { "error_x": { "color": "#2a3f5f" }, "error_y": { "color": "#2a3f5f" }, "marker": { "line": { "color": "#E5ECF6", "width": 0.5 } }, "type": "bar" } ], "barpolar": [ { "marker": { "line": { "color": "#E5ECF6", "width": 0.5 } }, "type": "barpolar" } ], "carpet": [ { "aaxis": { "endlinecolor": "#2a3f5f", "gridcolor": "white", "linecolor": "white", "minorgridcolor": "white", "startlinecolor": "#2a3f5f" }, "baxis": { "endlinecolor": "#2a3f5f", "gridcolor": "white", "linecolor": "white", "minorgridcolor": "white", "startlinecolor": "#2a3f5f" }, "type": "carpet" } ], "choropleth": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "type": "choropleth" } ], "contour": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0.0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1.0, "#f0f921" ] ], "type": "contour" } ], "contourcarpet": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "type": "contourcarpet" } ], "heatmap": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0.0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1.0, "#f0f921" ] ], "type": "heatmap" } ], "heatmapgl": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0.0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1.0, "#f0f921" ] ], "type": "heatmapgl" } ], "histogram": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "histogram" } ], "histogram2d": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0.0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1.0, "#f0f921" ] ], "type": "histogram2d" } ], "histogram2dcontour": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0.0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1.0, "#f0f921" ] ], "type": "histogram2dcontour" } ], "mesh3d": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "type": "mesh3d" } ], "parcoords": [ { "line": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "parcoords" } ], "pie": [ { "automargin": true, "type": "pie" } ], "scatter": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatter" } ], "scatter3d": [ { "line": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatter3d" } ], "scattercarpet": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattercarpet" } ], "scattergeo": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattergeo" } ], "scattergl": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattergl" } ], "scattermapbox": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattermapbox" } ], "scatterpolar": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatterpolar" } ], "scatterpolargl": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatterpolargl" } ], "scatterternary": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatterternary" } ], "surface": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0.0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1.0, "#f0f921" ] ], "type": "surface" } ], "table": [ { "cells": { "fill": { "color": "#EBF0F8" }, "line": { "color": "white" } }, "header": { "fill": { "color": "#C8D4E3" }, "line": { "color": "white" } }, "type": "table" } ] }, "layout": { "annotationdefaults": { "arrowcolor": "#2a3f5f", "arrowhead": 0, "arrowwidth": 1 }, "autotypenumbers": "strict", "coloraxis": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "colorscale": { "diverging": [ [ 0, "#8e0152" ], [ 0.1, "#c51b7d" ], [ 0.2, "#de77ae" ], [ 0.3, "#f1b6da" ], [ 0.4, "#fde0ef" ], [ 0.5, "#f7f7f7" ], [ 0.6, "#e6f5d0" ], [ 0.7, "#b8e186" ], [ 0.8, "#7fbc41" ], [ 0.9, "#4d9221" ], [ 1, "#276419" ] ], "sequential": [ [ 0.0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1.0, "#f0f921" ] ], "sequentialminus": [ [ 0.0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1.0, "#f0f921" ] ] }, "colorway": [ "#636efa", "#EF553B", "#00cc96", "#ab63fa", "#FFA15A", "#19d3f3", "#FF6692", "#B6E880", "#FF97FF", "#FECB52" ], "font": { "color": "#2a3f5f" }, "geo": { "bgcolor": "white", "lakecolor": "white", "landcolor": "#E5ECF6", "showlakes": true, "showland": true, "subunitcolor": "white" }, "hoverlabel": { "align": "left" }, "hovermode": "closest", "mapbox": { "style": "light" }, "paper_bgcolor": "white", "plot_bgcolor": "#E5ECF6", "polar": { "angularaxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" }, "bgcolor": "#E5ECF6", "radialaxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" } }, "scene": { "xaxis": { "backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white" }, "yaxis": { "backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white" }, "zaxis": { "backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white" } }, "shapedefaults": { "line": { "color": "#2a3f5f" } }, "ternary": { "aaxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" }, "baxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" }, "bgcolor": "#E5ECF6", "caxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" } }, "title": { "x": 0.05 }, "xaxis": { "automargin": true, "gridcolor": "white", "linecolor": "white", "ticks": "", "title": { "standoff": 15 }, "zerolinecolor": "white", "zerolinewidth": 2 }, "yaxis": { "automargin": true, "gridcolor": "white", "linecolor": "white", "ticks": "", "title": { "standoff": 15 }, "zerolinecolor": "white", "zerolinewidth": 2 } } } } }, "text/html": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "change_counter.map()" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "We can easily identify the most frequently changed files:" ] }, { "cell_type": "code", "execution_count": 54, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/plain": [ "[(('notebooks', 'PICS', 'Slicer-synopsis-1.png'), 183),\n", " (('notebooks', 'PICS', 'StatisticalDebugger-synopsis-1.png'), 176),\n", " (('notebooks', 'Slicer.ipynb'), 109),\n", " (('notebooks', 'PICS', 'Repairer-synopsis-1.png'), 73)]" ] }, "execution_count": 54, "metadata": {}, "output_type": "execute_result" } ], "source": [ "all_nodes = list(change_counter.changes.keys())\n", "all_nodes.sort(key=lambda node: change_counter.changes[node], reverse=True)\n", "[(node, change_counter.changes[node]) for node in all_nodes[:4]]" ] }, { "cell_type": "code", "execution_count": 55, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "# ignore\n", "all_notebooks = [node for node in change_counter.changes.keys()\n", " if len(node) == 2 and node[1].endswith('.ipynb')]\n", "all_notebooks.sort(key=lambda node: change_counter.changes[node], reverse=True)" ] }, { "cell_type": "code", "execution_count": 56, "metadata": { "slideshow": { "slide_type": "skip" } }, "outputs": [], "source": [ "from bookutils import quiz" ] }, { "cell_type": "code", "execution_count": 57, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/html": [ "\n", " \n", " \n", " \n", "
\n", "

Quiz

\n", "

\n", "

Which two notebooks have seen the most changes over time?
\n", "

\n", "

\n", "

\n", " \n", " \n", "
\n", " \n", " \n", "
\n", " \n", " \n", "
\n", " \n", " \n", "
\n", " \n", "
\n", "

\n", " \n", "
\n", " " ], "text/plain": [ "" ] }, "execution_count": 57, "metadata": {}, "output_type": "execute_result" } ], "source": [ "quiz(\"Which two notebooks have seen the most changes over time?\",\n", " [\n", " f\"`{all_notebooks[3][1].split('.')[0]}`\",\n", " f\"`{all_notebooks[1][1].split('.')[0]}`\",\n", " f\"`{all_notebooks[2][1].split('.')[0]}`\",\n", " f\"`{all_notebooks[0][1].split('.')[0]}`\",\n", " ], [1234 % 3, 3702 / 1234])" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Indeed, these two are the two most frequently changed notebooks:" ] }, { "cell_type": "code", "execution_count": 58, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "('Slicer', 'Repairer')" ] }, "execution_count": 58, "metadata": {}, "output_type": "execute_result" } ], "source": [ "all_notebooks[0][1].split('.')[0], all_notebooks[1][1].split('.')[0]" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Past Fixes\n", "\n", "Knowing which files have been changed most is useful in debugging, because any change increases the chance to introduce a new bug. Even more important, however, is the question of how frequently a file was _fixed_ in the past, as this is an important indicator for its bug-proneness." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "(One may think that fixing several bugs _reduces_ the number of bugs, but unfortunately, a file which has seen several fixes in the past is likely to see fixes in the future, too. This is because the bug-proneness of a software component very much depends on the requirements it has to fulfill, and if these requirements are unclear, complex, or frequently change, this translates into many fixes.)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "How can we tell _changes_ from _fixes_? \n", "\n", "* One indicator is _commit messages_:\n", " If they refer to \"bugs\" or \"fixes\", then the change is a fix.\n", "* Another indicator is _bug numbers_:\n", " If a commit message contains an issue number from an associated issue database, then we can make use of the issue referred to.\n", " * The issue database may provide us with additional information about the bug, such as its severity, how many people it was assigned to, how long it took to fix it, and more.\n", "* A final indicator is _time_:\n", " If a developer first committed a change and in the same time frame marked an issue as \"resolved\", then it is likely that the two refer to each other.\n", "\n", "The way these two are linked very much depends on the project – and the discipline of developers as it comes to change messages. _Branches_ and _merges_ bring additional challenges." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "For the `debuggingbook` project, identifying fixes is easy. The discipline is that if a change fixes a bug, it is prefixed with `Fix:`. We can use this to introduce a `FixCounter` class specific to our `debuggingbook` project." ] }, { "cell_type": "code", "execution_count": 59, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "class FixCounter(ChangeCounter):\n", " def include(self, m):\n", " \"\"\"Include all modifications whose commit messages start with 'Fix:'\"\"\"\n", " return super().include(m) and m and m.msg.startswith(\"Fix:\")" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "As a twist to our default `ChangeCounter` class, we include the \"fix\" messages in the tree map rectangles." ] }, { "cell_type": "code", "execution_count": 60, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "class FixCounter(FixCounter):\n", " def map_node_text(self, node):\n", " if node and node in self.messages:\n", " return \"
\".join(self.messages[node])\n", " return \"\"\n", "\n", " def map_hoverinfo(self):\n", " return 'label'" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "This is the tree map showing fixes. We see that \n", "* only those components that actually have seen a fix are shown; and\n", "* the fix distribution differs from the change distribution." ] }, { "cell_type": "code", "execution_count": 61, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "fix_counter = debuggingbook_change_counter(FixCounter)" ] }, { "cell_type": "code", "execution_count": 62, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "application/vnd.plotly.v1+json": { "config": { "plotlyServerURL": "https://plot.ly" }, "data": [ { "branchvalues": "total", "hoverinfo": "label", "ids": [ "/notebooks/index.ipynb", "/html/custom.css", "/notebooks/ReleaseNotes.ipynb", "/notebooks/Intro_Debugging.ipynb", "/Chapters.makefile", "/notebooks/Tracer.ipynb", "/notebooks/Guide_for_Authors.ipynb", "/notebooks/Debugger.ipynb", "/notebooks/StatisticalDebugger.ipynb", "/notebooks/Invariants.ipynb", "/notebooks/Time_Travel_Debugger.ipynb", "/notebooks/DeltaDebugger.ipynb", "/notebooks/Reducing_Code.ipynb", "/notebooks/Slicer.ipynb", "/beta/html/PICS", "/code/pycodestyle.cfg", "/notebooks/Repairer.ipynb", "/notebooks/Tracking.ipynb", "/notebooks/ChangeExplorer.ipynb", "/notebooks/99_Appendices.ipynb", "/", "/notebooks", "/html", "/beta/html", "/beta", "/code" ], "labels": [ "index.ipynb", "custom.css", "ReleaseNotes.ipynb", "Intro_Debugging.ipynb", "Chapters.makefile", "Tracer.ipynb", "Guide_for_Authors.ipynb", "Debugger.ipynb", "StatisticalDebugger.ipynb", "Invariants.ipynb", "Time_Travel_Debugger.ipynb", "DeltaDebugger.ipynb", "Reducing_Code.ipynb", "Slicer.ipynb", "PICS", "pycodestyle.cfg", "Repairer.ipynb", "Tracking.ipynb", "ChangeExplorer.ipynb", "99_Appendices.ipynb", "/Users/zeller/Projects/debuggingbook", "notebooks", "html", "html", "beta", "code" ], "marker": { "colors": [ 1, 2, 1, 3, 1, 3, 1, 3, 9, 1, 1, 6, 1, 22, 1, 1, 5, 2, 1, 1, null, null, null, null, null, null ], "colorscale": [ [ 0.0, "rgb(255,255,204)" ], [ 0.125, "rgb(255,237,160)" ], [ 0.25, "rgb(254,217,118)" ], [ 0.375, "rgb(254,178,76)" ], [ 0.5, "rgb(253,141,60)" ], [ 0.625, "rgb(252,78,42)" ], [ 0.75, "rgb(227,26,28)" ], [ 0.875, "rgb(189,0,38)" ], [ 1.0, "rgb(128,0,38)" ] ] }, "parents": [ "/notebooks", "/html", "/notebooks", "/notebooks", "/", "/notebooks", "/notebooks", "/notebooks", "/notebooks", "/notebooks", "/notebooks", "/notebooks", "/notebooks", "/notebooks", "/beta/html", "/code", "/notebooks", "/notebooks", "/notebooks", "/notebooks", null, "/", "/", "/beta", "/", "/" ], "text": [ "Fix: Set metadata for proper title", "Fix: bad font size (for pretty much everything)\nUpdated docs
Fix: made custom.css available for binder", "Fix: title", "Fix: Python choices
Fix: Python choices
Fix: Use for keyboard keys", "Fix: \"Tracer\" is ready", "Fix: typo
Fix: quiz code highlighting
Fix: bad exercise numbering", "Fix: typo", "Fix: bad quiz choice
Fix: time travel debugger: save string representation of vars
Fix: allow assignment to local vars", "Fix: when importing, line numbers were off by one
Fix: middle() invocation
Fix: bad hue
Fix: debugger only worked in notebook
Fix: missing rename
Fix: listing should include _multiple_ functions covered, not just 1
Fix: look up item in caller's context
Fix: code_with_coverage() was failing
Fix: when collecting a function, use the globals from current frame", "Fix: use local valgrind", "Fix: need separate import for bookutils", "Fix: bad code export
Fix: metadata, dependencies
Fix: ChangeCollector.call() used wrong args
Fix: CallCollector: better function resolution
Fix: revised intro
Fix: can have multiple 'with dd:'", "Fix: also work as standalone code", "Fix: adjust line numbers for external functions
Fix: spurious data dependencies
Fix: handle built-in functions correctly
Fix: better caller location
Fix: handle case when all is untracked
Fix: missing data dependencies
Fix: better checking for new locations
Fix: setup for standalone code
Fix: missing cells
Fix: handle names of nested functions
Fix: support for generators
Fix: handle `del x` correctly; new: stress test
Fix: f(f(x)) did not track properly
Fix: proper flow into/out of comprehensions
Fix: Synopsis
Fix: Str(), Num() wouldn't work when imported
Fix: no warnings for inner functions
Fix: make code() work again\n\nPlus minor fixes to docstrings
Fix: removed code for old dependency representation
Fix: restored simple listing of dependencies
Fix: call FunctionType() correctly
Fix: report `FunctionType()` errors", "Fix: bad link", "Fix: missing style config", "Fix: did not tie in suspiciousness
Fix: proper import
Fix: various issues with crossover
Fix: have covered_functions() return function objects
Fix: instrument in caller's space", "Fix: be publishable
Fix: cleanup after completion", "Fix: catch-all rule for fine-grained exploration wasn't such a good idea", "Fix: notebook crossrefs", "", "", "", "", "", "" ], "type": "treemap", "values": [ 9.628524252492122, 9.55414281969224, 7.0630481633881725, 11.358619773129229, 7.75833346749091, 10.98681698433972, 11.713054195414049, 10.81631228476711, 11.57362537806985, 11.459429747027478, 10.099136569540946, 11.694538437444265, 10.718564713832988, 12.068848729639251, 2.70805020110221, 3.6375861597263857, 11.75458454110969, 10.349806654652559, 10.140573455973044, 7.2640301428995295, 192.34762667173214, 168.6895140237202, 9.55414281969225, 2.708050201102213, 2.7080502011022154, 3.6375861597263897 ] } ], "layout": { "margin": { "b": 0, "l": 0, "r": 0, "t": 30 }, "template": { "data": { "bar": [ { "error_x": { "color": "#2a3f5f" }, "error_y": { "color": "#2a3f5f" }, "marker": { "line": { "color": "#E5ECF6", "width": 0.5 } }, "type": "bar" } ], "barpolar": [ { "marker": { "line": { "color": "#E5ECF6", "width": 0.5 } }, "type": "barpolar" } ], "carpet": [ { "aaxis": { "endlinecolor": "#2a3f5f", "gridcolor": "white", "linecolor": "white", "minorgridcolor": "white", "startlinecolor": "#2a3f5f" }, "baxis": { "endlinecolor": "#2a3f5f", "gridcolor": "white", "linecolor": "white", "minorgridcolor": "white", "startlinecolor": "#2a3f5f" }, "type": "carpet" } ], "choropleth": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "type": "choropleth" } ], "contour": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0.0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1.0, "#f0f921" ] ], "type": "contour" } ], "contourcarpet": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "type": "contourcarpet" } ], "heatmap": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0.0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1.0, "#f0f921" ] ], "type": "heatmap" } ], "heatmapgl": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0.0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1.0, "#f0f921" ] ], "type": "heatmapgl" } ], "histogram": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "histogram" } ], "histogram2d": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0.0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1.0, "#f0f921" ] ], "type": "histogram2d" } ], "histogram2dcontour": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0.0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1.0, "#f0f921" ] ], "type": "histogram2dcontour" } ], "mesh3d": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "type": "mesh3d" } ], "parcoords": [ { "line": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "parcoords" } ], "pie": [ { "automargin": true, "type": "pie" } ], "scatter": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatter" } ], "scatter3d": [ { "line": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatter3d" } ], "scattercarpet": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattercarpet" } ], "scattergeo": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattergeo" } ], "scattergl": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattergl" } ], "scattermapbox": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattermapbox" } ], "scatterpolar": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatterpolar" } ], "scatterpolargl": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatterpolargl" } ], "scatterternary": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatterternary" } ], "surface": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0.0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1.0, "#f0f921" ] ], "type": "surface" } ], "table": [ { "cells": { "fill": { "color": "#EBF0F8" }, "line": { "color": "white" } }, "header": { "fill": { "color": "#C8D4E3" }, "line": { "color": "white" } }, "type": "table" } ] }, "layout": { "annotationdefaults": { "arrowcolor": "#2a3f5f", "arrowhead": 0, "arrowwidth": 1 }, "autotypenumbers": "strict", "coloraxis": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "colorscale": { "diverging": [ [ 0, "#8e0152" ], [ 0.1, "#c51b7d" ], [ 0.2, "#de77ae" ], [ 0.3, "#f1b6da" ], [ 0.4, "#fde0ef" ], [ 0.5, "#f7f7f7" ], [ 0.6, "#e6f5d0" ], [ 0.7, "#b8e186" ], [ 0.8, "#7fbc41" ], [ 0.9, "#4d9221" ], [ 1, "#276419" ] ], "sequential": [ [ 0.0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1.0, "#f0f921" ] ], "sequentialminus": [ [ 0.0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1.0, "#f0f921" ] ] }, "colorway": [ "#636efa", "#EF553B", "#00cc96", "#ab63fa", "#FFA15A", "#19d3f3", "#FF6692", "#B6E880", "#FF97FF", "#FECB52" ], "font": { "color": "#2a3f5f" }, "geo": { "bgcolor": "white", "lakecolor": "white", "landcolor": "#E5ECF6", "showlakes": true, "showland": true, "subunitcolor": "white" }, "hoverlabel": { "align": "left" }, "hovermode": "closest", "mapbox": { "style": "light" }, "paper_bgcolor": "white", "plot_bgcolor": "#E5ECF6", "polar": { "angularaxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" }, "bgcolor": "#E5ECF6", "radialaxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" } }, "scene": { "xaxis": { "backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white" }, "yaxis": { "backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white" }, "zaxis": { "backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white" } }, "shapedefaults": { "line": { "color": "#2a3f5f" } }, "ternary": { "aaxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" }, "baxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" }, "bgcolor": "#E5ECF6", "caxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" } }, "title": { "x": 0.05 }, "xaxis": { "automargin": true, "gridcolor": "white", "linecolor": "white", "ticks": "", "title": { "standoff": 15 }, "zerolinecolor": "white", "zerolinewidth": 2 }, "yaxis": { "automargin": true, "gridcolor": "white", "linecolor": "white", "ticks": "", "title": { "standoff": 15 }, "zerolinecolor": "white", "zerolinewidth": 2 } } } } }, "text/html": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "fix_counter.map()" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Fine-Grained Changes\n", "\n", "In programming projects, individual files typically consist of _smaller units_ such as functions, classes, and methods. We want to determine which of these _units_ are frequently changed (and fixed). For this, we need to _break down_ individual files into smaller parts, and then determine which of these parts would be affected by a change." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### Mapping Elements to Locations\n", "\n", "Our first task is a simple means to split a (programming) file into smaller parts, each with their own locations. First, we need to know what kind of content a file contains. To this end, we use the Python [magic](https://github.com/ahupp/python-magic) package. (The \"magic\" in the name does not refer to some \"magic\" functionality, but to the practice of having files start with \"magic\" bytes that indicate their type.)" ] }, { "cell_type": "code", "execution_count": 63, "metadata": { "slideshow": { "slide_type": "skip" } }, "outputs": [], "source": [ "import magic" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "The `magic` package easily guesses that a file contains C code:" ] }, { "cell_type": "code", "execution_count": 64, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/plain": [ "'C source, ASCII text'" ] }, "execution_count": 64, "metadata": {}, "output_type": "execute_result" } ], "source": [ "magic.from_buffer('''\n", "#include \n", "\n", "int main(int argc, char *argv[]) {\n", " printf(\"Hello, world!\\n\")\n", "}\n", "''')" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "It also works well for Python code:" ] }, { "cell_type": "code", "execution_count": 65, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "'Python script, ASCII text executable'" ] }, "execution_count": 65, "metadata": {}, "output_type": "execute_result" } ], "source": [ "magic.from_buffer('''\n", "def foo():\n", " print(\"Hello, world!\")\n", "''')" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Jupyter Notebooks, however, are identified as `SGML` documents:" ] }, { "cell_type": "code", "execution_count": 66, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/plain": [ "'exported SGML document, UTF-8 Unicode text, with very long lines'" ] }, "execution_count": 66, "metadata": {}, "output_type": "execute_result" } ], "source": [ "magic.from_buffer(open(os.path.join(current_repo(), 'notebooks', 'ChangeExplorer.ipynb')).read())" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "We define a set of _delimiters_ for these languages which use _regular expressions_ to identify\n", "* the _language_ (matching the `magic` output)\n", "* the _beginning of a unit_, and\n", "* the _end_ of a unit,\n", "\n", "For Python, for instance, any line starting with `def` or `class` denotes the start of some unit; any line starting with something else denotes the end of a unit. For Jupyter, the delimiters do the same, yet encoded into JSON. The definitions for C are likely to work for a wide range of languages that all use `{` and `}` to delimit units." ] }, { "cell_type": "code", "execution_count": 67, "metadata": { "slideshow": { "slide_type": "skip" } }, "outputs": [], "source": [ "import re" ] }, { "cell_type": "code", "execution_count": 68, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "DELIMITERS = [\n", " (\n", " # Python\n", " re.compile(r'^python.*'),\n", "\n", " # Beginning of element\n", " re.compile(r'^(async\\s+)?(def|class)\\s+(?P\\w+)\\W.*'),\n", "\n", " # End of element\n", " re.compile(r'^[^#\\s]')\n", " ),\n", " (\n", " # Jupyter Notebooks\n", " re.compile(r'^(json|exported sgml|jupyter).*'),\n", " re.compile(r'^\\s+\"(async\\s+)?(def|class)\\s+(?P\\w+)\\W'),\n", " re.compile(r'^(\\s+\"[^#\\s\\\\]|\\s+\\])')\n", " ),\n", " (\n", " # C source code (actually, any { }-delimited language)\n", " re.compile(r'^(c |c\\+\\+|c#|java|perl|php).*'),\n", " re.compile(r'^[^\\s].*\\s+(?P\\w+)\\s*[({].*'),\n", " re.compile(r'^[}]')\n", " )\n", "]" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "The function `rxdelim()` returns suitable delimiters for a given content, using `DELIMITERS`." ] }, { "cell_type": "code", "execution_count": 69, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "def rxdelim(content):\n", " \"\"\"Return suitable begin and end delimiters for the content `content`.\n", "If no matching delimiters are found, return `None, None`.\"\"\"\n", " tp = magic.from_buffer(content).lower()\n", " for rxtp, rxbegin, rxend in DELIMITERS:\n", " if rxtp.match(tp):\n", " return rxbegin, rxend\n", "\n", " return None, None" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "The function `elem_mapping()` returns a list of the individual elements as found in the file, indexed by line numbers (starting with 1)." ] }, { "cell_type": "code", "execution_count": 70, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "def elem_mapping(content, log=False):\n", " \"\"\"Return a list of the elements in `content`, indexed by line number.\"\"\"\n", " rxbegin, rxend = rxdelim(content)\n", " if rxbegin is None:\n", " return []\n", "\n", " mapping = [None]\n", " current_elem = None\n", " lineno = 0\n", "\n", " for line in content.split('\\n'):\n", " lineno += 1\n", "\n", " match = rxbegin.match(line)\n", " if match:\n", " current_elem = match.group('name')\n", " elif rxend.match(line):\n", " current_elem = None\n", "\n", " mapping.append(current_elem)\n", "\n", " if log:\n", " print(f\"{lineno:3} {str(current_elem):15} {line}\")\n", "\n", " return mapping" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Here is an example of how `elem_mapping()` works. During execution (with `log` set to `True`), we already see the elements associated with individual line numbers." ] }, { "cell_type": "code", "execution_count": 71, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " 1 None \n", " 2 None #include \n", " 3 None \n", " 4 foo int foo(int x) {\n", " 5 foo return x;\n", " 6 None }\n", " 7 None \n", " 8 bar struct bar {\n", " 9 bar int x, y;\n", " 10 None }\n", " 11 None \n", " 12 main int main(int argc, char *argv[]) {\n", " 13 main return foo(argc);\n", " 14 None }\n", " 15 None \n", " 16 None \n" ] } ], "source": [ "some_c_source = \"\"\"\n", "#include \n", "\n", "int foo(int x) {\n", " return x;\n", "}\n", "\n", "struct bar {\n", " int x, y;\n", "}\n", "\n", "int main(int argc, char *argv[]) {\n", " return foo(argc);\n", "}\n", "\n", "\"\"\"\n", "some_c_mapping = elem_mapping(some_c_source, log=True)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "In the actual mapping, we can access the individual units for any line number:" ] }, { "cell_type": "code", "execution_count": 72, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "(None, 'bar')" ] }, "execution_count": 72, "metadata": {}, "output_type": "execute_result" } ], "source": [ "some_c_mapping[1], some_c_mapping[8]" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Here's how this works for Python:" ] }, { "cell_type": "code", "execution_count": 73, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " 1 None \n", " 2 foo def foo(x):\n", " 3 foo return x\n", " 4 foo \n", " 5 bar class bar(blue):\n", " 6 bar x = 25\n", " 7 bar def f(x):\n", " 8 bar return 26\n", " 9 bar \n", " 10 main def main(argc):\n", " 11 main return foo(argc)\n", " 12 main \n", " 13 main \n" ] } ], "source": [ "some_python_source = \"\"\"\n", "def foo(x):\n", " return x\n", "\n", "class bar(blue):\n", " x = 25\n", " def f(x):\n", " return 26\n", "\n", "def main(argc):\n", " return foo(argc)\n", "\n", "\"\"\"\n", "some_python_mapping = elem_mapping(some_python_source, log=True)" ] }, { "cell_type": "code", "execution_count": 74, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "# some_jupyter_source = open(\"Slicer.ipynb\").read()\n", "# some_jupyter_mapping = elem_mapping(some_jupyter_source, log=False)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### Determining Changed Elements\n", "\n", "Using a mapping from `elem_mapping()`, we can determine which elements are affected by a change. The `changed_elems_by_mapping()` function returns the set of affected elements." ] }, { "cell_type": "code", "execution_count": 75, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "def changed_elems_by_mapping(mapping, start, length=0):\n", " \"\"\"Within `mapping`, return the set of elements affected by a change\n", "starting in line `start` and extending over `length` additional lines\"\"\"\n", " elems = set()\n", " for line in range(start, start + length + 1):\n", " if line < len(mapping) and mapping[line]:\n", " elems.add(mapping[line])\n", "\n", " return elems" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Here's an example of `changed_elems_by_mapping()`, applied to the Python content, above:" ] }, { "cell_type": "code", "execution_count": 76, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "{'bar', 'foo'}" ] }, "execution_count": 76, "metadata": {}, "output_type": "execute_result" } ], "source": [ "changed_elems_by_mapping(some_python_mapping, start=2, length=4)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "The function `elem_size()` returns the size of an element (say, a function)." ] }, { "cell_type": "code", "execution_count": 77, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "def elem_size(elem, source):\n", " \"\"\"Within `source`, return the size of `elem`\"\"\"\n", " source_lines = [''] + source.split('\\n')\n", " size = 0\n", " mapping = elem_mapping(source)\n", "\n", " for line_no in range(len(mapping)):\n", " if mapping[line_no] == elem or mapping[line_no] is elem:\n", " size += len(source_lines[line_no] + '\\n')\n", "\n", " return size" ] }, { "cell_type": "code", "execution_count": 78, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "26" ] }, "execution_count": 78, "metadata": {}, "output_type": "execute_result" } ], "source": [ "elem_size('foo', some_python_source)" ] }, { "cell_type": "code", "execution_count": 79, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "assert sum(elem_size(name, some_python_source) \n", " for name in ['foo', 'bar', 'main']) == len(some_python_source)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Given an old version and a new version of a (text) file, we can use the `diff_match_patch` module to determine differences, and from these the affected lines:" ] }, { "cell_type": "code", "execution_count": 80, "metadata": { "slideshow": { "slide_type": "skip" } }, "outputs": [], "source": [ "from ChangeDebugger import diff # minor dependency" ] }, { "cell_type": "code", "execution_count": 81, "metadata": { "slideshow": { "slide_type": "skip" } }, "outputs": [], "source": [ "from diff_match_patch import diff_match_patch" ] }, { "cell_type": "code", "execution_count": 82, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "def changed_elems(old_source, new_source):\n", " \"\"\"Determine the elements affected by the change from `old_source` to `new_source`\"\"\"\n", " patches = diff(old_source, new_source)\n", "\n", " old_mapping = elem_mapping(old_source)\n", " new_mapping = elem_mapping(new_source)\n", "\n", " elems = set()\n", "\n", " for patch in patches:\n", " old_start_line = patch.start1 + 1\n", " new_start_line = patch.start2 + 1\n", "\n", " for (op, data) in patch.diffs:\n", " length = data.count('\\n')\n", "\n", " if op == diff_match_patch.DIFF_INSERT:\n", " elems |= changed_elems_by_mapping(old_mapping, old_start_line)\n", " elems |= changed_elems_by_mapping(new_mapping, new_start_line, length)\n", " elif op == diff_match_patch.DIFF_DELETE:\n", " elems |= changed_elems_by_mapping(old_mapping, old_start_line, length)\n", " elems |= changed_elems_by_mapping(new_mapping, new_start_line)\n", "\n", " old_start_line += length\n", " new_start_line += length\n", " \n", " return elems" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Here is how `changed_elems()` works. We define a \"new\" version of `some_python_source`:" ] }, { "cell_type": "code", "execution_count": 83, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "some_new_python_source = \"\"\"\n", "def foo(y):\n", " return y\n", "\n", "class qux(blue):\n", " x = 25\n", " def f(x):\n", " return 26\n", "\n", "def main(argc):\n", " return foo(argc)\n", "\n", "\"\"\"" ] }, { "cell_type": "code", "execution_count": 84, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/plain": [ "{'bar', 'foo', 'qux'}" ] }, "execution_count": 84, "metadata": {}, "output_type": "execute_result" } ], "source": [ "changed_elems(some_python_source, some_new_python_source)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Note that the list of changed elements includes added as well as deleted elements." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### Putting it all Together\n", "\n", "We introduce a class `FineChangeCounter` that, like `ChangeCounter`, counts changes for individual files; however, `FineChangeCounter` adds additional nodes for all elements affected by the change. For a file consisting of multiple elements, this has the same effect as if the file were a directory, and the elements were all contained as individual files in this directory." ] }, { "cell_type": "code", "execution_count": 85, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "class FineChangeCounter(ChangeCounter):\n", " def update_elems(self, node, m):\n", " old_source = m.source_code_before if m.source_code_before else \"\"\n", " new_source = m.source_code if m.source_code else \"\"\n", " \n", " for elem in changed_elems(old_source, new_source):\n", " elem_node = node + (elem,)\n", "\n", " self.update_size(elem_node, elem_size(elem, new_source))\n", " self.update_changes(elem_node, m.msg)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Retrieving fine-grained changes takes a bit more time, since all files have to be parsed..." ] }, { "cell_type": "code", "execution_count": 86, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/plain": [ "164.12128805500106" ] }, "execution_count": 86, "metadata": {}, "output_type": "execute_result" } ], "source": [ "with Timer() as t:\n", " fine_change_counter = debuggingbook_change_counter(FineChangeCounter)\n", "\n", "t.elapsed_time()" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "... but the result is very much worth it. We can now zoom into individual files and compare the change counts for the individual functions." ] }, { "cell_type": "code", "execution_count": 87, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "application/vnd.plotly.v1+json": { "config": { "plotlyServerURL": "https://plot.ly" }, "data": [ { "branchvalues": "total", "hoverinfo": "label+text", "ids": [ "/README.md", "/Chapters.makefile", "/.gitignore", "/full_notebooks/index.ipynb~", "/binder/README.md", "/notebooks/99_Appendices.ipynb", "/beta/html/PICS", "/notebooks/01_Intro.ipynb", "/html/custom.css", "/notebooks/404.ipynb", "/notebooks/404.ipynb/NotFoundError", "/notebooks/Guide_for_Authors.ipynb/student_example", "/notebooks/Guide_for_Authors.ipynb/Foo", "/notebooks/Intro_Debugging.ipynb/int_fuzzer", "/notebooks/Template.ipynb/int_fuzzer", "/beta/code/LICENSE.md", "/notebooks/index.ipynb", "/binder/postBuild", "/beta/code/bookutils", "/code/setup.py.in", "/PICS", "/pdf/PICS", "/.gitmodules", "/notebooks/ReleaseNotes.ipynb", "/notebooks/00_Table_of_Contents.ipynb", "/notebooks/Guide_for_Authors.ipynb", "/notebooks/Intro_Debugging.ipynb", "/notebooks/Chapters.ipynb", "/ipypublish_plugins/README.md", "/ipypublish_plugins/html_ipypublish_chapter.py/hide_solution", "/beta/slides/reveal.js", "/html/favicon/android-chrome-144x144.png", "/notebooks/Debugger.ipynb", "/notebooks/Debugger.ipynb/changed_vars", "/notebooks/Debugger.ipynb/traceit", "/notebooks/Debugger.ipynb/remove_html_markup_traced", "/notebooks/Debugger.ipynb/int_fuzzer", "/notebooks/Debugger.ipynb/debug", "/notebooks/Debugger.ipynb/Tracer", "/notebooks/Tracer.ipynb", "/notebooks/Tracer.ipynb/C", "/notebooks/Tracer.ipynb/ConditionalTracer", "/notebooks/Tracer.ipynb/remove_html_markup_traced", "/notebooks/Tracer.ipynb/Tracer", "/notebooks/Tracer.ipynb/traceit", "/notebooks/Tracer.ipynb/EventTracer", "/notebooks/03_Observing.ipynb", "/notebooks/Intro_Debugging.ipynb/remove_html_markup_with_tag_assert", "/notebooks/Intro_Debugging.ipynb/remove_html_markup_with_quote_assert", "/notebooks/Intro_Debugging.ipynb/remove_html_markup", "/notebooks/Intro_Debugging.ipynb/remove_html_markup_with_proper_quotes", "/notebooks/Debugger.ipynb/Debugger", "/notebooks/Importing.ipynb", "/notebooks/StatisticalDebugger.ipynb", "/notebooks/StatisticalDebugger.ipynb/TarantulaDebugger", "/notebooks/StatisticalDebugger.ipynb/show_covered_lines", "/notebooks/StatisticalDebugger.ipynb/Collector", "/notebooks/StatisticalDebugger.ipynb/CoverageCollector", "/notebooks/StatisticalDebugger.ipynb/DifferenceDebugger", "/notebooks/StatisticalDebugger.ipynb/StatisticalDebugger", "/notebooks/.ipynb_checkpoints/index-checkpoint.ipynb", "/code/requirements.txt", "/notebooks/Intro_Debugging.ipynb/remove_html_markup_fixed", "/notebooks/Template.ipynb", "/notebooks/StatisticalDebugger.ipynb/DiscreteSpectrumDebugger", "/notebooks/StatisticalDebugger.ipynb/list_with_coverage", "/notebooks/StatisticalDebugger.ipynb/test_debugger_middle", "/notebooks/PICS/ClassDiagram-synopsis-1.png", "/notebooks/ClassDiagram.ipynb", "/notebooks/ClassDiagram.ipynb/public_class_methods", "/notebooks/ClassDiagram.ipynb/B", "/notebooks/ClassDiagram.ipynb/doc_class_methods", "/notebooks/ClassDiagram.ipynb/display_class_hierarchy", "/notebooks/ClassDiagram.ipynb/A", "/notebooks/ClassDiagram.ipynb/C", "/notebooks/ClassDiagram.ipynb/class_methods", "/notebooks/ClassDiagram.ipynb/D", "/notebooks/ClassDiagram.ipynb/class_hierarchy", "/notebooks/ClassDiagram.ipynb/class_tree", "/notebooks/Invariants.ipynb", "/notebooks/Invariants.ipynb/RedBlackTree", "/notebooks/Invariants.ipynb/remove_html_markup", "/notebooks/Invariants.ipynb/some_obscure_function", "/notebooks/Invariants.ipynb/int_fuzzer", "/notebooks/Invariants.ipynb/Time", "/notebooks/Invariants.ipynb/test_square_root", "/notebooks/Invariants.ipynb/my_own_assert", "/notebooks/Invariants.ipynb/square_root", "/notebooks/Invariants.ipynb/fun", "/notebooks/PICS/StatisticalDebugger-synopsis-1.png", "/notebooks/Invariants.ipynb/DynamicMemory", "/binder/requirements.txt", "/binder/apt.txt", "/.gitattributes", "/binder/postBuild.template", "/notebooks/Assertions.ipynb", "/notebooks/PICS/timetravel_debugger_gui_demo.gif", "/notebooks/Time_Travel_Debugger.ipynb/remove_html_markup", "/notebooks/Time_Travel_Debugger.ipynb/TimeTravelDebugger", "/notebooks/Time_Travel_Debugger.ipynb", "/notebooks/Reducer.ipynb", "/notebooks/Reducer.ipynb/possible_combinations", "/notebooks/Reducer.ipynb/EvalMysteryRunner", "/notebooks/Reducer.ipynb/max_height", "/notebooks/Reducer.ipynb/CachingReducer", "/notebooks/Reducer.ipynb/DeltaDebuggingReducer", "/notebooks/Reducer.ipynb/CallCollector", "/notebooks/Reducer.ipynb/mystery", "/notebooks/Reducer.ipynb/Reducer", "/notebooks/Reducer.ipynb/GrammarReducer", "/notebooks/Reducer.ipynb/number_of_nodes", "/notebooks/Reducer.ipynb/tree_list_to_string", "/notebooks/Reducer.ipynb/ZeroDivisionRunner", "/notebooks/Reducer.ipynb/fuzz", "/notebooks/Assertions.ipynb/remove_html_markup", "/notebooks/DeltaDebugger.ipynb", "/notebooks/DeltaDebugger.ipynb/CachingReducer", "/notebooks/DeltaDebugger.ipynb/CallCollector", "/notebooks/DeltaDebugger.ipynb/mystery", "/notebooks/DeltaDebugger.ipynb/Reducer", "/notebooks/DeltaDebugger.ipynb/generic_test", "/notebooks/DeltaDebugger.ipynb/ddmin", "/notebooks/DeltaDebugger.ipynb/fuzz", "/notebooks/DeltaDebugger.ipynb/DeltaDebugger", "/notebooks/DeltaDebugger.ipynb/myeval", "/notebooks/DeltaDebugger.ipynb/CachingCallReducer", "/notebooks/ChangeDebugger.ipynb", "/notebooks/ChangeDebugger.ipynb/write_source", "/notebooks/ChangeDebugger.ipynb/remove_html_markup", "/notebooks/ChangeDebugger.ipynb/int_fuzzer", "/notebooks/diff_match_patch/__init__.py", "/notebooks/diff_match_patch/diff_match_patch.py/patch_obj", "/notebooks/diff_match_patch/diff_match_patch.py/diff_match_patch", "/notebooks/DeltaDebugger.ipynb/NodeReducer", "/notebooks/DeltaDebugger.ipynb/compile_and_test_html_markup", "/notebooks/ChangeDebugger.ipynb/ChangeDebugger", "/notebooks/Draft_Second_Project.ipynb", "/notebooks/Draft_Second_Project.ipynb/DeltaDebuggerReducer", "/notebooks/Draft_Second_Project.ipynb/Parser3", "/notebooks/Draft_Second_Project.ipynb/ParserException", "/notebooks/Draft_Second_Project.ipynb/Parser5", "/notebooks/Draft_Second_Project.ipynb/Parser2", "/notebooks/Draft_Second_Project.ipynb/MyReducer", "/notebooks/Draft_Second_Project.ipynb/Parser0", "/notebooks/Draft_Second_Project.ipynb/Reducer", "/notebooks/Draft_Second_Project.ipynb/Parser4", "/notebooks/Draft_Second_Project.ipynb/Parser", "/notebooks/Draft_Second_Project.ipynb/Parser1", "/notebooks/Draft_Second_Project.ipynb/NodeCounter", "/notebooks/Draft_Second_Project.ipynb/PublicTests", "/notebooks/Slicer.ipynb", "/notebooks/Slicer.ipynb/SaveArgsTransformer", "/notebooks/Slicer.ipynb/middle", "/notebooks/Slicer.ipynb/AccessTransformer", "/notebooks/Slicer.ipynb/Instrumenter", "/notebooks/Slicer.ipynb/DataStore", "/notebooks/Slicer.ipynb/Slicer", "/notebooks/Slicer.ipynb/DataLogger", "/notebooks/Slicer.ipynb/tint", "/notebooks/Slicer.ipynb/square_root", "/notebooks/Slicer.ipynb/data_access", "/notebooks/Reducing_Code.ipynb", "/notebooks/Reducing_Code.ipynb/Test4", "/notebooks/Reducing_Code.ipynb/Test1", "/notebooks/Reducing_Code.ipynb/Parser3", "/notebooks/Reducing_Code.ipynb/Test3", "/notebooks/Reducing_Code.ipynb/ParserException", "/notebooks/Reducing_Code.ipynb/Parser2", "/notebooks/Reducing_Code.ipynb/Test5", "/notebooks/Reducing_Code.ipynb/SimpleParser", "/notebooks/Reducing_Code.ipynb/ReducingDebugger", "/notebooks/Reducing_Code.ipynb/Parser4", "/notebooks/Reducing_Code.ipynb/Parser", "/notebooks/Reducing_Code.ipynb/NodeReducer", "/notebooks/Reducing_Code.ipynb/NodeCounter", "/notebooks/Reducing_Code.ipynb/foo", "/notebooks/Reducing_Code.ipynb/Parser5", "/notebooks/Reducing_Code.ipynb/MyReducer", "/notebooks/Reducing_Code.ipynb/Test0", "/notebooks/Reducing_Code.ipynb/Test2", "/notebooks/Reducing_Code.ipynb/Parser1", "/notebooks/Reducing_Code.ipynb/original", "/notebooks/Reducing_Code.ipynb/SimpleParserPlus", "/notebooks/Reducing_Code.ipynb/TestingFramework", "/notebooks/Slicer.ipynb/DataTracker", "/notebooks/Slicer.ipynb/Dependencies", "/notebooks/PICS/Slicer-synopsis-1.png", "/notebooks/Slicer.ipynb/DependencyTracker", "/notebooks/Slicer.ipynb/TrackGetTransformer", "/notebooks/Slicer.ipynb/generator_test", "/notebooks/PICS/ChangeDebugger-synopsis-1.png", "/notebooks/PICS/Debugger-synopsis-1.png", "/html/favicon/android-chrome-192x192.png", "/notebooks/PICS/DeltaDebugger-synopsis-1.png", "/notebooks/PICS/Tracer-synopsis-1.png", "/notebooks/Repairer.ipynb", "/notebooks/Repairer.ipynb/StatementVisitor", "/notebooks/Repairer.ipynb/middle_tree", "/notebooks/Repairer.ipynb/middle_passing_testcase", "/notebooks/Repairer.ipynb/all_statements", "/notebooks/Repairer.ipynb/middle_testcase", "/notebooks/Repairer.ipynb/RandomNodeMutator", "/notebooks/Repairer.ipynb/middle_test", "/notebooks/Repairer.ipynb/middle_failing_testcase", "/code/pycodestyle.cfg", "/notebooks/Repairer.ipynb/StatementMutator", "/notebooks/Repairer.ipynb/ConditionMutator", "/notebooks/Repairer.ipynb/random_string", "/notebooks/Repairer.ipynb/evolve_middle", "/notebooks/Repairer.ipynb/Repairer", "/notebooks/Repairer.ipynb/CrossoverOperator", "/notebooks/PICS/Repairer-synopsis-1.png", "/notebooks/Tours.ipynb", "/notebooks/Tracking.ipynb", "/notebooks/Tracking.ipynb/all_modifications", "/notebooks/Tracking.ipynb/node_color", "/notebooks/PICS/Tracking-synopsis-1.png", "/notebooks/02_Observing.ipynb", "/notebooks/ChangeExplorer.ipynb", "/notebooks/ChangeExplorer.ipynb/ChangeCounter", "/notebooks/Repairer.ipynb/square_root_fixed", "/notebooks/Repairer.ipynb/ConditionVisitor", "/notebooks/PICS/ChangeExplorer-synopsis-1.png", "/notebooks/Tracking.ipynb/with_mysql", "/notebooks/Tracking.ipynb/start_redmine", "/notebooks/Tracking.ipynb/start_webdriver", "/notebooks/Tracking.ipynb/with_ruby", "/notebooks/Tracking.ipynb/run_redmine", "/notebooks/DynamicInvariants.ipynb/print_sum", "/notebooks/DynamicInvariants.ipynb/type_string", "/notebooks/DynamicInvariants.ipynb/TypeAnnotator", "/notebooks/DynamicInvariants.ipynb/InvariantAnnotator", "/notebooks/DynamicInvariants.ipynb/precondition", "/notebooks/DynamicInvariants.ipynb/my_sqrt_with_postcondition", "/notebooks/DynamicInvariants.ipynb/my_sqrt_with_union_type", "/notebooks/DynamicInvariants.ipynb/EmbeddedInvariantAnnotator", "/notebooks/DynamicInvariants.ipynb/InvariantTracker", "/notebooks/DynamicInvariants.ipynb/annotate_function_ast_with_invariants", "/notebooks/DynamicInvariants.ipynb/annotate_function_with_types", "/notebooks/DynamicInvariants.ipynb/PreconditionTransformer", "/notebooks/DynamicInvariants.ipynb/true_property_instantiations", "/notebooks/DynamicInvariants.ipynb/annotate_function_ast_with_types", "/notebooks/DynamicInvariants.ipynb/my_sqrt_with_precondition", "/notebooks/DynamicInvariants.ipynb/remove_first_char", "/notebooks/DynamicInvariants.ipynb/parse_type", "/notebooks/DynamicInvariants.ipynb/sum2", "/notebooks/DynamicInvariants.ipynb/buggy_my_sqrt_with_postcondition", "/notebooks/DynamicInvariants.ipynb/my_sqrt_with_checked_type_annotations", "/notebooks/DynamicInvariants.ipynb/list_length", "/notebooks/DynamicInvariants.ipynb/simple_call_string", "/notebooks/DynamicInvariants.ipynb/CallTracker", "/notebooks/DynamicInvariants.ipynb/annotate_invariants", "/notebooks/DynamicInvariants.ipynb/prop_function", "/notebooks/DynamicInvariants.ipynb/my_sqrt_with_local_types", "/notebooks/DynamicInvariants.ipynb/EmbeddedInvariantTransformer", "/notebooks/DynamicInvariants.ipynb/hello", "/notebooks/DynamicInvariants.ipynb/my_sqrt", "/notebooks/DynamicInvariants.ipynb/instantiate_prop", "/notebooks/DynamicInvariants.ipynb/pretty_invariants", "/notebooks/DynamicInvariants.ipynb/TypeTracker", "/notebooks/DynamicInvariants.ipynb/prop_function_text", "/notebooks/DynamicInvariants.ipynb/my_sqrt_with_invariants", "/notebooks/DynamicInvariants.ipynb/instantiate_prop_ast", "/notebooks/DynamicInvariants.ipynb/get_arguments", "/notebooks/DynamicInvariants.ipynb/postcondition", "/notebooks/DynamicInvariants.ipynb/Tracker", "/notebooks/DynamicInvariants.ipynb/my_sqrt_annotated", "/notebooks/DynamicInvariants.ipynb/condition", "/notebooks/DynamicInvariants.ipynb/annotate_function_with_invariants", "/notebooks/DynamicInvariants.ipynb/my_sqrt_with_type_annotations", "/notebooks/DynamicInvariants.ipynb/TypeTransformer", "/notebooks/DynamicInvariants.ipynb/metavars", "/notebooks/DynamicInvariants.ipynb/sum3", "/notebooks/DynamicInvariants.ipynb/annotate_types", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb/CallTracer", "/notebooks/DDSet.ipynb/int_fuzzer", "/notebooks/DDSet.ipynb", "/", "/full_notebooks", "/binder", "/notebooks", "/beta/html", "/beta", "/html", "/beta/code", "/code", "/pdf", "/ipypublish_plugins", "/ipypublish_plugins/html_ipypublish_chapter.py", "/beta/slides", "/html/favicon", "/notebooks/.ipynb_checkpoints", "/notebooks/PICS", "/notebooks/diff_match_patch", "/notebooks/diff_match_patch/diff_match_patch.py" ], "labels": [ "README.md", "Chapters.makefile", ".gitignore", "index.ipynb~", "README.md", "99_Appendices.ipynb", "PICS", "01_Intro.ipynb", "custom.css", "404.ipynb", "NotFoundError", "student_example", "Foo", "int_fuzzer", "int_fuzzer", "LICENSE.md", "index.ipynb", "postBuild", "bookutils", "setup.py.in", "PICS", "PICS", ".gitmodules", "ReleaseNotes.ipynb", "00_Table_of_Contents.ipynb", "Guide_for_Authors.ipynb", "Intro_Debugging.ipynb", "Chapters.ipynb", "README.md", "hide_solution", "reveal.js", "android-chrome-144x144.png", "Debugger.ipynb", "changed_vars", "traceit", "remove_html_markup_traced", "int_fuzzer", "debug", "Tracer", "Tracer.ipynb", "C", "ConditionalTracer", "remove_html_markup_traced", "Tracer", "traceit", "EventTracer", "03_Observing.ipynb", "remove_html_markup_with_tag_assert", "remove_html_markup_with_quote_assert", "remove_html_markup", "remove_html_markup_with_proper_quotes", "Debugger", "Importing.ipynb", "StatisticalDebugger.ipynb", "TarantulaDebugger", "show_covered_lines", "Collector", "CoverageCollector", "DifferenceDebugger", "StatisticalDebugger", "index-checkpoint.ipynb", "requirements.txt", "remove_html_markup_fixed", "Template.ipynb", "DiscreteSpectrumDebugger", "list_with_coverage", "test_debugger_middle", "ClassDiagram-synopsis-1.png", "ClassDiagram.ipynb", "public_class_methods", "B", "doc_class_methods", "display_class_hierarchy", "A", "C", "class_methods", "D", "class_hierarchy", "class_tree", "Invariants.ipynb", "RedBlackTree", "remove_html_markup", "some_obscure_function", "int_fuzzer", "Time", "test_square_root", "my_own_assert", "square_root", "fun", "StatisticalDebugger-synopsis-1.png", "DynamicMemory", "requirements.txt", "apt.txt", ".gitattributes", "postBuild.template", "Assertions.ipynb", "timetravel_debugger_gui_demo.gif", "remove_html_markup", "TimeTravelDebugger", "Time_Travel_Debugger.ipynb", "Reducer.ipynb", "possible_combinations", "EvalMysteryRunner", "max_height", "CachingReducer", "DeltaDebuggingReducer", "CallCollector", "mystery", "Reducer", "GrammarReducer", "number_of_nodes", "tree_list_to_string", "ZeroDivisionRunner", "fuzz", "remove_html_markup", "DeltaDebugger.ipynb", "CachingReducer", "CallCollector", "mystery", "Reducer", "generic_test", "ddmin", "fuzz", "DeltaDebugger", "myeval", "CachingCallReducer", "ChangeDebugger.ipynb", "write_source", "remove_html_markup", "int_fuzzer", "__init__.py", "patch_obj", "diff_match_patch", "NodeReducer", "compile_and_test_html_markup", "ChangeDebugger", "Draft_Second_Project.ipynb", "DeltaDebuggerReducer", "Parser3", "ParserException", "Parser5", "Parser2", "MyReducer", "Parser0", "Reducer", "Parser4", "Parser", "Parser1", "NodeCounter", "PublicTests", "Slicer.ipynb", "SaveArgsTransformer", "middle", "AccessTransformer", "Instrumenter", "DataStore", "Slicer", "DataLogger", "tint", "square_root", "data_access", "Reducing_Code.ipynb", "Test4", "Test1", "Parser3", "Test3", "ParserException", "Parser2", "Test5", "SimpleParser", "ReducingDebugger", "Parser4", "Parser", "NodeReducer", "NodeCounter", "foo", "Parser5", "MyReducer", "Test0", "Test2", "Parser1", "original", "SimpleParserPlus", "TestingFramework", "DataTracker", "Dependencies", "Slicer-synopsis-1.png", "DependencyTracker", "TrackGetTransformer", "generator_test", "ChangeDebugger-synopsis-1.png", "Debugger-synopsis-1.png", "android-chrome-192x192.png", "DeltaDebugger-synopsis-1.png", "Tracer-synopsis-1.png", "Repairer.ipynb", "StatementVisitor", "middle_tree", "middle_passing_testcase", "all_statements", "middle_testcase", "RandomNodeMutator", "middle_test", "middle_failing_testcase", "pycodestyle.cfg", "StatementMutator", "ConditionMutator", "random_string", "evolve_middle", "Repairer", "CrossoverOperator", "Repairer-synopsis-1.png", "Tours.ipynb", "Tracking.ipynb", "all_modifications", "node_color", "Tracking-synopsis-1.png", "02_Observing.ipynb", "ChangeExplorer.ipynb", "ChangeCounter", "square_root_fixed", "ConditionVisitor", "ChangeExplorer-synopsis-1.png", "with_mysql", "start_redmine", "start_webdriver", "with_ruby", "run_redmine", "print_sum", "type_string", "TypeAnnotator", "InvariantAnnotator", "precondition", "my_sqrt_with_postcondition", "my_sqrt_with_union_type", "EmbeddedInvariantAnnotator", "InvariantTracker", "annotate_function_ast_with_invariants", "annotate_function_with_types", "PreconditionTransformer", "true_property_instantiations", "annotate_function_ast_with_types", "my_sqrt_with_precondition", "remove_first_char", "parse_type", "sum2", "buggy_my_sqrt_with_postcondition", "my_sqrt_with_checked_type_annotations", "list_length", "simple_call_string", "CallTracker", "annotate_invariants", "prop_function", "my_sqrt_with_local_types", "EmbeddedInvariantTransformer", "hello", "my_sqrt", "instantiate_prop", "pretty_invariants", "TypeTracker", "prop_function_text", "my_sqrt_with_invariants", "instantiate_prop_ast", "get_arguments", "postcondition", "Tracker", "my_sqrt_annotated", "condition", "annotate_function_with_invariants", "my_sqrt_with_type_annotations", "TypeTransformer", "metavars", "sum3", "annotate_types", "DynamicInvariants.ipynb", "CallTracer", "int_fuzzer", "DDSet.ipynb", "/Users/zeller/Projects/debuggingbook", "full_notebooks", "binder", "notebooks", "html", "beta", "html", "code", "code", "pdf", "ipypublish_plugins", "html_ipypublish_chapter.py", "slides", "favicon", ".ipynb_checkpoints", "PICS", "diff_match_patch", "diff_match_patch.py" ], "marker": { "colors": [ 7, 29, 1, 1, 1, 2, 2, 3, 9, 1, 1, 1, 1, 1, 3, 1, 5, 7, 1, 2, 1, 1, 1, 1, 1, 6, 31, 3, 1, 1, 1, 1, 21, 1, 1, 1, 1, 3, 1, 24, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 3, 2, 2, 38, 2, 1, 1, 1, 1, 3, 1, 1, 1, 2, 2, 1, 1, 16, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 2, 1, 1, 1, 1, 1, 1, 1, 1, 176, 1, 1, 2, 1, 1, 11, 1, 1, 1, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 40, 1, 3, 1, 1, 1, 1, 1, 2, 1, 1, 16, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 109, 1, 2, 1, 1, 1, 7, 1, 1, 1, 1, 6, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 2, 183, 4, 1, 1, 49, 26, 1, 50, 57, 66, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 2, 73, 1, 25, 1, 1, 1, 1, 8, 1, 1, 1, 44, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 9, 1, 1, 1, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null ], "colorscale": [ [ 0.0, "rgb(255,255,204)" ], [ 0.125, "rgb(255,237,160)" ], [ 0.25, "rgb(254,217,118)" ], [ 0.375, "rgb(254,178,76)" ], [ 0.5, "rgb(253,141,60)" ], [ 0.625, "rgb(252,78,42)" ], [ 0.75, "rgb(227,26,28)" ], [ 0.875, "rgb(189,0,38)" ], [ 1.0, "rgb(128,0,38)" ] ] }, "parents": [ "/", "/", "/", "/full_notebooks", "/binder", "/notebooks", "/beta/html", "/notebooks", "/html", "/notebooks", "/notebooks/404.ipynb", "/notebooks/Guide_for_Authors.ipynb", "/notebooks/Guide_for_Authors.ipynb", "/notebooks/Intro_Debugging.ipynb", "/notebooks/Template.ipynb", "/beta/code", "/notebooks", "/binder", "/beta/code", "/code", "/", "/pdf", "/", "/notebooks", "/notebooks", "/notebooks", "/notebooks", "/notebooks", "/ipypublish_plugins", "/ipypublish_plugins/html_ipypublish_chapter.py", "/beta/slides", "/html/favicon", "/notebooks", "/notebooks/Debugger.ipynb", "/notebooks/Debugger.ipynb", "/notebooks/Debugger.ipynb", "/notebooks/Debugger.ipynb", "/notebooks/Debugger.ipynb", "/notebooks/Debugger.ipynb", "/notebooks", "/notebooks/Tracer.ipynb", "/notebooks/Tracer.ipynb", "/notebooks/Tracer.ipynb", "/notebooks/Tracer.ipynb", "/notebooks/Tracer.ipynb", "/notebooks/Tracer.ipynb", "/notebooks", "/notebooks/Intro_Debugging.ipynb", "/notebooks/Intro_Debugging.ipynb", "/notebooks/Intro_Debugging.ipynb", "/notebooks/Intro_Debugging.ipynb", "/notebooks/Debugger.ipynb", "/notebooks", "/notebooks", "/notebooks/StatisticalDebugger.ipynb", "/notebooks/StatisticalDebugger.ipynb", "/notebooks/StatisticalDebugger.ipynb", "/notebooks/StatisticalDebugger.ipynb", "/notebooks/StatisticalDebugger.ipynb", "/notebooks/StatisticalDebugger.ipynb", "/notebooks/.ipynb_checkpoints", "/code", "/notebooks/Intro_Debugging.ipynb", "/notebooks", "/notebooks/StatisticalDebugger.ipynb", "/notebooks/StatisticalDebugger.ipynb", "/notebooks/StatisticalDebugger.ipynb", "/notebooks/PICS", "/notebooks", "/notebooks/ClassDiagram.ipynb", "/notebooks/ClassDiagram.ipynb", "/notebooks/ClassDiagram.ipynb", "/notebooks/ClassDiagram.ipynb", "/notebooks/ClassDiagram.ipynb", "/notebooks/ClassDiagram.ipynb", "/notebooks/ClassDiagram.ipynb", "/notebooks/ClassDiagram.ipynb", "/notebooks/ClassDiagram.ipynb", "/notebooks/ClassDiagram.ipynb", "/notebooks", "/notebooks/Invariants.ipynb", "/notebooks/Invariants.ipynb", "/notebooks/Invariants.ipynb", "/notebooks/Invariants.ipynb", "/notebooks/Invariants.ipynb", "/notebooks/Invariants.ipynb", "/notebooks/Invariants.ipynb", "/notebooks/Invariants.ipynb", "/notebooks/Invariants.ipynb", "/notebooks/PICS", "/notebooks/Invariants.ipynb", "/binder", "/binder", "/", "/binder", "/notebooks", "/notebooks/PICS", "/notebooks/Time_Travel_Debugger.ipynb", "/notebooks/Time_Travel_Debugger.ipynb", "/notebooks", "/notebooks", "/notebooks/Reducer.ipynb", "/notebooks/Reducer.ipynb", "/notebooks/Reducer.ipynb", "/notebooks/Reducer.ipynb", "/notebooks/Reducer.ipynb", "/notebooks/Reducer.ipynb", "/notebooks/Reducer.ipynb", "/notebooks/Reducer.ipynb", "/notebooks/Reducer.ipynb", "/notebooks/Reducer.ipynb", "/notebooks/Reducer.ipynb", "/notebooks/Reducer.ipynb", "/notebooks/Reducer.ipynb", "/notebooks/Assertions.ipynb", "/notebooks", "/notebooks/DeltaDebugger.ipynb", "/notebooks/DeltaDebugger.ipynb", "/notebooks/DeltaDebugger.ipynb", "/notebooks/DeltaDebugger.ipynb", "/notebooks/DeltaDebugger.ipynb", "/notebooks/DeltaDebugger.ipynb", "/notebooks/DeltaDebugger.ipynb", "/notebooks/DeltaDebugger.ipynb", "/notebooks/DeltaDebugger.ipynb", "/notebooks/DeltaDebugger.ipynb", "/notebooks", "/notebooks/ChangeDebugger.ipynb", "/notebooks/ChangeDebugger.ipynb", "/notebooks/ChangeDebugger.ipynb", "/notebooks/diff_match_patch", "/notebooks/diff_match_patch/diff_match_patch.py", "/notebooks/diff_match_patch/diff_match_patch.py", "/notebooks/DeltaDebugger.ipynb", "/notebooks/DeltaDebugger.ipynb", "/notebooks/ChangeDebugger.ipynb", "/notebooks", "/notebooks/Draft_Second_Project.ipynb", "/notebooks/Draft_Second_Project.ipynb", "/notebooks/Draft_Second_Project.ipynb", "/notebooks/Draft_Second_Project.ipynb", "/notebooks/Draft_Second_Project.ipynb", "/notebooks/Draft_Second_Project.ipynb", "/notebooks/Draft_Second_Project.ipynb", "/notebooks/Draft_Second_Project.ipynb", "/notebooks/Draft_Second_Project.ipynb", "/notebooks/Draft_Second_Project.ipynb", "/notebooks/Draft_Second_Project.ipynb", "/notebooks/Draft_Second_Project.ipynb", "/notebooks/Draft_Second_Project.ipynb", "/notebooks", "/notebooks/Slicer.ipynb", "/notebooks/Slicer.ipynb", "/notebooks/Slicer.ipynb", "/notebooks/Slicer.ipynb", "/notebooks/Slicer.ipynb", "/notebooks/Slicer.ipynb", "/notebooks/Slicer.ipynb", "/notebooks/Slicer.ipynb", "/notebooks/Slicer.ipynb", "/notebooks/Slicer.ipynb", "/notebooks", "/notebooks/Reducing_Code.ipynb", "/notebooks/Reducing_Code.ipynb", "/notebooks/Reducing_Code.ipynb", "/notebooks/Reducing_Code.ipynb", "/notebooks/Reducing_Code.ipynb", "/notebooks/Reducing_Code.ipynb", "/notebooks/Reducing_Code.ipynb", "/notebooks/Reducing_Code.ipynb", "/notebooks/Reducing_Code.ipynb", "/notebooks/Reducing_Code.ipynb", "/notebooks/Reducing_Code.ipynb", "/notebooks/Reducing_Code.ipynb", "/notebooks/Reducing_Code.ipynb", "/notebooks/Reducing_Code.ipynb", "/notebooks/Reducing_Code.ipynb", "/notebooks/Reducing_Code.ipynb", "/notebooks/Reducing_Code.ipynb", "/notebooks/Reducing_Code.ipynb", "/notebooks/Reducing_Code.ipynb", "/notebooks/Reducing_Code.ipynb", "/notebooks/Reducing_Code.ipynb", "/notebooks/Reducing_Code.ipynb", "/notebooks/Slicer.ipynb", "/notebooks/Slicer.ipynb", "/notebooks/PICS", "/notebooks/Slicer.ipynb", "/notebooks/Slicer.ipynb", "/notebooks/Slicer.ipynb", "/notebooks/PICS", "/notebooks/PICS", "/html/favicon", "/notebooks/PICS", "/notebooks/PICS", "/notebooks", "/notebooks/Repairer.ipynb", "/notebooks/Repairer.ipynb", "/notebooks/Repairer.ipynb", "/notebooks/Repairer.ipynb", "/notebooks/Repairer.ipynb", "/notebooks/Repairer.ipynb", "/notebooks/Repairer.ipynb", "/notebooks/Repairer.ipynb", "/code", "/notebooks/Repairer.ipynb", "/notebooks/Repairer.ipynb", "/notebooks/Repairer.ipynb", "/notebooks/Repairer.ipynb", "/notebooks/Repairer.ipynb", "/notebooks/Repairer.ipynb", "/notebooks/PICS", "/notebooks", "/notebooks", "/notebooks/Tracking.ipynb", "/notebooks/Tracking.ipynb", "/notebooks/PICS", "/notebooks", "/notebooks", "/notebooks/ChangeExplorer.ipynb", "/notebooks/Repairer.ipynb", "/notebooks/Repairer.ipynb", "/notebooks/PICS", "/notebooks/Tracking.ipynb", "/notebooks/Tracking.ipynb", "/notebooks/Tracking.ipynb", "/notebooks/Tracking.ipynb", "/notebooks/Tracking.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DDSet.ipynb", "/notebooks", null, "/", "/", "/", "/beta", "/", "/", "/beta", "/", "/", "/", "/ipypublish_plugins", "/beta", "/html", "/notebooks", "/notebooks", "/notebooks", "/notebooks/diff_match_patch" ], "text": [ 7, 29, 1, 1, 1, 2, 2, 3, 9, 1, 1, 1, 1, 1, 3, 1, 5, 7, 1, 2, 1, 1, 1, 1, 1, 6, 31, 3, 1, 1, 1, 1, 21, 1, 1, 1, 1, 3, 1, 24, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 3, 2, 2, 38, 2, 1, 1, 1, 1, 3, 1, 1, 1, 2, 2, 1, 1, 16, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 2, 1, 1, 1, 1, 1, 1, 1, 1, 176, 1, 1, 2, 1, 1, 11, 1, 1, 1, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 40, 1, 3, 1, 1, 1, 1, 1, 2, 1, 1, 16, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 109, 1, 2, 1, 1, 1, 7, 1, 1, 1, 1, 6, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 2, 183, 4, 1, 1, 49, 26, 1, 50, 57, 66, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 2, 73, 1, 25, 1, 1, 1, 1, 8, 1, 1, 1, 44, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 9, 1, 1, 1, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null ], "type": "treemap", "values": [ 9.278092474027002, 8.101374671228582, 3.2188758248682006, 0, 6.171700597410915, 7.2640301428995295, 2.70805020110221, 7.346010209913293, 9.567175303116281, 13.556513119372408, 5.3230099791384085, 4.7535901911063645, 5.318119993844216, 4.997212273764115, 4.997212273764115, 3.044522437723423, 9.614604759507829, 9.644198554585564, 3.2188758248682006, 7.142827401161621, 2.6390573296152584, 2.833213344056216, 5.384495062789089, 7.0630481633881725, 3.8918202981106265, 20.97707883719506, 48.155126310322416, 8.31115254800169, 5.003946305945459, 6.921658184151129, 5.53338948872752, 0, 59.227819856459504, 5.857933154483459, 7.687080155783135, 5.147494476813453, 4.997212273764115, 7.452402451223638, 8.182000136293405, 49.40167251345942, 4.430816798843313, 7.347943823148687, 5.733341276897746, 8.182000136293405, 5.765191102784844, 6.963189985870238, 7.335633981927201, 6.359573868672378, 6.349138991379798, 7.583247524303362, 6.582025138892826, 9.07280095795412, 8.619027497297505, 70.35053068502665, 5.556828061699537, 6.018593214496234, 5.924255797414532, 6.137727054086234, 6.84587987526405, 8.47886807709457, 9.629576884168266, 5.056245805348308, 4.859812404361672, 14.216215018818955, 7.512071245835466, 6.035481432524756, 6.267200548541362, 8.21878715560148, 58.315679828323454, 5.093750200806762, 4.770684624465665, 5.003946305945459, 8.006367567650246, 4.174387269895637, 4.174387269895637, 6.419994928147142, 4.382026634673881, 5.973809611869261, 6.48768401848461, 72.3354651897531, 7.224753405767971, 6.983789965258135, 5.342334251964811, 4.997212273764115, 8.036249942132116, 4.844187086458591, 4.553876891600541, 6.943122422819428, 3.871201010907891, 9.796681548218318, 8.079308192051961, 4.532599493153256, 6.056784013228625, 4.68213122712422, 7.038783541388542, 18.48142918869067, 14.227734771764943, 6.20050917404269, 4.0943445622221, 20.722122623727138, 91.2364591096562, 6.175867270105761, 6.003887067106539, 5.2574953720277815, 5.966146739123692, 7.034387929915503, 7.277247726631484, 5.5254529391317835, 6.9865664594064265, 8.863332833439587, 4.941642422609304, 4.77912349311153, 5.869296913133774, 5.337538079701318, 6.983789965258135, 89.1889475500515, 5.966146739123692, 8.348301054933943, 5.5254529391317835, 6.734591659972948, 5.762051382780177, 6.951772164398911, 5.337538079701318, 8.423102268016642, 3.970291913552122, 6.656726524178391, 38.20320503698738, 5.402677381872279, 8.619388703730907, 4.997212273764115, 4.07753744390572, 7.249925536717988, 11.083234260436102, 7.460490305825338, 6.345636360828596, 7.8838232148921525, 92.57946671194716, 7.093404625868766, 7.161622002939187, 4.2626798770413155, 6.371611847231857, 6.432940092739179, 5.117993812416755, 6.267200548541362, 6.100318952020064, 7.202661196523238, 6.858565034791365, 6.416732282512326, 6.049733455231958, 7.285506548522785, 116.06629305271647, 6.595780513961311, 5.777652323222656, 4.969813299576001, 6.687108607866515, 6.068425588244111, 8.584851839890053, 6.306275286948016, 8.350902451694811, 5.834810737062605, 5.308267697401205, 139.4629764458604, 4.77912349311153, 4.859812404361672, 6.79346613258001, 4.77912349311153, 4.060443010546419, 5.4680601411351315, 4.859812404361672, 7.275172319452771, 7.453561871643373, 6.945051063725834, 5.8971538676367405, 6.173786103901937, 6.410174881966167, 6.329720905522696, 5.556828061699537, 5.075173815233827, 4.859812404361672, 4.77912349311153, 5.402677381872279, 7.156176637480615, 5.991464547107982, 7.838737559599282, 8.36287583103188, 9.570180302058072, 9.104201775914515, 9.431642228411022, 6.586171654854675, 5.529429087511423, 11.555659230890438, 8.624791202014256, 8.698180525197055, 9.093357016490364, 8.177515823846075, 117.38526591952393, 7.085064293952548, 4.442651256490317, 5.638354669333745, 5.733341276897746, 5.14166355650266, 8.172164452111904, 4.709530201312334, 5.541263545158426, 3.6375861597263857, 8.917310693197807, 7.553286605600419, 5.056245805348308, 6.405228458030842, 9.615938804529582, 8.510369966068112, 9.641148287756142, 8.381373468273702, 52.85796759319715, 7.084226422097916, 5.147494476813453, 11.348923082759187, 0, 19.21728018560999, 8.233768709217097, 5.929589143389895, 7.126087273299125, 11.68596238595356, 7.00669522683704, 5.5134287461649825, 7.152268856032539, 5.117993812416755, 4.718498871295094, 3.970291913552122, 4.2626798770413155, 6.795705775173514, 8.11969625295725, 5.442417710521793, 4.276666119016055, 4.418840607796598, 7.156176637480615, 7.027314514039777, 5.459585514144159, 5.8805329864007, 7.226209010100671, 6.70073110954781, 7.0967213784947605, 4.2626798770413155, 4.859812404361672, 5.840641657373398, 5.71042701737487, 4.430816798843313, 5.231108616854587, 5.159055299214529, 6.1779441140506, 7.8160138391590275, 6.018593214496234, 4.406719247264253, 5.973809611869261, 7.283448228756631, 4.0943445622221, 7.01301578963963, 5.752572638825633, 5.365976015021851, 4.02535169073515, 4.844187086458591, 5.752572638825633, 6.597145701886651, 5.799092654460526, 5.342334251964811, 0, 4.343805421853684, 7.284820912568604, 5.808142489980444, 5.187385805840755, 7.426549072397305, 5.8664680569332965, 4.007333185232471, 5.955837369464831, 277.25431619404065, 7.928406026180535, 4.997212273764115, 14.245811357857393, 1834.893143574901, 0, 33.444066199766944, 1704.7793798043574, 2.708050201102213, 14.504837952421383, 18.265355828313364, 6.263398262591631, 15.836659366236331, 2.8332133440562193, 11.925604490096607, 6.921658184151137, 5.533389488727527, 8.698180525197063, 9.629576884168277, 111.4747622812094, 22.41069724105985, 18.33315979715411 ] } ], "layout": { "margin": { "b": 0, "l": 0, "r": 0, "t": 30 }, "template": { "data": { "bar": [ { "error_x": { "color": "#2a3f5f" }, "error_y": { "color": "#2a3f5f" }, "marker": { "line": { "color": "#E5ECF6", "width": 0.5 } }, "type": "bar" } ], "barpolar": [ { "marker": { "line": { "color": "#E5ECF6", "width": 0.5 } }, "type": "barpolar" } ], "carpet": [ { "aaxis": { "endlinecolor": "#2a3f5f", "gridcolor": "white", "linecolor": "white", "minorgridcolor": "white", "startlinecolor": "#2a3f5f" }, "baxis": { "endlinecolor": "#2a3f5f", "gridcolor": "white", "linecolor": "white", "minorgridcolor": "white", "startlinecolor": "#2a3f5f" }, "type": "carpet" } ], "choropleth": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "type": "choropleth" } ], "contour": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0.0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1.0, "#f0f921" ] ], "type": "contour" } ], "contourcarpet": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "type": "contourcarpet" } ], "heatmap": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0.0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1.0, "#f0f921" ] ], "type": "heatmap" } ], "heatmapgl": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0.0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1.0, "#f0f921" ] ], "type": "heatmapgl" } ], "histogram": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "histogram" } ], "histogram2d": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0.0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1.0, "#f0f921" ] ], "type": "histogram2d" } ], "histogram2dcontour": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0.0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1.0, "#f0f921" ] ], "type": "histogram2dcontour" } ], "mesh3d": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "type": "mesh3d" } ], "parcoords": [ { "line": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "parcoords" } ], "pie": [ { "automargin": true, "type": "pie" } ], "scatter": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatter" } ], "scatter3d": [ { "line": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatter3d" } ], "scattercarpet": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattercarpet" } ], "scattergeo": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattergeo" } ], "scattergl": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattergl" } ], "scattermapbox": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattermapbox" } ], "scatterpolar": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatterpolar" } ], "scatterpolargl": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatterpolargl" } ], "scatterternary": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatterternary" } ], "surface": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0.0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1.0, "#f0f921" ] ], "type": "surface" } ], "table": [ { "cells": { "fill": { "color": "#EBF0F8" }, "line": { "color": "white" } }, "header": { "fill": { "color": "#C8D4E3" }, "line": { "color": "white" } }, "type": "table" } ] }, "layout": { "annotationdefaults": { "arrowcolor": "#2a3f5f", "arrowhead": 0, "arrowwidth": 1 }, "autotypenumbers": "strict", "coloraxis": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "colorscale": { "diverging": [ [ 0, "#8e0152" ], [ 0.1, "#c51b7d" ], [ 0.2, "#de77ae" ], [ 0.3, "#f1b6da" ], [ 0.4, "#fde0ef" ], [ 0.5, "#f7f7f7" ], [ 0.6, "#e6f5d0" ], [ 0.7, "#b8e186" ], [ 0.8, "#7fbc41" ], [ 0.9, "#4d9221" ], [ 1, "#276419" ] ], "sequential": [ [ 0.0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1.0, "#f0f921" ] ], "sequentialminus": [ [ 0.0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1.0, "#f0f921" ] ] }, "colorway": [ "#636efa", "#EF553B", "#00cc96", "#ab63fa", "#FFA15A", "#19d3f3", "#FF6692", "#B6E880", "#FF97FF", "#FECB52" ], "font": { "color": "#2a3f5f" }, "geo": { "bgcolor": "white", "lakecolor": "white", "landcolor": "#E5ECF6", "showlakes": true, "showland": true, "subunitcolor": "white" }, "hoverlabel": { "align": "left" }, "hovermode": "closest", "mapbox": { "style": "light" }, "paper_bgcolor": "white", "plot_bgcolor": "#E5ECF6", "polar": { "angularaxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" }, "bgcolor": "#E5ECF6", "radialaxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" } }, "scene": { "xaxis": { "backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white" }, "yaxis": { "backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white" }, "zaxis": { "backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white" } }, "shapedefaults": { "line": { "color": "#2a3f5f" } }, "ternary": { "aaxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" }, "baxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" }, "bgcolor": "#E5ECF6", "caxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" } }, "title": { "x": 0.05 }, "xaxis": { "automargin": true, "gridcolor": "white", "linecolor": "white", "ticks": "", "title": { "standoff": 15 }, "zerolinecolor": "white", "zerolinewidth": 2 }, "yaxis": { "automargin": true, "gridcolor": "white", "linecolor": "white", "ticks": "", "title": { "standoff": 15 }, "zerolinecolor": "white", "zerolinewidth": 2 } } } } }, "text/html": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "fine_change_counter.map()" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Like before, we can access the most frequently changed elements, This is the most frequently changed item in the book:" ] }, { "cell_type": "code", "execution_count": 88, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "[(('notebooks', 'Slicer.ipynb', 'Slicer'), 7)]" ] }, "execution_count": 88, "metadata": {}, "output_type": "execute_result" } ], "source": [ "elem_nodes = [node for node in fine_change_counter.changes.keys()\n", " if len(node) == 3 and node[1].endswith('.ipynb')]\n", "elem_nodes.sort(key=lambda node: fine_change_counter.changes[node], reverse=True)\n", "[(node, fine_change_counter.changes[node]) for node in elem_nodes[:1]]" ] }, { "cell_type": "code", "execution_count": 89, "metadata": { "slideshow": { "slide_type": "skip" } }, "outputs": [], "source": [ "from bookutils import quiz" ] }, { "cell_type": "code", "execution_count": 90, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/html": [ "\n", " \n", " \n", " \n", "
\n", "

Quiz

\n", "

\n", "

Which is the second most changed element?
\n", "

\n", "

\n", "

\n", " \n", " \n", "
\n", " \n", " \n", "
\n", " \n", " \n", "
\n", " \n", " \n", "
\n", " \n", "
\n", "

\n", " \n", "
\n", " " ], "text/plain": [ "" ] }, "execution_count": 90, "metadata": {}, "output_type": "execute_result" } ], "source": [ "quiz(\"Which is the _second_ most changed element?\",\n", " [\n", " f\"`{elem_nodes[3][2]}` in `{elem_nodes[3][1].split('.ipynb')[0]}`\",\n", " f\"`{elem_nodes[1][2]}` in `{elem_nodes[1][1].split('.ipynb')[0]}`\",\n", " f\"`{elem_nodes[2][2]}` in `{elem_nodes[2][1].split('.ipynb')[0]}`\",\n", " f\"`{elem_nodes[0][2]}` in `{elem_nodes[0][1].split('.ipynb')[0]}`\",\n", " ], 1975308642 / 987654321)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Indeed, here comes the list of the top five most frequently changed elements:" ] }, { "cell_type": "code", "execution_count": 91, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/plain": [ "[(('notebooks', 'Slicer.ipynb', 'Slicer'), 7),\n", " (('notebooks', 'Slicer.ipynb', 'DependencyTracker'), 4),\n", " (('notebooks', 'Template.ipynb', 'int_fuzzer'), 3),\n", " (('notebooks', 'Debugger.ipynb', 'debug'), 3),\n", " (('notebooks', 'Tracer.ipynb', 'ConditionalTracer'), 3)]" ] }, "execution_count": 91, "metadata": {}, "output_type": "execute_result" } ], "source": [ "[(node, fine_change_counter.changes[node]) for node in elem_nodes[:5]]" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Now it is time to apply these tools on your own projects. Which are the most frequently changed (and fixed) elements? Why is that so? What can you do to improve things? All these are consequences of debugging – to help having fewer bugs in the future!" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Synopsis" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "This chapter provides two classes `ChangeCounter` and `FineChangeCounter` that allow to mine and visualize the distribution of changes in a given `git` repository." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "`ChangeCounter` is initialized as\n", "\n", "```python\n", "change_counter = ChangeCounter(repository)\n", "```\n", "where `repository` is either \n", "\n", "* a _directory_ containing a `git` clone (i.e., it contains a `.git` directory)\n", "* the URL of a `git` repository.\n", "\n", "Additional arguments are being passed to the underlying `RepositoryMining` class from the [PyDriller](https://pydriller.readthedocs.io/) Python package. A `filter` keyword argument, if given, is a predicate that takes a modification (from PyDriller) and returns True if it should be included." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "In a change counter, all elements in the repository are represented as _nodes_ – tuples $(f_1, f_2, ..., f_n)$ that denote a _hierarchy_: Each $f_i$ is a directory holding $f_{i+1}$, with $f_n$ being the actual file.\n", "\n", "A `change_counter` provides a number of attributes. `changes` is a mapping of nodes to the number of changes in that node:" ] }, { "cell_type": "code", "execution_count": 92, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "7" ] }, "execution_count": 92, "metadata": {}, "output_type": "execute_result" } ], "source": [ "change_counter.changes[('README.md',)]" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "The `messages` attribute holds all commit messages related to that node:" ] }, { "cell_type": "code", "execution_count": 93, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/plain": [ "['first commit',\n", " 'Adjusted to debuggingbook',\n", " 'New Twitter handle: @Debugging_Book',\n", " 'Doc update',\n", " 'Doc update',\n", " 'Doc update',\n", " 'Doc update']" ] }, "execution_count": 93, "metadata": {}, "output_type": "execute_result" } ], "source": [ "change_counter.messages[('README.md',)]" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "The `sizes` attribute holds the (last) size of the respective element:" ] }, { "cell_type": "code", "execution_count": 94, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "10701" ] }, "execution_count": 94, "metadata": {}, "output_type": "execute_result" } ], "source": [ "change_counter.sizes[('README.md',)]" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "`FineChangeCounter` acts like `ChangeCounter`, but also retrieves statistics for elements _within_ the respective files; it has been tested for C, Python, and Jupyter Notebooks and should provide sufficient results for programming languages with similar syntax." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "The `map()` method of `ChangeCounter` and `FineChangeCounter` produces an interactive tree map that allows to explore the elements of a repository. The redder (darker) a rectangle, the more changes it has seen; the larger a rectangle, the larger its size in bytes." ] }, { "cell_type": "code", "execution_count": 95, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "application/vnd.plotly.v1+json": { "config": { "plotlyServerURL": "https://plot.ly" }, "data": [ { "branchvalues": "total", "hoverinfo": "label+text", "ids": [ "/README.md", "/Chapters.makefile", "/.gitignore", "/full_notebooks/index.ipynb~", "/binder/README.md", "/notebooks/99_Appendices.ipynb", "/beta/html/PICS", "/notebooks/01_Intro.ipynb", "/html/custom.css", "/notebooks/404.ipynb", "/notebooks/404.ipynb/NotFoundError", "/notebooks/Guide_for_Authors.ipynb/student_example", "/notebooks/Guide_for_Authors.ipynb/Foo", "/notebooks/Intro_Debugging.ipynb/int_fuzzer", "/notebooks/Template.ipynb/int_fuzzer", "/beta/code/LICENSE.md", "/notebooks/index.ipynb", "/binder/postBuild", "/beta/code/bookutils", "/code/setup.py.in", "/PICS", "/pdf/PICS", "/.gitmodules", "/notebooks/ReleaseNotes.ipynb", "/notebooks/00_Table_of_Contents.ipynb", "/notebooks/Guide_for_Authors.ipynb", "/notebooks/Intro_Debugging.ipynb", "/notebooks/Chapters.ipynb", "/ipypublish_plugins/README.md", "/ipypublish_plugins/html_ipypublish_chapter.py/hide_solution", "/beta/slides/reveal.js", "/html/favicon/android-chrome-144x144.png", "/notebooks/Debugger.ipynb", "/notebooks/Debugger.ipynb/changed_vars", "/notebooks/Debugger.ipynb/traceit", "/notebooks/Debugger.ipynb/remove_html_markup_traced", "/notebooks/Debugger.ipynb/int_fuzzer", "/notebooks/Debugger.ipynb/debug", "/notebooks/Debugger.ipynb/Tracer", "/notebooks/Tracer.ipynb", "/notebooks/Tracer.ipynb/C", "/notebooks/Tracer.ipynb/ConditionalTracer", "/notebooks/Tracer.ipynb/remove_html_markup_traced", "/notebooks/Tracer.ipynb/Tracer", "/notebooks/Tracer.ipynb/traceit", "/notebooks/Tracer.ipynb/EventTracer", "/notebooks/03_Observing.ipynb", "/notebooks/Intro_Debugging.ipynb/remove_html_markup_with_tag_assert", "/notebooks/Intro_Debugging.ipynb/remove_html_markup_with_quote_assert", "/notebooks/Intro_Debugging.ipynb/remove_html_markup", "/notebooks/Intro_Debugging.ipynb/remove_html_markup_with_proper_quotes", "/notebooks/Debugger.ipynb/Debugger", "/notebooks/Importing.ipynb", "/notebooks/StatisticalDebugger.ipynb", "/notebooks/StatisticalDebugger.ipynb/TarantulaDebugger", "/notebooks/StatisticalDebugger.ipynb/show_covered_lines", "/notebooks/StatisticalDebugger.ipynb/Collector", "/notebooks/StatisticalDebugger.ipynb/CoverageCollector", "/notebooks/StatisticalDebugger.ipynb/DifferenceDebugger", "/notebooks/StatisticalDebugger.ipynb/StatisticalDebugger", "/notebooks/.ipynb_checkpoints/index-checkpoint.ipynb", "/code/requirements.txt", "/notebooks/Intro_Debugging.ipynb/remove_html_markup_fixed", "/notebooks/Template.ipynb", "/notebooks/StatisticalDebugger.ipynb/DiscreteSpectrumDebugger", "/notebooks/StatisticalDebugger.ipynb/list_with_coverage", "/notebooks/StatisticalDebugger.ipynb/test_debugger_middle", "/notebooks/PICS/ClassDiagram-synopsis-1.png", "/notebooks/ClassDiagram.ipynb", "/notebooks/ClassDiagram.ipynb/public_class_methods", "/notebooks/ClassDiagram.ipynb/B", "/notebooks/ClassDiagram.ipynb/doc_class_methods", "/notebooks/ClassDiagram.ipynb/display_class_hierarchy", "/notebooks/ClassDiagram.ipynb/A", "/notebooks/ClassDiagram.ipynb/C", "/notebooks/ClassDiagram.ipynb/class_methods", "/notebooks/ClassDiagram.ipynb/D", "/notebooks/ClassDiagram.ipynb/class_hierarchy", "/notebooks/ClassDiagram.ipynb/class_tree", "/notebooks/Invariants.ipynb", "/notebooks/Invariants.ipynb/RedBlackTree", "/notebooks/Invariants.ipynb/remove_html_markup", "/notebooks/Invariants.ipynb/some_obscure_function", "/notebooks/Invariants.ipynb/int_fuzzer", "/notebooks/Invariants.ipynb/Time", "/notebooks/Invariants.ipynb/test_square_root", "/notebooks/Invariants.ipynb/my_own_assert", "/notebooks/Invariants.ipynb/square_root", "/notebooks/Invariants.ipynb/fun", "/notebooks/PICS/StatisticalDebugger-synopsis-1.png", "/notebooks/Invariants.ipynb/DynamicMemory", "/binder/requirements.txt", "/binder/apt.txt", "/.gitattributes", "/binder/postBuild.template", "/notebooks/Assertions.ipynb", "/notebooks/PICS/timetravel_debugger_gui_demo.gif", "/notebooks/Time_Travel_Debugger.ipynb/remove_html_markup", "/notebooks/Time_Travel_Debugger.ipynb/TimeTravelDebugger", "/notebooks/Time_Travel_Debugger.ipynb", "/notebooks/Reducer.ipynb", "/notebooks/Reducer.ipynb/possible_combinations", "/notebooks/Reducer.ipynb/EvalMysteryRunner", "/notebooks/Reducer.ipynb/max_height", "/notebooks/Reducer.ipynb/CachingReducer", "/notebooks/Reducer.ipynb/DeltaDebuggingReducer", "/notebooks/Reducer.ipynb/CallCollector", "/notebooks/Reducer.ipynb/mystery", "/notebooks/Reducer.ipynb/Reducer", "/notebooks/Reducer.ipynb/GrammarReducer", "/notebooks/Reducer.ipynb/number_of_nodes", "/notebooks/Reducer.ipynb/tree_list_to_string", "/notebooks/Reducer.ipynb/ZeroDivisionRunner", "/notebooks/Reducer.ipynb/fuzz", "/notebooks/Assertions.ipynb/remove_html_markup", "/notebooks/DeltaDebugger.ipynb", "/notebooks/DeltaDebugger.ipynb/CachingReducer", "/notebooks/DeltaDebugger.ipynb/CallCollector", "/notebooks/DeltaDebugger.ipynb/mystery", "/notebooks/DeltaDebugger.ipynb/Reducer", "/notebooks/DeltaDebugger.ipynb/generic_test", "/notebooks/DeltaDebugger.ipynb/ddmin", "/notebooks/DeltaDebugger.ipynb/fuzz", "/notebooks/DeltaDebugger.ipynb/DeltaDebugger", "/notebooks/DeltaDebugger.ipynb/myeval", "/notebooks/DeltaDebugger.ipynb/CachingCallReducer", "/notebooks/ChangeDebugger.ipynb", "/notebooks/ChangeDebugger.ipynb/write_source", "/notebooks/ChangeDebugger.ipynb/remove_html_markup", "/notebooks/ChangeDebugger.ipynb/int_fuzzer", "/notebooks/diff_match_patch/__init__.py", "/notebooks/diff_match_patch/diff_match_patch.py/patch_obj", "/notebooks/diff_match_patch/diff_match_patch.py/diff_match_patch", "/notebooks/DeltaDebugger.ipynb/NodeReducer", "/notebooks/DeltaDebugger.ipynb/compile_and_test_html_markup", "/notebooks/ChangeDebugger.ipynb/ChangeDebugger", "/notebooks/Draft_Second_Project.ipynb", "/notebooks/Draft_Second_Project.ipynb/DeltaDebuggerReducer", "/notebooks/Draft_Second_Project.ipynb/Parser3", "/notebooks/Draft_Second_Project.ipynb/ParserException", "/notebooks/Draft_Second_Project.ipynb/Parser5", "/notebooks/Draft_Second_Project.ipynb/Parser2", "/notebooks/Draft_Second_Project.ipynb/MyReducer", "/notebooks/Draft_Second_Project.ipynb/Parser0", "/notebooks/Draft_Second_Project.ipynb/Reducer", "/notebooks/Draft_Second_Project.ipynb/Parser4", "/notebooks/Draft_Second_Project.ipynb/Parser", "/notebooks/Draft_Second_Project.ipynb/Parser1", "/notebooks/Draft_Second_Project.ipynb/NodeCounter", "/notebooks/Draft_Second_Project.ipynb/PublicTests", "/notebooks/Slicer.ipynb", "/notebooks/Slicer.ipynb/SaveArgsTransformer", "/notebooks/Slicer.ipynb/middle", "/notebooks/Slicer.ipynb/AccessTransformer", "/notebooks/Slicer.ipynb/Instrumenter", "/notebooks/Slicer.ipynb/DataStore", "/notebooks/Slicer.ipynb/Slicer", "/notebooks/Slicer.ipynb/DataLogger", "/notebooks/Slicer.ipynb/tint", "/notebooks/Slicer.ipynb/square_root", "/notebooks/Slicer.ipynb/data_access", "/notebooks/Reducing_Code.ipynb", "/notebooks/Reducing_Code.ipynb/Test4", "/notebooks/Reducing_Code.ipynb/Test1", "/notebooks/Reducing_Code.ipynb/Parser3", "/notebooks/Reducing_Code.ipynb/Test3", "/notebooks/Reducing_Code.ipynb/ParserException", "/notebooks/Reducing_Code.ipynb/Parser2", "/notebooks/Reducing_Code.ipynb/Test5", "/notebooks/Reducing_Code.ipynb/SimpleParser", "/notebooks/Reducing_Code.ipynb/ReducingDebugger", "/notebooks/Reducing_Code.ipynb/Parser4", "/notebooks/Reducing_Code.ipynb/Parser", "/notebooks/Reducing_Code.ipynb/NodeReducer", "/notebooks/Reducing_Code.ipynb/NodeCounter", "/notebooks/Reducing_Code.ipynb/foo", "/notebooks/Reducing_Code.ipynb/Parser5", "/notebooks/Reducing_Code.ipynb/MyReducer", "/notebooks/Reducing_Code.ipynb/Test0", "/notebooks/Reducing_Code.ipynb/Test2", "/notebooks/Reducing_Code.ipynb/Parser1", "/notebooks/Reducing_Code.ipynb/original", "/notebooks/Reducing_Code.ipynb/SimpleParserPlus", "/notebooks/Reducing_Code.ipynb/TestingFramework", "/notebooks/Slicer.ipynb/DataTracker", "/notebooks/Slicer.ipynb/Dependencies", "/notebooks/PICS/Slicer-synopsis-1.png", "/notebooks/Slicer.ipynb/DependencyTracker", "/notebooks/Slicer.ipynb/TrackGetTransformer", "/notebooks/Slicer.ipynb/generator_test", "/notebooks/PICS/ChangeDebugger-synopsis-1.png", "/notebooks/PICS/Debugger-synopsis-1.png", "/html/favicon/android-chrome-192x192.png", "/notebooks/PICS/DeltaDebugger-synopsis-1.png", "/notebooks/PICS/Tracer-synopsis-1.png", "/notebooks/Repairer.ipynb", "/notebooks/Repairer.ipynb/StatementVisitor", "/notebooks/Repairer.ipynb/middle_tree", "/notebooks/Repairer.ipynb/middle_passing_testcase", "/notebooks/Repairer.ipynb/all_statements", "/notebooks/Repairer.ipynb/middle_testcase", "/notebooks/Repairer.ipynb/RandomNodeMutator", "/notebooks/Repairer.ipynb/middle_test", "/notebooks/Repairer.ipynb/middle_failing_testcase", "/code/pycodestyle.cfg", "/notebooks/Repairer.ipynb/StatementMutator", "/notebooks/Repairer.ipynb/ConditionMutator", "/notebooks/Repairer.ipynb/random_string", "/notebooks/Repairer.ipynb/evolve_middle", "/notebooks/Repairer.ipynb/Repairer", "/notebooks/Repairer.ipynb/CrossoverOperator", "/notebooks/PICS/Repairer-synopsis-1.png", "/notebooks/Tours.ipynb", "/notebooks/Tracking.ipynb", "/notebooks/Tracking.ipynb/all_modifications", "/notebooks/Tracking.ipynb/node_color", "/notebooks/PICS/Tracking-synopsis-1.png", "/notebooks/02_Observing.ipynb", "/notebooks/ChangeExplorer.ipynb", "/notebooks/ChangeExplorer.ipynb/ChangeCounter", "/notebooks/Repairer.ipynb/square_root_fixed", "/notebooks/Repairer.ipynb/ConditionVisitor", "/notebooks/PICS/ChangeExplorer-synopsis-1.png", "/notebooks/Tracking.ipynb/with_mysql", "/notebooks/Tracking.ipynb/start_redmine", "/notebooks/Tracking.ipynb/start_webdriver", "/notebooks/Tracking.ipynb/with_ruby", "/notebooks/Tracking.ipynb/run_redmine", "/notebooks/DynamicInvariants.ipynb/print_sum", "/notebooks/DynamicInvariants.ipynb/type_string", "/notebooks/DynamicInvariants.ipynb/TypeAnnotator", "/notebooks/DynamicInvariants.ipynb/InvariantAnnotator", "/notebooks/DynamicInvariants.ipynb/precondition", "/notebooks/DynamicInvariants.ipynb/my_sqrt_with_postcondition", "/notebooks/DynamicInvariants.ipynb/my_sqrt_with_union_type", "/notebooks/DynamicInvariants.ipynb/EmbeddedInvariantAnnotator", "/notebooks/DynamicInvariants.ipynb/InvariantTracker", "/notebooks/DynamicInvariants.ipynb/annotate_function_ast_with_invariants", "/notebooks/DynamicInvariants.ipynb/annotate_function_with_types", "/notebooks/DynamicInvariants.ipynb/PreconditionTransformer", "/notebooks/DynamicInvariants.ipynb/true_property_instantiations", "/notebooks/DynamicInvariants.ipynb/annotate_function_ast_with_types", "/notebooks/DynamicInvariants.ipynb/my_sqrt_with_precondition", "/notebooks/DynamicInvariants.ipynb/remove_first_char", "/notebooks/DynamicInvariants.ipynb/parse_type", "/notebooks/DynamicInvariants.ipynb/sum2", "/notebooks/DynamicInvariants.ipynb/buggy_my_sqrt_with_postcondition", "/notebooks/DynamicInvariants.ipynb/my_sqrt_with_checked_type_annotations", "/notebooks/DynamicInvariants.ipynb/list_length", "/notebooks/DynamicInvariants.ipynb/simple_call_string", "/notebooks/DynamicInvariants.ipynb/CallTracker", "/notebooks/DynamicInvariants.ipynb/annotate_invariants", "/notebooks/DynamicInvariants.ipynb/prop_function", "/notebooks/DynamicInvariants.ipynb/my_sqrt_with_local_types", "/notebooks/DynamicInvariants.ipynb/EmbeddedInvariantTransformer", "/notebooks/DynamicInvariants.ipynb/hello", "/notebooks/DynamicInvariants.ipynb/my_sqrt", "/notebooks/DynamicInvariants.ipynb/instantiate_prop", "/notebooks/DynamicInvariants.ipynb/pretty_invariants", "/notebooks/DynamicInvariants.ipynb/TypeTracker", "/notebooks/DynamicInvariants.ipynb/prop_function_text", "/notebooks/DynamicInvariants.ipynb/my_sqrt_with_invariants", "/notebooks/DynamicInvariants.ipynb/instantiate_prop_ast", "/notebooks/DynamicInvariants.ipynb/get_arguments", "/notebooks/DynamicInvariants.ipynb/postcondition", "/notebooks/DynamicInvariants.ipynb/Tracker", "/notebooks/DynamicInvariants.ipynb/my_sqrt_annotated", "/notebooks/DynamicInvariants.ipynb/condition", "/notebooks/DynamicInvariants.ipynb/annotate_function_with_invariants", "/notebooks/DynamicInvariants.ipynb/my_sqrt_with_type_annotations", "/notebooks/DynamicInvariants.ipynb/TypeTransformer", "/notebooks/DynamicInvariants.ipynb/metavars", "/notebooks/DynamicInvariants.ipynb/sum3", "/notebooks/DynamicInvariants.ipynb/annotate_types", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb/CallTracer", "/notebooks/DDSet.ipynb/int_fuzzer", "/notebooks/DDSet.ipynb", "/", "/full_notebooks", "/binder", "/notebooks", "/beta/html", "/beta", "/html", "/beta/code", "/code", "/pdf", "/ipypublish_plugins", "/ipypublish_plugins/html_ipypublish_chapter.py", "/beta/slides", "/html/favicon", "/notebooks/.ipynb_checkpoints", "/notebooks/PICS", "/notebooks/diff_match_patch", "/notebooks/diff_match_patch/diff_match_patch.py" ], "labels": [ "README.md", "Chapters.makefile", ".gitignore", "index.ipynb~", "README.md", "99_Appendices.ipynb", "PICS", "01_Intro.ipynb", "custom.css", "404.ipynb", "NotFoundError", "student_example", "Foo", "int_fuzzer", "int_fuzzer", "LICENSE.md", "index.ipynb", "postBuild", "bookutils", "setup.py.in", "PICS", "PICS", ".gitmodules", "ReleaseNotes.ipynb", "00_Table_of_Contents.ipynb", "Guide_for_Authors.ipynb", "Intro_Debugging.ipynb", "Chapters.ipynb", "README.md", "hide_solution", "reveal.js", "android-chrome-144x144.png", "Debugger.ipynb", "changed_vars", "traceit", "remove_html_markup_traced", "int_fuzzer", "debug", "Tracer", "Tracer.ipynb", "C", "ConditionalTracer", "remove_html_markup_traced", "Tracer", "traceit", "EventTracer", "03_Observing.ipynb", "remove_html_markup_with_tag_assert", "remove_html_markup_with_quote_assert", "remove_html_markup", "remove_html_markup_with_proper_quotes", "Debugger", "Importing.ipynb", "StatisticalDebugger.ipynb", "TarantulaDebugger", "show_covered_lines", "Collector", "CoverageCollector", "DifferenceDebugger", "StatisticalDebugger", "index-checkpoint.ipynb", "requirements.txt", "remove_html_markup_fixed", "Template.ipynb", "DiscreteSpectrumDebugger", "list_with_coverage", "test_debugger_middle", "ClassDiagram-synopsis-1.png", "ClassDiagram.ipynb", "public_class_methods", "B", "doc_class_methods", "display_class_hierarchy", "A", "C", "class_methods", "D", "class_hierarchy", "class_tree", "Invariants.ipynb", "RedBlackTree", "remove_html_markup", "some_obscure_function", "int_fuzzer", "Time", "test_square_root", "my_own_assert", "square_root", "fun", "StatisticalDebugger-synopsis-1.png", "DynamicMemory", "requirements.txt", "apt.txt", ".gitattributes", "postBuild.template", "Assertions.ipynb", "timetravel_debugger_gui_demo.gif", "remove_html_markup", "TimeTravelDebugger", "Time_Travel_Debugger.ipynb", "Reducer.ipynb", "possible_combinations", "EvalMysteryRunner", "max_height", "CachingReducer", "DeltaDebuggingReducer", "CallCollector", "mystery", "Reducer", "GrammarReducer", "number_of_nodes", "tree_list_to_string", "ZeroDivisionRunner", "fuzz", "remove_html_markup", "DeltaDebugger.ipynb", "CachingReducer", "CallCollector", "mystery", "Reducer", "generic_test", "ddmin", "fuzz", "DeltaDebugger", "myeval", "CachingCallReducer", "ChangeDebugger.ipynb", "write_source", "remove_html_markup", "int_fuzzer", "__init__.py", "patch_obj", "diff_match_patch", "NodeReducer", "compile_and_test_html_markup", "ChangeDebugger", "Draft_Second_Project.ipynb", "DeltaDebuggerReducer", "Parser3", "ParserException", "Parser5", "Parser2", "MyReducer", "Parser0", "Reducer", "Parser4", "Parser", "Parser1", "NodeCounter", "PublicTests", "Slicer.ipynb", "SaveArgsTransformer", "middle", "AccessTransformer", "Instrumenter", "DataStore", "Slicer", "DataLogger", "tint", "square_root", "data_access", "Reducing_Code.ipynb", "Test4", "Test1", "Parser3", "Test3", "ParserException", "Parser2", "Test5", "SimpleParser", "ReducingDebugger", "Parser4", "Parser", "NodeReducer", "NodeCounter", "foo", "Parser5", "MyReducer", "Test0", "Test2", "Parser1", "original", "SimpleParserPlus", "TestingFramework", "DataTracker", "Dependencies", "Slicer-synopsis-1.png", "DependencyTracker", "TrackGetTransformer", "generator_test", "ChangeDebugger-synopsis-1.png", "Debugger-synopsis-1.png", "android-chrome-192x192.png", "DeltaDebugger-synopsis-1.png", "Tracer-synopsis-1.png", "Repairer.ipynb", "StatementVisitor", "middle_tree", "middle_passing_testcase", "all_statements", "middle_testcase", "RandomNodeMutator", "middle_test", "middle_failing_testcase", "pycodestyle.cfg", "StatementMutator", "ConditionMutator", "random_string", "evolve_middle", "Repairer", "CrossoverOperator", "Repairer-synopsis-1.png", "Tours.ipynb", "Tracking.ipynb", "all_modifications", "node_color", "Tracking-synopsis-1.png", "02_Observing.ipynb", "ChangeExplorer.ipynb", "ChangeCounter", "square_root_fixed", "ConditionVisitor", "ChangeExplorer-synopsis-1.png", "with_mysql", "start_redmine", "start_webdriver", "with_ruby", "run_redmine", "print_sum", "type_string", "TypeAnnotator", "InvariantAnnotator", "precondition", "my_sqrt_with_postcondition", "my_sqrt_with_union_type", "EmbeddedInvariantAnnotator", "InvariantTracker", "annotate_function_ast_with_invariants", "annotate_function_with_types", "PreconditionTransformer", "true_property_instantiations", "annotate_function_ast_with_types", "my_sqrt_with_precondition", "remove_first_char", "parse_type", "sum2", "buggy_my_sqrt_with_postcondition", "my_sqrt_with_checked_type_annotations", "list_length", "simple_call_string", "CallTracker", "annotate_invariants", "prop_function", "my_sqrt_with_local_types", "EmbeddedInvariantTransformer", "hello", "my_sqrt", "instantiate_prop", "pretty_invariants", "TypeTracker", "prop_function_text", "my_sqrt_with_invariants", "instantiate_prop_ast", "get_arguments", "postcondition", "Tracker", "my_sqrt_annotated", "condition", "annotate_function_with_invariants", "my_sqrt_with_type_annotations", "TypeTransformer", "metavars", "sum3", "annotate_types", "DynamicInvariants.ipynb", "CallTracer", "int_fuzzer", "DDSet.ipynb", "/Users/zeller/Projects/debuggingbook", "full_notebooks", "binder", "notebooks", "html", "beta", "html", "code", "code", "pdf", "ipypublish_plugins", "html_ipypublish_chapter.py", "slides", "favicon", ".ipynb_checkpoints", "PICS", "diff_match_patch", "diff_match_patch.py" ], "marker": { "colors": [ 7, 29, 1, 1, 1, 2, 2, 3, 9, 1, 1, 1, 1, 1, 3, 1, 5, 7, 1, 2, 1, 1, 1, 1, 1, 6, 31, 3, 1, 1, 1, 1, 21, 1, 1, 1, 1, 3, 1, 24, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 3, 2, 2, 38, 2, 1, 1, 1, 1, 3, 1, 1, 1, 2, 2, 1, 1, 16, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 2, 1, 1, 1, 1, 1, 1, 1, 1, 176, 1, 1, 2, 1, 1, 11, 1, 1, 1, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 40, 1, 3, 1, 1, 1, 1, 1, 2, 1, 1, 16, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 109, 1, 2, 1, 1, 1, 7, 1, 1, 1, 1, 6, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 2, 183, 4, 1, 1, 49, 26, 1, 50, 57, 66, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 2, 73, 1, 25, 1, 1, 1, 1, 8, 1, 1, 1, 44, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 9, 1, 1, 1, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null ], "colorscale": [ [ 0.0, "rgb(255,255,204)" ], [ 0.125, "rgb(255,237,160)" ], [ 0.25, "rgb(254,217,118)" ], [ 0.375, "rgb(254,178,76)" ], [ 0.5, "rgb(253,141,60)" ], [ 0.625, "rgb(252,78,42)" ], [ 0.75, "rgb(227,26,28)" ], [ 0.875, "rgb(189,0,38)" ], [ 1.0, "rgb(128,0,38)" ] ] }, "parents": [ "/", "/", "/", "/full_notebooks", "/binder", "/notebooks", "/beta/html", "/notebooks", "/html", "/notebooks", "/notebooks/404.ipynb", "/notebooks/Guide_for_Authors.ipynb", "/notebooks/Guide_for_Authors.ipynb", "/notebooks/Intro_Debugging.ipynb", "/notebooks/Template.ipynb", "/beta/code", "/notebooks", "/binder", "/beta/code", "/code", "/", "/pdf", "/", "/notebooks", "/notebooks", "/notebooks", "/notebooks", "/notebooks", "/ipypublish_plugins", "/ipypublish_plugins/html_ipypublish_chapter.py", "/beta/slides", "/html/favicon", "/notebooks", "/notebooks/Debugger.ipynb", "/notebooks/Debugger.ipynb", "/notebooks/Debugger.ipynb", "/notebooks/Debugger.ipynb", "/notebooks/Debugger.ipynb", "/notebooks/Debugger.ipynb", "/notebooks", "/notebooks/Tracer.ipynb", "/notebooks/Tracer.ipynb", "/notebooks/Tracer.ipynb", "/notebooks/Tracer.ipynb", "/notebooks/Tracer.ipynb", "/notebooks/Tracer.ipynb", "/notebooks", "/notebooks/Intro_Debugging.ipynb", "/notebooks/Intro_Debugging.ipynb", "/notebooks/Intro_Debugging.ipynb", "/notebooks/Intro_Debugging.ipynb", "/notebooks/Debugger.ipynb", "/notebooks", "/notebooks", "/notebooks/StatisticalDebugger.ipynb", "/notebooks/StatisticalDebugger.ipynb", "/notebooks/StatisticalDebugger.ipynb", "/notebooks/StatisticalDebugger.ipynb", "/notebooks/StatisticalDebugger.ipynb", "/notebooks/StatisticalDebugger.ipynb", "/notebooks/.ipynb_checkpoints", "/code", "/notebooks/Intro_Debugging.ipynb", "/notebooks", "/notebooks/StatisticalDebugger.ipynb", "/notebooks/StatisticalDebugger.ipynb", "/notebooks/StatisticalDebugger.ipynb", "/notebooks/PICS", "/notebooks", "/notebooks/ClassDiagram.ipynb", "/notebooks/ClassDiagram.ipynb", "/notebooks/ClassDiagram.ipynb", "/notebooks/ClassDiagram.ipynb", "/notebooks/ClassDiagram.ipynb", "/notebooks/ClassDiagram.ipynb", "/notebooks/ClassDiagram.ipynb", "/notebooks/ClassDiagram.ipynb", "/notebooks/ClassDiagram.ipynb", "/notebooks/ClassDiagram.ipynb", "/notebooks", "/notebooks/Invariants.ipynb", "/notebooks/Invariants.ipynb", "/notebooks/Invariants.ipynb", "/notebooks/Invariants.ipynb", "/notebooks/Invariants.ipynb", "/notebooks/Invariants.ipynb", "/notebooks/Invariants.ipynb", "/notebooks/Invariants.ipynb", "/notebooks/Invariants.ipynb", "/notebooks/PICS", "/notebooks/Invariants.ipynb", "/binder", "/binder", "/", "/binder", "/notebooks", "/notebooks/PICS", "/notebooks/Time_Travel_Debugger.ipynb", "/notebooks/Time_Travel_Debugger.ipynb", "/notebooks", "/notebooks", "/notebooks/Reducer.ipynb", "/notebooks/Reducer.ipynb", "/notebooks/Reducer.ipynb", "/notebooks/Reducer.ipynb", "/notebooks/Reducer.ipynb", "/notebooks/Reducer.ipynb", "/notebooks/Reducer.ipynb", "/notebooks/Reducer.ipynb", "/notebooks/Reducer.ipynb", "/notebooks/Reducer.ipynb", "/notebooks/Reducer.ipynb", "/notebooks/Reducer.ipynb", "/notebooks/Reducer.ipynb", "/notebooks/Assertions.ipynb", "/notebooks", "/notebooks/DeltaDebugger.ipynb", "/notebooks/DeltaDebugger.ipynb", "/notebooks/DeltaDebugger.ipynb", "/notebooks/DeltaDebugger.ipynb", "/notebooks/DeltaDebugger.ipynb", "/notebooks/DeltaDebugger.ipynb", "/notebooks/DeltaDebugger.ipynb", "/notebooks/DeltaDebugger.ipynb", "/notebooks/DeltaDebugger.ipynb", "/notebooks/DeltaDebugger.ipynb", "/notebooks", "/notebooks/ChangeDebugger.ipynb", "/notebooks/ChangeDebugger.ipynb", "/notebooks/ChangeDebugger.ipynb", "/notebooks/diff_match_patch", "/notebooks/diff_match_patch/diff_match_patch.py", "/notebooks/diff_match_patch/diff_match_patch.py", "/notebooks/DeltaDebugger.ipynb", "/notebooks/DeltaDebugger.ipynb", "/notebooks/ChangeDebugger.ipynb", "/notebooks", "/notebooks/Draft_Second_Project.ipynb", "/notebooks/Draft_Second_Project.ipynb", "/notebooks/Draft_Second_Project.ipynb", "/notebooks/Draft_Second_Project.ipynb", "/notebooks/Draft_Second_Project.ipynb", "/notebooks/Draft_Second_Project.ipynb", "/notebooks/Draft_Second_Project.ipynb", "/notebooks/Draft_Second_Project.ipynb", "/notebooks/Draft_Second_Project.ipynb", "/notebooks/Draft_Second_Project.ipynb", "/notebooks/Draft_Second_Project.ipynb", "/notebooks/Draft_Second_Project.ipynb", "/notebooks/Draft_Second_Project.ipynb", "/notebooks", "/notebooks/Slicer.ipynb", "/notebooks/Slicer.ipynb", "/notebooks/Slicer.ipynb", "/notebooks/Slicer.ipynb", "/notebooks/Slicer.ipynb", "/notebooks/Slicer.ipynb", "/notebooks/Slicer.ipynb", "/notebooks/Slicer.ipynb", "/notebooks/Slicer.ipynb", "/notebooks/Slicer.ipynb", "/notebooks", "/notebooks/Reducing_Code.ipynb", "/notebooks/Reducing_Code.ipynb", "/notebooks/Reducing_Code.ipynb", "/notebooks/Reducing_Code.ipynb", "/notebooks/Reducing_Code.ipynb", "/notebooks/Reducing_Code.ipynb", "/notebooks/Reducing_Code.ipynb", "/notebooks/Reducing_Code.ipynb", "/notebooks/Reducing_Code.ipynb", "/notebooks/Reducing_Code.ipynb", "/notebooks/Reducing_Code.ipynb", "/notebooks/Reducing_Code.ipynb", "/notebooks/Reducing_Code.ipynb", "/notebooks/Reducing_Code.ipynb", "/notebooks/Reducing_Code.ipynb", "/notebooks/Reducing_Code.ipynb", "/notebooks/Reducing_Code.ipynb", "/notebooks/Reducing_Code.ipynb", "/notebooks/Reducing_Code.ipynb", "/notebooks/Reducing_Code.ipynb", "/notebooks/Reducing_Code.ipynb", "/notebooks/Reducing_Code.ipynb", "/notebooks/Slicer.ipynb", "/notebooks/Slicer.ipynb", "/notebooks/PICS", "/notebooks/Slicer.ipynb", "/notebooks/Slicer.ipynb", "/notebooks/Slicer.ipynb", "/notebooks/PICS", "/notebooks/PICS", "/html/favicon", "/notebooks/PICS", "/notebooks/PICS", "/notebooks", "/notebooks/Repairer.ipynb", "/notebooks/Repairer.ipynb", "/notebooks/Repairer.ipynb", "/notebooks/Repairer.ipynb", "/notebooks/Repairer.ipynb", "/notebooks/Repairer.ipynb", "/notebooks/Repairer.ipynb", "/notebooks/Repairer.ipynb", "/code", "/notebooks/Repairer.ipynb", "/notebooks/Repairer.ipynb", "/notebooks/Repairer.ipynb", "/notebooks/Repairer.ipynb", "/notebooks/Repairer.ipynb", "/notebooks/Repairer.ipynb", "/notebooks/PICS", "/notebooks", "/notebooks", "/notebooks/Tracking.ipynb", "/notebooks/Tracking.ipynb", "/notebooks/PICS", "/notebooks", "/notebooks", "/notebooks/ChangeExplorer.ipynb", "/notebooks/Repairer.ipynb", "/notebooks/Repairer.ipynb", "/notebooks/PICS", "/notebooks/Tracking.ipynb", "/notebooks/Tracking.ipynb", "/notebooks/Tracking.ipynb", "/notebooks/Tracking.ipynb", "/notebooks/Tracking.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DynamicInvariants.ipynb", "/notebooks", "/notebooks/DynamicInvariants.ipynb", "/notebooks/DDSet.ipynb", "/notebooks", null, "/", "/", "/", "/beta", "/", "/", "/beta", "/", "/", "/", "/ipypublish_plugins", "/beta", "/html", "/notebooks", "/notebooks", "/notebooks", "/notebooks/diff_match_patch" ], "text": [ 7, 29, 1, 1, 1, 2, 2, 3, 9, 1, 1, 1, 1, 1, 3, 1, 5, 7, 1, 2, 1, 1, 1, 1, 1, 6, 31, 3, 1, 1, 1, 1, 21, 1, 1, 1, 1, 3, 1, 24, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 3, 2, 2, 38, 2, 1, 1, 1, 1, 3, 1, 1, 1, 2, 2, 1, 1, 16, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 2, 1, 1, 1, 1, 1, 1, 1, 1, 176, 1, 1, 2, 1, 1, 11, 1, 1, 1, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 40, 1, 3, 1, 1, 1, 1, 1, 2, 1, 1, 16, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 109, 1, 2, 1, 1, 1, 7, 1, 1, 1, 1, 6, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 2, 183, 4, 1, 1, 49, 26, 1, 50, 57, 66, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 2, 73, 1, 25, 1, 1, 1, 1, 8, 1, 1, 1, 44, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 9, 1, 1, 1, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null ], "type": "treemap", "values": [ 9.278092474027002, 8.101374671228582, 3.2188758248682006, 0, 6.171700597410915, 7.2640301428995295, 2.70805020110221, 7.346010209913293, 9.567175303116281, 13.556513119372408, 5.3230099791384085, 4.7535901911063645, 5.318119993844216, 4.997212273764115, 4.997212273764115, 3.044522437723423, 9.614604759507829, 9.644198554585564, 3.2188758248682006, 7.142827401161621, 2.6390573296152584, 2.833213344056216, 5.384495062789089, 7.0630481633881725, 3.8918202981106265, 20.97707883719506, 48.155126310322416, 8.31115254800169, 5.003946305945459, 6.921658184151129, 5.53338948872752, 0, 59.227819856459504, 5.857933154483459, 7.687080155783135, 5.147494476813453, 4.997212273764115, 7.452402451223638, 8.182000136293405, 49.40167251345942, 4.430816798843313, 7.347943823148687, 5.733341276897746, 8.182000136293405, 5.765191102784844, 6.963189985870238, 7.335633981927201, 6.359573868672378, 6.349138991379798, 7.583247524303362, 6.582025138892826, 9.07280095795412, 8.619027497297505, 70.35053068502665, 5.556828061699537, 6.018593214496234, 5.924255797414532, 6.137727054086234, 6.84587987526405, 8.47886807709457, 9.629576884168266, 5.056245805348308, 4.859812404361672, 14.216215018818955, 7.512071245835466, 6.035481432524756, 6.267200548541362, 8.21878715560148, 58.315679828323454, 5.093750200806762, 4.770684624465665, 5.003946305945459, 8.006367567650246, 4.174387269895637, 4.174387269895637, 6.419994928147142, 4.382026634673881, 5.973809611869261, 6.48768401848461, 72.3354651897531, 7.224753405767971, 6.983789965258135, 5.342334251964811, 4.997212273764115, 8.036249942132116, 4.844187086458591, 4.553876891600541, 6.943122422819428, 3.871201010907891, 9.796681548218318, 8.079308192051961, 4.532599493153256, 6.056784013228625, 4.68213122712422, 7.038783541388542, 18.48142918869067, 14.227734771764943, 6.20050917404269, 4.0943445622221, 20.722122623727138, 91.2364591096562, 6.175867270105761, 6.003887067106539, 5.2574953720277815, 5.966146739123692, 7.034387929915503, 7.277247726631484, 5.5254529391317835, 6.9865664594064265, 8.863332833439587, 4.941642422609304, 4.77912349311153, 5.869296913133774, 5.337538079701318, 6.983789965258135, 89.1889475500515, 5.966146739123692, 8.348301054933943, 5.5254529391317835, 6.734591659972948, 5.762051382780177, 6.951772164398911, 5.337538079701318, 8.423102268016642, 3.970291913552122, 6.656726524178391, 38.20320503698738, 5.402677381872279, 8.619388703730907, 4.997212273764115, 4.07753744390572, 7.249925536717988, 11.083234260436102, 7.460490305825338, 6.345636360828596, 7.8838232148921525, 92.57946671194716, 7.093404625868766, 7.161622002939187, 4.2626798770413155, 6.371611847231857, 6.432940092739179, 5.117993812416755, 6.267200548541362, 6.100318952020064, 7.202661196523238, 6.858565034791365, 6.416732282512326, 6.049733455231958, 7.285506548522785, 116.06629305271647, 6.595780513961311, 5.777652323222656, 4.969813299576001, 6.687108607866515, 6.068425588244111, 8.584851839890053, 6.306275286948016, 8.350902451694811, 5.834810737062605, 5.308267697401205, 139.4629764458604, 4.77912349311153, 4.859812404361672, 6.79346613258001, 4.77912349311153, 4.060443010546419, 5.4680601411351315, 4.859812404361672, 7.275172319452771, 7.453561871643373, 6.945051063725834, 5.8971538676367405, 6.173786103901937, 6.410174881966167, 6.329720905522696, 5.556828061699537, 5.075173815233827, 4.859812404361672, 4.77912349311153, 5.402677381872279, 7.156176637480615, 5.991464547107982, 7.838737559599282, 8.36287583103188, 9.570180302058072, 9.104201775914515, 9.431642228411022, 6.586171654854675, 5.529429087511423, 11.555659230890438, 8.624791202014256, 8.698180525197055, 9.093357016490364, 8.177515823846075, 117.38526591952393, 7.085064293952548, 4.442651256490317, 5.638354669333745, 5.733341276897746, 5.14166355650266, 8.172164452111904, 4.709530201312334, 5.541263545158426, 3.6375861597263857, 8.917310693197807, 7.553286605600419, 5.056245805348308, 6.405228458030842, 9.615938804529582, 8.510369966068112, 9.641148287756142, 8.381373468273702, 52.85796759319715, 7.084226422097916, 5.147494476813453, 11.348923082759187, 0, 19.21728018560999, 8.233768709217097, 5.929589143389895, 7.126087273299125, 11.68596238595356, 7.00669522683704, 5.5134287461649825, 7.152268856032539, 5.117993812416755, 4.718498871295094, 3.970291913552122, 4.2626798770413155, 6.795705775173514, 8.11969625295725, 5.442417710521793, 4.276666119016055, 4.418840607796598, 7.156176637480615, 7.027314514039777, 5.459585514144159, 5.8805329864007, 7.226209010100671, 6.70073110954781, 7.0967213784947605, 4.2626798770413155, 4.859812404361672, 5.840641657373398, 5.71042701737487, 4.430816798843313, 5.231108616854587, 5.159055299214529, 6.1779441140506, 7.8160138391590275, 6.018593214496234, 4.406719247264253, 5.973809611869261, 7.283448228756631, 4.0943445622221, 7.01301578963963, 5.752572638825633, 5.365976015021851, 4.02535169073515, 4.844187086458591, 5.752572638825633, 6.597145701886651, 5.799092654460526, 5.342334251964811, 0, 4.343805421853684, 7.284820912568604, 5.808142489980444, 5.187385805840755, 7.426549072397305, 5.8664680569332965, 4.007333185232471, 5.955837369464831, 277.25431619404065, 7.928406026180535, 4.997212273764115, 14.245811357857393, 1834.893143574901, 0, 33.444066199766944, 1704.7793798043574, 2.708050201102213, 14.504837952421383, 18.265355828313364, 6.263398262591631, 15.836659366236331, 2.8332133440562193, 11.925604490096607, 6.921658184151137, 5.533389488727527, 8.698180525197063, 9.629576884168277, 111.4747622812094, 22.41069724105985, 18.33315979715411 ] } ], "layout": { "margin": { "b": 0, "l": 0, "r": 0, "t": 30 }, "template": { "data": { "bar": [ { "error_x": { "color": "#2a3f5f" }, "error_y": { "color": "#2a3f5f" }, "marker": { "line": { "color": "#E5ECF6", "width": 0.5 } }, "type": "bar" } ], "barpolar": [ { "marker": { "line": { "color": "#E5ECF6", "width": 0.5 } }, "type": "barpolar" } ], "carpet": [ { "aaxis": { "endlinecolor": "#2a3f5f", "gridcolor": "white", "linecolor": "white", "minorgridcolor": "white", "startlinecolor": "#2a3f5f" }, "baxis": { "endlinecolor": "#2a3f5f", "gridcolor": "white", "linecolor": "white", "minorgridcolor": "white", "startlinecolor": "#2a3f5f" }, "type": "carpet" } ], "choropleth": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "type": "choropleth" } ], "contour": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0.0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1.0, "#f0f921" ] ], "type": "contour" } ], "contourcarpet": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "type": "contourcarpet" } ], "heatmap": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0.0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1.0, "#f0f921" ] ], "type": "heatmap" } ], "heatmapgl": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0.0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1.0, "#f0f921" ] ], "type": "heatmapgl" } ], "histogram": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "histogram" } ], "histogram2d": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0.0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1.0, "#f0f921" ] ], "type": "histogram2d" } ], "histogram2dcontour": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0.0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1.0, "#f0f921" ] ], "type": "histogram2dcontour" } ], "mesh3d": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "type": "mesh3d" } ], "parcoords": [ { "line": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "parcoords" } ], "pie": [ { "automargin": true, "type": "pie" } ], "scatter": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatter" } ], "scatter3d": [ { "line": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatter3d" } ], "scattercarpet": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattercarpet" } ], "scattergeo": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattergeo" } ], "scattergl": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattergl" } ], "scattermapbox": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattermapbox" } ], "scatterpolar": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatterpolar" } ], "scatterpolargl": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatterpolargl" } ], "scatterternary": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatterternary" } ], "surface": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0.0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1.0, "#f0f921" ] ], "type": "surface" } ], "table": [ { "cells": { "fill": { "color": "#EBF0F8" }, "line": { "color": "white" } }, "header": { "fill": { "color": "#C8D4E3" }, "line": { "color": "white" } }, "type": "table" } ] }, "layout": { "annotationdefaults": { "arrowcolor": "#2a3f5f", "arrowhead": 0, "arrowwidth": 1 }, "autotypenumbers": "strict", "coloraxis": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "colorscale": { "diverging": [ [ 0, "#8e0152" ], [ 0.1, "#c51b7d" ], [ 0.2, "#de77ae" ], [ 0.3, "#f1b6da" ], [ 0.4, "#fde0ef" ], [ 0.5, "#f7f7f7" ], [ 0.6, "#e6f5d0" ], [ 0.7, "#b8e186" ], [ 0.8, "#7fbc41" ], [ 0.9, "#4d9221" ], [ 1, "#276419" ] ], "sequential": [ [ 0.0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1.0, "#f0f921" ] ], "sequentialminus": [ [ 0.0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1.0, "#f0f921" ] ] }, "colorway": [ "#636efa", "#EF553B", "#00cc96", "#ab63fa", "#FFA15A", "#19d3f3", "#FF6692", "#B6E880", "#FF97FF", "#FECB52" ], "font": { "color": "#2a3f5f" }, "geo": { "bgcolor": "white", "lakecolor": "white", "landcolor": "#E5ECF6", "showlakes": true, "showland": true, "subunitcolor": "white" }, "hoverlabel": { "align": "left" }, "hovermode": "closest", "mapbox": { "style": "light" }, "paper_bgcolor": "white", "plot_bgcolor": "#E5ECF6", "polar": { "angularaxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" }, "bgcolor": "#E5ECF6", "radialaxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" } }, "scene": { "xaxis": { "backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white" }, "yaxis": { "backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white" }, "zaxis": { "backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white" } }, "shapedefaults": { "line": { "color": "#2a3f5f" } }, "ternary": { "aaxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" }, "baxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" }, "bgcolor": "#E5ECF6", "caxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" } }, "title": { "x": 0.05 }, "xaxis": { "automargin": true, "gridcolor": "white", "linecolor": "white", "ticks": "", "title": { "standoff": 15 }, "zerolinecolor": "white", "zerolinewidth": 2 }, "yaxis": { "automargin": true, "gridcolor": "white", "linecolor": "white", "ticks": "", "title": { "standoff": 15 }, "zerolinecolor": "white", "zerolinewidth": 2 } } } } }, "text/html": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "fine_change_counter.map()" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Subclassing offers several ways to customize what to mine and how to visualize it. See the chapter for details." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Here are all the classes defined in this chapter:" ] }, { "cell_type": "code", "execution_count": 96, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "# ignore\n", "from ClassDiagram import display_class_hierarchy" ] }, { "cell_type": "code", "execution_count": 97, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "%3\n", "\n", "\n", "\n", "\n", "\n", "\n", "FineChangeCounter\n", "\n", "\n", "FineChangeCounter\n", "\n", "\n", "\n", "update_elems()\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "ChangeCounter\n", "\n", "\n", "ChangeCounter\n", "\n", "\n", "\n", "__init__()\n", "\n", "\n", "\n", "map()\n", "\n", "\n", "\n", "include()\n", "\n", "\n", "\n", "map_colorscale()\n", "\n", "\n", "\n", "map_hoverinfo()\n", "\n", "\n", "\n", "map_node_color()\n", "\n", "\n", "\n", "map_node_sizes()\n", "\n", "\n", "\n", "map_node_text()\n", "\n", "\n", "\n", "mine()\n", "\n", "\n", "\n", "update_changes()\n", "\n", "\n", "\n", "update_elems()\n", "\n", "\n", "\n", "update_size()\n", "\n", "\n", "\n", "update_stats()\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "FineChangeCounter->ChangeCounter\n", "\n", "\n", "\n", "\n", "\n", "FixCounter\n", "\n", "\n", "FixCounter\n", "\n", "\n", "\n", "include()\n", "\n", "\n", "\n", "map_hoverinfo()\n", "\n", "\n", "\n", "map_node_text()\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "FixCounter->ChangeCounter\n", "\n", "\n", "\n", "\n", "\n", "Legend\n", "Legend\n", "• \n", "public_method()\n", "• \n", "private_method()\n", "• \n", "overloaded_method()\n", "Hover over names to see doc\n", "\n", "\n", "\n" ], "text/plain": [ "" ] }, "execution_count": 97, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# ignore\n", "display_class_hierarchy([FineChangeCounter, FixCounter],\n", " public_methods=[\n", " ChangeCounter.__init__,\n", " ChangeCounter.map # FIXME: Why is `map()` not highlighted?\n", " ],\n", " project='debuggingbook')" ] }, { "cell_type": "markdown", "metadata": { "button": false, "new_sheet": true, "run_control": { "read_only": false }, "slideshow": { "slide_type": "slide" } }, "source": [ "## Lessons Learned\n", "\n", "* We can easily _mine_ past changes and map these to individual files and elements\n", "* This information can be helpful in guiding the debugging and development process\n", "* Counting _fixes_ needs to be customized to the conventions used in the project at hand" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Background\n", "\n", "To be added" ] }, { "cell_type": "markdown", "metadata": { "button": false, "new_sheet": true, "run_control": { "read_only": false }, "slideshow": { "slide_type": "slide" } }, "source": [ "## Exercises\n", "\n", "To be added" ] }, { "cell_type": "markdown", "metadata": { "button": false, "new_sheet": false, "run_control": { "read_only": false }, "slideshow": { "slide_type": "subslide" }, "solution": "hidden", "solution2": "hidden", "solution2_first": true, "solution_first": true }, "source": [ "### Exercise 1: _Title_\n", "\n", "_Text of the exercise_" ] }, { "cell_type": "markdown", "metadata": { "button": false, "new_sheet": false, "run_control": { "read_only": false }, "slideshow": { "slide_type": "skip" }, "solution": "hidden", "solution2": "hidden" }, "source": [ "**Solution.** _Solution for the exercise_" ] } ], "metadata": { "ipub": { "bibliography": "fuzzingbook.bib", "toc": true }, "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.10" }, "toc": { "base_numbering": 1, "nav_menu": {}, "number_sections": true, "sideBar": true, "skip_h1_title": true, "title_cell": "", "title_sidebar": "Contents", "toc_cell": false, "toc_position": {}, "toc_section_display": true, "toc_window_display": true }, "toc-autonumbering": false }, "nbformat": 4, "nbformat_minor": 4 }