Add typ to tvcm/third_party/.

BUG=https://github.com/google/trace-viewer/issues/1037
R=dpranke@chromium.org, nduca@chromium.org

Review URL: https://codereview.appspot.com/247120043.
diff --git a/third_party/tvcm/third_party/typ/.gitignore b/third_party/tvcm/third_party/typ/.gitignore
new file mode 100644
index 0000000..b8987c5
--- /dev/null
+++ b/third_party/tvcm/third_party/typ/.gitignore
@@ -0,0 +1,5 @@
+build
+*.pyc
+*.pyc.d
+*.py,cover
+typ.egg-info
diff --git a/third_party/tvcm/third_party/typ/LICENSE b/third_party/tvcm/third_party/typ/LICENSE
new file mode 100644
index 0000000..ad410e1
--- /dev/null
+++ b/third_party/tvcm/third_party/typ/LICENSE
@@ -0,0 +1,201 @@
+Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "{}"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright {yyyy} {name of copyright owner}
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
\ No newline at end of file
diff --git a/third_party/tvcm/third_party/typ/README.chromium b/third_party/tvcm/third_party/typ/README.chromium
new file mode 100644
index 0000000..2837b80
--- /dev/null
+++ b/third_party/tvcm/third_party/typ/README.chromium
@@ -0,0 +1,32 @@
+Name: typ
+URL: https://github.com/dpranke/typ.git
+Version: 0.8.9
+Revision: 68b64ff805d266c7a249294abc45cc12076aeb9f
+Security Critical: no
+License: Apache 2.0
+License File: NOT_SHIPPED
+
+Description:
+
+typ is a simple wrapper around Python's unittest library that provides a
+somewhat nicer command-line interface, parallel test execution,
+code coverage support, and support for Chromium's JSON Results format.
+
+This code is not considered security critical since it is only to be linked
+into test binaries! This should never be linked into chrome or any production
+code.
+
+To update this copy of typ from the source repo (assuming you are in
+src/third_party/typ):
+
+    # can just do "sed -n '/^   /p' README.chromium | bash -e"
+    cd ..
+    git clone https://github.com/dpranke/typ.git typ_new
+    revision=$(cd typ_new && git log -1 | head -1 | awk '{ print $2 }')
+    version=$(cd typ_new && python -m typ --version)
+    cp typ/OWNERS typ_new
+    cat typ/README.chromium | sed -e "s/^Version: .*/Version: $version/" \
+                                  -e "s/^Revision: .*/Revision: $revision/" \
+                                  > typ_new/README.chromium
+    rm -fr typ_new/.git typ_new/.gitignore typ/
+    mv typ_new typ
diff --git a/third_party/tvcm/third_party/typ/README.rst b/third_party/tvcm/third_party/typ/README.rst
new file mode 100644
index 0000000..dc03841
--- /dev/null
+++ b/third_party/tvcm/third_party/typ/README.rst
@@ -0,0 +1,68 @@
+typ (Test Your Program)
+=======================
+typ is a simple program for testing command line executables and Python code.
+
+When testing Python code, it is basically a wrapper around the standard
+unittest module, but it provides the following bits of additional
+functionality:
+
+* Parallel test execution.
+* Clean output in the style of the Ninja build tool.
+* A more flexible mechanism for discovering tests from the
+  command line and controlling how they are run:
+
+  * Support for importing tests by directory, filename, or module.
+  * Support for specifying tests to skip, tests to run in parallel,
+    and tests that need to be run by themselves
+
+* Support for producing traces of test times compatible with Chrome's
+  tracing infrastructure (trace_viewer).
+* Integrated test coverage reporting (including parallel coverage).
+* Integrated support for debugging tests.
+* Support for uploading test results automatically to a server
+  (useful for continuous integration monitoring of test results).
+* An abstraction of operating system functionality called the
+  Host class. This can be used by other python code to write more
+  portable and easily testable code by wrapping the multiprocessing,
+  os, subprocess, and time modules.
+* Simple libraries for integrating Ninja-style statistics and line
+  printing into your own code (the Stats and Printer classes).
+* Support for processing arbitrary arguments from calling code to
+  test cases.
+* Support for once-per-process setup and teardown hooks.
+
+(These last two bullet points allow one to write tests that do not require
+Python globals).
+
+History
+-------
+
+typ originated out of work on the Blink and Chromium projects, as a way to
+provide a friendlier interface to the Python unittest modules.
+
+Work remaining
+--------------
+
+typ is still a work in progress, but it's getting close to being done.
+Things remaining for 1.0, roughly in priority order:
+
+- Implement a non-python file format for testing command line interfaces
+- Write documentation
+
+Possible future work
+--------------------
+
+- MainTestCase.check() improvements:
+
+  - check all arguments and show all errors at once?
+  - make multi-line regexp matches easier to follow?
+
+- --debugger improvements:
+
+  - make it skip the initial breakpoint?
+
+- Support testing javascript, java, c++/gtest-style binaries?
+- Support for test sharding in addition to parallel execution (so that
+  run-webkit-tests can re-use as much of the code as possible)?
+- Support for non-unittest runtest invocation (for run-webkit-tests,
+  other harnesses?)
diff --git a/third_party/tvcm/third_party/typ/pylintrc b/third_party/tvcm/third_party/typ/pylintrc
new file mode 100644
index 0000000..4abb6c6
--- /dev/null
+++ b/third_party/tvcm/third_party/typ/pylintrc
@@ -0,0 +1,274 @@
+# Copyright 2014 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+[MASTER]
+
+# Specify a configuration file.
+#rcfile=
+
+# Python code to execute, usually for sys.path manipulation such as
+# pygtk.require().
+#init-hook=
+
+# Profiled execution.
+profile=no
+
+# Add files or directories to the blacklist. They should be base names, not
+# paths.
+ignore=CVS
+
+# Pickle collected data for later comparisons.
+persistent=yes
+
+# List of plugins (as comma separated values of python modules names) to load,
+# usually to register additional checkers.
+load-plugins=
+
+
+[MESSAGES CONTROL]
+
+# Enable the message, report, category or checker with the given id(s). You can
+# either give multiple identifier separated by comma (,) or put this option
+# multiple time.
+#enable=
+
+# Disable the message, report, category or checker with the given id(s). You
+# can either give multiple identifier separated by comma (,) or put this option
+# multiple time (only on the command line, not in the configuration file where
+# it should appear only once).
+# CHANGED:
+# C0111: Missing docstring
+# I0011: Locally disabling WNNNN
+# R0201: Method could be a function
+# R0801: Similar lines
+# W0141: Used builtin function 'map'
+# W0142: Used * or ** magic
+# W0511: TODO
+# W0703: Catch "Exception"
+disable=C0111,I0011,R0201,R0801,W0141,W0142,W0511,W0703
+
+
+[REPORTS]
+
+# Set the output format. Available formats are text, parseable, colorized, msvs
+# (visual studio) and html
+output-format=text
+
+# Include message's id in output
+include-ids=yes
+
+# Put messages in a separate file for each module / package specified on the
+# command line instead of printing them on stdout. Reports (if any) will be
+# written in a file name "pylint_global.[txt|html]".
+files-output=no
+
+# Tells whether to display a full report or only the messages
+# CHANGED:
+reports=no
+
+# Python expression which should return a note less than 10 (10 is the highest
+# note). You have access to the variables errors warning, statement which
+# respectively contain the number of errors / warnings messages and the total
+# number of statements analyzed. This is used by the global evaluation report
+# (RP0004).
+evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
+
+# Add a comment according to your evaluation note. This is used by the global
+# evaluation report (RP0004).
+comment=no
+
+
+[VARIABLES]
+
+# Tells whether we should check for unused import in __init__ files.
+init-import=no
+
+# A regular expression matching the beginning of the name of dummy variables
+# (i.e. not used).
+dummy-variables-rgx=_|dummy
+
+# List of additional names supposed to be defined in builtins. Remember that
+# you should avoid to define new builtins when possible.
+additional-builtins=
+
+
+[TYPECHECK]
+
+# Tells whether missing members accessed in mixin class should be ignored. A
+# mixin class is detected if its name ends with "mixin" (case insensitive).
+ignore-mixin-members=yes
+
+# List of classes names for which member attributes should not be checked
+# (useful for classes with attributes dynamically set).
+ignored-classes=
+
+# When zope mode is activated, add a predefined set of Zope acquired attributes
+# to generated-members.
+zope=no
+
+# List of members which are set dynamically and missed by pylint inference
+# system, and so shouldn't trigger E0201 when accessed. Python regular
+# expressions are accepted.
+generated-members=
+
+
+[MISCELLANEOUS]
+
+# List of note tags to take in consideration, separated by a comma.
+notes=FIXME,XXX,TODO
+
+
+[SIMILARITIES]
+
+# Minimum lines number of a similarity.
+min-similarity-lines=4
+
+# Ignore comments when computing similarities.
+ignore-comments=yes
+
+# Ignore docstrings when computing similarities.
+ignore-docstrings=yes
+
+
+[FORMAT]
+
+# Maximum number of characters on a single line.
+# max-line-length=200
+
+# Maximum number of lines in a module
+# max-module-lines=1000
+
+# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
+# tab).
+# CHANGED:
+indent-string='    '
+
+
+[BASIC]
+
+# Required attributes for module, separated by a comma
+required-attributes=
+
+# List of builtins function names that should not be used, separated by a comma
+bad-functions=map,filter,apply,input
+
+# Regular expression which should only match correct module names
+module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
+
+# Regular expression which should only match correct module level names
+const-rgx=(([a-zA-Z_][a-zA-Z0-9_]*)|(__.*__))$
+
+# Regular expression which should only match correct class names
+class-rgx=[A-Z_][a-zA-Z0-9]+$
+
+# Regular expression which should only match correct function names
+function-rgx=[a-z_][a-z0-9_]{0,40}$
+
+# Regular expression which should only match correct method names
+method-rgx=[a-z_][a-z0-9_]{0,48}$
+
+# Regular expression which should only match correct instance attribute names
+attr-rgx=[a-z_][a-z0-9_]{0,30}$
+
+# Regular expression which should only match correct argument names
+argument-rgx=[a-z_][a-z0-9_]{0,30}$
+
+# Regular expression which should only match correct variable names
+variable-rgx=[a-zA-Z0-9_]{0,30}$
+
+# Regular expression which should only match correct list comprehension /
+# generator expression variable names
+inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
+
+# Good variable names which should always be accepted, separated by a comma
+good-names=i,j,k,ex,Run,_
+
+# Bad variable names which should always be refused, separated by a comma
+bad-names=foo,bar,baz,toto,tutu,tata
+
+# Regular expression which should only match functions or classes name which do
+# not require a docstring
+no-docstring-rgx=__.*__
+
+
+[DESIGN]
+
+# Maximum number of arguments for function / method
+max-args=8
+
+# Argument names that match this expression will be ignored. Default to name
+# with leading underscore
+ignored-argument-names=_.*
+
+# Maximum number of locals for function / method body
+max-locals=32
+
+# Maximum number of return / yield for function / method body
+max-returns=32
+
+# Maximum number of branch for function / method body
+max-branchs=32
+
+# Maximum number of statements in function / method body
+max-statements=65
+
+# Maximum number of parents for a class (see R0901).
+max-parents=7
+
+# Maximum number of attributes for a class (see R0902).
+max-attributes=16
+
+# Minimum number of public methods for a class (see R0903).
+min-public-methods=0
+
+# Maximum number of public methods for a class (see R0904).
+max-public-methods=100
+
+
+[CLASSES]
+
+# List of interface methods to ignore, separated by a comma. This is used for
+# instance to not check methods defines in Zope's Interface base class.
+ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by
+
+# List of method names used to declare (i.e. assign) instance attributes.
+defining-attr-methods=__init__,__new__,setUp
+
+# List of valid names for the first argument in a class method.
+valid-classmethod-first-arg=cls
+
+
+[IMPORTS]
+
+# Deprecated modules which should not be used, separated by a comma
+deprecated-modules=regsub,string,TERMIOS,Bastion,rexec
+
+# Create a graph of every (i.e. internal and external) dependencies in the
+# given file (report RP0402 must not be disabled)
+import-graph=
+
+# Create a graph of external dependencies in the given file (report RP0402 must
+# not be disabled)
+ext-import-graph=
+
+# Create a graph of internal dependencies in the given file (report RP0402 must
+# not be disabled)
+int-import-graph=
+
+
+[EXCEPTIONS]
+
+# Exceptions that will emit a warning when being caught. Defaults to
+# "Exception"
+overgeneral-exceptions=Exception
diff --git a/third_party/tvcm/third_party/typ/run b/third_party/tvcm/third_party/typ/run
new file mode 100755
index 0000000..7b07985
--- /dev/null
+++ b/third_party/tvcm/third_party/typ/run
@@ -0,0 +1,157 @@
+#!/usr/bin/env python
+
+from __future__ import print_function
+
+import argparse
+import os
+import subprocess
+import sys
+
+from tools import cov
+
+
+is_python3 = bool(sys.version_info.major == 3)
+has_python34 = False
+verbose = False
+repo_dir = os.path.abspath(os.path.dirname(__file__))
+path_to_cov = os.path.join(repo_dir, 'tools', 'cov.py')
+path_to_runner = os.path.join(repo_dir, 'typ', 'runner.py')
+
+
+def call(*args, **kwargs):
+    if verbose:
+        print(' '.join(args[0]))
+    ret = subprocess.call(*args, **kwargs)
+    if ret != 0:
+        sys.exit(ret)
+
+
+def main(argv):
+    parser = argparse.ArgumentParser(prog='mbw')
+    parser.add_argument('--no3', action='store_true',
+                        help='Do not run the tests under Python 3.')
+    parser.add_argument('-v', '--verbose', action='store_true')
+    subps = parser.add_subparsers()
+
+    subp = subps.add_parser('build', help='build the package')
+    subp.set_defaults(func=run_build)
+
+    subp = subps.add_parser('clean', help='Remove any local files.')
+    subp.set_defaults(func=run_clean)
+
+    subp = subps.add_parser('coverage',
+                            help='Run the tests and report code coverage.')
+    subp.set_defaults(func=run_coverage)
+    cov.add_arguments(subp)
+
+    subp = subps.add_parser('develop',
+                             help='Install a symlinked package locally.')
+    subp.set_defaults(func=run_develop)
+    subp.add_argument('--system', action='store_true',
+                      help=('Install to the system site-package dir '
+                            'rather than the user\'s (requires root).'))
+
+    subp = subps.add_parser('format',
+                            help='Reformat the source code.')
+    subp.set_defaults(func=run_format)
+
+    subp = subps.add_parser('help',
+                            help='Get help on a subcommand.')
+    subp.add_argument(nargs='?', action='store', dest='subcommand',
+                      help='The command to get help for.')
+    subp.set_defaults(func=run_help)
+
+    subp = subps.add_parser('install',
+                            help='build the package and install locally.')
+    subp.set_defaults(func=run_install)
+    subp.add_argument('--system', action='store_true',
+                      help=('Install to the system site-package dir '
+                            'rather than the user\'s (requires root).'))
+
+    subp = subps.add_parser('lint',
+                            help='run lint over the source')
+    subp.set_defaults(func=run_lint)
+
+    subp = subps.add_parser('tests',
+                            help='run the tests')
+    subp.set_defaults(func=run_tests)
+
+    args = parser.parse_args(argv)
+
+    global verbose
+    if args.verbose:
+        verbose = True
+    global has_python34
+    if not args.no3:
+        try:
+            ver = subprocess.check_output(['python3', '--version'])
+            has_python34 = ver.split()[1] >= '3.4'
+        except:
+            pass
+    args.func(args)
+
+
+def run_build(args):
+    call([sys.executable, 'setup.py', 'build', '--quiet'])
+
+
+def run_clean(args):
+    call(['git', 'clean', '-fxd'])
+
+
+def run_coverage(args):
+    if not args.path:
+        args.path = [repo_dir]
+    if not args.source:
+        args.source = [os.path.join(repo_dir, 'typ')]
+    argv = cov.argv_from_args(args)
+    cov_args = [path_to_runner, '-j', '1']
+    call(['python', path_to_cov] + argv + cov_args)
+    if has_python34:
+        call(['python3', path_to_cov] + argv + cov_args)
+
+
+def run_develop(args):
+    call([sys.executable, 'setup.py', 'develop'])
+
+
+def run_format(args):
+    call('autopep8 --in-place *.py */*.py */*/*.py', shell=True)
+
+
+def run_help(args):
+    if args.subcommand:
+        main([args.subcommand, '--help'])
+    main(['--help'])
+
+
+def run_install(args):
+    if args.system:
+        argv = []
+    else:
+        argv = ['--user']
+    call([sys.executable, 'setup.py', 'install'] + argv)
+
+
+def run_lint(args):
+    call('pylint --rcfile=pylintrc */*.py */*/*.py', shell=True)
+    call('pep8 *.py */*.py */*/*.py', shell=True)
+
+
+def run_tests(args):
+    # Test that we can run the module directly if typ is in sys.path.
+    call(['python', '-m', 'typ', 'typ.tests.main_test.TestMain.test_basic'])
+
+    # Test that we can run the command line directly if typ is not in sys.path.
+    home_dir = os.environ['HOME']
+    call(['python', path_to_runner, 'typ.tests.main_test.TestMain.test_basic'],
+         cwd=home_dir)
+
+    # Now run all the tests under Python2 and Python3.
+    call(['python', path_to_runner])
+    if has_python34:
+        call(['python3', path_to_runner])
+
+
+if __name__ == '__main__':
+    sys.exit(main(sys.argv[1:]))
diff --git a/third_party/tvcm/third_party/typ/setup.cfg b/third_party/tvcm/third_party/typ/setup.cfg
new file mode 100644
index 0000000..3c6e79c
--- /dev/null
+++ b/third_party/tvcm/third_party/typ/setup.cfg
@@ -0,0 +1,2 @@
+[bdist_wheel]
+universal=1
diff --git a/third_party/tvcm/third_party/typ/setup.py b/third_party/tvcm/third_party/typ/setup.py
new file mode 100644
index 0000000..8a684ae
--- /dev/null
+++ b/third_party/tvcm/third_party/typ/setup.py
@@ -0,0 +1,59 @@
+# Copyright 2014 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+import sys
+
+from setuptools import setup, find_packages
+
+here = os.path.abspath(os.path.dirname(__file__))
+if here not in sys.path:
+    sys.path.insert(0, here)
+
+from typ.version import VERSION
+
+with open(os.path.join(here, 'README.rst')) as fp:
+    readme = fp.read().strip()
+
+readme_lines = readme.splitlines()
+
+setup(
+    name='typ',
+    packages=find_packages(),
+    package_data={'': ['../README.rst']},
+    entry_points={
+        'console_scripts': [
+            'typ=typ.runner:main',
+        ]
+    },
+    install_requires=[
+    ],
+    version=VERSION,
+    author='Dirk Pranke',
+    author_email='dpranke@chromium.org',
+    description=readme_lines[3],
+    long_description=('\n' + '\n'.join(readme_lines)),
+    url='https://github.com/dpranke/typ',
+    license='Apache',
+    classifiers=[
+        'Development Status :: 3 - Alpha',
+        'Intended Audience :: Developers',
+        'License :: OSI Approved :: Apache Software License',
+        'Programming Language :: Python :: 2',
+        'Programming Language :: Python :: 2.7',
+        'Programming Language :: Python :: 3',
+        'Programming Language :: Python :: 3.4',
+        'Topic :: Software Development :: Testing',
+    ],
+)
diff --git a/third_party/tvcm/third_party/typ/tools/__init__.py b/third_party/tvcm/third_party/typ/tools/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/third_party/tvcm/third_party/typ/tools/__init__.py
diff --git a/third_party/tvcm/third_party/typ/tools/cov.py b/third_party/tvcm/third_party/typ/tools/cov.py
new file mode 100755
index 0000000..8e78fc4
--- /dev/null
+++ b/third_party/tvcm/third_party/typ/tools/cov.py
@@ -0,0 +1,140 @@
+#!/usr/bin/python
+# Copyright 2014 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import argparse
+import sys
+import textwrap
+
+is_python3 = bool(sys.version_info.major == 3)
+
+
+ALL_PRAGMAS = ['no cover', 'no win32', 'python2', 'python3', 'untested',
+               'win32']
+DEFAULT_PRAGMAS = ALL_PRAGMAS[:]
+
+if is_python3:
+    DEFAULT_PRAGMAS.remove('python3')
+else:
+    DEFAULT_PRAGMAS.remove('python2')
+
+if sys.platform == 'win32':
+    DEFAULT_PRAGMAS.remove('win32')
+else:
+    DEFAULT_PRAGMAS.remove('no win32')
+
+
+def add_arguments(parser):
+    parser.add_argument('--no-pragmas', action='store_true', default=False,
+                        help='Show all uncovered lines (no pragmas).')
+    parser.add_argument('--path', action='append', default=[],
+                        help='Prepend given directories to sys.path.')
+    parser.add_argument('--pragma', action='append', default=[],
+                        help=('The coverage pragmas to honor '
+                              '(defaults to %s).' % DEFAULT_PRAGMAS))
+    parser.add_argument('--show', action='append', default=[],
+                        help='Show code protected by the specified pragmas '
+                             '(uses all pragmas *except* for the ones '
+                             'specified).')
+    parser.add_argument('--show-missing', action='store_true',
+                        default=False, help='Show missing lines.')
+    parser.add_argument('--source', action='append', default=[],
+                        help='Limit coverage data to the given directories.')
+
+    parser.formatter_class = argparse.RawTextHelpFormatter
+    parser.epilog = textwrap.dedent("""
+    Valid pragma values are:
+        'no cover': The default coverage pragma, this now means we
+                    truly cannot cover it.
+        'no win32': Code that only executes when not on Windows.
+        'python2':  Code that only executes under Python2.
+        'python3':  Code that only executees under Python3.
+        'untested': Code that does not yet have tests.
+        'win32':    Code that only executes on Windows.
+
+    In typ, we aim for 'no cover' to only apply to code that executes only
+    when coverage is not available (and hence can never be counted). Most
+    code, if annotated at all, should be 'untested', and we should strive
+    for 'untested' to not be used, either.
+    """)
+
+
+def argv_from_args(args):
+    argv = []
+    if args.no_pragmas:
+        argv.append('--no-pragmas')
+    for arg in args.path:
+        argv.extend(['--path', arg])
+    for arg in args.show:
+        argv.extend(['--show', arg])
+    if args.show_missing:
+        argv.append('--show-missing')
+    for arg in args.source:
+        argv.extend(['--source', arg])
+    for arg in args.pragma:
+        argv.extend(['--pragma', arg])
+    return argv
+
+
+def main(argv=None):
+    parser = argparse.ArgumentParser()
+    add_arguments(parser)
+    args, remaining_args = parser.parse_known_args(argv)
+
+    for path in args.path:
+        if path not in sys.path:
+            sys.path.append(path)
+
+    try:
+        import coverage
+        from coverage.execfile import run_python_module, run_python_file
+    except ImportError:
+        print("Error: coverage is not available.")
+        sys.exit(1)
+
+    cov = coverage.coverage(source=args.source)
+    cov.erase()
+    cov.clear_exclude()
+
+    if args.no_pragmas:
+        args.pragma = []
+
+    args.pragma = args.pragma or DEFAULT_PRAGMAS
+
+    if args.show:
+        args.show_missing = True
+    for pragma in args.show:
+        if pragma in args.pragma:
+            args.pragma.remove(pragma)
+
+    for pragma in args.pragma:
+        cov.exclude('pragma: %s' % pragma)
+
+    ret = 0
+    cov.start()
+    try:
+        if remaining_args[0] == '-m':
+            run_python_module(remaining_args[1], remaining_args[1:])
+        else:
+            run_python_file(remaining_args[0], remaining_args)
+    except SystemExit as e:
+        ret = e.code
+    cov.stop()
+    cov.save()
+    cov.report(show_missing=args.show_missing)
+    return ret
+
+
+if __name__ == '__main__':
+    sys.exit(main())
diff --git a/third_party/tvcm/third_party/typ/typ/__init__.py b/third_party/tvcm/third_party/typ/typ/__init__.py
new file mode 100644
index 0000000..ab04414
--- /dev/null
+++ b/third_party/tvcm/third_party/typ/typ/__init__.py
@@ -0,0 +1,93 @@
+# Copyright 2014 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Test Your Project
+
+typ is a simple program for testing command line executables and Python code.
+
+When testing Python code, it is basically a wrapper around the standard
+unittest module, but it provides the following bits of additional
+functionality:
+
+    * Parallel test execution.
+
+    * Clean output in the style of the Ninja build tool.
+
+    * A more flexible mechanism for discovering tests from the
+      command line and controlling how they are run:
+      * Support for importing tests by directory, filename, or module.
+      * Support for specifying tests to skip, tests to run in parallel,
+        and tests that need to be run by themselves
+
+    * Support for producing traces of test times compatible with Chrome's
+      tracing infrastructure (trace_viewer).
+
+    * Integrated test coverage reporting.
+
+    * Integrated support for debugging tests.
+
+    * Support for uploading test results automatically to a server
+      (useful for continuous integration monitoring of test results).
+
+    * An abstraction of operating system functionality called the
+      Host class. This can be used by other python code to write more
+      portable and easily testable code by wrapping the multiprocessing,
+      os, subprocess, and time modules.
+
+    * Simple libraries for integrating Ninja-style statistics and line
+      printing into your own code (the Stats and Printer classes).
+
+    * Support for processing arbitrary arguments from calling code to
+      test cases.
+
+    * Support for once-per-process setup and teardown hooks.
+      (These last two bullet points allow one to write tests that do not
+       require Python globals).
+"""
+
+from typ.arg_parser import ArgumentParser
+from typ.fakes.host_fake import FakeHost
+from typ.host import Host
+from typ.json_results import exit_code_from_full_results
+from typ.json_results import make_full_results, make_upload_request
+from typ.json_results import Result, ResultSet, ResultType
+from typ.runner import Runner, TestInput, TestSet, WinMultiprocessing, main
+from typ.stats import Stats
+from typ.printer import Printer
+from typ.test_case import convert_newlines, TestCase, MainTestCase
+from typ.version import VERSION
+
+
+__all__ = [
+    'ArgumentParser',
+    'FakeHost',
+    'Host',
+    'MainTestCase',
+    'Printer',
+    'Result',
+    'ResultSet',
+    'ResultType',
+    'Runner',
+    'Stats',
+    'TestCase',
+    'TestInput',
+    'TestSet',
+    'VERSION',
+    'WinMultiprocessing',
+    'convert_newlines',
+    'exit_code_from_full_results',
+    'main',
+    'make_full_results',
+    'make_upload_request',
+]
diff --git a/third_party/tvcm/third_party/typ/typ/__main__.py b/third_party/tvcm/third_party/typ/typ/__main__.py
new file mode 100644
index 0000000..0e026e8
--- /dev/null
+++ b/third_party/tvcm/third_party/typ/typ/__main__.py
@@ -0,0 +1,21 @@
+# Copyright 2014 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys  # pragma: no cover
+
+from typ import main  # pragma: no cover
+
+
+if __name__ == '__main__':  # pragma: no cover
+    sys.exit(main())
diff --git a/third_party/tvcm/third_party/typ/typ/arg_parser.py b/third_party/tvcm/third_party/typ/typ/arg_parser.py
new file mode 100644
index 0000000..cb51711
--- /dev/null
+++ b/third_party/tvcm/third_party/typ/typ/arg_parser.py
@@ -0,0 +1,315 @@
+# Copyright 2014 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import argparse
+import optparse
+
+from typ.host import Host
+
+
+class _Bailout(Exception):
+    pass
+
+
+DEFAULT_COVERAGE_OMIT = ['*/typ/*', '*/site-packages/*']
+DEFAULT_STATUS_FORMAT = '[%f/%t] '
+DEFAULT_SUFFIXES = ['*_test.py', '*_unittest.py']
+
+
+class ArgumentParser(argparse.ArgumentParser):
+
+    @staticmethod
+    def add_option_group(parser, title, discovery=False,
+                         running=False, reporting=False, skip=None):
+        # TODO: Get rid of this when telemetry upgrades to argparse.
+        ap = ArgumentParser(add_help=False, version=False, discovery=discovery,
+                            running=running, reporting=reporting)
+        optlist = ap.optparse_options(skip=skip)
+        group = optparse.OptionGroup(parser, title)
+        group.add_options(optlist)
+        parser.add_option_group(group)
+
+    def __init__(self, host=None, add_help=True, version=True, discovery=True,
+                 reporting=True, running=True):
+        super(ArgumentParser, self).__init__(prog='typ', add_help=add_help)
+
+        self._host = host or Host()
+        self.exit_status = None
+
+        self.usage = '%(prog)s [options] [tests...]'
+
+        if version:
+            self.add_argument('-V', '--version', action='store_true',
+                              help='Print the typ version and exit.')
+
+        if discovery:
+            self.add_argument('-f', '--file-list', metavar='FILENAME',
+                              action='store',
+                              help=('Takes the list of tests from the file '
+                                    '(use "-" for stdin).'))
+            self.add_argument('--all', action='store_true',
+                              help=('Run all the tests, including the ones '
+                                    'normally skipped.'))
+            self.add_argument('--isolate', metavar='glob', default=[],
+                              action='append',
+                              help=('Globs of tests to run in isolation '
+                                    '(serially).'))
+            self.add_argument('--skip', metavar='glob', default=[],
+                              action='append',
+                              help=('Globs of test names to skip ('
+                                    'defaults to %(default)s).'))
+            self.add_argument('--suffixes', metavar='glob', default=[],
+                              action='append',
+                              help=('Globs of test filenames to look for ('
+                                    'can specify multiple times; defaults '
+                                    'to %s).' % DEFAULT_SUFFIXES))
+
+        if reporting:
+            self.add_argument('--builder-name',
+                              help=('Builder name to include in the '
+                                    'uploaded data.'))
+            self.add_argument('-c', '--coverage', action='store_true',
+                              help='Reports coverage information.')
+            self.add_argument('--coverage-source', action='append',
+                              default=[],
+                              help=('Directories to include when running and '
+                                    'reporting coverage (defaults to '
+                                    '--top-level-dir plus --path)'))
+            self.add_argument('--coverage-omit', action='append',
+                              default=[],
+                              help=('Globs to omit when reporting coverage '
+                                    '(defaults to %s).' %
+                                    DEFAULT_COVERAGE_OMIT))
+            self.add_argument('--coverage-annotate', action='store_true',
+                              help=('Produce an annotate source report.'))
+            self.add_argument('--coverage-show-missing', action='store_true',
+                              help=('Show missing line ranges in coverage '
+                                    'report.'))
+            self.add_argument('--master-name',
+                              help=('Buildbot master name to include in the '
+                                    'uploaded data.'))
+            self.add_argument('--metadata', action='append', default=[],
+                              help=('Optional key=value metadata that will '
+                                    'be included in the results.'))
+            self.add_argument('--test-results-server',
+                              help=('If specified, uploads the full results '
+                                    'to this server.'))
+            self.add_argument('--test-type',
+                              help=('Name of test type to include in the '
+                                    'uploaded data (e.g., '
+                                    '"telemetry_unittests").'))
+            self.add_argument('--write-full-results-to', metavar='FILENAME',
+                              action='store',
+                              help=('If specified, writes the full results to '
+                                    'that path.'))
+            self.add_argument('--write-trace-to', metavar='FILENAME',
+                              action='store',
+                              help=('If specified, writes the trace to '
+                                    'that path.'))
+            self.add_argument('tests', nargs='*', default=[],
+                              help=argparse.SUPPRESS)
+
+        if running:
+            self.add_argument('-d', '--debugger', action='store_true',
+                              help='Runs the tests under the debugger.')
+            self.add_argument('-j', '--jobs', metavar='N', type=int,
+                              default=self._host.cpu_count(),
+                              help=('Runs N jobs in parallel '
+                                    '(defaults to %(default)s).'))
+            self.add_argument('-l', '--list-only', action='store_true',
+                              help='Lists all the test names found and exits.')
+            self.add_argument('-n', '--dry-run', action='store_true',
+                              help=argparse.SUPPRESS)
+            self.add_argument('-q', '--quiet', action='store_true',
+                              default=False,
+                              help=('Runs as quietly as possible '
+                                    '(only prints errors).'))
+            self.add_argument('-s', '--status-format',
+                              default=self._host.getenv('NINJA_STATUS',
+                                                        DEFAULT_STATUS_FORMAT),
+                              help=argparse.SUPPRESS)
+            self.add_argument('-t', '--timing', action='store_true',
+                              help='Prints timing info.')
+            self.add_argument('-v', '--verbose', action='count', default=0,
+                              help=('Prints more stuff (can specify multiple '
+                                    'times for more output).'))
+            self.add_argument('--passthrough', action='store_true',
+                              default=False,
+                              help='Prints all output while running.')
+            self.add_argument('--retry-limit', type=int, default=0,
+                              help='Retries each failure up to N times.')
+            self.add_argument('--terminal-width', type=int,
+                              default=self._host.terminal_width(),
+                              help=argparse.SUPPRESS)
+            self.add_argument('--overwrite', action='store_true',
+                              default=None,
+                              help=argparse.SUPPRESS)
+            self.add_argument('--no-overwrite', action='store_false',
+                              dest='overwrite', default=None,
+                              help=argparse.SUPPRESS)
+
+        if discovery or running:
+            self.add_argument('-P', '--path', action='append', default=[],
+                              help=('Adds dir to sys.path (can specify '
+                                    'multiple times).'))
+            self.add_argument('--top-level-dir', default=None,
+                              help=('Sets the top directory of project '
+                                    '(used when running subdirs).'))
+
+    def parse_args(self, args=None, namespace=None):
+        try:
+            rargs = super(ArgumentParser, self).parse_args(args=args,
+                                                           namespace=namespace)
+        except _Bailout:
+            return None
+
+        for val in rargs.metadata:
+            if '=' not in val:
+                self._print_message('Error: malformed --metadata "%s"' % val)
+                self.exit_status = 2
+
+        if rargs.test_results_server:
+            if not rargs.builder_name:
+                self._print_message('Error: --builder-name must be specified '
+                                    'along with --test-result-server')
+                self.exit_status = 2
+            if not rargs.master_name:
+                self._print_message('Error: --master-name must be specified '
+                                    'along with --test-result-server')
+                self.exit_status = 2
+            if not rargs.test_type:
+                self._print_message('Error: --test-type must be specified '
+                                    'along with --test-result-server')
+                self.exit_status = 2
+
+        if not rargs.suffixes:
+            rargs.suffixes = DEFAULT_SUFFIXES
+
+        if not rargs.coverage_omit:
+            rargs.coverage_omit = DEFAULT_COVERAGE_OMIT
+
+        if rargs.debugger:  # pragma: no cover
+            rargs.jobs = 1
+            rargs.passthrough = True
+
+        if rargs.overwrite is None:
+            rargs.overwrite = self._host.stdout.isatty() and not rargs.verbose
+
+        return rargs
+
+    # Redefining built-in 'file' pylint: disable=W0622
+
+    def _print_message(self, msg, file=None):
+        self._host.print_(msg=msg, stream=file, end='\n')
+
+    def print_help(self, file=None):
+        self._print_message(msg=self.format_help(), file=file)
+
+    def error(self, message, bailout=True):  # pylint: disable=W0221
+        self.exit(2, '%s: error: %s\n' % (self.prog, message), bailout=bailout)
+
+    def exit(self, status=0, message=None,  # pylint: disable=W0221
+             bailout=True):
+        self.exit_status = status
+        if message:
+            self._print_message(message, file=self._host.stderr)
+        if bailout:
+            raise _Bailout()
+
+    def optparse_options(self, skip=None):
+        skip = skip or []
+        options = []
+        for action in self._actions:
+            args = [flag for flag in action.option_strings if flag not in skip]
+            if not args or action.help == '==SUPPRESS==':
+                # must either be a positional argument like 'tests'
+                # or an option we want to skip altogether.
+                continue
+
+            kwargs = {
+                'default': action.default,
+                'dest': action.dest,
+                'help': action.help,
+                'metavar': action.metavar,
+                'type': action.type,
+                'action': _action_str(action)
+            }
+            options.append(optparse.make_option(*args, **kwargs))
+        return options
+
+    def argv_from_args(self, args):
+        default_parser = ArgumentParser(host=self._host)
+        default_args = default_parser.parse_args([])
+        argv = []
+        tests = []
+        d = vars(args)
+        for k in sorted(d.keys()):
+            v = d[k]
+            argname = _argname_from_key(k)
+            action = self._action_for_key(k)
+            action_str = _action_str(action)
+            if k == 'tests':
+                tests = v
+                continue
+            if getattr(default_args, k) == v:
+                # this arg has the default value, so skip it.
+                continue
+
+            assert action_str in ['append', 'count', 'store', 'store_true']
+            if action_str == 'append':
+                for el in v:
+                    argv.append(argname)
+                    argv.append(el)
+            elif action_str == 'count':
+                for _ in range(v):
+                    argv.append(argname)
+            elif action_str == 'store':
+                argv.append(argname)
+                argv.append(str(v))
+            else:
+                # action_str == 'store_true'
+                argv.append(argname)
+
+        return argv + tests
+
+    def _action_for_key(self, key):
+        for action in self._actions:
+            if action.dest == key:
+                return action
+
+        assert False, ('Could not find an action for %s'  # pragma: no cover
+                       % key)
+
+
+def _action_str(action):
+    # Access to a protected member pylint: disable=W0212
+    assert action.__class__ in (
+        argparse._AppendAction,
+        argparse._CountAction,
+        argparse._StoreAction,
+        argparse._StoreTrueAction
+    )
+
+    if isinstance(action, argparse._AppendAction):
+        return 'append'
+    if isinstance(action, argparse._CountAction):
+        return 'count'
+    if isinstance(action, argparse._StoreAction):
+        return 'store'
+    if isinstance(action, argparse._StoreTrueAction):
+        return 'store_true'
+
+
+def _argname_from_key(key):
+    return '--' + key.replace('_', '-')
diff --git a/third_party/tvcm/third_party/typ/typ/fakes/__init__.py b/third_party/tvcm/third_party/typ/typ/fakes/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/third_party/tvcm/third_party/typ/typ/fakes/__init__.py
diff --git a/third_party/tvcm/third_party/typ/typ/fakes/host_fake.py b/third_party/tvcm/third_party/typ/typ/fakes/host_fake.py
new file mode 100644
index 0000000..5b9e46d
--- /dev/null
+++ b/third_party/tvcm/third_party/typ/typ/fakes/host_fake.py
@@ -0,0 +1,292 @@
+# Copyright 2014 Dirk Pranke. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import copy
+import io
+import logging
+import sys
+
+from typ.host import _TeedStream
+
+
+is_python3 = bool(sys.version_info.major == 3)
+
+if is_python3:  # pragma: python3
+    # redefining built-in 'unicode' pylint: disable=W0622
+    unicode = str
+
+
+class FakeHost(object):
+    # "too many instance attributes" pylint: disable=R0902
+    # "redefining built-in" pylint: disable=W0622
+    # "unused arg" pylint: disable=W0613
+
+    python_interpreter = 'python'
+    is_python3 = bool(sys.version_info.major == 3)
+
+    def __init__(self):
+        self.logger = logging.getLogger()
+        self.stdin = io.StringIO()
+        self.stdout = io.StringIO()
+        self.stderr = io.StringIO()
+        self.platform = 'linux2'
+        self.env = {}
+        self.sep = '/'
+        self.dirs = set([])
+        self.files = {}
+        self.fetches = []
+        self.fetch_responses = {}
+        self.written_files = {}
+        self.last_tmpdir = None
+        self.current_tmpno = 0
+        self.mtimes = {}
+        self.cmds = []
+        self.cwd = '/tmp'
+        self._orig_logging_handlers = []
+
+    def __getstate__(self):
+        d = copy.copy(self.__dict__)
+        del d['stderr']
+        del d['stdout']
+        del d['stdin']
+        del d['logger']
+        del d['_orig_logging_handlers']
+        return d
+
+    def __setstate__(self, d):
+        for k, v in d.items():
+            setattr(self, k, v)
+        self.logger = logging.getLogger()
+        self.stdin = io.StringIO()
+        self.stdout = io.StringIO()
+        self.stderr = io.StringIO()
+
+    def abspath(self, *comps):
+        relpath = self.join(*comps)
+        if relpath.startswith('/'):
+            return relpath
+        return self.join(self.cwd, relpath)
+
+    def add_to_path(self, *comps):
+        absolute_path = self.abspath(*comps)
+        if absolute_path not in sys.path:
+            sys.path.append(absolute_path)
+
+    def basename(self, path):
+        return path.split(self.sep)[-1]
+
+    def call(self, argv, stdin=None, env=None):
+        self.cmds.append(argv)
+        return 0, '', ''
+
+    def call_inline(self, argv):
+        return self.call(argv)[0]
+
+    def chdir(self, *comps):
+        path = self.join(*comps)
+        if not path.startswith('/'):
+            path = self.join(self.cwd, path)
+        self.cwd = path
+
+    def cpu_count(self):
+        return 1
+
+    def dirname(self, path):
+        return '/'.join(path.split('/')[:-1])
+
+    def exists(self, *comps):
+        path = self.abspath(*comps)
+        return ((path in self.files and self.files[path] is not None) or
+                path in self.dirs)
+
+    def files_under(self, top):
+        files = []
+        top = self.abspath(top)
+        for f in self.files:
+            if self.files[f] is not None and f.startswith(top):
+                files.append(self.relpath(f, top))
+        return files
+
+    def for_mp(self):
+        return self
+
+    def getcwd(self):
+        return self.cwd
+
+    def getenv(self, key, default=None):
+        return self.env.get(key, default)
+
+    def getpid(self):
+        return 1
+
+    def isdir(self, *comps):
+        path = self.abspath(*comps)
+        return path in self.dirs
+
+    def isfile(self, *comps):
+        path = self.abspath(*comps)
+        return path in self.files and self.files[path] is not None
+
+    def join(self, *comps):
+        p = ''
+        for c in comps:
+            if c in ('', '.'):
+                continue
+            elif c.startswith('/'):
+                p = c
+            elif p:
+                p += '/' + c
+            else:
+                p = c
+
+        # Handle ./
+        p = p.replace('/./', '/')
+
+        # Handle ../
+        while '/..' in p:
+            comps = p.split('/')
+            idx = comps.index('..')
+            comps = comps[:idx-1] + comps[idx+1:]
+            p = '/'.join(comps)
+        return p
+
+    def maybe_mkdir(self, *comps):
+        path = self.abspath(self.join(*comps))
+        if path not in self.dirs:
+            self.dirs.add(path)
+
+    def mktempfile(self, delete=True):
+        curno = self.current_tmpno
+        self.current_tmpno += 1
+        f = io.StringIO()
+        f.name = '__im_tmp/tmpfile_%u' % curno
+        return f
+
+    def mkdtemp(self, suffix='', prefix='tmp', dir=None, **_kwargs):
+        if dir is None:
+            dir = self.sep + '__im_tmp'
+        curno = self.current_tmpno
+        self.current_tmpno += 1
+        self.last_tmpdir = self.join(dir, '%s_%u_%s' % (prefix, curno, suffix))
+        self.dirs.add(self.last_tmpdir)
+        return self.last_tmpdir
+
+    def mtime(self, *comps):
+        return self.mtimes.get(self.join(*comps), 0)
+
+    def print_(self, msg='', end='\n', stream=None):
+        stream = stream or self.stdout
+        stream.write(msg + end)
+        stream.flush()
+
+    def read_binary_file(self, *comps):
+        return self._read(comps)
+
+    def read_text_file(self, *comps):
+        return self._read(comps)
+
+    def _read(self, comps):
+        return self.files[self.abspath(*comps)]
+
+    def realpath(self, *comps):
+        return self.abspath(*comps)
+
+    def relpath(self, path, start):
+        return path.replace(start + '/', '')
+
+    def remove(self, *comps):
+        path = self.abspath(*comps)
+        self.files[path] = None
+        self.written_files[path] = None
+
+    def rmtree(self, *comps):
+        path = self.abspath(*comps)
+        for f in self.files:
+            if f.startswith(path):
+                self.files[f] = None
+                self.written_files[f] = None
+        self.dirs.remove(path)
+
+    def terminal_width(self):
+        return 80
+
+    def splitext(self, path):
+        idx = path.rfind('.')
+        if idx == -1:
+            return (path, '')
+        return (path[:idx], path[idx:])
+
+    def time(self):
+        return 0
+
+    def write_binary_file(self, path, contents):
+        self._write(path, contents)
+
+    def write_text_file(self, path, contents):
+        self._write(path, contents)
+
+    def _write(self, path, contents):
+        full_path = self.abspath(path)
+        self.maybe_mkdir(self.dirname(full_path))
+        self.files[full_path] = contents
+        self.written_files[full_path] = contents
+
+    def fetch(self, url, data=None, headers=None):
+        resp = self.fetch_responses.get(url, FakeResponse(unicode(''), url))
+        self.fetches.append((url, data, headers, resp))
+        return resp
+
+    def _tap_output(self):
+        self.stdout = _TeedStream(self.stdout)
+        self.stderr = _TeedStream(self.stderr)
+        if True:
+            sys.stdout = self.stdout
+            sys.stderr = self.stderr
+
+    def _untap_output(self):
+        assert isinstance(self.stdout, _TeedStream)
+        self.stdout = self.stdout.stream
+        self.stderr = self.stderr.stream
+        if True:
+            sys.stdout = self.stdout
+            sys.stderr = self.stderr
+
+    def capture_output(self, divert=True):
+        self._tap_output()
+        self._orig_logging_handlers = self.logger.handlers
+        if self._orig_logging_handlers:
+            self.logger.handlers = [logging.StreamHandler(self.stderr)]
+        self.stdout.capture(divert=divert)
+        self.stderr.capture(divert=divert)
+
+    def restore_output(self):
+        assert isinstance(self.stdout, _TeedStream)
+        out, err = (self.stdout.restore(), self.stderr.restore())
+        self.logger.handlers = self._orig_logging_handlers
+        self._untap_output()
+        return out, err
+
+
+class FakeResponse(io.StringIO):
+
+    def __init__(self, response, url, code=200):
+        io.StringIO.__init__(self, response)
+        self._url = url
+        self.code = code
+
+    def geturl(self):
+        return self._url
+
+    def getcode(self):
+        return self.code
diff --git a/third_party/tvcm/third_party/typ/typ/fakes/test_result_server_fake.py b/third_party/tvcm/third_party/typ/typ/fakes/test_result_server_fake.py
new file mode 100644
index 0000000..e7b81e9
--- /dev/null
+++ b/third_party/tvcm/third_party/typ/typ/fakes/test_result_server_fake.py
@@ -0,0 +1,78 @@
+# Copyright 2014 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""A fake implementation of test-results.appspot.com."""
+
+import io
+import sys
+import threading
+
+
+if sys.version_info.major == 2:  # pragma: python2
+    from SimpleHTTPServer import SimpleHTTPRequestHandler as HTTPRequestHandler
+    from SocketServer import TCPServer
+else:  # pragma: python3
+    assert sys.version_info.major == 3
+    unicode = str  # pylint: disable=W0622
+    from http.server import BaseHTTPRequestHandler  # pylint: disable=F0401
+    HTTPRequestHandler = BaseHTTPRequestHandler
+    from socketserver import TCPServer  # pylint: disable=F0401
+
+
+def start(code=200):
+    server = _Server(code=code)
+    thread = threading.Thread(target=_run, args=(server,))
+    server.main_thread = thread
+    thread.daemon = True
+    thread.start()
+    return server
+
+
+def _run(server):
+    server.serve_forever(0.05)
+
+
+class _Server(TCPServer):
+
+    def __init__(self, code):
+        self.allow_reuse_address = True
+        TCPServer.__init__(self, ('localhost', 0), _RequestHandler)
+        self.log = io.StringIO()
+        self.requests = []
+        self.main_thread = None
+        self.code = code
+
+    def stop(self):
+        self.shutdown()
+        self.main_thread.join()
+        return self.requests
+
+
+class _RequestHandler(HTTPRequestHandler):
+
+    def __init__(self, *args, **kwargs):
+        HTTPRequestHandler.__init__(self, *args, **kwargs)
+
+    # 'Invalid Name' pylint: disable=C0103
+    def do_POST(self):
+        path = self.path
+        length = int(self.headers['content-length'])
+        payload = self.rfile.read(length)
+        self.server.requests.append(('post', path, payload))
+        self.send_response(self.server.code)
+        self.end_headers()
+
+    # 'Redefining built-in' pylint: disable=W0622
+    def log_message(self, format, *args):
+        self.server.log.write(unicode('%s\n' % (format % args)))
diff --git a/third_party/tvcm/third_party/typ/typ/fakes/tests/__init__.py b/third_party/tvcm/third_party/typ/typ/fakes/tests/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/third_party/tvcm/third_party/typ/typ/fakes/tests/__init__.py
diff --git a/third_party/tvcm/third_party/typ/typ/fakes/tests/host_fake_test.py b/third_party/tvcm/third_party/typ/typ/fakes/tests/host_fake_test.py
new file mode 100644
index 0000000..a16b7ba
--- /dev/null
+++ b/third_party/tvcm/third_party/typ/typ/fakes/tests/host_fake_test.py
@@ -0,0 +1,83 @@
+# Copyright 2014 Dirk Pranke. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+
+from typ.tests import host_test
+from typ.fakes.host_fake import FakeHost, FakeResponse
+
+is_python3 = bool(sys.version_info.major == 3)
+
+if is_python3:  # pragma: python3
+    # redefining built-in 'unicode' pylint: disable=W0622
+    unicode = str
+
+class TestFakeHost(host_test.TestHost):
+
+    def host(self):
+        return FakeHost()
+
+    def test_add_to_path(self):
+        # TODO: FakeHost uses the real sys.path, and then gets
+        # confused becayse host.abspath() doesn't work right for
+        # windows-style paths.
+        if sys.platform != 'win32':
+            super(TestFakeHost, self).test_add_to_path()
+
+    def test_call(self):
+        h = self.host()
+        ret, out, err = h.call(['echo', 'hello, world'])
+        self.assertEqual(ret, 0)
+        self.assertEqual(out, '')
+        self.assertEqual(err, '')
+        self.assertEqual(h.cmds, [['echo', 'hello, world']])
+
+    def test_call_inline(self):
+        h = self.host()
+        ret = h.call_inline(['echo', 'hello, world'])
+        self.assertEqual(ret, 0)
+
+    def test_capture_output(self):
+        h = self.host()
+        self.host = lambda: h
+        super(TestFakeHost, self).test_capture_output()
+
+        # This tests that the super-method only tested the
+        # divert=True case, and things were diverted properly.
+        self.assertEqual(h.stdout.getvalue(), '')
+        self.assertEqual(h.stderr.getvalue(), '')
+
+        h.capture_output(divert=False)
+        h.print_('on stdout')
+        h.print_('on stderr', stream=h.stderr)
+        out, err = h.restore_output()
+        self.assertEqual(out, 'on stdout\n')
+        self.assertEqual(err, 'on stderr\n')
+        self.assertEqual(h.stdout.getvalue(), 'on stdout\n')
+        self.assertEqual(h.stderr.getvalue(), 'on stderr\n')
+
+    def test_for_mp(self):
+        h = self.host()
+        self.assertNotEqual(h.for_mp(), None)
+
+    def test_fetch(self):
+        h = self.host()
+        url = 'http://localhost/test'
+        resp = FakeResponse(unicode('foo'), url)
+        h.fetch_responses[url] = resp
+        actual_resp = h.fetch(url)
+        self.assertEqual(actual_resp.geturl(), url)
+        self.assertEqual(actual_resp.getcode(), 200)
+        self.assertEqual(resp, actual_resp)
+        self.assertEqual(h.fetches, [(url, None, None, actual_resp)])
diff --git a/third_party/tvcm/third_party/typ/typ/fakes/tests/test_result_server_fake_test.py b/third_party/tvcm/third_party/typ/typ/fakes/tests/test_result_server_fake_test.py
new file mode 100644
index 0000000..87316c8
--- /dev/null
+++ b/third_party/tvcm/third_party/typ/typ/fakes/tests/test_result_server_fake_test.py
@@ -0,0 +1,36 @@
+# Copyright 2014 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import unittest
+
+from typ.fakes import test_result_server_fake
+from typ import Host
+
+
+class TestResultServerFakeTest(unittest.TestCase):
+    def test_basic_upload(self):
+        host = Host()
+        server = None
+        posts = []
+        try:
+            server = test_result_server_fake.start()
+            url = 'http://%s:%d/testfile/upload' % server.server_address
+            if server:
+                resp = host.fetch(url, 'foo=bar')
+        finally:
+            if server:
+                posts = server.stop()
+        self.assertEqual(posts, [('post', '/testfile/upload',
+                                  'foo=bar'.encode('utf8'))])
+        self.assertNotEqual(server.log.getvalue(), '')
diff --git a/third_party/tvcm/third_party/typ/typ/host.py b/third_party/tvcm/third_party/typ/typ/host.py
new file mode 100644
index 0000000..fc9e113
--- /dev/null
+++ b/third_party/tvcm/third_party/typ/typ/host.py
@@ -0,0 +1,286 @@
+# Copyright 2014 Dirk Pranke. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import io
+import logging
+import multiprocessing
+import os
+import shutil
+import subprocess
+import sys
+import tempfile
+import time
+
+
+if sys.version_info.major == 2:  # pragma: python2
+    from urllib2 import urlopen, Request
+else:  # pragma: python3
+    # pylint: disable=E0611
+    assert sys.version_info.major == 3
+    from urllib.request import urlopen, Request  # pylint: disable=F0401,E0611
+
+
+class Host(object):
+    python_interpreter = sys.executable
+    is_python3 = bool(sys.version_info.major == 3)
+
+    pathsep = os.pathsep
+    sep = os.sep
+    env = os.environ
+
+    _orig_stdout = sys.stdout
+    _orig_stderr = sys.stderr
+
+    def __init__(self):
+        self.logger = logging.getLogger()
+        self._orig_logging_handlers = None
+        self.stdout = sys.stdout
+        self.stderr = sys.stderr
+        self.stdin = sys.stdin
+        self.env = os.environ
+        self.platform = sys.platform
+
+    def abspath(self, *comps):
+        return os.path.abspath(self.join(*comps))
+
+    def add_to_path(self, *comps):
+        absolute_path = self.abspath(*comps)
+        if absolute_path not in sys.path:
+            sys.path.append(absolute_path)
+
+    def basename(self, path):
+        return os.path.basename(path)
+
+    def call(self, argv, stdin=None, env=None):
+        if stdin:
+            stdin_pipe = subprocess.PIPE
+        else:
+            stdin_pipe = None
+        proc = subprocess.Popen(argv, stdout=subprocess.PIPE,
+                                stderr=subprocess.PIPE, stdin=stdin_pipe,
+                                env=env)
+        if stdin_pipe:
+            proc.stdin.write(stdin.encode('utf-8'))
+        stdout, stderr = proc.communicate()
+
+        # pylint type checking bug - pylint: disable=E1103
+        return proc.returncode, stdout.decode('utf-8'), stderr.decode('utf-8')
+
+    def call_inline(self, argv, env=None):
+        if isinstance(self.stdout, _TeedStream):  # pragma: no cover
+            ret, out, err = self.call(argv, env)
+            self.print_(out, end='')
+            self.print_(err, end='', stream=self.stderr)
+            return ret
+        return subprocess.call(argv, stdin=self.stdin, stdout=self.stdout,
+                               stderr=self.stderr, env=env)
+
+    def chdir(self, *comps):
+        return os.chdir(self.join(*comps))
+
+    def cpu_count(self):
+        return multiprocessing.cpu_count()
+
+    def dirname(self, *comps):
+        return os.path.dirname(self.join(*comps))
+
+    def exists(self, *comps):
+        return os.path.exists(self.join(*comps))
+
+    def files_under(self, top):
+        all_files = []
+        for root, _, files in os.walk(top):
+            for f in files:
+                relpath = self.relpath(os.path.join(root, f), top)
+                all_files.append(relpath)
+        return all_files
+
+    def getcwd(self):
+        return os.getcwd()
+
+    def getenv(self, key, default=None):
+        return self.env.get(key, default)
+
+    def getpid(self):
+        return os.getpid()
+
+    def for_mp(self):
+        return None
+
+    def isdir(self, *comps):
+        return os.path.isdir(os.path.join(*comps))
+
+    def isfile(self, *comps):
+        return os.path.isfile(os.path.join(*comps))
+
+    def join(self, *comps):
+        return os.path.join(*comps)
+
+    def maybe_mkdir(self, *comps):
+        path = self.abspath(self.join(*comps))
+        if not self.exists(path):
+            os.makedirs(path)
+
+    def mktempfile(self, delete=True):
+        return tempfile.NamedTemporaryFile(delete=delete)
+
+    def mkdtemp(self, **kwargs):
+        return tempfile.mkdtemp(**kwargs)
+
+    def mtime(self, *comps):
+        return os.stat(self.join(*comps)).st_mtime
+
+    def print_(self, msg='', end='\n', stream=None):
+        stream = stream or self.stdout
+        stream.write(str(msg) + end)
+        stream.flush()
+
+    def read_text_file(self, *comps):
+        return self._read(comps, 'r')
+
+    def read_binary_file(self, *comps):
+        return self._read(comps, 'rb')
+
+    def _read(self, comps, mode):
+        path = self.join(*comps)
+        with open(path, mode) as f:
+            return f.read()
+
+    def realpath(self, *comps):
+        return os.path.realpath(os.path.join(*comps))
+
+    def relpath(self, path, start):
+        return os.path.relpath(path, start)
+
+    def remove(self, *comps):
+        os.remove(self.join(*comps))
+
+    def rmtree(self, path):
+        shutil.rmtree(path, ignore_errors=True)
+
+    def splitext(self, path):
+        return os.path.splitext(path)
+
+    def time(self):
+        return time.time()
+
+    def write_text_file(self, path, contents):
+        return self._write(path, contents, mode='w')
+
+    def write_binary_file(self, path, contents):
+        return self._write(path, contents, mode='wb')
+
+    def _write(self, path, contents, mode):
+        with open(path, mode) as f:
+            f.write(contents)
+
+    def fetch(self, url, data=None, headers=None):
+        headers = headers or {}
+        return urlopen(Request(url, data.encode('utf8'), headers))
+
+    def terminal_width(self):
+        """Returns 0 if the width cannot be determined."""
+        try:
+            if sys.platform == 'win32':  # pragma: win32
+                # From http://code.activestate.com/recipes/ \
+                #   440694-determine-size-of-console-window-on-windows/
+                from ctypes import windll, create_string_buffer
+
+                STDERR_HANDLE = -12
+                handle = windll.kernel32.GetStdHandle(STDERR_HANDLE)
+
+                SCREEN_BUFFER_INFO_SZ = 22
+                buf = create_string_buffer(SCREEN_BUFFER_INFO_SZ)
+
+                if windll.kernel32.GetConsoleScreenBufferInfo(handle, buf):
+                    import struct
+                    fields = struct.unpack("hhhhHhhhhhh", buf.raw)
+                    left = fields[5]
+                    right = fields[7]
+
+                    # Note that we return 1 less than the width since writing
+                    # into the rightmost column automatically performs a
+                    # line feed.
+                    return right - left
+                return 0
+            else:  # pragma: no win32
+                import fcntl
+                import struct
+                import termios
+                packed = fcntl.ioctl(self.stderr.fileno(),
+                                     termios.TIOCGWINSZ, '\0' * 8)
+                _, columns, _, _ = struct.unpack('HHHH', packed)
+                return columns
+        except Exception:
+            return 0
+
+    def _tap_output(self):
+        self.stdout = sys.stdout = _TeedStream(self.stdout)
+        self.stderr = sys.stderr = _TeedStream(self.stderr)
+
+    def _untap_output(self):
+        assert isinstance(self.stdout, _TeedStream)
+        self.stdout = sys.stdout = self.stdout.stream
+        self.stderr = sys.stderr = self.stderr.stream
+
+    def capture_output(self, divert=True):
+        self._tap_output()
+        self._orig_logging_handlers = self.logger.handlers
+        if self._orig_logging_handlers:
+            self.logger.handlers = [logging.StreamHandler(self.stderr)]
+        self.stdout.capture(divert)
+        self.stderr.capture(divert)
+
+    def restore_output(self):
+        assert isinstance(self.stdout, _TeedStream)
+        out, err = (self.stdout.restore(), self.stderr.restore())
+        self.logger.handlers = self._orig_logging_handlers
+        self._untap_output()
+        return out, err
+
+
+class _TeedStream(io.StringIO):
+
+    def __init__(self, stream):
+        super(_TeedStream, self).__init__()
+        self.stream = stream
+        self.capturing = False
+        self.diverting = False
+
+    def write(self, msg, *args, **kwargs):
+        if self.capturing:
+            if (sys.version_info.major == 2 and
+                    isinstance(msg, str)):  # pragma: python2
+                msg = unicode(msg)
+            super(_TeedStream, self).write(msg, *args, **kwargs)
+        if not self.diverting:
+            self.stream.write(msg, *args, **kwargs)
+
+    def flush(self):
+        if self.capturing:
+            super(_TeedStream, self).flush()
+        if not self.diverting:
+            self.stream.flush()
+
+    def capture(self, divert=True):
+        self.truncate(0)
+        self.capturing = True
+        self.diverting = divert
+
+    def restore(self):
+        msg = self.getvalue()
+        self.truncate(0)
+        self.capturing = False
+        self.diverting = False
+        return msg
diff --git a/third_party/tvcm/third_party/typ/typ/json_results.py b/third_party/tvcm/third_party/typ/typ/json_results.py
new file mode 100644
index 0000000..5e95ed5
--- /dev/null
+++ b/third_party/tvcm/third_party/typ/typ/json_results.py
@@ -0,0 +1,185 @@
+# Copyright 2014 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from collections import OrderedDict
+
+import json
+
+
+class ResultType(object):
+    Pass = 'Pass'
+    Failure = 'Failure'
+    ImageOnlyFailure = 'ImageOnlyFailure'
+    Timeout = 'Timeout'
+    Crash = 'Crash'
+    Skip = 'Skip'
+
+    values = (Pass, Failure, ImageOnlyFailure, Timeout, Crash, Skip)
+
+
+class Result(object):
+    # too many instance attributes  pylint: disable=R0902
+    # too many arguments  pylint: disable=R0913
+
+    def __init__(self, name, actual, started, took, worker,
+                 expected=None, unexpected=False,
+                 flaky=False, code=0, out='', err='', pid=0):
+        self.name = name
+        self.actual = actual
+        self.started = started
+        self.took = took
+        self.worker = worker
+        self.expected = expected or [ResultType.Pass]
+        self.unexpected = unexpected
+        self.flaky = flaky
+        self.code = code
+        self.out = out
+        self.err = err
+        self.pid = pid
+
+
+class ResultSet(object):
+
+    def __init__(self):
+        self.results = []
+
+    def add(self, result):
+        self.results.append(result)
+
+
+TEST_SEPARATOR = '.'
+
+
+def make_full_results(metadata, seconds_since_epoch, all_test_names, results):
+    """Convert the typ results to the Chromium JSON test result format.
+
+    See http://www.chromium.org/developers/the-json-test-results-format
+    """
+
+    # We use OrderedDicts here so that the output is stable.
+    full_results = OrderedDict()
+    full_results['version'] = 3
+    full_results['interrupted'] = False
+    full_results['path_delimiter'] = TEST_SEPARATOR
+    full_results['seconds_since_epoch'] = seconds_since_epoch
+
+    for md in metadata:
+        key, val = md.split('=', 1)
+        full_results[key] = val
+
+    passing_tests = _passing_test_names(results)
+    failed_tests = failed_test_names(results)
+    skipped_tests = set(all_test_names) - passing_tests - failed_tests
+
+    full_results['num_failures_by_type'] = OrderedDict()
+    full_results['num_failures_by_type']['FAIL'] = len(failed_tests)
+    full_results['num_failures_by_type']['PASS'] = len(passing_tests)
+    full_results['num_failures_by_type']['SKIP'] = len(skipped_tests)
+
+    full_results['tests'] = OrderedDict()
+
+    for test_name in all_test_names:
+        value = OrderedDict()
+        if test_name in skipped_tests:
+            value['expected'] = 'SKIP'
+            value['actual'] = 'SKIP'
+        else:
+            value['expected'] = 'PASS'
+            value['actual'] = _actual_results_for_test(test_name, results)
+            if value['actual'].endswith('FAIL'):
+                value['is_unexpected'] = True
+        _add_path_to_trie(full_results['tests'], test_name, value)
+
+    return full_results
+
+
+def make_upload_request(test_results_server, builder, master, testtype,
+                        full_results):
+    url = 'http://%s/testfile/upload' % test_results_server
+    attrs = [('builder', builder),
+             ('master', master),
+             ('testtype', testtype)]
+    content_type, data = _encode_multipart_form_data(attrs, full_results)
+    return url, content_type, data
+
+
+def exit_code_from_full_results(full_results):
+    return 1 if num_failures(full_results) else 0
+
+
+def num_failures(full_results):
+    return full_results['num_failures_by_type']['FAIL']
+
+
+def failed_test_names(results):
+    names = set()
+    for r in results.results:
+        if r.actual == ResultType.Failure:
+            names.add(r.name)
+        elif (r.actual == ResultType.Pass and r.name in names):
+            names.remove(r.name)
+    return names
+
+
+def _passing_test_names(results):
+    return set(r.name for r in results.results if r.actual == ResultType.Pass)
+
+
+def _actual_results_for_test(test_name, results):
+    actuals = []
+    for r in results.results:
+        if r.name == test_name:
+            if r.actual == ResultType.Failure:
+                actuals.append('FAIL')
+            elif r.actual == ResultType.Pass:
+                actuals.append('PASS')
+
+    assert actuals, 'We did not find any result data for %s.' % test_name
+    return ' '.join(actuals)
+
+
+def _add_path_to_trie(trie, path, value):
+    if TEST_SEPARATOR not in path:
+        trie[path] = value
+        return
+    directory, rest = path.split(TEST_SEPARATOR, 1)
+    if directory not in trie:
+        trie[directory] = {}
+    _add_path_to_trie(trie[directory], rest, value)
+
+
+def _encode_multipart_form_data(attrs, test_results):
+    # Cloned from webkitpy/common/net/file_uploader.py
+    BOUNDARY = '-J-S-O-N-R-E-S-U-L-T-S---B-O-U-N-D-A-R-Y-'
+    CRLF = '\r\n'
+    lines = []
+
+    for key, value in attrs:
+        lines.append('--' + BOUNDARY)
+        lines.append('Content-Disposition: form-data; name="%s"' % key)
+        lines.append('')
+        lines.append(value)
+
+    lines.append('--' + BOUNDARY)
+    lines.append('Content-Disposition: form-data; name="file"; '
+                 'filename="full_results.json"')
+    lines.append('Content-Type: application/json')
+    lines.append('')
+    lines.append(json.dumps(test_results))
+
+    lines.append('--' + BOUNDARY + '--')
+    lines.append('')
+    body = CRLF.join(lines)
+    content_type = 'multipart/form-data; boundary=%s' % BOUNDARY
+    return content_type, body
diff --git a/third_party/tvcm/third_party/typ/typ/pool.py b/third_party/tvcm/third_party/typ/typ/pool.py
new file mode 100644
index 0000000..a843226
--- /dev/null
+++ b/third_party/tvcm/third_party/typ/typ/pool.py
@@ -0,0 +1,204 @@
+# Copyright 2014 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import copy
+import multiprocessing
+import pickle
+import sys
+import traceback
+
+from typ.host import Host
+
+
+def make_pool(host, jobs, callback, context, pre_fn, post_fn):
+    _validate_args(context, pre_fn, post_fn)
+    if jobs > 1:
+        return _ProcessPool(host, jobs, callback, context, pre_fn, post_fn)
+    else:
+        return _AsyncPool(host, jobs, callback, context, pre_fn, post_fn)
+
+
+class _MessageType(object):
+    Request = 'Request'
+    Response = 'Response'
+    Close = 'Close'
+    Done = 'Done'
+    Error = 'Error'
+    Interrupt = 'Interrupt'
+
+    values = [Request, Response, Close, Done, Error, Interrupt]
+
+
+def _validate_args(context, pre_fn, post_fn):
+    try:
+        _ = pickle.dumps(context)
+    except Exception as e:
+        raise ValueError('context passed to make_pool is not picklable: %s'
+                         % str(e))
+    try:
+        _ = pickle.dumps(pre_fn)
+    except pickle.PickleError:
+        raise ValueError('pre_fn passed to make_pool is not picklable')
+    try:
+        _ = pickle.dumps(post_fn)
+    except pickle.PickleError:
+        raise ValueError('post_fn passed to make_pool is not picklable')
+
+
+class _ProcessPool(object):
+
+    def __init__(self, host, jobs, callback, context, pre_fn, post_fn):
+        self.host = host
+        self.jobs = jobs
+        self.requests = multiprocessing.Queue()
+        self.responses = multiprocessing.Queue()
+        self.workers = []
+        self.discarded_responses = []
+        self.closed = False
+        self.erred = False
+        for worker_num in range(1, jobs + 1):
+            w = multiprocessing.Process(target=_loop,
+                                        args=(self.requests, self.responses,
+                                              host.for_mp(), worker_num,
+                                              callback, context,
+                                              pre_fn, post_fn))
+            w.start()
+            self.workers.append(w)
+
+    def send(self, msg):
+        self.requests.put((_MessageType.Request, msg))
+
+    def get(self):
+        msg_type, resp = self.responses.get()
+        if msg_type == _MessageType.Error:
+            self._handle_error(resp)
+        elif msg_type == _MessageType.Interrupt:
+            raise KeyboardInterrupt
+        assert msg_type == _MessageType.Response
+        return resp
+
+    def close(self):
+        for _ in self.workers:
+            self.requests.put((_MessageType.Close, None))
+        self.closed = True
+
+    def join(self):
+        # TODO: one would think that we could close self.requests in close(),
+        # above, and close self.responses below, but if we do, we get
+        # weird tracebacks in the daemon threads multiprocessing starts up.
+        # Instead, we have to hack the innards of multiprocessing. It
+        # seems likely that there's a bug somewhere, either in this module or
+        # in multiprocessing.
+        if self.host.is_python3:  # pragma: python3
+            multiprocessing.queues.is_exiting = lambda: True
+        else:  # pragma: python2
+            multiprocessing.util._exiting = True
+
+        if not self.closed:
+            # We must be aborting; terminate the workers rather than
+            # shutting down cleanly.
+            for w in self.workers:
+                w.terminate()
+                w.join()
+            return []
+
+        final_responses = []
+        error = None
+        interrupted = None
+        for w in self.workers:
+            while True:
+                msg_type, resp = self.responses.get()
+                if msg_type == _MessageType.Error:
+                    error = resp
+                    break
+                if msg_type == _MessageType.Interrupt:
+                    interrupted = True
+                    break
+                if msg_type == _MessageType.Done:
+                    final_responses.append(resp[1])
+                    break
+                self.discarded_responses.append(resp)
+
+        for w in self.workers:
+            w.join()
+
+        # TODO: See comment above at the beginning of the function for
+        # why this is commented out.
+        # self.responses.close()
+
+        if error:
+            self._handle_error(error)
+        if interrupted:
+            raise KeyboardInterrupt
+        return final_responses
+
+    def _handle_error(self, msg):
+        worker_num, tb = msg
+        self.erred = True
+        raise Exception("Error from worker %d (traceback follows):\n%s" %
+                        (worker_num, tb))
+
+
+# 'Too many arguments' pylint: disable=R0913
+
+def _loop(requests, responses, host, worker_num,
+          callback, context, pre_fn, post_fn, should_loop=True):
+    host = host or Host()
+    try:
+        context_after_pre = pre_fn(host, worker_num, context)
+        keep_looping = True
+        while keep_looping:
+            message_type, args = requests.get(block=True)
+            if message_type == _MessageType.Close:
+                responses.put((_MessageType.Done,
+                               (worker_num, post_fn(context_after_pre))))
+                break
+            assert message_type == _MessageType.Request
+            resp = callback(context_after_pre, args)
+            responses.put((_MessageType.Response, resp))
+            keep_looping = should_loop
+    except KeyboardInterrupt as e:
+        responses.put((_MessageType.Interrupt, (worker_num, str(e))))
+    except Exception as e:
+        responses.put((_MessageType.Error,
+                       (worker_num, traceback.format_exc(e))))
+
+
+class _AsyncPool(object):
+
+    def __init__(self, host, jobs, callback, context, pre_fn, post_fn):
+        self.host = host or Host()
+        self.jobs = jobs
+        self.callback = callback
+        self.context = copy.deepcopy(context)
+        self.msgs = []
+        self.closed = False
+        self.post_fn = post_fn
+        self.context_after_pre = pre_fn(self.host, 1, self.context)
+        self.final_context = None
+
+    def send(self, msg):
+        self.msgs.append(msg)
+
+    def get(self):
+        return self.callback(self.context_after_pre, self.msgs.pop(0))
+
+    def close(self):
+        self.closed = True
+        self.final_context = self.post_fn(self.context_after_pre)
+
+    def join(self):
+        if not self.closed:
+            self.close()
+        return [self.final_context]
diff --git a/third_party/tvcm/third_party/typ/typ/printer.py b/third_party/tvcm/third_party/typ/typ/printer.py
new file mode 100644
index 0000000..473537b
--- /dev/null
+++ b/third_party/tvcm/third_party/typ/typ/printer.py
@@ -0,0 +1,40 @@
+# Copyright 2014 Dirk Pranke. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+class Printer(object):
+
+    def __init__(self, print_, should_overwrite, cols):
+        self.print_ = print_
+        self.should_overwrite = should_overwrite
+        self.cols = cols
+        self.last_line = ''
+
+    def flush(self):
+        if self.last_line:
+            self.print_('')
+            self.last_line = ''
+
+    def update(self, msg, elide=True):
+        msg_len = len(msg)
+        if elide and self.cols and msg_len > self.cols - 5:
+            new_len = int((self.cols - 5) / 2)
+            msg = msg[:new_len] + '...' + msg[-new_len:]
+        if self.should_overwrite and self.last_line:
+            self.print_('\r' + ' ' * len(self.last_line) + '\r', end='')
+        elif self.last_line:
+            self.print_('')
+        self.print_(msg, end='')
+        last_nl = msg.rfind('\n')
+        self.last_line = msg[last_nl + 1:]
diff --git a/third_party/tvcm/third_party/typ/typ/runner.py b/third_party/tvcm/third_party/typ/typ/runner.py
new file mode 100644
index 0000000..03d2ae7
--- /dev/null
+++ b/third_party/tvcm/third_party/typ/typ/runner.py
@@ -0,0 +1,923 @@
+# Copyright 2014 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import fnmatch
+import importlib
+import inspect
+import json
+import os
+import pdb
+import sys
+import unittest
+import traceback
+
+from collections import OrderedDict
+
+# This ensures that absolute imports of typ modules will work when
+# running typ/runner.py as a script even if typ is not installed.
+# We need this entry in addition to the one in __main__.py to ensure
+# that typ/runner.py works when invoked via subprocess on windows in
+# _spawn_main().
+path_to_file = os.path.realpath(__file__)
+if path_to_file.endswith('.pyc'):  # pragma: no cover
+    path_to_file = path_to_file[:-1]
+dir_above_typ = os.path.dirname(os.path.dirname(path_to_file))
+if dir_above_typ not in sys.path:  # pragma: no cover
+    sys.path.append(dir_above_typ)
+
+
+from typ import json_results
+from typ.arg_parser import ArgumentParser
+from typ.host import Host
+from typ.pool import make_pool
+from typ.stats import Stats
+from typ.printer import Printer
+from typ.test_case import TestCase as TypTestCase
+from typ.version import VERSION
+
+
+Result = json_results.Result
+ResultSet = json_results.ResultSet
+ResultType = json_results.ResultType
+
+
+def main(argv=None, host=None, win_multiprocessing=None, **defaults):
+    host = host or Host()
+    runner = Runner(host=host)
+    if win_multiprocessing is not None:
+        runner.win_multiprocessing = win_multiprocessing
+    return runner.main(argv, **defaults)
+
+
+class TestInput(object):
+
+    def __init__(self, name, msg='', timeout=None, expected=None):
+        self.name = name
+        self.msg = msg
+        self.timeout = timeout
+        self.expected = expected
+
+
+class TestSet(object):
+
+    def __init__(self, parallel_tests=None, isolated_tests=None,
+                 tests_to_skip=None):
+
+        def promote(tests):
+            tests = tests or []
+            return [test if isinstance(test, TestInput) else TestInput(test)
+                    for test in tests]
+
+        self.parallel_tests = promote(parallel_tests)
+        self.isolated_tests = promote(isolated_tests)
+        self.tests_to_skip = promote(tests_to_skip)
+
+
+class WinMultiprocessing(object):
+    ignore = 'ignore'
+    importable = 'importable'
+    spawn = 'spawn'
+
+    values = [ignore, importable, spawn]
+
+
+class _AddTestsError(Exception):
+    pass
+
+
+class Runner(object):
+
+    def __init__(self, host=None):
+        self.args = None
+        self.classifier = None
+        self.cov = None
+        self.context = None
+        self.coverage_source = None
+        self.host = host or Host()
+        self.loader = unittest.loader.TestLoader()
+        self.printer = None
+        self.setup_fn = None
+        self.stats = None
+        self.teardown_fn = None
+        self.top_level_dir = None
+        self.win_multiprocessing = WinMultiprocessing.spawn
+        self.final_responses = []
+
+        # initialize self.args to the defaults.
+        parser = ArgumentParser(self.host)
+        self.parse_args(parser, [])
+
+    def main(self, argv=None, **defaults):
+        parser = ArgumentParser(self.host)
+        self.parse_args(parser, argv, **defaults)
+        if parser.exit_status is not None:
+            return parser.exit_status
+
+        try:
+            ret, _, _ = self.run()
+            return ret
+        except KeyboardInterrupt:
+            self.print_("interrupted, exiting", stream=self.host.stderr)
+            return 130
+
+    def parse_args(self, parser, argv, **defaults):
+        for attrname in defaults:
+            if not hasattr(self.args, attrname):
+                parser.error("Unknown default argument name '%s'" % attrname,
+                             bailout=False)
+                return
+        parser.set_defaults(**defaults)
+        self.args = parser.parse_args(args=argv)
+        if parser.exit_status is not None:
+            return
+
+    def print_(self, msg='', end='\n', stream=None):
+        self.host.print_(msg, end, stream=stream)
+
+    def run(self, test_set=None):
+
+        ret = 0
+        h = self.host
+
+        if self.args.version:
+            self.print_(VERSION)
+            return ret, None, None
+
+        should_spawn = self._check_win_multiprocessing()
+        if should_spawn:
+            return self._spawn(test_set)
+
+        ret = self._set_up_runner()
+        if ret:  # pragma: no cover
+            return ret, None, None
+
+        find_start = h.time()
+        if self.cov:  # pragma: no cover
+            self.cov.erase()
+            self.cov.start()
+
+        full_results = None
+        result_set = ResultSet()
+
+        if not test_set:
+            ret, test_set = self.find_tests(self.args)
+        find_end = h.time()
+
+        if not ret:
+            ret, full_results = self._run_tests(result_set, test_set)
+
+        if self.cov:  # pragma: no cover
+            self.cov.stop()
+            self.cov.save()
+        test_end = h.time()
+
+        trace = self._trace_from_results(result_set)
+        if full_results:
+            self._summarize(full_results)
+            self._write(self.args.write_full_results_to, full_results)
+            upload_ret = self._upload(full_results)
+            if not ret:
+                ret = upload_ret
+            reporting_end = h.time()
+            self._add_trace_event(trace, 'run', find_start, reporting_end)
+            self._add_trace_event(trace, 'discovery', find_start, find_end)
+            self._add_trace_event(trace, 'testing', find_end, test_end)
+            self._add_trace_event(trace, 'reporting', test_end, reporting_end)
+            self._write(self.args.write_trace_to, trace)
+            self.report_coverage()
+        else:
+            upload_ret = 0
+
+        return ret, full_results, trace
+
+    def _check_win_multiprocessing(self):
+        wmp = self.win_multiprocessing
+
+        ignore, importable, spawn = WinMultiprocessing.values
+
+        if wmp not in WinMultiprocessing.values:
+            raise ValueError('illegal value %s for win_multiprocessing' %
+                             wmp)
+
+        h = self.host
+        if wmp == ignore and h.platform == 'win32':  # pragma: win32
+            raise ValueError('Cannot use WinMultiprocessing.ignore for '
+                             'win_multiprocessing when actually running '
+                             'on Windows.')
+
+        if wmp == ignore or self.args.jobs == 1:
+            return False
+
+        if wmp == importable:
+            if self._main_is_importable():
+                return False
+            raise ValueError('The __main__ module (%s) '  # pragma: no cover
+                             'may not be importable' %
+                             sys.modules['__main__'].__file__)
+
+        assert wmp == spawn
+        return True
+
+    def _main_is_importable(self):  # pragma: untested
+        path = sys.modules['__main__'].__file__
+        if not path:
+            return False
+        if path.endswith('.pyc'):
+            path = path[:-1]
+        if not path.endswith('.py'):
+            return False
+        if path.endswith('__main__.py'):
+            # main modules are not directly importable.
+            return False
+
+        path = self.host.realpath(path)
+        for d in sys.path:
+            if path.startswith(self.host.realpath(d)):
+                return True
+        return False  # pragma: no cover
+
+    def _spawn(self, test_set):
+        # TODO: Handle picklable hooks, rather than requiring them to be None.
+        assert self.classifier is None
+        assert self.context is None
+        assert self.setup_fn is None
+        assert self.teardown_fn is None
+        assert test_set is None
+        h = self.host
+
+        if self.args.write_trace_to:  # pragma: untested
+            should_delete_trace = False
+        else:
+            should_delete_trace = True
+            fp = h.mktempfile(delete=False)
+            fp.close()
+            self.args.write_trace_to = fp.name
+
+        if self.args.write_full_results_to:  # pragma: untested
+            should_delete_results = False
+        else:
+            should_delete_results = True
+            fp = h.mktempfile(delete=False)
+            fp.close()
+            self.args.write_full_results_to = fp.name
+
+        argv = ArgumentParser(h).argv_from_args(self.args)
+        ret = h.call_inline([h.python_interpreter, path_to_file] + argv)
+
+        trace = self._read_and_delete(self.args.write_trace_to,
+                                      should_delete_trace)
+        full_results = self._read_and_delete(self.args.write_full_results_to,
+                                             should_delete_results)
+        return ret, full_results, trace
+
+    def _set_up_runner(self):
+        h = self.host
+        args = self.args
+
+        self.stats = Stats(args.status_format, h.time, args.jobs)
+        self.printer = Printer(
+            self.print_, args.overwrite, args.terminal_width)
+
+        self.top_level_dir = args.top_level_dir
+        if not self.top_level_dir:
+            if args.tests and h.isdir(args.tests[0]):
+                # TODO: figure out what to do if multiple files are
+                # specified and they don't all have the same correct
+                # top level dir.
+                if h.exists(h.dirname(args.tests[0]), '__init__.py'):
+                    top_dir = h.dirname(args.tests[0])
+                else:
+                    top_dir = args.tests[0]
+            else:
+                top_dir = h.getcwd()
+            while h.exists(top_dir, '__init__.py'):
+                top_dir = h.dirname(top_dir)
+            self.top_level_dir = h.realpath(top_dir)
+
+        h.add_to_path(self.top_level_dir)
+
+        for path in args.path:
+            h.add_to_path(path)
+
+        if args.coverage:  # pragma: no cover
+            try:
+                import coverage
+            except ImportError:
+                h.print_("Error: coverage is not installed")
+                return 1
+            source = self.args.coverage_source
+            if not source:
+                source = [self.top_level_dir] + self.args.path
+            self.coverage_source = source
+            self.cov = coverage.coverage(source=self.coverage_source,
+                                         data_suffix=True)
+            self.cov.erase()
+        return 0
+
+    def find_tests(self, args):
+        test_set = TestSet()
+
+        orig_skip = unittest.skip
+        orig_skip_if = unittest.skipIf
+        if args.all:
+            unittest.skip = lambda reason: lambda x: x
+            unittest.skipIf = lambda condition, reason: lambda x: x
+
+        try:
+            names = self._name_list_from_args(args)
+            classifier = self.classifier or _default_classifier(args)
+
+            for name in names:
+                try:
+                    self._add_tests_to_set(test_set, args.suffixes,
+                                           self.top_level_dir, classifier,
+                                           name)
+                except (AttributeError, ImportError, SyntaxError) as e:
+                    self.print_('Failed to load "%s": %s' % (name, e))
+                    return 1, None
+                except _AddTestsError as e:
+                    self.print_(str(e))
+                    return 1, None
+
+            # TODO: Add support for discovering setupProcess/teardownProcess?
+
+            test_set.parallel_tests = _sort_inputs(test_set.parallel_tests)
+            test_set.isolated_tests = _sort_inputs(test_set.isolated_tests)
+            test_set.tests_to_skip = _sort_inputs(test_set.tests_to_skip)
+            return 0, test_set
+        finally:
+            unittest.skip = orig_skip
+            unittest.skipIf = orig_skip_if
+
+    def _name_list_from_args(self, args):
+        if args.tests:
+            names = args.tests
+        elif args.file_list:
+            if args.file_list == '-':
+                s = self.host.stdin.read()
+            else:
+                s = self.host.read_text_file(args.file_list)
+            names = [line.strip() for line in s.splitlines()]
+        else:
+            names = [self.top_level_dir]
+        return names
+
+    def _add_tests_to_set(self, test_set, suffixes, top_level_dir, classifier,
+                          name):
+        h = self.host
+        loader = self.loader
+        add_tests = _test_adder(test_set, classifier)
+
+        if h.isfile(name):
+            rpath = h.relpath(name, top_level_dir)
+            if rpath.endswith('.py'):
+                rpath = rpath[:-3]
+            module = rpath.replace(h.sep, '.')
+            add_tests(loader.loadTestsFromName(module))
+        elif h.isdir(name):
+            for suffix in suffixes:
+                add_tests(loader.discover(name, suffix, top_level_dir))
+        else:
+            possible_dir = name.replace('.', h.sep)
+            if h.isdir(top_level_dir, possible_dir):
+                for suffix in suffixes:
+                    path = h.join(top_level_dir, possible_dir)
+                    suite = loader.discover(path, suffix, top_level_dir)
+                    add_tests(suite)
+            else:
+                add_tests(loader.loadTestsFromName(name))
+
+    def _run_tests(self, result_set, test_set):
+        h = self.host
+        if not test_set.parallel_tests and not test_set.isolated_tests:
+            self.print_('No tests to run.')
+            return 1, None
+
+        all_tests = [ti.name for ti in
+                     _sort_inputs(test_set.parallel_tests +
+                                  test_set.isolated_tests +
+                                  test_set.tests_to_skip)]
+
+        if self.args.list_only:
+            self.print_('\n'.join(all_tests))
+            return 0, None
+
+        self._run_one_set(self.stats, result_set, test_set)
+
+        failed_tests = sorted(json_results.failed_test_names(result_set))
+        retry_limit = self.args.retry_limit
+
+        while retry_limit and failed_tests:
+            if retry_limit == self.args.retry_limit:
+                self.flush()
+                self.args.overwrite = False
+                self.printer.should_overwrite = False
+                self.args.verbose = min(self.args.verbose, 1)
+
+            self.print_('')
+            self.print_('Retrying failed tests (attempt #%d of %d)...' %
+                        (self.args.retry_limit - retry_limit + 1,
+                         self.args.retry_limit))
+            self.print_('')
+
+            stats = Stats(self.args.status_format, h.time, 1)
+            stats.total = len(failed_tests)
+            tests_to_retry = TestSet(isolated_tests=list(failed_tests))
+            retry_set = ResultSet()
+            self._run_one_set(stats, retry_set, tests_to_retry)
+            result_set.results.extend(retry_set.results)
+            failed_tests = json_results.failed_test_names(retry_set)
+            retry_limit -= 1
+
+        if retry_limit != self.args.retry_limit:
+            self.print_('')
+
+        full_results = json_results.make_full_results(self.args.metadata,
+                                                      int(h.time()),
+                                                      all_tests, result_set)
+
+        return (json_results.exit_code_from_full_results(full_results),
+                full_results)
+
+    def _run_one_set(self, stats, result_set, test_set):
+        stats.total = (len(test_set.parallel_tests) +
+                       len(test_set.isolated_tests) +
+                       len(test_set.tests_to_skip))
+        self._skip_tests(stats, result_set, test_set.tests_to_skip)
+        self._run_list(stats, result_set,
+                       test_set.parallel_tests, self.args.jobs)
+        self._run_list(stats, result_set,
+                       test_set.isolated_tests, 1)
+
+    def _skip_tests(self, stats, result_set, tests_to_skip):
+        for test_input in tests_to_skip:
+            last = self.host.time()
+            stats.started += 1
+            self._print_test_started(stats, test_input)
+            now = self.host.time()
+            result = Result(test_input.name, actual=ResultType.Skip,
+                            started=last, took=(now - last), worker=0,
+                            expected=[ResultType.Skip],
+                            out=test_input.msg)
+            result_set.add(result)
+            stats.finished += 1
+            self._print_test_finished(stats, result)
+
+    def _run_list(self, stats, result_set, test_inputs, jobs):
+        h = self.host
+        running_jobs = set()
+
+        jobs = min(len(test_inputs), jobs)
+        if not jobs:
+            return
+
+        child = _Child(self)
+        pool = make_pool(h, jobs, _run_one_test, child,
+                         _setup_process, _teardown_process)
+        try:
+            while test_inputs or running_jobs:
+                while test_inputs and (len(running_jobs) < self.args.jobs):
+                    test_input = test_inputs.pop(0)
+                    stats.started += 1
+                    pool.send(test_input)
+                    running_jobs.add(test_input.name)
+                    self._print_test_started(stats, test_input)
+
+                result = pool.get()
+                running_jobs.remove(result.name)
+                result_set.add(result)
+                stats.finished += 1
+                self._print_test_finished(stats, result)
+            pool.close()
+        finally:
+            self.final_responses.extend(pool.join())
+
+    def _print_test_started(self, stats, test_input):
+        if not self.args.quiet and self.args.overwrite:
+            self.update(stats.format() + test_input.name,
+                        elide=(not self.args.verbose))
+
+    def _print_test_finished(self, stats, result):
+        stats.add_time()
+
+        assert result.actual in [ResultType.Failure, ResultType.Skip,
+                                 ResultType.Pass]
+        if result.actual == ResultType.Failure:
+            result_str = ' failed'
+        elif result.actual == ResultType.Skip:
+            result_str = ' was skipped'
+        elif result.actual == ResultType.Pass:
+            result_str = ' passed'
+
+        if result.unexpected:
+            result_str += ' unexpectedly'
+        if self.args.timing:
+            timing_str = ' %.4fs' % result.took
+        else:
+            timing_str = ''
+        suffix = '%s%s' % (result_str, timing_str)
+        out = result.out
+        err = result.err
+        if result.code:
+            if out or err:
+                suffix += ':\n'
+            self.update(stats.format() + result.name + suffix, elide=False)
+            for l in out.splitlines():
+                self.print_('  %s' % l)
+            for l in err.splitlines():
+                self.print_('  %s' % l)
+        elif not self.args.quiet:
+            if self.args.verbose > 1 and (out or err):
+                suffix += ':\n'
+            self.update(stats.format() + result.name + suffix,
+                        elide=(not self.args.verbose))
+            if self.args.verbose > 1:
+                for l in out.splitlines():
+                    self.print_('  %s' % l)
+                for l in err.splitlines():
+                    self.print_('  %s' % l)
+            if self.args.verbose:
+                self.flush()
+
+    def update(self, msg, elide):
+        self.printer.update(msg, elide)
+
+    def flush(self):
+        self.printer.flush()
+
+    def _summarize(self, full_results):
+        num_tests = self.stats.finished
+        num_failures = json_results.num_failures(full_results)
+
+        if self.args.quiet and num_failures == 0:
+            return
+
+        if self.args.timing:
+            timing_clause = ' in %.1fs' % (self.host.time() -
+                                           self.stats.started_time)
+        else:
+            timing_clause = ''
+        self.update('%d test%s run%s, %d failure%s.' %
+                    (num_tests,
+                     '' if num_tests == 1 else 's',
+                     timing_clause,
+                     num_failures,
+                     '' if num_failures == 1 else 's'), elide=False)
+        self.print_()
+
+    def _read_and_delete(self, path, delete):
+        h = self.host
+        obj = None
+        if h.exists(path):
+            contents = h.read_text_file(path)
+            if contents:
+                obj = json.loads(contents)
+            if delete:
+                h.remove(path)
+        return obj
+
+    def _write(self, path, obj):
+        if path:
+            self.host.write_text_file(path, json.dumps(obj, indent=2) + '\n')
+
+    def _upload(self, full_results):
+        h = self.host
+        if not self.args.test_results_server:
+            return 0
+
+        url, content_type, data = json_results.make_upload_request(
+            self.args.test_results_server, self.args.builder_name,
+            self.args.master_name, self.args.test_type,
+            full_results)
+
+        try:
+            h.fetch(url, data, {'Content-Type': content_type})
+            return 0
+        except Exception as e:
+            h.print_('Uploading the JSON results raised "%s"' % str(e))
+            return 1
+
+    def report_coverage(self):
+        if self.args.coverage:  # pragma: no cover
+            self.host.print_()
+            import coverage
+            cov = coverage.coverage(data_suffix=True)
+            cov.combine()
+            cov.report(show_missing=self.args.coverage_show_missing,
+                       omit=self.args.coverage_omit)
+            if self.args.coverage_annotate:
+                cov.annotate(omit=self.args.coverage_omit)
+
+    def _add_trace_event(self, trace, name, start, end):
+        event = {
+            'name': name,
+            'ts': int((start - self.stats.started_time) * 1000000),
+            'dur': int((end - start) * 1000000),
+            'ph': 'X',
+            'pid': self.host.getpid(),
+            'tid': 0,
+        }
+        trace['traceEvents'].append(event)
+
+    def _trace_from_results(self, result_set):
+        trace = OrderedDict()
+        trace['traceEvents'] = []
+        trace['otherData'] = {}
+        for m in self.args.metadata:
+            k, v = m.split('=')
+            trace['otherData'][k] = v
+
+        for result in result_set.results:
+            started = int((result.started - self.stats.started_time) * 1000000)
+            took = int(result.took * 1000000)
+            event = OrderedDict()
+            event['name'] = result.name
+            event['dur'] = took
+            event['ts'] = started
+            event['ph'] = 'X'  # "Complete" events
+            event['pid'] = result.pid
+            event['tid'] = result.worker
+
+            args = OrderedDict()
+            args['expected'] = sorted(str(r) for r in result.expected)
+            args['actual'] = str(result.actual)
+            args['out'] = result.out
+            args['err'] = result.err
+            args['code'] = result.code
+            args['unexpected'] = result.unexpected
+            args['flaky'] = result.flaky
+            event['args'] = args
+
+            trace['traceEvents'].append(event)
+        return trace
+
+
+def _matches(name, globs):
+    return any(fnmatch.fnmatch(name, glob) for glob in globs)
+
+
+def _default_classifier(args):
+    def default_classifier(test_set, test):
+        name = test.id()
+        if not args.all and _matches(name, args.skip):
+            test_set.tests_to_skip.append(TestInput(name,
+                                                    'skipped by request'))
+        elif _matches(name, args.isolate):
+            test_set.isolated_tests.append(TestInput(name))
+        else:
+            test_set.parallel_tests.append(TestInput(name))
+    return default_classifier
+
+
+def _test_adder(test_set, classifier):
+    def add_tests(obj):
+        if isinstance(obj, unittest.suite.TestSuite):
+            for el in obj:
+                add_tests(el)
+        elif (obj.id().startswith('unittest.loader.LoadTestsFailure') or
+              obj.id().startswith('unittest.loader.ModuleImportFailure')):
+            # Access to protected member pylint: disable=W0212
+            module_name = obj._testMethodName
+            try:
+                method = getattr(obj, obj._testMethodName)
+                method()
+            except Exception as e:
+                if 'LoadTests' in obj.id():
+                    raise _AddTestsError('%s.load_tests() failed: %s'
+                                         % (module_name, str(e)))
+                else:
+                    raise _AddTestsError(str(e))
+        else:
+            assert isinstance(obj, unittest.TestCase)
+            classifier(test_set, obj)
+    return add_tests
+
+
+class _Child(object):
+
+    def __init__(self, parent):
+        self.host = None
+        self.worker_num = None
+        self.all = parent.args.all
+        self.debugger = parent.args.debugger
+        self.coverage = parent.args.coverage and parent.args.jobs > 1
+        self.coverage_source = parent.coverage_source
+        self.dry_run = parent.args.dry_run
+        self.loader = parent.loader
+        self.passthrough = parent.args.passthrough
+        self.context = parent.context
+        self.setup_fn = parent.setup_fn
+        self.teardown_fn = parent.teardown_fn
+        self.context_after_setup = None
+        self.top_level_dir = parent.top_level_dir
+        self.loaded_suites = {}
+        self.cov = None
+
+
+def _setup_process(host, worker_num, child):
+    child.host = host
+    child.worker_num = worker_num
+
+    if child.coverage:  # pragma: no cover
+        import coverage
+        child.cov = coverage.coverage(source=child.coverage_source,
+                                      data_suffix=True)
+        child.cov._warn_no_data = False
+        child.cov.start()
+
+    if child.setup_fn:
+        child.context_after_setup = child.setup_fn(child, child.context)
+    else:
+        child.context_after_setup = child.context
+    return child
+
+
+def _teardown_process(child):
+    res = None
+    e = None
+    if child.teardown_fn:
+        try:
+          res = child.teardown_fn(child, child.context_after_setup)
+        except Exception as e:
+          pass
+
+    if child.cov:  # pragma: no cover
+        child.cov.stop()
+        child.cov.save()
+
+    return (child.worker_num, res, e)
+
+
+def _run_one_test(child, test_input):
+    h = child.host
+    pid = h.getpid()
+    test_name = test_input.name
+
+    start = h.time()
+
+    # It is important to capture the output before loading the test
+    # to ensure that
+    # 1) the loader doesn't logs something we don't captured
+    # 2) neither the loader nor the test case grab a reference to the
+    #    uncaptured stdout or stderr that later is used when the test is run.
+    # This comes up when using the FakeTestLoader and testing typ itself,
+    # but could come up when testing non-typ code as well.
+    h.capture_output(divert=not child.passthrough)
+
+    tb_str = ''
+    try:
+        orig_skip = unittest.skip
+        orig_skip_if = unittest.skipIf
+        if child.all:
+            unittest.skip = lambda reason: lambda x: x
+            unittest.skipIf = lambda condition, reason: lambda x: x
+
+        try:
+            suite = child.loader.loadTestsFromName(test_name)
+        except Exception as e:
+            try:
+                suite = _load_via_load_tests(child, test_name)
+            except Exception as e:  # pragma: untested
+                suite = []
+                tb_str = traceback.format_exc(e)
+    finally:
+        unittest.skip = orig_skip
+        unittest.skipIf = orig_skip_if
+
+    tests = list(suite)
+    if len(tests) != 1:
+        err = 'Failed to load %s'
+        if tb_str:  # pragma: untested
+            err += ' (traceback follows):\n  %s' % (
+                    '  \n'.join(tb.splitlines()))
+
+        h.restore_output()
+        return Result(test_name, ResultType.Failure, start, 0,
+                      child.worker_num, unexpected=True, code=1,
+                      err=err, pid=pid)
+
+    test_case = tests[0]
+    if isinstance(test_case, TypTestCase):
+        test_case.child = child
+        test_case.context = child.context_after_setup
+
+    test_result = unittest.TestResult()
+    out = ''
+    err = ''
+    try:
+        if child.dry_run:
+            pass
+        elif child.debugger:  # pragma: no cover
+            _run_under_debugger(h, test_case, suite, test_result)
+        else:
+            suite.run(test_result)
+    finally:
+        out, err = h.restore_output()
+
+    took = h.time() - start
+    return _result_from_test_result(test_result, test_name, start, took, out,
+                                    err, child.worker_num, pid)
+
+
+def _run_under_debugger(host, test_case, suite,
+                        test_result):  # pragma: no cover
+    # Access to protected member pylint: disable=W0212
+    test_func = getattr(test_case, test_case._testMethodName)
+    fname = inspect.getsourcefile(test_func)
+    lineno = inspect.getsourcelines(test_func)[1] + 1
+    dbg = pdb.Pdb(stdout=host.stdout.stream)
+    dbg.set_break(fname, lineno)
+    dbg.runcall(suite.run, test_result)
+
+
+def _result_from_test_result(test_result, test_name, start, took, out, err,
+                             worker_num, pid):
+    flaky = False
+    if test_result.failures:
+        expected = [ResultType.Pass]
+        actual = ResultType.Failure
+        code = 1
+        unexpected = True
+        err = err + test_result.failures[0][1]
+    elif test_result.errors:
+        expected = [ResultType.Pass]
+        actual = ResultType.Failure
+        code = 1
+        unexpected = True
+        err = err + test_result.errors[0][1]
+    elif test_result.skipped:
+        expected = [ResultType.Skip]
+        actual = ResultType.Skip
+        err = err + test_result.skipped[0][1]
+        code = 0
+        unexpected = False
+    elif test_result.expectedFailures:
+        expected = [ResultType.Failure]
+        actual = ResultType.Failure
+        code = 1
+        err = err + test_result.expectedFailures[0][1]
+        unexpected = False
+    elif test_result.unexpectedSuccesses:
+        expected = [ResultType.Failure]
+        actual = ResultType.Pass
+        code = 0
+        unexpected = True
+    else:
+        expected = [ResultType.Pass]
+        actual = ResultType.Pass
+        code = 0
+        unexpected = False
+
+    return Result(test_name, actual, start, took, worker_num,
+                  expected, unexpected, flaky, code, out, err, pid)
+
+
+def _load_via_load_tests(child, test_name):
+    # If we couldn't import a test directly, the test may be only loadable
+    # via unittest's load_tests protocol. See if we can find a load_tests
+    # entry point that will work for this test.
+    loader = child.loader
+    comps = test_name.split('.')
+    new_suite = unittest.TestSuite()
+
+    while comps:
+        name = '.'.join(comps)
+        module = None
+        suite = None
+        if name not in child.loaded_suites:
+            try:
+                module = importlib.import_module(name)
+            except ImportError:
+                pass
+            if module:
+                suite = loader.loadTestsFromModule(module)
+            child.loaded_suites[name] = suite
+        suite = child.loaded_suites[name]
+        if suite:
+            for test_case in suite:
+                assert isinstance(test_case, unittest.TestCase)
+                if test_case.id() == test_name:
+                    new_suite.addTest(test_case)
+                    break
+        comps.pop()
+    return new_suite
+
+
+def _sort_inputs(inps):
+    return sorted(inps, key=lambda inp: inp.name)
+
+
+if __name__ == '__main__':  # pragma: no cover
+    sys.modules['__main__'].__file__ = path_to_file
+    sys.exit(main(win_multiprocessing=WinMultiprocessing.importable))
diff --git a/third_party/tvcm/third_party/typ/typ/stats.py b/third_party/tvcm/third_party/typ/typ/stats.py
new file mode 100644
index 0000000..0cd408d
--- /dev/null
+++ b/third_party/tvcm/third_party/typ/typ/stats.py
@@ -0,0 +1,83 @@
+# Copyright 2014 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+class Stats(object):
+
+    def __init__(self, status_format, time_fn, size):
+        self.fmt = status_format
+        self.finished = 0
+        self.started = 0
+        self.total = 0
+        self.started_time = time_fn()
+        self._times = []
+        self._size = size
+        self._time = time_fn
+        self._times.append(self.started_time)
+
+    def add_time(self):
+        if len(self._times) > self._size:
+            self._times.pop(0)
+        self._times.append(self._time())
+
+    def format(self):
+        # Too many statements pylint: disable=R0915
+        out = ''
+        p = 0
+        end = len(self.fmt)
+        while p < end:
+            c = self.fmt[p]
+            if c == '%' and p < end - 1:
+                cn = self.fmt[p + 1]
+                if cn == 'c':
+                    elapsed = self._times[-1] - self._times[0]
+                    if elapsed > 0:
+                        out += '%5.1f' % ((len(self._times) - 1) / elapsed)
+                    else:
+                        out += '-'
+                elif cn == 'e':
+                    now = self._time()
+                    assert now >= self.started_time
+                    out += '%-5.3f' % (now - self.started_time)
+                elif cn == 'f':
+                    out += str(self.finished)
+                elif cn == 'o':
+                    now = self._time()
+                    if now > self.started_time:
+                        out += '%5.1f' % (self.finished * 1.0 /
+                                          (now - self.started_time))
+                    else:
+                        out += '-'
+                elif cn == 'p':
+                    if self.total:
+                        out += '%5.1f' % (self.started * 100.0 / self.total)
+                    else:
+                        out += '-'
+                elif cn == 'r':
+                    out += str(self.started - self.finished)
+                elif cn == 's':
+                    out += str(self.started)
+                elif cn == 't':
+                    out += str(self.total)
+                elif cn == 'u':
+                    out += str(self.total - self.finished)
+                elif cn == '%':
+                    out += '%'
+                else:
+                    out += c + cn
+                p += 2
+            else:
+                out += c
+                p += 1
+        return out
diff --git a/third_party/tvcm/third_party/typ/typ/test_case.py b/third_party/tvcm/third_party/typ/typ/test_case.py
new file mode 100644
index 0000000..5be83ae
--- /dev/null
+++ b/third_party/tvcm/third_party/typ/typ/test_case.py
@@ -0,0 +1,127 @@
+# Copyright 2014 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import fnmatch
+import shlex
+import unittest
+
+
+def convert_newlines(msg):
+    """A routine that mimics Python's universal_newlines conversion."""
+    return msg.replace('\r\n', '\n').replace('\r', '\n')
+
+
+class TestCase(unittest.TestCase):
+    child = None
+    context = None
+    maxDiff = 80 * 66
+
+
+class MainTestCase(TestCase):
+    prog = None
+    files_to_ignore = []
+
+    def _write_files(self, host, files):
+        for path, contents in list(files.items()):
+            dirname = host.dirname(path)
+            if dirname:
+                host.maybe_mkdir(dirname)
+            host.write_text_file(path, contents)
+
+    def _read_files(self, host, tmpdir):
+        out_files = {}
+        for f in host.files_under(tmpdir):
+            if any(fnmatch.fnmatch(f, pat) for pat in self.files_to_ignore):
+                continue
+            key = f.replace(host.sep, '/')
+            out_files[key] = host.read_text_file(tmpdir, f)
+        return out_files
+
+    def assert_files(self, expected_files, actual_files, files_to_ignore=None):
+        files_to_ignore = files_to_ignore or []
+        for k, v in expected_files.items():
+            self.assertMultiLineEqual(expected_files[k], v)
+        interesting_files = set(actual_files.keys()).difference(
+            files_to_ignore)
+        self.assertEqual(interesting_files, set(expected_files.keys()))
+
+    def make_host(self):
+        # If we are ever called by unittest directly, and not through typ,
+        # this will probably fail.
+        assert(self.child)
+        return self.child.host
+
+    def call(self, host, argv, stdin, env):
+        return host.call(argv, stdin=stdin, env=env)
+
+    def check(self, cmd=None, stdin=None, env=None, aenv=None, files=None,
+              prog=None, cwd=None, host=None,
+              ret=None, out=None, rout=None, err=None, rerr=None,
+              exp_files=None,
+              files_to_ignore=None, universal_newlines=True):
+        # Too many arguments pylint: disable=R0913
+        prog = prog or self.prog or []
+        host = host or self.make_host()
+        argv = shlex.split(cmd) if isinstance(cmd, str) else cmd or []
+
+        tmpdir = None
+        orig_wd = host.getcwd()
+        try:
+            tmpdir = host.mkdtemp()
+            host.chdir(tmpdir)
+            if files:
+                self._write_files(host, files)
+            if cwd:
+                host.chdir(cwd)
+            if aenv:
+                env = host.env.copy()
+                env.update(aenv)
+
+            if self.child.debugger:  # pragma: no cover
+                host.print_('')
+                host.print_('cd %s' % tmpdir, stream=host.stdout.stream)
+                host.print_(' '.join(prog + argv), stream=host.stdout.stream)
+                host.print_('')
+                import pdb
+                dbg = pdb.Pdb(stdout=host.stdout.stream)
+                dbg.set_trace()
+
+            result = self.call(host, prog + argv, stdin=stdin, env=env)
+
+            actual_ret, actual_out, actual_err = result
+            actual_files = self._read_files(host, tmpdir)
+        finally:
+            host.chdir(orig_wd)
+            if tmpdir:
+                host.rmtree(tmpdir)
+
+        if universal_newlines:
+            actual_out = convert_newlines(actual_out)
+        if universal_newlines:
+            actual_err = convert_newlines(actual_err)
+
+        if ret is not None:
+            self.assertEqual(ret, actual_ret)
+        if out is not None:
+            self.assertMultiLineEqual(out, actual_out)
+        if rout is not None:
+            self.assertRegexpMatches(actual_out, rout)
+        if err is not None:
+            self.assertMultiLineEqual(err, actual_err)
+        if rerr is not None:
+            self.assertRegexpMatches(actual_err, rerr)
+        if exp_files:
+            self.assert_files(exp_files, actual_files, files_to_ignore)
+
+        return actual_ret, actual_out, actual_err, actual_files
diff --git a/third_party/tvcm/third_party/typ/typ/tests/__init__.py b/third_party/tvcm/third_party/typ/typ/tests/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/third_party/tvcm/third_party/typ/typ/tests/__init__.py
diff --git a/third_party/tvcm/third_party/typ/typ/tests/arg_parser_test.py b/third_party/tvcm/third_party/typ/typ/tests/arg_parser_test.py
new file mode 100644
index 0000000..e603ecd
--- /dev/null
+++ b/third_party/tvcm/third_party/typ/typ/tests/arg_parser_test.py
@@ -0,0 +1,45 @@
+# Copyright 2014 Dirk Pranke. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import optparse
+import unittest
+
+from typ import ArgumentParser
+
+
+class ArgumentParserTest(unittest.TestCase):
+
+    def test_optparse_options(self):
+        parser = optparse.OptionParser()
+        ArgumentParser.add_option_group(parser, 'foo',
+                                        discovery=True,
+                                        running=True,
+                                        reporting=True,
+                                        skip='[-d]')
+        options, _ = parser.parse_args(['-j', '1'])
+        self.assertEqual(options.jobs, 1)
+
+    def test_argv_from_args(self):
+
+        def check(argv, expected=None):
+            parser = ArgumentParser()
+            args = parser.parse_args(argv)
+            actual_argv = parser.argv_from_args(args)
+            expected = expected or argv
+            self.assertEqual(expected, actual_argv)
+
+        check(['--version'])
+        check(['--coverage', '--coverage-omit', 'foo'])
+        check(['--jobs', '3'])
+        check(['-vv'], ['--verbose', '--verbose'])
diff --git a/third_party/tvcm/third_party/typ/typ/tests/host_test.py b/third_party/tvcm/third_party/typ/typ/tests/host_test.py
new file mode 100644
index 0000000..a06085a
--- /dev/null
+++ b/third_party/tvcm/third_party/typ/typ/tests/host_test.py
@@ -0,0 +1,216 @@
+# Copyright 2014 Dirk Pranke. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import logging
+import pickle
+import sys
+import unittest
+
+from typ.host import Host
+
+
+class TestHost(unittest.TestCase):
+
+    def host(self):
+        return Host()
+
+    def test_capture_output(self):
+        try:
+            logging.basicConfig()
+            h = self.host()
+            h.capture_output()
+            h.print_('on stdout')
+            h.print_('on stderr', stream=h.stderr)
+            logging.critical('critical log failure')
+            out, err = h.restore_output()
+            self.assertEqual(out, 'on stdout\n')
+            self.assertEqual(err, 'on stderr\ncritical log failure\n')
+        finally:
+            h.logger.handlers = []
+
+        # TODO: Add tests for divert=False or eliminate the flag?
+
+    def test_abspath_and_realpath(self):
+        h = self.host()
+        self.assertNotEqual(h.abspath(h.getcwd()), None)
+        self.assertNotEqual(h.realpath(h.getcwd()), None)
+
+    def test_chdir(self):
+        h = self.host()
+        orig_cwd = h.getcwd()
+        h.chdir('.')
+        self.assertEqual(orig_cwd, h.getcwd())
+        h.chdir('..')
+        self.assertNotEqual(orig_cwd, h.getcwd())
+
+    def test_files(self):
+        h = self.host()
+        orig_cwd = h.getcwd()
+        try:
+            now = h.time()
+
+            # TODO: MacOS does goofy things with temp dirs by default, so
+            # we can't compare for equality. Figure out how to get the normpath
+            # from mkdtemp
+            dirpath = h.mkdtemp(suffix='host_test')
+            self.assertTrue(h.isdir(dirpath))
+            h.chdir(dirpath)
+            self.assertIn(dirpath, h.getcwd())
+
+            h.maybe_mkdir('bar')
+            self.assertTrue(h.exists(dirpath, 'bar'))
+            self.assertTrue(h.isdir(dirpath, 'bar'))
+            self.assertFalse(h.isfile(dirpath, 'bar'))
+
+            bar_path = h.join(dirpath, 'bar')
+            self.assertEqual(dirpath, h.dirname(bar_path))
+
+            h.write_text_file('bar/foo.txt', 'foo')
+            self.assertTrue(h.exists('bar', 'foo.txt'))
+            self.assertEqual(h.read_text_file('bar/foo.txt'), 'foo')
+            self.assertTrue(h.exists(dirpath, 'bar', 'foo.txt'))
+            self.assertTrue(h.isfile(dirpath, 'bar', 'foo.txt'))
+            self.assertFalse(h.isdir(dirpath, 'bar', 'foo.txt'))
+
+            h.write_binary_file('binfile', b'bin contents')
+            self.assertEqual(h.read_binary_file('binfile'),
+                             b'bin contents')
+
+            self.assertEqual(sorted(h.files_under(dirpath)),
+                             ['bar' + h.sep + 'foo.txt', 'binfile'])
+
+            mtime = h.mtime(dirpath, 'bar', 'foo.txt')
+            self.assertGreaterEqual(now, mtime - 0.1)
+            h.remove(dirpath, 'bar', 'foo.txt')
+            self.assertFalse(h.exists(dirpath, 'bar', 'foo.txt'))
+            self.assertFalse(h.isfile(dirpath, 'bar', 'foo.txt'))
+
+            h.chdir(orig_cwd)
+            h.rmtree(dirpath)
+            self.assertFalse(h.exists(dirpath))
+            self.assertFalse(h.isdir(dirpath))
+        finally:
+            h.chdir(orig_cwd)
+
+    def test_terminal_width(self):
+        h = self.host()
+        self.assertGreaterEqual(h.terminal_width(), 0)
+
+    def test_for_mp_and_pickling(self):
+        h = self.host()
+        mp_host = h.for_mp()
+        s = pickle.dumps(mp_host)
+        pickle.loads(s)
+
+    def test_cpu_count(self):
+        h = self.host()
+        self.assertGreaterEqual(h.cpu_count(), 1)
+
+    def test_getenv(self):
+        h = self.host()
+        self.assertNotEqual(h.getenv('PATH', ''), None)
+
+    def test_getpid(self):
+        h = self.host()
+        self.assertNotEqual(h.getpid(), 0)
+
+    def test_basename(self):
+        h = self.host()
+        self.assertEqual(h.basename('foo.txt'), 'foo.txt')
+        self.assertEqual(h.basename('foo/bar.txt'), 'bar.txt')
+
+    def test_mktempfile(self, delete=False):
+        h = self.host()
+        f= h.mktempfile()
+        f.close()
+        self.assertNotEqual(f.name, None)
+
+    def test_splitext(self):
+        h = self.host()
+        self.assertEqual(h.splitext('foo'), ('foo', ''))
+        self.assertEqual(h.splitext('foo.txt'), ('foo', '.txt'))
+        self.assertEqual(h.splitext('foo/bar'), ('foo/bar', ''))
+        self.assertEqual(h.splitext('foo/bar.txt'), ('foo/bar', '.txt'))
+
+    def test_print(self):
+        h = self.host()
+
+        class FakeStream(object):
+
+            def __init__(self):
+                self.contents = None
+                self.flush_called = False
+
+            def write(self, m):
+                self.contents = m
+
+            def flush(self):
+                self.flush_called = True
+
+        s = FakeStream()
+        h.print_('hello', stream=s)
+        self.assertEqual(s.contents, 'hello\n')
+        self.assertTrue(s.flush_called)
+
+        s = FakeStream()
+        h.stdout = s
+        h.print_('hello')
+        self.assertEqual(s.contents, 'hello\n')
+
+        s = FakeStream()
+        h.stdout = s
+        h.print_('hello', '')
+        self.assertEqual(s.contents, 'hello')
+
+    def test_call(self):
+        h = self.host()
+        ret, out, err = h.call(
+            [h.python_interpreter,
+             '-c', 'import sys; sys.stdout.write(sys.stdin.read())'],
+            stdin='foo', env={})
+        self.assertEqual(ret, 0)
+        self.assertEqual(out, 'foo')
+        self.assertEqual(err, '')
+
+        ret, out, err = h.call(
+            [h.python_interpreter,
+             '-c', 'import sys; sys.stderr.write("err\\n")'])
+        self.assertEqual(ret, 0)
+        self.assertEqual(out, '')
+        self.assertIn(err, ('err\n', 'err\r\n'))
+
+    def test_call_inline(self):
+        h = self.host()
+        h.stdout = None
+        h.stderr = None
+        ret = h.call_inline([h.python_interpreter,
+                             '-c', 'import sys; sys.exit(0)'])
+        self.assertEqual(ret, 0)
+
+    def test_add_to_path(self):
+        orig_sys_path = sys.path[:]
+        try:
+            h = self.host()
+            h.add_to_path(sys.path[-1])
+            self.assertEqual(sys.path, orig_sys_path)
+
+            dirpath = h.mkdtemp()
+            h.add_to_path(dirpath)
+            self.assertNotEqual(sys.path, orig_sys_path)
+        finally:
+            sys.path = orig_sys_path
+
+    def test_platform(self):
+        h = self.host()
+        self.assertNotEqual(h.platform, None)
diff --git a/third_party/tvcm/third_party/typ/typ/tests/json_results_test.py b/third_party/tvcm/third_party/typ/typ/tests/json_results_test.py
new file mode 100644
index 0000000..363ceab
--- /dev/null
+++ b/third_party/tvcm/third_party/typ/typ/tests/json_results_test.py
@@ -0,0 +1,107 @@
+# Copyright 2014 Dirk Pranke. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import unittest
+
+from typ import json_results
+
+
+class TestMakeUploadRequest(unittest.TestCase):
+    maxDiff = 4096
+
+    def test_basic_upload(self):
+        results = json_results.ResultSet()
+        full_results = json_results.make_full_results([], 0, [], results)
+        url, content_type, data = json_results.make_upload_request(
+            'localhost', 'fake_builder_name', 'fake_master', 'fake_test_type',
+            full_results)
+
+        self.assertEqual(
+            content_type,
+            'multipart/form-data; '
+            'boundary=-J-S-O-N-R-E-S-U-L-T-S---B-O-U-N-D-A-R-Y-')
+
+        self.assertEqual(url, 'http://localhost/testfile/upload')
+        self.assertMultiLineEqual(
+            data,
+            ('---J-S-O-N-R-E-S-U-L-T-S---B-O-U-N-D-A-R-Y-\r\n'
+             'Content-Disposition: form-data; name="builder"\r\n'
+             '\r\n'
+             'fake_builder_name\r\n'
+             '---J-S-O-N-R-E-S-U-L-T-S---B-O-U-N-D-A-R-Y-\r\n'
+             'Content-Disposition: form-data; name="master"\r\n'
+             '\r\n'
+             'fake_master\r\n'
+             '---J-S-O-N-R-E-S-U-L-T-S---B-O-U-N-D-A-R-Y-\r\n'
+             'Content-Disposition: form-data; name="testtype"\r\n'
+             '\r\n'
+             'fake_test_type\r\n'
+             '---J-S-O-N-R-E-S-U-L-T-S---B-O-U-N-D-A-R-Y-\r\n'
+             'Content-Disposition: form-data; name="file"; '
+             'filename="full_results.json"\r\n'
+             'Content-Type: application/json\r\n'
+             '\r\n'
+             '{"version": 3, "interrupted": false, "path_delimiter": ".", '
+             '"seconds_since_epoch": 0, '
+             '"num_failures_by_type": {"FAIL": 0, "PASS": 0, "SKIP": 0}, '
+             '"tests": {}}\r\n'
+             '---J-S-O-N-R-E-S-U-L-T-S---B-O-U-N-D-A-R-Y---\r\n'))
+
+
+class TestMakeFullResults(unittest.TestCase):
+    maxDiff = 2048
+
+    def test_basic(self):
+        test_names = ['foo_test.FooTest.test_fail',
+                      'foo_test.FooTest.test_pass',
+                      'foo_test.FooTest.test_skip']
+
+        result_set = json_results.ResultSet()
+        result_set.add(
+            json_results.Result('foo_test.FooTest.test_fail',
+                                json_results.ResultType.Failure, 0, 0, 0,
+                                unexpected=True))
+        result_set.add(json_results.Result('foo_test.FooTest.test_pass',
+                                           json_results.ResultType.Pass,
+                                           0, 0, 0))
+        result_set.add(json_results.Result('foo_test.FooTest.test_skip',
+                                           json_results.ResultType.Skip,
+                                           0, 0, 0, unexpected=False))
+
+        full_results = json_results.make_full_results(
+            ['foo=bar'], 0, test_names, result_set)
+        expected_full_results = {
+            'foo': 'bar',
+            'interrupted': False,
+            'num_failures_by_type': {
+                'FAIL': 1,
+                'PASS': 1,
+                'SKIP': 1},
+            'path_delimiter': '.',
+            'seconds_since_epoch': 0,
+            'tests': {
+                'foo_test': {
+                    'FooTest': {
+                        'test_fail': {
+                            'expected': 'PASS',
+                            'actual': 'FAIL',
+                            'is_unexpected': True},
+                        'test_pass': {
+                            'expected': 'PASS',
+                            'actual': 'PASS'},
+                        'test_skip': {
+                            'expected': 'SKIP',
+                            'actual': 'SKIP'}}}},
+            'version': 3}
+        self.assertEqual(full_results, expected_full_results)
diff --git a/third_party/tvcm/third_party/typ/typ/tests/main_test.py b/third_party/tvcm/third_party/typ/typ/tests/main_test.py
new file mode 100644
index 0000000..cc690d5
--- /dev/null
+++ b/third_party/tvcm/third_party/typ/typ/tests/main_test.py
@@ -0,0 +1,680 @@
+# Copyright 2014 Dirk Pranke. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import io
+import json
+import os
+import sys
+import textwrap
+
+
+from typ import main
+from typ import test_case
+from typ import Host
+from typ import VERSION
+from typ.fakes import test_result_server_fake
+
+
+is_python3 = bool(sys.version_info.major == 3)
+
+if is_python3:  # pragma: python3
+    # redefining built-in 'unicode' pylint: disable=W0622
+    unicode = str
+
+d = textwrap.dedent
+
+
+PASS_TEST_PY = """
+import unittest
+class PassingTest(unittest.TestCase):
+    def test_pass(self):
+        pass
+"""
+
+
+PASS_TEST_FILES = {'pass_test.py': PASS_TEST_PY}
+
+
+FAIL_TEST_PY = """
+import unittest
+class FailingTest(unittest.TestCase):
+    def test_fail(self):
+        self.fail()
+"""
+
+
+FAIL_TEST_FILES = {'fail_test.py': FAIL_TEST_PY}
+
+
+OUTPUT_TEST_PY = """
+import sys
+import unittest
+
+class PassTest(unittest.TestCase):
+  def test_out(self):
+    sys.stdout.write("hello on stdout\\n")
+    sys.stdout.flush()
+
+  def test_err(self):
+    sys.stderr.write("hello on stderr\\n")
+
+class FailTest(unittest.TestCase):
+ def test_out_err_fail(self):
+    sys.stdout.write("hello on stdout\\n")
+    sys.stdout.flush()
+    sys.stderr.write("hello on stderr\\n")
+    self.fail()
+"""
+
+
+OUTPUT_TEST_FILES = {'output_test.py': OUTPUT_TEST_PY}
+
+
+SF_TEST_PY = """
+import sys
+import unittest
+
+class SkipMethods(unittest.TestCase):
+    @unittest.skip('reason')
+    def test_reason(self):
+        self.fail()
+
+    @unittest.skipIf(True, 'reason')
+    def test_skip_if_true(self):
+        self.fail()
+
+    @unittest.skipIf(False, 'reason')
+    def test_skip_if_false(self):
+        self.fail()
+
+
+class SkipSetup(unittest.TestCase):
+    def setUp(self):
+        self.skipTest('setup failed')
+
+    def test_notrun(self):
+        self.fail()
+
+
+@unittest.skip('skip class')
+class SkipClass(unittest.TestCase):
+    def test_method(self):
+        self.fail()
+
+class SetupClass(unittest.TestCase):
+    @classmethod
+    def setUpClass(cls):
+        sys.stdout.write('in setupClass\\n')
+        sys.stdout.flush()
+        assert False, 'setupClass failed'
+
+    def test_method1(self):
+        pass
+
+    def test_method2(self):
+        pass
+
+class ExpectedFailures(unittest.TestCase):
+    @unittest.expectedFailure
+    def test_fail(self):
+        self.fail()
+
+    @unittest.expectedFailure
+    def test_pass(self):
+        pass
+"""
+
+
+SF_TEST_FILES = {'sf_test.py': SF_TEST_PY}
+
+
+LOAD_TEST_PY = """
+import unittest
+def load_tests(_, _2, _3):
+    class BaseTest(unittest.TestCase):
+        pass
+
+    def method_fail(self):
+        self.fail()
+
+    def method_pass(self):
+        pass
+
+    setattr(BaseTest, "test_fail", method_fail)
+    setattr(BaseTest, "test_pass", method_pass)
+    suite = unittest.TestSuite()
+    suite.addTest(BaseTest("test_fail"))
+    suite.addTest(BaseTest("test_pass"))
+    return suite
+"""
+
+
+LOAD_TEST_FILES = {'load_test.py': LOAD_TEST_PY}
+
+
+path_to_main = os.path.join(
+    os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
+    'runner.py')
+
+
+class TestCli(test_case.MainTestCase):
+    prog = [sys.executable, path_to_main]
+    files_to_ignore = ['*.pyc']
+
+    def test_bad_arg(self):
+        self.check(['--bad-arg'], ret=2, out='',
+                   rerr='.*: error: unrecognized arguments: --bad-arg\n')
+        self.check(['-help'], ret=2, out='',
+                   rerr=(".*: error: argument -h/--help: "
+                         "ignored explicit argument 'elp'\n"))
+
+    def test_bad_metadata(self):
+        self.check(['--metadata', 'foo'], ret=2, err='',
+                   out='Error: malformed --metadata "foo"\n')
+
+    def test_basic(self):
+        self.check([], files=PASS_TEST_FILES,
+                   ret=0,
+                   out=('[1/1] pass_test.PassingTest.test_pass passed\n'
+                        '1 test run, 0 failures.\n'), err='')
+
+    def test_coverage(self):
+        try:
+            import coverage  # pylint: disable=W0612
+            files = {
+                'pass_test.py': PASS_TEST_PY,
+                'fail_test.py': FAIL_TEST_PY,
+            }
+            self.check(['-c', 'pass_test'], files=files, ret=0, err='',
+                       out=d("""\
+                             [1/1] pass_test.PassingTest.test_pass passed
+                             1 test run, 0 failures.
+
+                             Name        Stmts   Miss  Cover
+                             -------------------------------
+                             fail_test       4      4     0%
+                             pass_test       4      0   100%
+                             -------------------------------
+                             TOTAL           8      4    50%
+                             """))
+        except ImportError:  # pragma: no cover
+            # We can never cover this line, since running coverage means
+            # that import will succeed.
+            self.check(['-c'], files=PASS_TEST_FILES, ret=1,
+                       out='Error: coverage is not installed\n', err='')
+
+    def test_debugger(self):
+        if sys.version_info.major == 3:  # pragma: python3
+            return
+        else:  # pragma: python2
+            _, out, _, _ = self.check(['-d'], stdin='quit()\n',
+                                      files=PASS_TEST_FILES, ret=0, err='')
+            self.assertIn('(Pdb) ', out)
+
+    def test_dryrun(self):
+        self.check(['-n'], files=PASS_TEST_FILES, ret=0, err='',
+                   out=d("""\
+                         [1/1] pass_test.PassingTest.test_pass passed
+                         1 test run, 0 failures.
+                         """))
+
+    def test_error(self):
+        files = {'err_test.py': d("""\
+                                  import unittest
+                                  class ErrTest(unittest.TestCase):
+                                      def test_err(self):
+                                          foo = bar
+                                  """)}
+        _, out, _, _ = self.check([''], files=files, ret=1, err='')
+        self.assertIn('[1/1] err_test.ErrTest.test_err failed unexpectedly',
+                      out)
+        self.assertIn('1 test run, 1 failure', out)
+
+    def test_fail(self):
+        _, out, _, _ = self.check([], files=FAIL_TEST_FILES, ret=1, err='')
+        self.assertIn('fail_test.FailingTest.test_fail failed unexpectedly',
+                      out)
+
+    def test_fail_then_pass(self):
+        files = {'fail_then_pass_test.py': d("""\
+            import unittest
+            count = 0
+            class FPTest(unittest.TestCase):
+                def test_count(self):
+                    global count
+                    count += 1
+                    if count == 1:
+                        self.fail()
+            """)}
+        _, out, _, files = self.check(['--retry-limit', '3',
+                                       '--write-full-results-to',
+                                       'full_results.json'],
+                                      files=files, ret=0, err='')
+        self.assertIn('Retrying failed tests (attempt #1 of 3)', out)
+        self.assertNotIn('Retrying failed tests (attempt #2 of 3)', out)
+        self.assertIn('1 test run, 0 failures.\n', out)
+        results = json.loads(files['full_results.json'])
+        self.assertEqual(results['tests'][
+            'fail_then_pass_test']['FPTest']['test_count']['actual'],
+            'FAIL PASS')
+
+    def test_failures_are_not_elided(self):
+        _, out, _, _ = self.check(['--terminal-width=20'],
+                                  files=FAIL_TEST_FILES, ret=1, err='')
+        self.assertIn('[1/1] fail_test.FailingTest.test_fail failed '
+                      'unexpectedly:\n', out)
+
+    def test_file_list(self):
+        files = PASS_TEST_FILES
+        self.check(['-f', '-'], files=files, stdin='pass_test\n', ret=0)
+        self.check(['-f', '-'], files=files, stdin='pass_test.PassingTest\n',
+                   ret=0)
+        self.check(['-f', '-'], files=files,
+                   stdin='pass_test.PassingTest.test_pass\n',
+                   ret=0)
+        files = {'pass_test.py': PASS_TEST_PY,
+                 'test_list.txt': 'pass_test.PassingTest.test_pass\n'}
+        self.check(['-f', 'test_list.txt'], files=files, ret=0)
+
+    def test_find(self):
+        files = PASS_TEST_FILES
+        self.check(['-l'], files=files, ret=0,
+                   out='pass_test.PassingTest.test_pass\n')
+        self.check(['-l', 'pass_test'], files=files, ret=0, err='',
+                   out='pass_test.PassingTest.test_pass\n')
+        self.check(['-l', 'pass_test.py'], files=files, ret=0, err='',
+                   out='pass_test.PassingTest.test_pass\n')
+        self.check(['-l', './pass_test.py'], files=files, ret=0, err='',
+                   out='pass_test.PassingTest.test_pass\n')
+        self.check(['-l', '.'], files=files, ret=0, err='',
+                   out='pass_test.PassingTest.test_pass\n')
+        self.check(['-l', 'pass_test.PassingTest.test_pass'], files=files,
+                   ret=0, err='',
+                   out='pass_test.PassingTest.test_pass\n')
+        self.check(['-l', '.'], files=files, ret=0, err='',
+                   out='pass_test.PassingTest.test_pass\n')
+
+    def test_find_from_subdirs(self):
+        files = {
+            'foo/__init__.py': '',
+            'foo/pass_test.py': PASS_TEST_PY,
+            'bar/__init__.py': '',
+            'bar/tmp': '',
+
+        }
+        self.check(['-l', '../foo/pass_test.py'], files=files, cwd='bar',
+                   ret=0, err='',
+                   out='foo.pass_test.PassingTest.test_pass\n')
+        self.check(['-l', 'foo'], files=files, cwd='bar',
+                   ret=0, err='',
+                   out='foo.pass_test.PassingTest.test_pass\n')
+        self.check(['-l', '--path', '../foo', 'pass_test'],
+                   files=files, cwd='bar', ret=0, err='',
+                   out='pass_test.PassingTest.test_pass\n')
+
+    def test_help(self):
+        self.check(['--help'], ret=0, rout='.*', err='')
+
+    def test_import_failure_missing_file(self):
+        self.check(['-l', 'foo'], ret=1, err='',
+                   rout='Failed to load "foo".*')
+
+    def test_import_failure_missing_package(self):
+        files = {'foo.py': d("""\
+                             import unittest
+                             import package_that_does_not_exist
+
+                             class ImportFailureTest(unittest.TestCase):
+                                def test_case(self):
+                                    pass
+                             """)}
+        self.check(['-l', 'foo.py'], files=files, ret=1, err='',
+                   rout=('Failed to load "foo.py": No module named '
+                         '\'?package_that_does_not_exist\'?\n'))
+
+    def test_import_failure_no_tests(self):
+        files = {'foo.py': 'import unittest'}
+        self.check(['-l', 'foo.bar'], files=files, ret=1, err='',
+                   rout='Failed to load "foo.bar":.*')
+
+    def test_import_failure_syntax_error(self):
+        files = {'syn_test.py': d("""\
+                             import unittest
+
+                             class SyntaxErrorTest(unittest.TestCase):
+                                 def test_syntax_error_in_test(self):
+                                     syntax error
+                             """)}
+        _, out, _, _ = self.check([], files=files, ret=1, err='')
+        self.assertIn('Failed to import test module: syn_test', out)
+        self.assertIn(('    syntax error\n'
+                       '               ^\n'
+                       'SyntaxError: invalid syntax\n'), out)
+
+    def test_interrupt(self):
+        files = {'interrupt_test.py': d("""\
+                                        import unittest
+                                        class Foo(unittest.TestCase):
+                                           def test_interrupt(self):
+                                               raise KeyboardInterrupt()
+                                        """)}
+        self.check(['-j', '1'], files=files, ret=130, out='',
+                   err='interrupted, exiting\n')
+
+    def test_isolate(self):
+        self.check(['--isolate', '*test_pass*'], files=PASS_TEST_FILES, ret=0,
+                   out=('[1/1] pass_test.PassingTest.test_pass passed\n'
+                        '1 test run, 0 failures.\n'), err='')
+
+    def test_load_tests_failure(self):
+        files = {'foo_test.py': d("""\
+                                  import unittest
+
+                                  def load_tests(_, _2, _3):
+                                      raise ValueError('this should fail')
+                                  """)}
+        self.check([], files=files, ret=1, err='',
+                   out=('foo_test.load_tests() failed: this should fail\n'))
+
+    def test_load_tests_single_worker(self):
+        files = LOAD_TEST_FILES
+        _, out, _, _ = self.check(['-j', '1', '-v'], files=files, ret=1,
+                                  err='')
+        self.assertIn('[1/2] load_test.BaseTest.test_fail failed', out)
+        self.assertIn('[2/2] load_test.BaseTest.test_pass passed', out)
+        self.assertIn('2 tests run, 1 failure.\n', out)
+
+    def test_load_tests_multiple_workers(self):
+        _, out, _, _ = self.check([], files=LOAD_TEST_FILES, ret=1, err='')
+
+        # The output for this test is nondeterministic since we may run
+        # two tests in parallel. So, we just test that some of the substrings
+        # we care about are present.
+        self.assertIn('test_pass passed', out)
+        self.assertIn('test_fail failed', out)
+        self.assertIn('2 tests run, 1 failure.\n', out)
+
+    def test_missing_builder_name(self):
+        self.check(['--test-results-server', 'localhost'], ret=2,
+                   out=('Error: --builder-name must be specified '
+                        'along with --test-result-server\n'
+                        'Error: --master-name must be specified '
+                        'along with --test-result-server\n'
+                        'Error: --test-type must be specified '
+                        'along with --test-result-server\n'), err='')
+
+    def test_ninja_status_env(self):
+        self.check(['-v', 'output_test.PassTest.test_out'],
+                   files=OUTPUT_TEST_FILES, aenv={'NINJA_STATUS': 'ns: '},
+                   out=d("""\
+                         ns: output_test.PassTest.test_out passed
+                         1 test run, 0 failures.
+                         """), err='')
+
+    def test_output_for_failures(self):
+        _, out, _, _ = self.check(['output_test.FailTest'],
+                                  files=OUTPUT_TEST_FILES,
+                                  ret=1, err='')
+        self.assertIn('[1/1] output_test.FailTest.test_out_err_fail '
+                      'failed unexpectedly:\n'
+                      '  hello on stdout\n'
+                      '  hello on stderr\n', out)
+
+    def test_quiet(self):
+        self.check(['-q'], files=PASS_TEST_FILES, ret=0, err='', out='')
+
+    def test_retry_limit(self):
+        _, out, _, _ = self.check(['--retry-limit', '2'],
+                                  files=FAIL_TEST_FILES, ret=1, err='')
+        self.assertIn('Retrying failed tests', out)
+        lines = out.splitlines()
+        self.assertEqual(len([l for l in lines
+                              if 'test_fail failed unexpectedly:' in l]),
+                         3)
+
+    def test_skip(self):
+        self.check(['--skip', '*test_fail*'], files=FAIL_TEST_FILES, ret=1,
+                   out='No tests to run.\n', err='')
+
+        files = {'fail_test.py': FAIL_TEST_PY,
+                 'pass_test.py': PASS_TEST_PY}
+        self.check(['-j', '1', '--skip', '*test_fail*'], files=files, ret=0,
+                   out=('[1/2] fail_test.FailingTest.test_fail was skipped\n'
+                        '[2/2] pass_test.PassingTest.test_pass passed\n'
+                        '2 tests run, 0 failures.\n'), err='')
+
+        # This tests that we print test_started updates for skipped tests
+        # properly. It also tests how overwriting works.
+        _, out, _, _ = self.check(['-j', '1', '--overwrite', '--skip',
+                                   '*test_fail*'], files=files, ret=0,
+                                  err='', universal_newlines=False)
+
+        # We test this string separately and call out.strip() to
+        # avoid the trailing \r\n we get on windows, while keeping
+        # the \r's elsewhere in the string.
+        self.assertMultiLineEqual(
+            out.strip(),
+            ('[0/2] fail_test.FailingTest.test_fail\r'
+             '                                     \r'
+             '[1/2] fail_test.FailingTest.test_fail was skipped\r'
+             '                                                 \r'
+             '[1/2] pass_test.PassingTest.test_pass\r'
+             '                                     \r'
+             '[2/2] pass_test.PassingTest.test_pass passed\r'
+             '                                            \r'
+             '2 tests run, 0 failures.'))
+
+    def test_skips_and_failures(self):
+        _, out, _, _ = self.check(['-j', '1', '-v', '-v'], files=SF_TEST_FILES,
+                                  ret=1, err='')
+
+        # We do a bunch of assertIn()'s to work around the non-portable
+        # tracebacks.
+        self.assertIn(('[1/9] sf_test.ExpectedFailures.test_fail failed:\n'
+                       '  Traceback '), out)
+        self.assertIn(('[2/9] sf_test.ExpectedFailures.test_pass '
+                       'passed unexpectedly'), out)
+        self.assertIn(('[3/9] sf_test.SetupClass.test_method1 '
+                       'failed unexpectedly:\n'
+                       '  in setupClass\n'), out)
+        self.assertIn(('[4/9] sf_test.SetupClass.test_method2 '
+                       'failed unexpectedly:\n'
+                       '  in setupClass\n'), out)
+        self.assertIn(('[5/9] sf_test.SkipClass.test_method was skipped:\n'
+                       '  skip class\n'), out)
+        self.assertIn(('[6/9] sf_test.SkipMethods.test_reason was skipped:\n'
+                       '  reason\n'), out)
+        self.assertIn(('[7/9] sf_test.SkipMethods.test_skip_if_false '
+                       'failed unexpectedly:\n'
+                       '  Traceback'), out)
+        self.assertIn(('[8/9] sf_test.SkipMethods.test_skip_if_true '
+                       'was skipped:\n'
+                       '  reason\n'
+                       '[9/9] sf_test.SkipSetup.test_notrun was skipped:\n'
+                       '  setup failed\n'
+                       '9 tests run, 4 failures.\n'), out)
+
+    def test_skip_and_all(self):
+        # --all should override --skip
+        self.check(['-l', '--skip', '*test_pass'],
+                   files=PASS_TEST_FILES, ret=1, err='',
+                   out='No tests to run.\n')
+        self.check(['-l', '--all', '--skip', '*test_pass'],
+                   files=PASS_TEST_FILES, ret=0, err='',
+                   out='pass_test.PassingTest.test_pass\n')
+
+    def test_skip_decorators_and_all(self):
+        _, out, _, _ = self.check(['--all', '-j', '1', '-v', '-v'],
+                                  files=SF_TEST_FILES, ret=1, err='')
+        self.assertIn('sf_test.SkipClass.test_method failed', out)
+        self.assertIn('sf_test.SkipMethods.test_reason failed', out)
+        self.assertIn('sf_test.SkipMethods.test_skip_if_true failed', out)
+        self.assertIn('sf_test.SkipMethods.test_skip_if_false failed', out)
+
+        # --all does not override explicit calls to skipTest(), only
+        # the decorators.
+        self.assertIn('sf_test.SkipSetup.test_notrun was skipped', out)
+
+    def test_subdir(self):
+        files = {
+            'foo/__init__.py': '',
+            'foo/bar/__init__.py': '',
+            'foo/bar/pass_test.py': PASS_TEST_PY
+        }
+        self.check(['foo/bar'], files=files, ret=0, err='',
+                   out=d("""\
+                         [1/1] foo.bar.pass_test.PassingTest.test_pass passed
+                         1 test run, 0 failures.
+                         """))
+
+    def test_timing(self):
+        self.check(['-t'], files=PASS_TEST_FILES, ret=0, err='',
+                   rout=('\[1/1\] pass_test.PassingTest.test_pass passed '
+                         '\d+.\d+s\n'
+                         '1 test run in \d+.\d+s, 0 failures.'))
+
+    def test_test_results_server(self):
+        server = test_result_server_fake.start()
+        self.assertNotEqual(server, None, 'could not start fake server')
+
+        try:
+            self.check(['--test-results-server',
+                        '%s:%d' % server.server_address,
+                        '--master-name', 'fake_master',
+                        '--builder-name', 'fake_builder',
+                        '--test-type', 'typ_tests',
+                        '--metadata', 'foo=bar'],
+                       files=PASS_TEST_FILES, ret=0, err='',
+                       out=('[1/1] pass_test.PassingTest.test_pass passed\n'
+                            '1 test run, 0 failures.\n'))
+
+        finally:
+            posts = server.stop()
+
+        self.assertEqual(len(posts), 1)
+        payload = posts[0][2].decode('utf8')
+        self.assertIn('"test_pass": {"expected": "PASS", "actual": "PASS"}',
+                      payload)
+        self.assertTrue(payload.endswith('--\r\n'))
+        self.assertNotEqual(server.log.getvalue(), '')
+
+    def test_test_results_server_error(self):
+        server = test_result_server_fake.start(code=500)
+        self.assertNotEqual(server, None, 'could not start fake server')
+
+        try:
+            self.check(['--test-results-server',
+                        '%s:%d' % server.server_address,
+                        '--master-name', 'fake_master',
+                        '--builder-name', 'fake_builder',
+                        '--test-type', 'typ_tests',
+                        '--metadata', 'foo=bar'],
+                       files=PASS_TEST_FILES, ret=1, err='',
+                       out=('[1/1] pass_test.PassingTest.test_pass passed\n'
+                            '1 test run, 0 failures.\n'
+                            'Uploading the JSON results raised '
+                            '"HTTP Error 500: Internal Server Error"\n'))
+
+        finally:
+            _ = server.stop()
+
+    def test_test_results_server_not_running(self):
+        self.check(['--test-results-server', 'localhost:99999',
+                    '--master-name', 'fake_master',
+                    '--builder-name', 'fake_builder',
+                    '--test-type', 'typ_tests',
+                    '--metadata', 'foo=bar'],
+                   files=PASS_TEST_FILES, ret=1, err='',
+                   rout=('\[1/1\] pass_test.PassingTest.test_pass passed\n'
+                         '1 test run, 0 failures.\n'
+                         'Uploading the JSON results raised .*\n'))
+
+    def test_verbose(self):
+        self.check(['-vv', '-j', '1', 'output_test.PassTest'],
+                   files=OUTPUT_TEST_FILES, ret=0,
+                   out=d("""\
+                         [1/2] output_test.PassTest.test_err passed:
+                           hello on stderr
+                         [2/2] output_test.PassTest.test_out passed:
+                           hello on stdout
+                         2 tests run, 0 failures.
+                         """), err='')
+
+    def test_version(self):
+        self.check('--version', ret=0, out=(VERSION + '\n'))
+
+    def test_write_full_results_to(self):
+        _, _, _, files = self.check(['--write-full-results-to',
+                                     'results.json'], files=PASS_TEST_FILES)
+        self.assertIn('results.json', files)
+        results = json.loads(files['results.json'])
+        self.assertEqual(results['interrupted'], False)
+        self.assertEqual(results['path_delimiter'], '.')
+        self.assertEqual(results['tests'],
+                         {u'pass_test': {
+                             u'PassingTest': {
+                                 u'test_pass': {
+                                     u'actual': u'PASS',
+                                     u'expected': u'PASS',
+                                 }
+                             }
+                         }})
+
+    def test_write_trace_to(self):
+        _, _, _, files = self.check(['--write-trace-to', 'trace.json'],
+                                    files=PASS_TEST_FILES)
+        self.assertIn('trace.json', files)
+        trace_obj = json.loads(files['trace.json'])
+        self.assertEqual(trace_obj['otherData'], {})
+        self.assertEqual(len(trace_obj['traceEvents']), 5)
+        event = trace_obj['traceEvents'][0]
+        self.assertEqual(event['name'], 'pass_test.PassingTest.test_pass')
+        self.assertEqual(event['ph'], 'X')
+        self.assertEqual(event['tid'], 1)
+        self.assertEqual(event['args']['expected'], ['Pass'])
+        self.assertEqual(event['args']['actual'], 'Pass')
+
+
+class TestMain(TestCli):
+    prog = []
+
+    def make_host(self):
+        return Host()
+
+    def call(self, host, argv, stdin, env):
+        stdin = unicode(stdin)
+        host.stdin = io.StringIO(stdin)
+        if env:
+            host.getenv = env.get
+        host.capture_output()
+        orig_sys_path = sys.path[:]
+        orig_sys_modules = list(sys.modules.keys())
+
+        try:
+            ret = main(argv + ['-j', '1'], host)
+        finally:
+            out, err = host.restore_output()
+            modules_to_unload = []
+            for k in sys.modules:
+                if k not in orig_sys_modules:
+                    modules_to_unload.append(k)
+            for k in modules_to_unload:
+                del sys.modules[k]
+            sys.path = orig_sys_path
+
+        return ret, out, err
+
+    def test_debugger(self):
+        # TODO: this test seems to hang under coverage.
+        pass
diff --git a/third_party/tvcm/third_party/typ/typ/tests/pool_test.py b/third_party/tvcm/third_party/typ/typ/tests/pool_test.py
new file mode 100644
index 0000000..fdb3f39
--- /dev/null
+++ b/third_party/tvcm/third_party/typ/typ/tests/pool_test.py
@@ -0,0 +1,167 @@
+# Copyright 2014 Dirk Pranke. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from typ import test_case
+from typ.host import Host
+from typ.pool import make_pool, _MessageType, _ProcessPool, _loop
+
+
+def _pre(host, worker_num, context):  # pylint: disable=W0613
+    context['pre'] = True
+    return context
+
+
+def _post(context):
+    context['post'] = True
+    return context
+
+
+def _echo(context, msg):
+    return '%s/%s/%s' % (context['pre'], context['post'], msg)
+
+
+def _error(context, msg):  # pylint: disable=W0613
+    raise Exception('_error() raised Exception')
+
+
+def _interrupt(context, msg):  # pylint: disable=W0613
+    raise KeyboardInterrupt()
+
+
+def _stub(*args):  # pylint: disable=W0613
+    return None
+
+
+class TestPool(test_case.TestCase):
+
+    def run_basic_test(self, jobs):
+        host = Host()
+        context = {'pre': False, 'post': False}
+        pool = make_pool(host, jobs, _echo, context, _pre, _post)
+        pool.send('hello')
+        pool.send('world')
+        msg1 = pool.get()
+        msg2 = pool.get()
+        pool.close()
+        final_contexts = pool.join()
+        self.assertEqual(set([msg1, msg2]),
+                         set(['True/False/hello',
+                              'True/False/world']))
+        expected_context = {'pre': True, 'post': True}
+        expected_final_contexts = [expected_context for _ in range(jobs)]
+        self.assertEqual(final_contexts, expected_final_contexts)
+
+    def run_through_loop(self, callback=None, pool=None):
+        callback = callback or _stub
+        if pool:
+            host = pool.host
+        else:
+            host = Host()
+            pool = _ProcessPool(host, 0, _stub, None, _stub, _stub)
+            pool.send('hello')
+
+        worker_num = 1
+        _loop(pool.requests, pool.responses, host, worker_num, callback,
+              None, _stub, _stub, should_loop=False)
+        return pool
+
+    def test_async_close(self):
+        host = Host()
+        pool = make_pool(host, 1, _echo, None, _stub, _stub)
+        pool.join()
+
+    def test_basic_one_job(self):
+        self.run_basic_test(1)
+
+    def test_basic_two_jobs(self):
+        self.run_basic_test(2)
+
+    def test_join_discards_messages(self):
+        host = Host()
+        context = {'pre': False, 'post': False}
+        pool = make_pool(host, 2, _echo, context, _pre, _post)
+        pool.send('hello')
+        pool.close()
+        pool.join()
+        self.assertEqual(len(pool.discarded_responses), 1)
+
+    def test_join_gets_an_error(self):
+        host = Host()
+        pool = make_pool(host, 2, _error, None, _stub, _stub)
+        pool.send('hello')
+        pool.close()
+        try:
+            pool.join()
+        except Exception as e:
+            self.assertIn('_error() raised Exception', str(e))
+
+    def test_join_gets_an_interrupt(self):
+        host = Host()
+        pool = make_pool(host, 2, _interrupt, None, _stub, _stub)
+        pool.send('hello')
+        pool.close()
+        self.assertRaises(KeyboardInterrupt, pool.join)
+
+    def test_loop(self):
+        pool = self.run_through_loop()
+        resp = pool.get()
+        self.assertEqual(resp, None)
+        pool.requests.put((_MessageType.Close, None))
+        pool.close()
+        self.run_through_loop(pool=pool)
+        pool.join()
+
+    def test_loop_fails_to_respond(self):
+        # This tests what happens if _loop() tries to send a response
+        # on a closed queue; we can't simulate this directly through the
+        # api in a single thread.
+        pool = self.run_through_loop()
+        pool.requests.put((_MessageType.Request, None))
+        pool.requests.put((_MessageType.Close, None))
+        self.run_through_loop(pool=pool)
+        pool.join()
+
+    def test_loop_get_raises_error(self):
+        pool = self.run_through_loop(_error)
+        self.assertRaises(Exception, pool.get)
+        pool.requests.put((_MessageType.Close, None))
+        pool.close()
+        pool.join()
+
+    def test_loop_get_raises_interrupt(self):
+        pool = self.run_through_loop(_interrupt)
+        self.assertRaises(KeyboardInterrupt, pool.get)
+        pool.requests.put((_MessageType.Close, None))
+        pool.close()
+        pool.join()
+
+    def test_pickling_errors(self):
+        def unpicklable_fn():  # pragma: no cover
+            pass
+
+        host = Host()
+        jobs = 2
+        self.assertRaises(ValueError, make_pool,
+                          host, jobs, _stub, unpicklable_fn, None, None)
+        self.assertRaises(ValueError, make_pool,
+                          host, jobs, _stub, None, unpicklable_fn, None)
+        self.assertRaises(ValueError, make_pool,
+                          host, jobs, _stub, None, None, unpicklable_fn)
+
+    def test_no_close(self):
+        host = Host()
+        context = {'pre': False, 'post': False}
+        pool = make_pool(host, 2, _echo, context, _pre, _post)
+        final_contexts = pool.join()
+        self.assertEqual(final_contexts, [])
diff --git a/third_party/tvcm/third_party/typ/typ/tests/printer_test.py b/third_party/tvcm/third_party/typ/typ/tests/printer_test.py
new file mode 100644
index 0000000..b2310bc
--- /dev/null
+++ b/third_party/tvcm/third_party/typ/typ/tests/printer_test.py
@@ -0,0 +1,61 @@
+# Copyright 2014 Dirk Pranke. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import unittest
+
+from typ.printer import Printer
+
+
+class TestPrinter(unittest.TestCase):
+
+    def setUp(self):
+        # 'Invalid name' pylint: disable=C0103
+        self.out = []
+
+    def print_(self, msg, end='\n'):
+        self.out.append(msg + end)
+
+    def test_basic(self):
+        pr = Printer(self.print_, False, 80)
+        pr.update('foo')
+        pr.flush()
+        self.assertEqual(self.out, ['foo', '\n'])
+
+    def test_elide(self):
+        pr = Printer(self.print_, False, 8)
+        pr.update('hello world')
+        pr.flush()
+        self.assertEqual(self.out, ['h...d', '\n'])
+
+    def test_overwrite(self):
+        pr = Printer(self.print_, True, 80)
+        pr.update('hello world')
+        pr.update('goodbye world')
+        pr.flush()
+        self.assertEqual(self.out,
+                         ['hello world',
+                          '\r           \r',
+                          'goodbye world',
+                          '\n'])
+
+    def test_last_line_flushed_when_not_overwriting(self):
+        pr = Printer(self.print_, False, 80)
+        pr.update('foo\nbar')
+        pr.update('baz')
+        pr.flush()
+        self.assertEqual(self.out,
+                         ['foo\nbar',
+                          '\n',
+                          'baz',
+                          '\n'])
diff --git a/third_party/tvcm/third_party/typ/typ/tests/runner_test.py b/third_party/tvcm/third_party/typ/typ/tests/runner_test.py
new file mode 100644
index 0000000..e03d611
--- /dev/null
+++ b/third_party/tvcm/third_party/typ/typ/tests/runner_test.py
@@ -0,0 +1,218 @@
+# Copyright 2014 Dirk Pranke. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import tempfile
+
+from textwrap import dedent as d
+
+
+from typ import Host, Runner, TestCase, TestSet, TestInput
+from typ import WinMultiprocessing
+
+
+def _setup_process(child, context):  # pylint: disable=W0613
+    return context
+
+
+def _teardown_process(child, context):  # pylint: disable=W0613
+    return context
+
+def _teardown_throws(child, context):  # pylint: disable=W0613
+    raise Exception("exception in teardown")
+
+
+class RunnerTests(TestCase):
+    def test_context(self):
+        r = Runner()
+        r.args.tests = ['typ.tests.runner_test.ContextTests']
+        r.context = {'foo': 'bar'}
+        r.setup_fn = _setup_process
+        r.teardown_fn = _teardown_process
+        r.win_multiprocessing = WinMultiprocessing.importable
+        ret, _, _ = r.run()
+        self.assertEqual(ret, 0)
+
+    def test_exception_in_teardown(self):
+        r = Runner()
+        r.args.tests = ['typ.tests.runner_test.ContextTests']
+        r.context = {'foo': 'bar'}
+        r.setup_fn = _setup_process
+        r.teardown_fn = _teardown_throws
+        r.win_multiprocessing = WinMultiprocessing.importable
+        ret, _, _ = r.run()
+        self.assertEqual(ret, 0)
+        self.assertEqual(r.final_responses[0][2].message,
+                         'exception in teardown')
+
+    def test_bad_default(self):
+        r = Runner()
+        ret = r.main([], foo='bar')
+        self.assertEqual(ret, 2)
+
+    def test_good_default(self):
+        r = Runner()
+        ret = r.main([], tests=['typ.tests.runner_test.ContextTests'])
+        self.assertEqual(ret, 0)
+
+
+class TestSetTests(TestCase):
+    # This class exists to test the failures that can come up if you
+    # create your own test sets and bypass find_tests(); failures that
+    # would normally be caught there can occur later during test execution.
+
+    def test_missing_name(self):
+        test_set = TestSet()
+        test_set.parallel_tests = [TestInput('nonexistent test')]
+        r = Runner()
+        r.args.jobs = 1
+        ret, _, _ = r.run(test_set)
+        self.assertEqual(ret, 1)
+
+    def test_failing_load_test(self):
+        h = Host()
+        orig_wd = h.getcwd()
+        tmpdir = None
+        try:
+            tmpdir = h.mkdtemp()
+            h.chdir(tmpdir)
+            h.write_text_file('load_test.py', d("""\
+                import unittest
+                def load_tests(_, _2, _3):
+                    assert False
+                """))
+            test_set = TestSet()
+            test_set.parallel_tests = [TestInput('load_test.BaseTest.test_x')]
+            r = Runner()
+            r.args.jobs = 1
+            ret, _, _ = r.run(test_set)
+            self.assertEqual(ret, 1)
+        finally:
+            h.chdir(orig_wd)
+            if tmpdir:
+                h.rmtree(tmpdir)
+
+
+class TestWinMultiprocessing(TestCase):
+    def make_host(self):
+        return Host()
+
+    def call(self, argv, platform=None, win_multiprocessing=None, **kwargs):
+        h = self.make_host()
+        orig_wd = h.getcwd()
+        tmpdir = None
+        try:
+            tmpdir = h.mkdtemp()
+            h.chdir(tmpdir)
+            h.capture_output()
+            if platform is not None:
+                h.platform = platform
+            r = Runner(h)
+            if win_multiprocessing is not None:
+                r.win_multiprocessing = win_multiprocessing
+            ret = r.main(argv, **kwargs)
+        finally:
+            out, err = h.restore_output()
+            h.chdir(orig_wd)
+            if tmpdir:
+                h.rmtree(tmpdir)
+
+        return ret, out, err
+
+    def test_bad_value(self):
+        self.assertRaises(ValueError, self.call, [], win_multiprocessing='foo')
+
+    def test_ignore(self):
+        h = self.make_host()
+        if h.platform == 'win32':  # pragma: win32
+            self.assertRaises(ValueError, self.call, [],
+                              win_multiprocessing=WinMultiprocessing.ignore)
+        else:
+            result = self.call([],
+                               win_multiprocessing=WinMultiprocessing.ignore)
+            ret, out, err = result
+            self.assertEqual(ret, 1)
+            self.assertEqual(out, 'No tests to run.\n')
+            self.assertEqual(err, '')
+
+    def test_real_unimportable_main(self):
+        h = self.make_host()
+        tmpdir = None
+        orig_wd = h.getcwd()
+        out = err = None
+        out_str = err_str = ''
+        try:
+            tmpdir = h.mkdtemp()
+            h.chdir(tmpdir)
+            out = tempfile.NamedTemporaryFile(delete=False)
+            err = tempfile.NamedTemporaryFile(delete=False)
+            path_above_typ = h.realpath(h.dirname(__file__), '..', '..')
+            env = h.env.copy()
+            if 'PYTHONPATH' in env:  # pragma: untested
+                env['PYTHONPATH'] = '%s%s%s' % (env['PYTHONPATH'],
+                                                h.pathsep,
+                                                path_above_typ)
+            else:  # pragma: untested.
+                env['PYTHONPATH'] = path_above_typ
+
+            h.write_text_file('test', d("""
+                import sys
+                import typ
+                importable = typ.WinMultiprocessing.importable
+                sys.exit(typ.main(win_multiprocessing=importable))
+                """))
+            h.stdout = out
+            h.stderr = err
+            ret = h.call_inline([h.python_interpreter, h.join(tmpdir, 'test')],
+                                env=env)
+        finally:
+            h.chdir(orig_wd)
+            if tmpdir:
+                h.rmtree(tmpdir)
+            if out:
+                out.close()
+                out = open(out.name)
+                out_str = out.read()
+                out.close()
+                h.remove(out.name)
+            if err:
+                err.close()
+                err = open(err.name)
+                err_str = err.read()
+                err.close()
+                h.remove(err.name)
+
+        self.assertEqual(ret, 1)
+        self.assertEqual(out_str, '')
+        self.assertIn('ValueError: The __main__ module ',
+                      err_str)
+
+    def test_single_job(self):
+        ret, out, err = self.call(['-j', '1'], platform='win32')
+        self.assertEqual(ret, 1)
+        self.assertIn('No tests to run.', out)
+        self.assertEqual(err, '')
+
+    def test_spawn(self):
+        ret, out, err = self.call([])
+        self.assertEqual(ret, 1)
+        self.assertIn('No tests to run.', out)
+        self.assertEqual(err, '')
+
+
+class ContextTests(TestCase):
+    def test_context(self):
+        # This test is mostly intended to be called by
+        # RunnerTests.test_context, above. It is not interesting on its own.
+        if self.context:
+            self.assertEquals(self.context['foo'], 'bar')
diff --git a/third_party/tvcm/third_party/typ/typ/tests/stats_test.py b/third_party/tvcm/third_party/typ/typ/tests/stats_test.py
new file mode 100644
index 0000000..3154768
--- /dev/null
+++ b/third_party/tvcm/third_party/typ/typ/tests/stats_test.py
@@ -0,0 +1,74 @@
+# Copyright 2014 Dirk Pranke. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import unittest
+
+from typ.stats import Stats
+
+
+class TestStats(unittest.TestCase):
+
+    def test_basic(self):
+        s = Stats('foo', lambda: 0, 32)
+        self.assertEqual(s.format(), 'foo')
+
+    def test_edges(self):
+        s = Stats('[%s/%f/%t/%r/%p]', lambda: 0, 32)
+        self.assertEqual(s.format(), '[0/0/0/0/-]')
+        s.started = 3
+        s.total = 5
+        s.finished = 1
+        self.assertEqual(s.format(), '[3/1/5/2/ 60.0]')
+
+        s.started = 5
+        s.finished = 5
+        self.assertEqual(s.format(), '[5/5/5/0/100.0]')
+
+    def test_elapsed_time(self):
+        times = [0.0, 0.4]
+        s = Stats('[%e]', lambda: times.pop(0), 32)
+        self.assertEqual(s.format(), '[0.400]')
+
+        s = Stats('[%e]', lambda: 0, 32)
+        self.assertEqual(s.format(), '[0.000]')
+
+    def test_current_rate(self):
+        times = [0.0, 0.1, 0.2]
+        s = Stats('[%c]', lambda: times.pop(0), 1)
+        self.assertEquals(s.format(), '[-]')
+        s.add_time()
+        s.add_time()
+        self.assertEquals(s.format(), '[ 10.0]')
+
+    def test_overall_rate(self):
+        times = [0, 0, 5]
+        s = Stats('[%o]', lambda: times.pop(0), 32)
+        self.assertEqual(s.format(), '[-]')
+        s.started = 3
+        s.finished = 1
+        s.total = 5
+        self.assertEqual(s.format(), '[  0.2]')
+
+    def test_escaped_percent(self):
+        s = Stats('%%', lambda: 0, 32)
+        self.assertEqual(s.format(), '%')
+
+    def test_unrecognized_escape(self):
+        s = Stats('%x', lambda: 0, 32)
+        self.assertEqual(s.format(), '%x')
+
+    def test_remaining(self):
+        s = Stats('%u', lambda: 0, 32)
+        s.total = 2
+        self.assertEqual(s.format(), '2')
diff --git a/third_party/tvcm/third_party/typ/typ/tests/test_case_test.py b/third_party/tvcm/third_party/typ/typ/tests/test_case_test.py
new file mode 100644
index 0000000..4d22bd9
--- /dev/null
+++ b/third_party/tvcm/third_party/typ/typ/tests/test_case_test.py
@@ -0,0 +1,54 @@
+# Copyright 2014 Dirk Pranke. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from typ import test_case
+
+
+class TestFuncs(test_case.MainTestCase):
+
+    def test_convert_newlines(self):
+        cn = test_case.convert_newlines
+        self.assertEqual(cn('foo'), 'foo')
+        self.assertEqual(cn('foo\nbar\nbaz'), 'foo\nbar\nbaz')
+        self.assertEqual(cn('foo\rbar\nbaz\r'), 'foo\nbar\nbaz\n')
+        self.assertEqual(cn('foo\r\nbar\r\nbaz\r\nmeh\n'),
+                         'foo\nbar\nbaz\nmeh\n')
+
+
+class TestMainTestCase(test_case.MainTestCase):
+
+    def test_basic(self):
+        h = self.make_host()
+        files = {
+            'test.py': """
+import os
+import sys
+sys.stdout.write("in: %s\\n" % sys.stdin.read())
+sys.stdout.write("out: %s\\n" % os.environ['TEST_VAR'])
+sys.stderr.write("err\\n")
+with open("../results", "w") as fp:
+  fp.write(open("../input", "r").read() + " written")
+""",
+            'input': 'results',
+            'subdir/x': 'y',
+        }
+        exp_files = files.copy()
+        exp_files['results'] = 'results written'
+        self.check(prog=[h.python_interpreter, '../test.py'],
+                   stdin='hello on stdin',
+                   env={'TEST_VAR': 'foo'},
+                   cwd='subdir',
+                   files=files,
+                   ret=0, out='in: hello on stdin\nout: foo\n',
+                   err='err\n', exp_files=exp_files)
diff --git a/third_party/tvcm/third_party/typ/typ/version.py b/third_party/tvcm/third_party/typ/typ/version.py
new file mode 100644
index 0000000..69ac8d0
--- /dev/null
+++ b/third_party/tvcm/third_party/typ/typ/version.py
@@ -0,0 +1,15 @@
+# Copyright 2014 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+VERSION = '0.9.1'