Merge autoland to mozilla-central. a=merge
authorTiberius Oros <toros@mozilla.com>
Thu, 11 Oct 2018 06:52:43 +0300
changeset 499089 b89a744deccb5be6113036d95c5c208e1ae2b59f
parent 499032 2f85c2b55cd2f1b241f27b7ad8b9dfe42dfc139c (current diff)
parent 499088 9605a2bb0c596ed1badeead50ebd3f47d8378d6f (diff)
child 499113 e4220fa7a191903a814e8cf473cf544fe9762625
push id1864
push userffxbld-merge
push dateMon, 03 Dec 2018 15:51:40 +0000
treeherdermozilla-release@f040763d99ad [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone64.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge autoland to mozilla-central. a=merge
browser/components/enterprisepolicies/tests/browser/browser_policy_disable_pdfjs.js
build/build-clang/clang-win32-st-an.json
build/build-clang/msvc-host-x64.patch
js/xpconnect/tests/chrome/test_getweakmapkeys.xul
js/xpconnect/tests/chrome/test_paris_weakmap_keys.xul
js/xpconnect/tests/chrome/test_weakmaps.xul
layout/tools/reftest/Makefile.in
taskcluster/scripts/misc/build-clang32-st-an-windows.sh
third_party/python/psutil/psutil/tests/__main__.py
third_party/python/psutil/psutil/tests/test_bsd.py
third_party/python/psutil/psutil/tests/test_connections.py
third_party/python/psutil/psutil/tests/test_contracts.py
third_party/python/psutil/psutil/tests/test_linux.py
third_party/python/psutil/psutil/tests/test_memory_leaks.py
third_party/python/psutil/psutil/tests/test_misc.py
third_party/python/psutil/psutil/tests/test_osx.py
third_party/python/psutil/psutil/tests/test_posix.py
third_party/python/psutil/psutil/tests/test_process.py
third_party/python/psutil/psutil/tests/test_sunos.py
third_party/python/psutil/psutil/tests/test_system.py
third_party/python/psutil/psutil/tests/test_unicode.py
third_party/python/psutil/psutil/tests/test_windows.py
third_party/python/psutil/scripts/battery.py
third_party/python/psutil/scripts/cpu_distribution.py
third_party/python/psutil/scripts/disk_usage.py
third_party/python/psutil/scripts/fans.py
third_party/python/psutil/scripts/free.py
third_party/python/psutil/scripts/ifconfig.py
third_party/python/psutil/scripts/internal/bench_oneshot.py
third_party/python/psutil/scripts/internal/check_broken_links.py
third_party/python/psutil/scripts/internal/download_exes.py
third_party/python/psutil/scripts/internal/generate_manifest.py
third_party/python/psutil/scripts/internal/winmake.py
third_party/python/psutil/scripts/iotop.py
third_party/python/psutil/scripts/killall.py
third_party/python/psutil/scripts/meminfo.py
third_party/python/psutil/scripts/netstat.py
third_party/python/psutil/scripts/nettop.py
third_party/python/psutil/scripts/pidof.py
third_party/python/psutil/scripts/pmap.py
third_party/python/psutil/scripts/procinfo.py
third_party/python/psutil/scripts/procsmem.py
third_party/python/psutil/scripts/ps.py
third_party/python/psutil/scripts/pstree.py
third_party/python/psutil/scripts/sensors.py
third_party/python/psutil/scripts/temperatures.py
third_party/python/psutil/scripts/top.py
third_party/python/psutil/scripts/who.py
third_party/python/psutil/scripts/winservices.py
toolkit/components/antitracking/test/browser/browser_blockingWorkers.js
--- a/browser/components/enterprisepolicies/Policies.jsm
+++ b/browser/components/enterprisepolicies/Policies.jsm
@@ -127,17 +127,17 @@ var Policies = {
     onAllWindowsRestored(manager, param) {
       BookmarksPolicies.processBookmarks(param);
     },
   },
 
   "Certificates": {
     onBeforeAddons(manager, param) {
       if ("ImportEnterpriseRoots" in param) {
-        setAndLockPref("security.enterprise_roots.enabled", true);
+        setAndLockPref("security.enterprise_roots.enabled", param.ImportEnterpriseRoots);
       }
     },
   },
 
   "Cookies": {
     onBeforeUIStartup(manager, param) {
       addAllowDenyPermissions("cookie", param.Allow, param.Block);
 
@@ -222,19 +222,19 @@ var Policies = {
     onBeforeAddons(manager, param) {
       if (param) {
         manager.disallowFeature("appUpdate");
       }
     },
   },
 
   "DisableBuiltinPDFViewer": {
-    onBeforeUIStartup(manager, param) {
+    onBeforeAddons(manager, param) {
       if (param) {
-        manager.disallowFeature("PDF.js");
+        setAndLockPref("pdfjs.disabled", true);
       }
     },
   },
 
   "DisableDeveloperTools": {
     onBeforeAddons(manager, param) {
       if (param) {
         setAndLockPref("devtools.policy.disabled", true);
@@ -739,16 +739,17 @@ var Policies = {
               let newEngineParameters = {
                 template:    newEngine.URLTemplate,
                 iconURL:     newEngine.IconURL ? newEngine.IconURL.href : null,
                 alias:       newEngine.Alias,
                 description: newEngine.Description,
                 method:      newEngine.Method,
                 suggestURL:  newEngine.SuggestURLTemplate,
                 extensionID: "set-via-policy",
+                queryCharset: "UTF-8",
               };
               try {
                 Services.search.addEngineWithDetails(newEngine.Name,
                                                      newEngineParameters);
               } catch (ex) {
                 log.error("Unable to add search engine", ex);
               }
             }
--- a/browser/components/enterprisepolicies/tests/browser/browser.ini
+++ b/browser/components/enterprisepolicies/tests/browser/browser.ini
@@ -32,17 +32,16 @@ support-files =
 [browser_policy_clear_blocked_cookies.js]
 [browser_policy_cookie_settings.js]
 [browser_policy_default_browser_check.js]
 [browser_policy_disable_feedback_commands.js]
 [browser_policy_disable_flash_plugin.js]
 [browser_policy_disable_fxaccounts.js]
 skip-if = (verify && debug && (os == 'mac'))
 [browser_policy_disable_masterpassword.js]
-[browser_policy_disable_pdfjs.js]
 [browser_policy_disable_pocket.js]
 [browser_policy_disable_popup_blocker.js]
 [browser_policy_disable_privatebrowsing.js]
 [browser_policy_disable_profile_reset.js]
 [browser_policy_disable_profile_import.js]
 [browser_policy_disable_safemode.js]
 [browser_policy_disable_shield.js]
 [browser_policy_disable_telemetry.js]
--- a/browser/components/enterprisepolicies/tests/browser/browser_policies_simple_pref_policies.js
+++ b/browser/components/enterprisepolicies/tests/browser/browser_policies_simple_pref_policies.js
@@ -48,16 +48,21 @@ const POLICIES_TESTS = [
       },
     },
     lockedPrefs: {
       "security.certerror.hideAddException": true,
       "browser.safebrowsing.allowOverride": false,
     },
   },
 
+  // POLICY: DisableBuiltinPDFViewer
+  {
+    policies: { "DisableBuiltinPDFViewer": true },
+    lockedPrefs: { "pdfjs.disabled": true },
+  },
 
   // POLICY: DisableFormHistory
   {
     policies: { "DisableFormHistory": true },
     lockedPrefs: { "browser.formfill.enable": false },
   },
 
   // POLICY: EnableTrackingProtection
@@ -108,28 +113,40 @@ const POLICIES_TESTS = [
       "network.negotiate-auth.trusted-uris": "a.com, b.com",
       "network.negotiate-auth.delegation-uris": "a.com, b.com",
       "network.automatic-ntlm-auth.trusted-uris": "a.com, b.com",
       "network.automatic-ntlm-auth.allow-non-fqdn": true,
       "network.negotiate-auth.allow-non-fqdn": true,
     },
   },
 
-  // POLICY: Certificates
+  // POLICY: Certificates (true)
   {
     policies: {
       "Certificates": {
         "ImportEnterpriseRoots": true,
       },
     },
     lockedPrefs: {
       "security.enterprise_roots.enabled": true,
     },
   },
 
+  // POLICY: Certificates (false)
+  {
+    policies: {
+      "Certificates": {
+        "ImportEnterpriseRoots": false,
+      },
+    },
+    lockedPrefs: {
+      "security.enterprise_roots.enabled": false,
+    },
+  },
+
   // POLICY: InstallAddons.Default (block addon installs)
   {
     policies: {
       "InstallAddonsPermission": {
         "Default": false,
       },
     },
     lockedPrefs: {
deleted file mode 100644
--- a/browser/components/enterprisepolicies/tests/browser/browser_policy_disable_pdfjs.js
+++ /dev/null
@@ -1,17 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
-
-const {PdfJs} = ChromeUtils.import("resource://pdf.js/PdfJs.jsm", {});
-
-add_task(async function test_disable_pdfjs() {
-  is(PdfJs.enabled, true, "PDFjs should be enabled before policy runs");
-
-  await setupPolicyEngineWithJson({
-    "policies": {
-      "DisableBuiltinPDFViewer": true,
-    },
-  });
-
-  is(PdfJs.enabled, false, "PDFjs should be disabled after policy runs");
-});
--- a/browser/components/enterprisepolicies/tests/browser/browser_policy_locale.js
+++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_locale.js
@@ -18,16 +18,18 @@ function promiseLocaleChanged() {
         }
       },
     };
     Services.obs.addObserver(localeObserver, REQ_LOC_CHANGE_EVENT);
   });
 }
 
 add_task(async function test_requested_locale() {
+  let originalLocales = Services.locale.requestedLocales;
   let localePromise = promiseLocaleChanged();
   await setupPolicyEngineWithJson({
     "policies": {
       "RequestedLocales": ["de"],
     },
   });
   await localePromise;
+  Services.locale.requestedLocales = originalLocales;
 });
--- a/browser/components/preferences/in-content/main.js
+++ b/browser/components/preferences/in-content/main.js
@@ -3243,12 +3243,11 @@ class PDFHandlerInfoWrapper extends Inte
     return TOPIC_PDFJS_HANDLER_CHANGED;
   }
 
   get _appPrefLabel() {
     return "portableDocumentFormat";
   }
 
   get enabled() {
-    return !Services.prefs.getBoolPref(PREF_PDFJS_DISABLED) &&
-           Services.policies.isAllowed("PDF.js");
+    return !Services.prefs.getBoolPref(PREF_PDFJS_DISABLED);
   }
 }
--- a/browser/config/mozconfigs/win32/clang
+++ b/browser/config/mozconfigs/win32/clang
@@ -5,14 +5,16 @@ MOZ_AUTOMATION_L10N_CHECK=0
 . "$topsrcdir/build/mozconfig.win-common"
 . "$topsrcdir/browser/config/mozconfigs/common"
 
 ac_add_options --enable-optimize
 
 ac_add_options --enable-clang-plugin
 
 . $topsrcdir/build/win32/mozconfig.vs-latest
-# Regardless of what mozconfig.vs-latest sets, clang-plugin builds need to use
-# the Microsoft linker until at least bugs 1414287 and 1427808 are resolved.
+
+# Regardless of what mozconfig.vs-latest sets, lld-link that comes with the old
+# clang version used for static analysis fails to link multiple things. So
+# until bug 1427808 is resolved, use the Microsoft linker.
 export LINKER=link
 
 . "$topsrcdir/build/mozconfig.common.override"
 . "$topsrcdir/build/mozconfig.clang-cl"
--- a/browser/config/mozconfigs/win32/clang-debug
+++ b/browser/config/mozconfigs/win32/clang-debug
@@ -6,14 +6,16 @@ MOZ_AUTOMATION_L10N_CHECK=0
 . "$topsrcdir/browser/config/mozconfigs/common"
 
 ac_add_options --enable-optimize
 ac_add_options --enable-debug
 
 ac_add_options --enable-clang-plugin
 
 . $topsrcdir/build/win32/mozconfig.vs-latest
-# Regardless of what mozconfig.vs-latest sets, clang-plugin builds need to use
-# the Microsoft linker until at least bugs 1414287 and 1427808 are resolved.
+
+# Regardless of what mozconfig.vs-latest sets, lld-link that comes with the old
+# clang version used for static analysis fails to link multiple things. So
+# until bug 1427808 is resolved, use the Microsoft linker.
 export LINKER=link
 
 . "$topsrcdir/build/mozconfig.common.override"
 . "$topsrcdir/build/mozconfig.clang-cl"
--- a/browser/config/mozconfigs/win32/debug-msvc
+++ b/browser/config/mozconfigs/win32/debug-msvc
@@ -1,5 +1,8 @@
 . "$topsrcdir/browser/config/mozconfigs/win32/debug"
 
 export CC="cl.exe"
 export CXX="cl.exe"
 export LINKER="link.exe"
+
+export HOST_CC=${VSPATH}/VC/bin/Hostx64/x64/cl.exe
+export HOST_CXX=${VSPATH}/VC/bin/Hostx64/x64/cl.exe
--- a/browser/config/mozconfigs/win32/opt-msvc
+++ b/browser/config/mozconfigs/win32/opt-msvc
@@ -1,5 +1,8 @@
 . "$topsrcdir/browser/config/mozconfigs/win32/nightly"
 
 export CC="cl.exe"
 export CXX="cl.exe"
 export LINKER="link.exe"
+
+export HOST_CC=${VSPATH}/VC/bin/Hostx64/x64/cl.exe
+export HOST_CXX=${VSPATH}/VC/bin/Hostx64/x64/cl.exe
--- a/browser/extensions/pdfjs/content/PdfJs.jsm
+++ b/browser/extensions/pdfjs/content/PdfJs.jsm
@@ -263,20 +263,16 @@ var PdfJs = {
   },
 
   /**
    * pdf.js is only enabled if it is both selected as the pdf viewer and if the
    * global switch enabling it is true.
    * @return {boolean} Whether or not it's enabled.
    */
   get enabled() {
-    if (!Services.policies.isAllowed("PDF.js")) {
-      return false;
-    }
-
     if (!Services.prefs.getBoolPref(PREF_ENABLED_CACHE_INITIALIZED, false)) {
       // If we just updated, and the cache hasn't been initialized, then we
       // can't assume a default state, and need to synchronously initialize
       // PdfJs
       if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_POSTUPDATE)) {
         this.checkEnabled();
       }
 
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -37,39 +37,49 @@ left instead of right. -->
 <!ENTITY  closeTabsToTheEnd.label            "Close Tabs to the Right">
 <!ENTITY  closeTabsToTheEnd.accesskey        "i">
 <!ENTITY  closeOtherTabs.label               "Close Other Tabs">
 <!ENTITY  closeOtherTabs.accesskey           "o">
 
 <!ENTITY  closeTabs.label                    "Close Tabs">
 <!ENTITY  closeTabs.accesskey                "S">
 <!ENTITY  pinSelectedTabs.label              "Pin Tabs">
-<!-- Pin Tab and Pin Selected Tabs have the same accesskey
-but will never be visible at the same time. -->
+<!-- LOCALIZATION NOTE(pinTab.accesskey, pinSelectedTabs.accesskey,
+unpinTab.accesskey, unpinSelectedTabs.accesskey): These share the
+same accesskey but will never be visible at the same time. -->
 <!ENTITY  pinSelectedTabs.accesskey          "P">
 <!ENTITY  unpinSelectedTabs.label            "Unpin Tabs">
-<!-- Unpin Tab and Unpin Selected Tabs have the same accesskey
-but will never be visible at the same time. -->
-<!ENTITY  unpinSelectedTabs.accesskey        "b">
+<!-- LOCALIZATION NOTE(pinTab.accesskey, pinSelectedTabs.accesskey,
+unpinTab.accesskey, unpinSelectedTabs.accesskey): These share the
+same accesskey but will never be visible at the same time. -->
+<!ENTITY  unpinSelectedTabs.accesskey        "p">
 <!-- LOCALIZATION NOTE(reloadTab.label, reloadTabs.label): have the same accesskey
 but will never be visible at the same time. -->
 <!ENTITY  reloadTabs.label                   "Reload Tabs">
 <!ENTITY  reloadTabs.accesskey               "R">
 <!ENTITY  bookmarkSelectedTabs.label         "Bookmark Tabs…">
-<!ENTITY  bookmarkSelectedTabs.accesskey     "k">
+<!-- LOCALIZATION NOTE(bookmarkTab.accesskey, bookmarkSelectedTabs.accesskey):
+These items have the same accesskey but will never be visible at the same time. -->
+<!ENTITY  bookmarkSelectedTabs.accesskey     "B">
 
 <!-- LOCALIZATION NOTE (pinTab.label, unpinTab.label): "Pin" is being
 used as a metaphor for expressing the fact that these tabs are "pinned" to the
 left edge of the tabstrip. Really we just want the string to express the idea
 that this is a lightweight and reversible action that keeps your tab where you
 can reach it easily. -->
 <!ENTITY  pinTab.label                       "Pin Tab">
+<!-- LOCALIZATION NOTE(pinTab.accesskey, pinSelectedTabs.accesskey,
+unpinTab.accesskey, unpinSelectedTabs.accesskey): These share the
+same accesskey but will never be visible at the same time. -->
 <!ENTITY  pinTab.accesskey                   "P">
 <!ENTITY  unpinTab.label                     "Unpin Tab">
-<!ENTITY  unpinTab.accesskey                 "b">
+<!-- LOCALIZATION NOTE(pinTab.accesskey, pinSelectedTabs.accesskey,
+unpinTab.accesskey, unpinSelectedTabs.accesskey): These share the
+same accesskey but will never be visible at the same time. -->
+<!ENTITY  unpinTab.accesskey                 "p">
 <!ENTITY  sendPageToDevice.label             "Send Page to Device">
 <!ENTITY  sendPageToDevice.accesskey         "n">
 <!ENTITY  sendLinkToDevice.label             "Send Link to Device">
 <!ENTITY  sendLinkToDevice.accesskey         "n">
 <!-- LOCALIZATION NOTE (moveTabOptions.label and moveSelectedTabOptions.label):
 These two items have the same accesskey but will never be visible at the same time. -->
 <!ENTITY  moveTabOptions.label               "Move Tab">
 <!ENTITY  moveTabOptions.accesskey           "v">
@@ -79,17 +89,19 @@ These two items have the same accesskey 
 <!ENTITY  moveToStart.accesskey              "S">
 <!ENTITY  moveToEnd.label                    "Move to End">
 <!ENTITY  moveToEnd.accesskey                "E">
 <!ENTITY  moveToNewWindow.label              "Move to New Window">
 <!ENTITY  moveToNewWindow.accesskey          "W">
 <!ENTITY  reopenInContainer.label            "Reopen in Container">
 <!ENTITY  reopenInContainer.accesskey        "e">
 <!ENTITY  bookmarkTab.label                  "Bookmark Tab">
-<!ENTITY  bookmarkTab.accesskey              "T">
+<!-- LOCALIZATION NOTE(bookmarkTab.accesskey, bookmarkSelectedTabs.accesskey):
+These items have the same accesskey but will never be visible at the same time. -->
+<!ENTITY  bookmarkTab.accesskey              "B">
 <!ENTITY  undoCloseTab.label                 "Undo Close Tab">
 <!ENTITY  undoCloseTab.accesskey             "U">
 <!ENTITY  closeTab.label                     "Close Tab">
 <!ENTITY  closeTab.accesskey                 "c">
 <!ENTITY  hiddenTabs.label                   "Hidden Tabs">
 
 <!ENTITY  listAllTabs.label      "List all tabs">
 
deleted file mode 100644
--- a/build/build-clang/clang-win32-st-an.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
-    "llvm_revision": "317840",
-    "stages": "3",
-    "build_libcxx": false,
-    "build_type": "Release",
-    "assertions": false,
-    "llvm_repo": "https://llvm.org/svn/llvm-project/llvm/trunk",
-    "clang_repo": "https://llvm.org/svn/llvm-project/cfe/trunk",
-    "lld_repo": "https://llvm.org/svn/llvm-project/lld/trunk",
-    "compiler_repo": "https://llvm.org/svn/llvm-project/compiler-rt/trunk",
-    "libcxx_repo": "https://llvm.org/svn/llvm-project/libcxx/trunk",
-    "python_path": "c:/mozilla-build/python/python.exe",
-    "cc": "cl.exe",
-    "cxx": "cl.exe",
-    "patches": [
-      "r318309.patch",
-      "r320462.patch",
-      "msvc-host-x64.patch",
-      "aarch64-vastart-checking.patch",
-      "loosen-msvc-detection.patch"
-    ]
-}
deleted file mode 100644
--- a/build/build-clang/msvc-host-x64.patch
+++ /dev/null
@@ -1,17 +0,0 @@
-When looking for a linker, 32-bit clang-cl.exe wants to use the 32-bit-native link.exe located in Hostx86/x86, but this executable does not exist in our releng package, because we only use 64-bit-host toolchains.
-
-This patch makes clang-cl use the Hostx64/x86 linker instead. Ideally we wouldn't be using 32-bit clang-cl.exe in the first place. Bug 1414287 is on file to do so and remove this hack.
-
-diff --git a/clang/lib/Driver/ToolChains/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp
---- a/clang/lib/Driver/ToolChains/MSVC.cpp
-+++ b/clang/lib/Driver/ToolChains/MSVC.cpp
-@@ -817,8 +816,7 @@
-   switch (Type) {
-   case SubDirectoryType::Bin:
-     if (VSLayout == ToolsetLayout::VS2017OrNewer) {
--      const bool HostIsX64 =
--          llvm::Triple(llvm::sys::getProcessTriple()).isArch64Bit();
-+      const bool HostIsX64 = true;
-       const char *const HostName = HostIsX64 ? "HostX64" : "HostX86";
-       llvm::sys::path::append(Path, "bin", HostName, SubdirName);
-     } else { // OlderVS or DevDivInternal
--- a/build/mach_bootstrap.py
+++ b/build/mach_bootstrap.py
@@ -127,16 +127,23 @@ def search_path(mozilla_dir, packages_tx
     def handle_package(package):
         if package[0] == 'optional':
             try:
                 for path in handle_package(package[1:]):
                     yield path
             except Exception:
                 pass
 
+        if package[0] in ('windows', '!windows'):
+            for_win = not package[0].startswith('!')
+            is_win = sys.platform == 'win32'
+            if is_win == for_win:
+                for path in handle_package(package[1:]):
+                    yield path
+
         if package[0] == 'packages.txt':
             assert len(package) == 2
             for p in search_path(mozilla_dir, package[1]):
                 yield os.path.join(mozilla_dir, p)
 
         if package[0].endswith('.pth'):
             assert len(package) == 2
             yield os.path.join(mozilla_dir, package[1])
--- a/build/virtualenv_packages.txt
+++ b/build/virtualenv_packages.txt
@@ -17,24 +17,26 @@ mozilla.pth:third_party/python/dlmanager
 mozilla.pth:third_party/python/fluent
 mozilla.pth:third_party/python/funcsigs
 mozilla.pth:third_party/python/futures
 mozilla.pth:third_party/python/more-itertools
 mozilla.pth:third_party/python/gyp/pylib
 mozilla.pth:third_party/python/python-hglib
 mozilla.pth:third_party/python/pluggy
 mozilla.pth:third_party/python/jsmin
-optional:setup.py:third_party/python/psutil:build_ext:--inplace
-mozilla.pth:third_party/python/psutil
+!windows:optional:setup.py:third_party/python/psutil:build_ext:--inplace
+!windows:mozilla.pth:third_party/python/psutil
+windows:mozilla.pth:third_party/python/psutil-cp27-none-win_amd64
 mozilla.pth:third_party/python/pylru
 mozilla.pth:third_party/python/which
 mozilla.pth:third_party/python/pystache
 mozilla.pth:third_party/python/pyyaml/lib
 mozilla.pth:third_party/python/requests
 mozilla.pth:third_party/python/requests-unixsocket
+mozilla.pth:third_party/python/scandir
 mozilla.pth:third_party/python/slugid
 mozilla.pth:third_party/python/py
 mozilla.pth:third_party/python/pytest/src
 mozilla.pth:third_party/python/pytoml
 mozilla.pth:third_party/python/redo
 mozilla.pth:third_party/python/six
 mozilla.pth:third_party/python/voluptuous
 mozilla.pth:third_party/python/json-e
--- a/build/win32/mozconfig.vs2017
+++ b/build/win32/mozconfig.vs2017
@@ -4,28 +4,31 @@ if [ -z "${VSPATH}" ]; then
 fi
 
 if [ -d "${VSPATH}" ]; then
     VSWINPATH="$(cd ${VSPATH} && pwd -W)"
 
     export WINDOWSSDKDIR="${VSWINPATH}/SDK"
     export WIN32_REDIST_DIR="${VSPATH}/VC/redist/x86/Microsoft.VC141.CRT"
     export WIN_UCRT_REDIST_DIR="${VSPATH}/SDK/Redist/ucrt/DLLs/x86"
-    export WIN_DIA_SDK_BIN_DIR="${VSPATH}/DIA SDK/bin"
+    export WIN_DIA_SDK_BIN_DIR="${VSPATH}/DIA SDK/bin/amd64"
 
     export PATH="${VSPATH}/VC/bin/Hostx86/x86:${VSPATH}/VC/bin/Hostx64/x86:${VSPATH}/VC/bin/Hostx64/x64:${VSPATH}/SDK/bin/10.0.17134.0/x64:${WIN_DIA_SDK_BIN_DIR}:${PATH}"
     export PATH="${VSPATH}/VC/redist/x86/Microsoft.VC141.CRT:${VSPATH}/SDK/Redist/ucrt/DLLs/x86:${PATH}"
 
     export INCLUDE="${VSPATH}/VC/include:${VSPATH}/VC/atlmfc/include:${VSPATH}/SDK/Include/10.0.17134.0/ucrt:${VSPATH}/SDK/Include/10.0.17134.0/shared:${VSPATH}/SDK/Include/10.0.17134.0/um:${VSPATH}/SDK/Include/10.0.17134.0/winrt:${VSPATH}/DIA SDK/include"
     export LIB="${VSPATH}/VC/lib/x86:${VSPATH}/VC/atlmfc/lib/x86:${VSPATH}/SDK/Lib/10.0.17134.0/ucrt/x86:${VSPATH}/SDK/Lib/10.0.17134.0/um/x86:${VSPATH}/DIA SDK/lib"
 
     export WIN64_LINK="${VSPATH}/VC/bin/Hostx64/x64/link.exe"
     export WIN64_LIB="${VSPATH}/VC/lib/x64:${VSPATH}/VC/atlmfc/lib/x64:${VSPATH}/SDK/Lib/10.0.17134.0/ucrt/x64:${VSPATH}/SDK/Lib/10.0.17134.0/um/x64:${VSPATH}/DIA SDK/lib/amd64"
 fi
 
+ac_add_options --target=i686-pc-mingw32
+ac_add_options --host=x86_64-pc-mingw32
+
 . $topsrcdir/build/mozconfig.vs-common
 
 mk_export_correct_style WINDOWSSDKDIR
 mk_export_correct_style WIN32_REDIST_DIR
 mk_export_correct_style WIN_UCRT_REDIST_DIR
 mk_export_correct_style WIN_DIA_SDK_BIN_DIR
 mk_export_correct_style PATH
 mk_export_correct_style INCLUDE
--- a/config/config.mk
+++ b/config/config.mk
@@ -196,16 +196,23 @@ COMPILE_CMFLAGS = $(MOZ_LTO_CFLAGS) $(OS
 COMPILE_CMMFLAGS = $(MOZ_LTO_CFLAGS) $(OS_COMPILE_CMMFLAGS) $(MOZBUILD_CMMFLAGS)
 ASFLAGS = $(COMPUTED_ASFLAGS)
 SFLAGS = $(COMPUTED_SFLAGS)
 
 HOST_CFLAGS = $(COMPUTED_HOST_CFLAGS) $(_DEPEND_CFLAGS)
 HOST_CXXFLAGS = $(COMPUTED_HOST_CXXFLAGS) $(_DEPEND_CFLAGS)
 HOST_C_LDFLAGS = $(COMPUTED_HOST_C_LDFLAGS)
 HOST_CXX_LDFLAGS = $(COMPUTED_HOST_CXX_LDFLAGS)
+# Win32 Cross-builds on win64 need to override LIB when invoking the linker,
+# which we do for rust through cargo-linker.bat, so we abuse it here.
+# Ideally, we'd empty LIB and pass -LIBPATH options to the linker somehow but
+# we don't have this in place for rust, so...
+ifdef WIN64_CARGO_LINKER
+HOST_LINKER = $(topobjdir)/build/win64/cargo-linker.bat
+endif
 
 ifdef MOZ_LTO
 ifeq (Darwin,$(OS_TARGET))
 # When linking on macOS, debug info is not linked along with the final binary,
 # and the dwarf data stays in object files until they are "linked" with the
 # dsymutil tool.
 # With LTO, object files are temporary, and are not kept around, which
 # means there's no object file for dsymutil to do its job. Consequently,
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -7961,217 +7961,208 @@ nsContentUtils::TransferableToIPCTransfe
                                               IPCDataTransfer* aIPCDataTransfer,
                                               bool aInSyncMessage,
                                               mozilla::dom::nsIContentChild* aChild,
                                               mozilla::dom::nsIContentParent* aParent)
 {
   MOZ_ASSERT((aChild && !aParent) || (!aChild && aParent));
 
   if (aTransferable) {
-    nsCOMPtr<nsIArray> flavorList;
-    aTransferable->FlavorsTransferableCanExport(getter_AddRefs(flavorList));
-    if (flavorList) {
-      uint32_t flavorCount = 0;
-      flavorList->GetLength(&flavorCount);
-      for (uint32_t j = 0; j < flavorCount; ++j) {
-        nsCOMPtr<nsISupportsCString> flavor = do_QueryElementAt(flavorList, j);
-        if (!flavor) {
-          continue;
-        }
-
-        nsAutoCString flavorStr;
-        flavor->GetData(flavorStr);
-        if (!flavorStr.Length()) {
+    nsTArray<nsCString> flavorList;
+    aTransferable->FlavorsTransferableCanExport(flavorList);
+
+    for (uint32_t j = 0; j < flavorList.Length(); ++j) {
+      nsCString& flavorStr = flavorList[j];
+      if (!flavorStr.Length()) {
+        continue;
+      }
+
+      nsCOMPtr<nsISupports> data;
+      uint32_t dataLen = 0;
+      aTransferable->GetTransferData(flavorStr.get(), getter_AddRefs(data), &dataLen);
+
+      nsCOMPtr<nsISupportsString> text = do_QueryInterface(data);
+      nsCOMPtr<nsISupportsCString> ctext = do_QueryInterface(data);
+      if (text) {
+        nsAutoString dataAsString;
+        text->GetData(dataAsString);
+        IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement();
+        item->flavor() = flavorStr;
+        item->data() = dataAsString;
+      } else if (ctext) {
+        nsAutoCString dataAsString;
+        ctext->GetData(dataAsString);
+        IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement();
+        item->flavor() = flavorStr;
+
+        Shmem dataAsShmem = ConvertToShmem(aChild, aParent, dataAsString);
+        if (!dataAsShmem.IsReadable() || !dataAsShmem.Size<char>()) {
           continue;
         }
 
-        nsCOMPtr<nsISupports> data;
-        uint32_t dataLen = 0;
-        aTransferable->GetTransferData(flavorStr.get(), getter_AddRefs(data), &dataLen);
-
-        nsCOMPtr<nsISupportsString> text = do_QueryInterface(data);
-        nsCOMPtr<nsISupportsCString> ctext = do_QueryInterface(data);
-        if (text) {
-          nsAutoString dataAsString;
-          text->GetData(dataAsString);
+        item->data() = dataAsShmem;
+      } else {
+        // Images to be pasted on the clipboard are nsIInputStreams
+        nsCOMPtr<nsIInputStream> stream(do_QueryInterface(data));
+        if (stream) {
           IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement();
           item->flavor() = flavorStr;
-          item->data() = dataAsString;
-        } else if (ctext) {
-          nsAutoCString dataAsString;
-          ctext->GetData(dataAsString);
-          IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement();
-          item->flavor() = flavorStr;
-
-          Shmem dataAsShmem = ConvertToShmem(aChild, aParent, dataAsString);
-          if (!dataAsShmem.IsReadable() || !dataAsShmem.Size<char>()) {
+
+          nsCString imageData;
+          NS_ConsumeStream(stream, UINT32_MAX, imageData);
+
+          Shmem imageDataShmem = ConvertToShmem(aChild, aParent, imageData);
+          if (!imageDataShmem.IsReadable() || !imageDataShmem.Size<char>()) {
             continue;
           }
 
-          item->data() = dataAsShmem;
-        } else {
-          // Images to be pasted on the clipboard are nsIInputStreams
-          nsCOMPtr<nsIInputStream> stream(do_QueryInterface(data));
-          if (stream) {
-            IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement();
-            item->flavor() = flavorStr;
-
-            nsCString imageData;
-            NS_ConsumeStream(stream, UINT32_MAX, imageData);
-
-            Shmem imageDataShmem = ConvertToShmem(aChild, aParent, imageData);
-            if (!imageDataShmem.IsReadable() || !imageDataShmem.Size<char>()) {
-              continue;
-            }
-
-            item->data() = imageDataShmem;
+          item->data() = imageDataShmem;
+          continue;
+        }
+
+        // Images to be placed on the clipboard are imgIContainers.
+        nsCOMPtr<imgIContainer> image(do_QueryInterface(data));
+        if (image) {
+          RefPtr<mozilla::gfx::SourceSurface> surface =
+            image->GetFrame(imgIContainer::FRAME_CURRENT,
+                            imgIContainer::FLAG_SYNC_DECODE);
+          if (!surface) {
+            continue;
+          }
+          RefPtr<mozilla::gfx::DataSourceSurface> dataSurface =
+            surface->GetDataSurface();
+          if (!dataSurface) {
+            continue;
+          }
+          size_t length;
+          int32_t stride;
+          IShmemAllocator* allocator = aChild ? static_cast<IShmemAllocator*>(aChild)
+                                              : static_cast<IShmemAllocator*>(aParent);
+          Maybe<Shmem> surfaceData = GetSurfaceData(dataSurface, &length, &stride,
+                                                    allocator);
+
+          if (surfaceData.isNothing()) {
             continue;
           }
 
-          // Images to be placed on the clipboard are imgIContainers.
-          nsCOMPtr<imgIContainer> image(do_QueryInterface(data));
-          if (image) {
-            RefPtr<mozilla::gfx::SourceSurface> surface =
-              image->GetFrame(imgIContainer::FRAME_CURRENT,
-                              imgIContainer::FLAG_SYNC_DECODE);
-            if (!surface) {
-              continue;
-            }
-            RefPtr<mozilla::gfx::DataSourceSurface> dataSurface =
-              surface->GetDataSurface();
-            if (!dataSurface) {
-              continue;
+          IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement();
+          item->flavor() = flavorStr;
+          // Turn item->data() into an nsCString prior to accessing it.
+          item->data() = surfaceData.ref();
+
+          IPCDataTransferImage& imageDetails = item->imageDetails();
+          mozilla::gfx::IntSize size = dataSurface->GetSize();
+          imageDetails.width() = size.width;
+          imageDetails.height() = size.height;
+          imageDetails.stride() = stride;
+          imageDetails.format() = dataSurface->GetFormat();
+
+          continue;
+        }
+
+        // Otherwise, handle this as a file.
+        nsCOMPtr<BlobImpl> blobImpl;
+        nsCOMPtr<nsIFile> file = do_QueryInterface(data);
+        if (file) {
+          // If we can send this over as a blob, do so. Otherwise, we're
+          // responding to a sync message and the child can't process the blob
+          // constructor before processing our response, which would crash. In
+          // that case, hope that the caller is nsClipboardProxy::GetData,
+          // called from editor and send over images as raw data.
+          if (aInSyncMessage) {
+            nsAutoCString type;
+            if (IsFileImage(file, type)) {
+              IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement();
+              item->flavor() = type;
+              nsAutoCString data;
+              SlurpFileToString(file, data);
+
+              Shmem dataAsShmem = ConvertToShmem(aChild, aParent, data);
+              item->data() = dataAsShmem;
             }
-            size_t length;
-            int32_t stride;
-            IShmemAllocator* allocator = aChild ? static_cast<IShmemAllocator*>(aChild)
-                                                : static_cast<IShmemAllocator*>(aParent);
-            Maybe<Shmem> surfaceData = GetSurfaceData(dataSurface, &length, &stride,
-                                                      allocator);
-
-            if (surfaceData.isNothing()) {
-              continue;
-            }
-
-            IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement();
-            item->flavor() = flavorStr;
-            // Turn item->data() into an nsCString prior to accessing it.
-            item->data() = surfaceData.ref();
-
-            IPCDataTransferImage& imageDetails = item->imageDetails();
-            mozilla::gfx::IntSize size = dataSurface->GetSize();
-            imageDetails.width() = size.width;
-            imageDetails.height() = size.height;
-            imageDetails.stride() = stride;
-            imageDetails.format() = dataSurface->GetFormat();
 
             continue;
           }
 
-          // Otherwise, handle this as a file.
-          nsCOMPtr<BlobImpl> blobImpl;
-          nsCOMPtr<nsIFile> file = do_QueryInterface(data);
-          if (file) {
-            // If we can send this over as a blob, do so. Otherwise, we're
-            // responding to a sync message and the child can't process the blob
-            // constructor before processing our response, which would crash. In
-            // that case, hope that the caller is nsClipboardProxy::GetData,
-            // called from editor and send over images as raw data.
-            if (aInSyncMessage) {
-              nsAutoCString type;
-              if (IsFileImage(file, type)) {
-                IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement();
-                item->flavor() = type;
-                nsAutoCString data;
-                SlurpFileToString(file, data);
-
-                Shmem dataAsShmem = ConvertToShmem(aChild, aParent, data);
-                item->data() = dataAsShmem;
+          if (aParent) {
+            bool isDir = false;
+            if (NS_SUCCEEDED(file->IsDirectory(&isDir)) && isDir) {
+              nsAutoString path;
+              if (NS_WARN_IF(NS_FAILED(file->GetPath(path)))) {
+                continue;
               }
 
-              continue;
+              RefPtr<FileSystemSecurity> fss = FileSystemSecurity::GetOrCreate();
+              fss->GrantAccessToContentProcess(aParent->ChildID(), path);
             }
-
-            if (aParent) {
-              bool isDir = false;
-              if (NS_SUCCEEDED(file->IsDirectory(&isDir)) && isDir) {
-                nsAutoString path;
-                if (NS_WARN_IF(NS_FAILED(file->GetPath(path)))) {
-                  continue;
-                }
-
-                RefPtr<FileSystemSecurity> fss = FileSystemSecurity::GetOrCreate();
-                fss->GrantAccessToContentProcess(aParent->ChildID(), path);
-              }
-            }
-
-            blobImpl = new FileBlobImpl(file);
-
-            IgnoredErrorResult rv;
-
-            // Ensure that file data is cached no that the content process
-            // has this data available to it when passed over:
-            blobImpl->GetSize(rv);
-            if (NS_WARN_IF(rv.Failed())) {
+          }
+
+          blobImpl = new FileBlobImpl(file);
+
+          IgnoredErrorResult rv;
+
+          // Ensure that file data is cached no that the content process
+          // has this data available to it when passed over:
+          blobImpl->GetSize(rv);
+          if (NS_WARN_IF(rv.Failed())) {
+            continue;
+          }
+
+          blobImpl->GetLastModified(rv);
+          if (NS_WARN_IF(rv.Failed())) {
+            continue;
+          }
+        } else {
+          if (aInSyncMessage) {
+            // Can't do anything.
+            continue;
+          }
+          blobImpl = do_QueryInterface(data);
+        }
+        if (blobImpl) {
+          IPCDataTransferData data;
+          IPCBlob ipcBlob;
+
+          // If we failed to create the blob actor, then this blob probably
+          // can't get the file size for the underlying file, ignore it for
+          // now. TODO pass this through anyway.
+          if (aChild) {
+            nsresult rv = IPCBlobUtils::Serialize(blobImpl, aChild, ipcBlob);
+            if (NS_WARN_IF(NS_FAILED(rv))) {
               continue;
             }
 
-            blobImpl->GetLastModified(rv);
-            if (NS_WARN_IF(rv.Failed())) {
-              continue;
-            }
-          } else {
-            if (aInSyncMessage) {
-              // Can't do anything.
+            data = ipcBlob;
+          } else if (aParent) {
+            nsresult rv = IPCBlobUtils::Serialize(blobImpl, aParent, ipcBlob);
+            if (NS_WARN_IF(NS_FAILED(rv))) {
               continue;
             }
-            blobImpl = do_QueryInterface(data);
+
+            data = ipcBlob;
           }
-          if (blobImpl) {
-            IPCDataTransferData data;
-            IPCBlob ipcBlob;
-
-            // If we failed to create the blob actor, then this blob probably
-            // can't get the file size for the underlying file, ignore it for
-            // now. TODO pass this through anyway.
-            if (aChild) {
-              nsresult rv = IPCBlobUtils::Serialize(blobImpl, aChild, ipcBlob);
-              if (NS_WARN_IF(NS_FAILED(rv))) {
-                continue;
-              }
-
-              data = ipcBlob;
-            } else if (aParent) {
-              nsresult rv = IPCBlobUtils::Serialize(blobImpl, aParent, ipcBlob);
-              if (NS_WARN_IF(NS_FAILED(rv))) {
-                continue;
-              }
-
-              data = ipcBlob;
-            }
-
+
+          IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement();
+          item->flavor() = flavorStr;
+          item->data() = data;
+        } else {
+          // This is a hack to support kFilePromiseMime.
+          // On Windows there just needs to be an entry for it,
+          // and for OSX we need to create
+          // nsContentAreaDragDropDataProvider as nsIFlavorDataProvider.
+          if (flavorStr.EqualsLiteral(kFilePromiseMime)) {
             IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement();
             item->flavor() = flavorStr;
-            item->data() = data;
-          } else {
-            // This is a hack to support kFilePromiseMime.
-            // On Windows there just needs to be an entry for it,
-            // and for OSX we need to create
-            // nsContentAreaDragDropDataProvider as nsIFlavorDataProvider.
-            if (flavorStr.EqualsLiteral(kFilePromiseMime)) {
-              IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement();
-              item->flavor() = flavorStr;
-              item->data() = NS_ConvertUTF8toUTF16(flavorStr);
-            } else if (!data) {
-              // Empty element, transfer only the flavor
-              IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement();
-              item->flavor() = flavorStr;
-              item->data() = nsString();
-              continue;
-            }
+            item->data() = NS_ConvertUTF8toUTF16(flavorStr);
+          } else if (!data) {
+            // Empty element, transfer only the flavor
+            IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement();
+            item->flavor() = flavorStr;
+            item->data() = nsString();
+            continue;
           }
         }
       }
     }
   }
 }
 
 namespace {
--- a/gfx/graphite2/src/moz.build
+++ b/gfx/graphite2/src/moz.build
@@ -38,32 +38,27 @@ UNIFIED_SOURCES += [
     'gr_features.cpp',
     'gr_font.cpp',
     'gr_logging.cpp',
     'gr_segment.cpp',
     'gr_slot.cpp',
     'Intervals.cpp',
     'json.cpp',
     'Justifier.cpp',
+    'NameTable.cpp',
     'Pass.cpp',
     'Position.cpp',
     'Segment.cpp',
     'Silf.cpp',
     'Slot.cpp',
     'Sparse.cpp',
     'TtfUtil.cpp',
     'UtfCodec.cpp',
 ]
 
-# Excluded from UNIFIED_SOURCES because <cmath> from other files breaks it,
-# see bug 1272647.
-SOURCES += [
-    'NameTable.cpp',
-]
-
 # tell graphite2 not to export symbols, we'll be linking it directly with
 # thebes
 DEFINES['GRAPHITE2_STATIC'] = True
 
 # We allow warnings for third-party code that can be updated from upstream.
 AllowCompilerWarnings()
 
 FINAL_LIBRARY = 'gkmedias'
--- a/gfx/layers/apz/test/mochitest/mochitest.ini
+++ b/gfx/layers/apz/test/mochitest/mochitest.ini
@@ -21,16 +21,18 @@
 [test_group_pointerevents.html]
   skip-if = os == 'win' && os_version == '10.0' # Bug 1404836
 [test_group_touchevents.html]
   skip-if = (verify && debug && (os == 'win'))
 [test_group_touchevents-2.html]
   skip-if = (verify && debug && (os == 'win'))
 [test_group_touchevents-3.html]
   skip-if = (verify && debug && (os == 'win'))
+[test_group_touchevents-4.html]
+  skip-if = (verify && debug && (os == 'win'))
 [test_group_wheelevents.html]
   skip-if = (toolkit == 'android') # wheel events not supported on mobile
 [test_group_zoom.html]
   skip-if = (os == 'win') || webrender # zooming is not supported yet on WebRender; see bug 1495580 for Windows
 [test_interrupted_reflow.html]
 [test_group_keyboard.html]
 [test_layerization.html]
   skip-if = (os == 'android') # wheel events not supported on mobile
--- a/gfx/layers/apz/test/mochitest/test_group_touchevents-2.html
+++ b/gfx/layers/apz/test/mochitest/test_group_touchevents-2.html
@@ -33,17 +33,17 @@ var subtests = [
   // end up waiting.
   {'file': 'helper_tap_passive.html', 'prefs': [["apz.content_response_timeout", 24 * 60 * 60 * 1000],
                                                 ["apz.test.fails_with_native_injection", isWindows]]},
 
   {'file': 'helper_tap_default_passive.html', 'prefs': [["apz.content_response_timeout", 24 * 60 * 60 * 1000],
                                                         ["apz.test.fails_with_native_injection", isWindows],
                                                         ["dom.event.default_to_passive_touch_listeners", true]]},
 
-  // Add new subtests to test_group_touch_events-3.html, not this file.
+  // Add new subtests to test_group_touch_events-4.html, not this file.
 ];
 
 if (isApzEnabled()) {
   ok(window.TouchEvent, "Check if TouchEvent is supported (it should be, the test harness forces it on everywhere)");
   if (getPlatform() == "android") {
     // This has a lot of subtests, and Android emulators are slow.
     SimpleTest.requestLongerTimeout(2);
   }
--- a/gfx/layers/apz/test/mochitest/test_group_touchevents-3.html
+++ b/gfx/layers/apz/test/mochitest/test_group_touchevents-3.html
@@ -18,21 +18,18 @@ var touch_action_prefs = [
 var subtests = [
   // Simple test to exercise touch-action CSS property
   {'file': 'helper_touch_action.html', 'prefs': touch_action_prefs},
   // More complex touch-action tests, with overlapping regions and such
   {'file': 'helper_touch_action_complex.html', 'prefs': touch_action_prefs},
   // Tests that touch-action CSS properties are handled in APZ without waiting
   // on the main-thread, when possible
   {'file': 'helper_touch_action_regions.html', 'prefs': touch_action_prefs},
-  // touch-action tests with :active::after CSS property
-  {'file': 'helper_bug1473108.html'},
-  // Add new subtests here. If this starts timing out because it's taking too
-  // long, create a test_group_touchevents-4.html file. Refer to 1423011#c57
-  // for more details.
+
+  // Add new subtests to test_group_touch_events-4.html, not this file.
 ];
 
 if (isApzEnabled()) {
   ok(window.TouchEvent, "Check if TouchEvent is supported (it should be, the test harness forces it on everywhere)");
   if (getPlatform() == "android") {
     // This has a lot of subtests, and Android emulators are slow.
     SimpleTest.requestLongerTimeout(2);
   }
new file mode 100644
--- /dev/null
+++ b/gfx/layers/apz/test/mochitest/test_group_touchevents-4.html
@@ -0,0 +1,38 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Various touch tests that spawn in new windows (4)</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="apz_test_native_event_utils.js"></script>
+  <script type="application/javascript" src="apz_test_utils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="application/javascript">
+
+var subtests = [
+  // touch-action tests with :active::after CSS property
+  {'file': 'helper_bug1473108.html'},
+  // Add new subtests here. If this starts timing out because it's taking too
+  // long, create a test_group_touchevents-5.html file. Refer to 1423011#c57
+  // for more details.
+];
+
+if (isApzEnabled()) {
+  ok(window.TouchEvent, "Check if TouchEvent is supported (it should be, the test harness forces it on everywhere)");
+  if (getPlatform() == "android") {
+    // This has a lot of subtests, and Android emulators are slow.
+    SimpleTest.requestLongerTimeout(2);
+  }
+
+  SimpleTest.waitForExplicitFinish();
+  window.onload = function() {
+    runSubtestsSeriallyInFreshWindows(subtests)
+    .then(SimpleTest.finish, SimpleTest.finish);
+  };
+}
+
+  </script>
+</head>
+<body>
+</body>
+</html>
--- a/gfx/layers/apz/test/mochitest/test_group_touchevents.html
+++ b/gfx/layers/apz/test/mochitest/test_group_touchevents.html
@@ -22,17 +22,17 @@ var subtests = [
   // Tapping, but with a full-zoom applied
   {'file': 'helper_tap_fullzoom.html'},
 
   // For the following two tests, disable displayport suppression to make sure it
   // doesn't interfere with the test by scheduling paints non-deterministically.
   {'file': 'helper_scrollto_tap.html?true', 'prefs': [["apz.paint_skipping.enabled", true]], 'dp_suppression': false},
   {'file': 'helper_scrollto_tap.html?false', 'prefs': [["apz.paint_skipping.enabled", false]], 'dp_suppression': false},
 
-  // Add new subtests to test_group_touch_events-3.html, not this file.
+  // Add new subtests to test_group_touch_events-4.html, not this file.
 ];
 
 if (isApzEnabled()) {
   ok(window.TouchEvent, "Check if TouchEvent is supported (it should be, the test harness forces it on everywhere)");
   if (getPlatform() == "android") {
     // This has a lot of subtests, and Android emulators are slow.
     SimpleTest.requestLongerTimeout(2);
   }
--- a/gfx/webrender_bindings/src/moz2d_renderer.rs
+++ b/gfx/webrender_bindings/src/moz2d_renderer.rs
@@ -432,87 +432,107 @@ struct BlobFont {
 #[derive(Clone)]
 struct BlobCommand {
     /// The blob.
     data: Arc<BlobImageData>,
     /// The size of the tiles to use in rasterization, if tiling should be used.
     tile_size: Option<TileSize>,
 }
 
+ struct Job {
+    request: BlobImageRequest,
+    descriptor: BlobImageDescriptor,
+    commands: Arc<BlobImageData>,
+    dirty_rect: Option<DeviceUintRect>,
+    tile_size: Option<TileSize>,
+}
+
 /// Rasterizes gecko blob images.
 struct Moz2dBlobRasterizer {
     /// Pool of rasterizers.
     workers: Arc<ThreadPool>,
     /// Blobs to rasterize.
     blob_commands: HashMap<ImageKey, BlobCommand>,
 }
 
 impl AsyncBlobImageRasterizer for Moz2dBlobRasterizer {
    
-    fn rasterize(&mut self, requests: &[BlobImageParams], _low_priority: bool) -> Vec<(BlobImageRequest, BlobImageResult)> {
+    fn rasterize(&mut self, requests: &[BlobImageParams], low_priority: bool) -> Vec<(BlobImageRequest, BlobImageResult)> {
         // All we do here is spin up our workers to callback into gecko to replay the drawing commands.
 
-        struct Job {
-            request: BlobImageRequest,
-            descriptor: BlobImageDescriptor,
-            commands: Arc<BlobImageData>,
-            dirty_rect: Option<DeviceUintRect>,
-            tile_size: Option<TileSize>,
-        }
-
         let requests: Vec<Job> = requests.into_iter().map(|params| {
             let command = &self.blob_commands[&params.request.key];
             let blob = Arc::clone(&command.data);
             Job {
                 request: params.request,
                 descriptor: params.descriptor,
                 commands: blob,
                 dirty_rect: params.dirty_rect,
                 tile_size: command.tile_size,
             }
         }).collect();
 
-        self.workers.install(|| {
-            requests.into_par_iter().map(|item| {
-                let descriptor = item.descriptor;
-                let buf_size = (descriptor.size.width
-                    * descriptor.size.height
-                    * descriptor.format.bytes_per_pixel()) as usize;
+        // If we don't have a lot of blobs it is probably not worth the initial cost
+        // of installing work on rayon's thread pool so we do it serially on this thread.
+        let should_parallelize = if low_priority {
+            requests.len() > 2
+        } else {
+            // For high priority requests we don't "risk" the potential priority inversion of
+            // dispatching to a thread pool full of low priority jobs unless it is really
+            // appealing.
+            requests.len() > 4
+        };
 
-                let mut output = vec![0u8; buf_size];
+        if should_parallelize {
+            // Parallel version synchronously installs a job on the thread pool which will
+            // try to do the work in parallel.
+            // This thread is blocked until the thread pool is done doing the work.
+            self.workers.install(||{
+                requests.into_par_iter().map(rasterize_blob).collect()
+            })
+        } else {
+            requests.into_iter().map(rasterize_blob).collect()
+        }
+    }
+}
 
-                let result = unsafe {
-                    if wr_moz2d_render_cb(
-                        ByteSlice::new(&item.commands[..]),
-                        descriptor.size.width,
-                        descriptor.size.height,
-                        descriptor.format,
-                        item.tile_size.as_ref(),
-                        item.request.tile.as_ref(),
-                        item.dirty_rect.as_ref(),
-                        MutByteSlice::new(output.as_mut_slice()),
-                    ) {
-                        Ok(RasterizedBlobImage {
-                            rasterized_rect: item.dirty_rect.unwrap_or(
-                                DeviceUintRect {
-                                    origin: DeviceUintPoint::origin(),
-                                    size: descriptor.size,
-                                }
-                            ),
-                            data: Arc::new(output),
-                        })
-                    } else {
-                        panic!("Moz2D replay problem");
+fn rasterize_blob(job: Job) -> (BlobImageRequest, BlobImageResult) {
+    let descriptor = job.descriptor;
+    let buf_size = (descriptor.size.width
+        * descriptor.size.height
+        * descriptor.format.bytes_per_pixel()) as usize;
+
+    let mut output = vec![0u8; buf_size];
+
+    let result = unsafe {
+        if wr_moz2d_render_cb(
+            ByteSlice::new(&job.commands[..]),
+            descriptor.size.width,
+            descriptor.size.height,
+            descriptor.format,
+            job.tile_size.as_ref(),
+            job.request.tile.as_ref(),
+            job.dirty_rect.as_ref(),
+            MutByteSlice::new(output.as_mut_slice()),
+        ) {
+            Ok(RasterizedBlobImage {
+                rasterized_rect: job.dirty_rect.unwrap_or(
+                    DeviceUintRect {
+                        origin: DeviceUintPoint::origin(),
+                        size: descriptor.size,
                     }
-                };
+                ),
+                data: Arc::new(output),
+            })
+        } else {
+            panic!("Moz2D replay problem");
+        }
+    };
 
-                (item.request, result)
-            }).collect()
-        })
-    }
+    (job.request, result)    
 }
 
 impl BlobImageHandler for Moz2dBlobImageHandler {
     fn add(&mut self, key: ImageKey, data: Arc<BlobImageData>, tile_size: Option<TileSize>) {
         {
             let index = BlobReader::new(&data);
             assert!(index.reader.has_more());
         }
--- a/js/src/jit-test/tests/tracelogger/bug1138265.js
+++ b/js/src/jit-test/tests/tracelogger/bug1138265.js
@@ -1,9 +1,8 @@
-setJitCompilerOption("jit.enable-tracelogger", 1);
 try {
     (function(b, foreign, p) {
          "use asm"
          var ff = foreign.ff
          function f() {
             ff() | 0
          }
          return f
--- a/js/src/jit/BaselineCacheIRCompiler.cpp
+++ b/js/src/jit/BaselineCacheIRCompiler.cpp
@@ -406,17 +406,17 @@ BaselineCacheIRCompiler::emitGuardSpecif
     // function to do the comparison.
     LiveRegisterSet volatileRegs(GeneralRegisterSet::Volatile(), liveVolatileFloatRegs());
     masm.PushRegsInMask(volatileRegs);
 
     masm.setupUnalignedABICall(scratch);
     masm.loadPtr(atomAddr, scratch);
     masm.passABIArg(scratch);
     masm.passABIArg(str);
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, EqualStringsHelper));
+    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, EqualStringsHelperPure));
     masm.mov(ReturnReg, scratch);
 
     LiveRegisterSet ignore;
     ignore.add(scratch);
     masm.PopRegsInMaskIgnore(volatileRegs, ignore);
     masm.branchIfFalseBool(scratch, failure->label());
 
     masm.bind(&done);
@@ -492,17 +492,17 @@ BaselineCacheIRCompiler::emitGuardHasGet
     masm.PushRegsInMask(volatileRegs);
 
     masm.setupUnalignedABICall(scratch1);
     masm.loadJSContext(scratch1);
     masm.passABIArg(scratch1);
     masm.passABIArg(obj);
     masm.loadPtr(shapeAddr, scratch2);
     masm.passABIArg(scratch2);
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, ObjectHasGetterSetter));
+    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, ObjectHasGetterSetterPure));
     masm.mov(ReturnReg, scratch1);
     masm.PopRegsInMask(volatileRegs);
 
     masm.branchIfFalseBool(scratch1, failure->label());
     return true;
 }
 
 bool
@@ -1072,17 +1072,17 @@ BaselineCacheIRCompiler::emitAddAndStore
     bool changeGroup = reader.readBool();
     Address newGroupAddr = stubAddress(reader.stubOffset());
     Address newShapeAddr = stubAddress(reader.stubOffset());
 
     if (op == CacheOp::AllocateAndStoreDynamicSlot) {
         // We have to (re)allocate dynamic slots. Do this first, as it's the
         // only fallible operation here. This simplifies the callTypeUpdateIC
         // call below: it does not have to worry about saving registers used by
-        // failure paths. Note that growSlotsDontReportOOM is fallible but does
+        // failure paths. Note that growSlotsPure is fallible but does
         // not GC.
         Address numNewSlotsAddr = stubAddress(reader.stubOffset());
 
         FailurePath* failure;
         if (!addFailurePath(&failure)) {
             return false;
         }
 
@@ -1090,17 +1090,17 @@ BaselineCacheIRCompiler::emitAddAndStore
         masm.PushRegsInMask(save);
 
         masm.setupUnalignedABICall(scratch1);
         masm.loadJSContext(scratch1);
         masm.passABIArg(scratch1);
         masm.passABIArg(obj);
         masm.load32(numNewSlotsAddr, scratch2);
         masm.passABIArg(scratch2);
-        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, NativeObject::growSlotsDontReportOOM));
+        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, NativeObject::growSlotsPure));
         masm.mov(ReturnReg, scratch1);
 
         LiveRegisterSet ignore;
         ignore.add(scratch1);
         masm.PopRegsInMaskIgnore(save, ignore);
 
         masm.branchIfFalseBool(scratch1, failure->label());
     }
@@ -1421,17 +1421,17 @@ BaselineCacheIRCompiler::emitStoreDenseE
         LiveRegisterSet save(GeneralRegisterSet::Volatile(), liveVolatileFloatRegs());
         save.takeUnchecked(scratch);
         masm.PushRegsInMask(save);
 
         masm.setupUnalignedABICall(scratch);
         masm.loadJSContext(scratch);
         masm.passABIArg(scratch);
         masm.passABIArg(obj);
-        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, NativeObject::addDenseElementDontReportOOM));
+        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, NativeObject::addDenseElementPure));
         masm.mov(ReturnReg, scratch);
 
         masm.PopRegsInMask(save);
         masm.branchIfFalseBool(scratch, failure->label());
 
         // Load the reallocated elements pointer.
         masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratch);
 
@@ -1561,17 +1561,17 @@ BaselineCacheIRCompiler::emitArrayPush()
     LiveRegisterSet save(GeneralRegisterSet::Volatile(), liveVolatileFloatRegs());
     save.takeUnchecked(scratch);
     masm.PushRegsInMask(save);
 
     masm.setupUnalignedABICall(scratch);
     masm.loadJSContext(scratch);
     masm.passABIArg(scratch);
     masm.passABIArg(obj);
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, NativeObject::addDenseElementDontReportOOM));
+    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, NativeObject::addDenseElementPure));
     masm.mov(ReturnReg, scratch);
 
     masm.PopRegsInMask(save);
     masm.branchIfFalseBool(scratch, failure->label());
 
     // Load the reallocated elements pointer.
     masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratch);
 
--- a/js/src/jit/CacheIRCompiler.cpp
+++ b/js/src/jit/CacheIRCompiler.cpp
@@ -1960,36 +1960,36 @@ CacheIRCompiler::emitGuardAndGetNumberFr
         LiveRegisterSet volatileRegs(GeneralRegisterSet::Volatile(), liveVolatileFloatRegs());
         masm.PushRegsInMask(volatileRegs);
 
         masm.setupUnalignedABICall(scratch);
         masm.loadJSContext(scratch);
         masm.passABIArg(scratch);
         masm.passABIArg(str);
         masm.passABIArg(output.payloadOrValueReg());
-        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, StringToNumberDontReportOOM));
+        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, StringToNumberPure));
         masm.mov(ReturnReg, scratch);
 
         LiveRegisterSet ignore;
         ignore.add(scratch);
         masm.PopRegsInMaskIgnore(volatileRegs, ignore);
 
         Label ok;
         masm.branchIfTrueBool(scratch, &ok);
         {
-            // OOM path, recovered by StringToNumberDontReportOOM.
+            // OOM path, recovered by StringToNumberPure.
             //
             // Use addToStackPtr instead of freeStack as freeStack tracks stack height
             // flow-insensitively, and using it twice would confuse the stack height
-            // tracking. 
+            // tracking.
             masm.addToStackPtr(Imm32(sizeof(double)));
             masm.jump(failure->label());
         }
         masm.bind(&ok);
-        
+
         masm.loadDouble(Address(output.payloadOrValueReg(), 0), FloatReg0);
         masm.boxDouble(FloatReg0, output, FloatReg0);
         masm.freeStack(sizeof(double));
     }
     masm.bind(&done);
     return true;
 }
 
@@ -3798,17 +3798,17 @@ CacheIRCompiler::emitCallObjectHasSparse
     masm.PushRegsInMask(volatileRegs);
 
     masm.setupUnalignedABICall(scratch1);
     masm.loadJSContext(scratch1);
     masm.passABIArg(scratch1);
     masm.passABIArg(obj);
     masm.passABIArg(index);
     masm.passABIArg(scratch2);
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, HasNativeElement));
+    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, HasNativeElementPure));
     masm.mov(ReturnReg, scratch1);
     masm.PopRegsInMask(volatileRegs);
 
     Label ok;
     uint32_t framePushed = masm.framePushed();
     masm.branchIfTrueBool(scratch1, &ok);
     masm.adjustStack(sizeof(Value));
     masm.jump(failure->label());
@@ -3945,19 +3945,19 @@ CacheIRCompiler::emitMegamorphicLoadSlot
     masm.setupUnalignedABICall(scratch1);
     masm.loadJSContext(scratch1);
     masm.passABIArg(scratch1);
     masm.passABIArg(obj);
     emitLoadStubField(name, scratch2);
     masm.passABIArg(scratch2);
     masm.passABIArg(scratch3);
     if (handleMissing) {
-        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, (GetNativeDataProperty<true>)));
+        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, (GetNativeDataPropertyPure<true>)));
     } else {
-        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, (GetNativeDataProperty<false>)));
+        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, (GetNativeDataPropertyPure<false>)));
     }
     masm.mov(ReturnReg, scratch2);
     masm.PopRegsInMask(volatileRegs);
 
     masm.loadTypedOrValue(Address(masm.getStackPointer(), 0), output);
     masm.adjustStack(sizeof(Value));
 
     masm.branchIfFalseBool(scratch2, failure->label());
@@ -3996,19 +3996,19 @@ CacheIRCompiler::emitMegamorphicStoreSlo
     masm.setupUnalignedABICall(scratch1);
     masm.loadJSContext(scratch1);
     masm.passABIArg(scratch1);
     masm.passABIArg(obj);
     emitLoadStubField(name, scratch2);
     masm.passABIArg(scratch2);
     masm.passABIArg(val.scratchReg());
     if (needsTypeBarrier) {
-        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, (SetNativeDataProperty<true>)));
+        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, (SetNativeDataPropertyPure<true>)));
     } else {
-        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, (SetNativeDataProperty<false>)));
+        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, (SetNativeDataPropertyPure<false>)));
     }
     masm.mov(ReturnReg, scratch1);
     masm.PopRegsInMask(volatileRegs);
 
     masm.loadValue(Address(masm.getStackPointer(), 0), val);
     masm.adjustStack(sizeof(Value));
 
     masm.branchIfFalseBool(scratch1, failure->label());
@@ -4054,17 +4054,17 @@ CacheIRCompiler::emitCallInt32ToString()
     LiveRegisterSet volatileRegs(GeneralRegisterSet::Volatile(), liveVolatileFloatRegs());
     volatileRegs.takeUnchecked(result);
     masm.PushRegsInMask(volatileRegs);
 
     masm.setupUnalignedABICall(result);
     masm.loadJSContext(result);
     masm.passABIArg(result);
     masm.passABIArg(input);
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, (js::Int32ToStringHelper)));
+    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, (js::Int32ToStringHelperPure)));
 
     masm.mov(ReturnReg, result);
     masm.PopRegsInMask(volatileRegs);
 
     masm.branchPtr(Assembler::Equal, result, ImmPtr(0), failure->label());
     return true;
 }
 
@@ -4085,17 +4085,17 @@ CacheIRCompiler::emitCallNumberToString(
     volatileRegs.takeUnchecked(result);
     volatileRegs.addUnchecked(FloatReg0);
     masm.PushRegsInMask(volatileRegs);
 
     masm.setupUnalignedABICall(result);
     masm.loadJSContext(result);
     masm.passABIArg(result);
     masm.passABIArg(FloatReg0, MoveOp::DOUBLE);
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, (js::NumberToStringHelper)));
+    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, (js::NumberToStringHelperPure)));
 
     masm.mov(ReturnReg, result);
     masm.PopRegsInMask(volatileRegs);
 
     masm.branchPtr(Assembler::Equal, result, ImmPtr(0), failure->label());
     return true;
 }
 
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -6912,33 +6912,33 @@ CodeGenerator::visitCreateArgumentsObjec
     if (ArgumentsObject* templateObj = lir->mir()->templateObject()) {
         Register objTemp = ToRegister(lir->temp1());
         Register cxTemp = ToRegister(lir->temp2());
 
         masm.Push(callObj);
 
         // Try to allocate an arguments object. This will leave the reserved
         // slots uninitialized, so it's important we don't GC until we
-        // initialize these slots in ArgumentsObject::finishForIon.
+        // initialize these slots in ArgumentsObject::finishForIonPure.
         Label failure;
         TemplateObject templateObject(templateObj);
         masm.createGCObject(objTemp, temp, templateObject, gc::DefaultHeap, &failure,
                             /* initContents = */ false);
 
         masm.moveStackPtrTo(temp);
         masm.addPtr(Imm32(masm.framePushed()), temp);
 
         masm.setupUnalignedABICall(cxTemp);
         masm.loadJSContext(cxTemp);
         masm.passABIArg(cxTemp);
         masm.passABIArg(temp);
         masm.passABIArg(callObj);
         masm.passABIArg(objTemp);
 
-        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, ArgumentsObject::finishForIon));
+        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, ArgumentsObject::finishForIonPure));
         masm.branchTestPtr(Assembler::Zero, ReturnReg, ReturnReg, &failure);
 
         // Discard saved callObj on the stack.
         masm.addToStackPtr(Imm32(sizeof(uintptr_t)));
         masm.jump(&done);
 
         masm.bind(&failure);
         masm.Pop(callObj);
--- a/js/src/jit/IonCacheIRCompiler.cpp
+++ b/js/src/jit/IonCacheIRCompiler.cpp
@@ -829,17 +829,17 @@ IonCacheIRCompiler::emitGuardSpecificAto
     // function to do the comparison.
     LiveRegisterSet volatileRegs(GeneralRegisterSet::Volatile(), liveVolatileFloatRegs());
     masm.PushRegsInMask(volatileRegs);
 
     masm.setupUnalignedABICall(scratch);
     masm.movePtr(ImmGCPtr(atom), scratch);
     masm.passABIArg(scratch);
     masm.passABIArg(str);
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, EqualStringsHelper));
+    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, EqualStringsHelperPure));
     masm.mov(ReturnReg, scratch);
 
     LiveRegisterSet ignore;
     ignore.add(scratch);
     masm.PopRegsInMaskIgnore(volatileRegs, ignore);
     masm.branchIfFalseBool(scratch, failure->label());
 
     masm.bind(&done);
@@ -911,17 +911,17 @@ IonCacheIRCompiler::emitGuardHasGetterSe
     masm.PushRegsInMask(volatileRegs);
 
     masm.setupUnalignedABICall(scratch1);
     masm.loadJSContext(scratch1);
     masm.passABIArg(scratch1);
     masm.passABIArg(obj);
     masm.movePtr(ImmGCPtr(shape), scratch2);
     masm.passABIArg(scratch2);
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, ObjectHasGetterSetter));
+    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, ObjectHasGetterSetterPure));
     masm.mov(ReturnReg, scratch1);
     masm.PopRegsInMask(volatileRegs);
 
     masm.branchIfFalseBool(scratch1, failure->label());
     return true;
 }
 
 bool
@@ -1601,31 +1601,31 @@ IonCacheIRCompiler::emitAddAndStoreSlotS
     if (!addFailurePath(&failure)) {
         return false;
     }
 
     EmitCheckPropertyTypes(masm, typeCheckInfo_, obj, val, *liveRegs_, failure->label());
 
     if (op == CacheOp::AllocateAndStoreDynamicSlot) {
         // We have to (re)allocate dynamic slots. Do this first, as it's the
-        // only fallible operation here. Note that growSlotsDontReportOOM is
+        // only fallible operation here. Note that growSlotsPure is
         // fallible but does not GC.
         int32_t numNewSlots = int32StubField(reader.stubOffset());
         MOZ_ASSERT(numNewSlots > 0);
 
         LiveRegisterSet save(GeneralRegisterSet::Volatile(), liveVolatileFloatRegs());
         masm.PushRegsInMask(save);
 
         masm.setupUnalignedABICall(scratch1);
         masm.loadJSContext(scratch1);
         masm.passABIArg(scratch1);
         masm.passABIArg(obj);
         masm.move32(Imm32(numNewSlots), scratch2.ref());
         masm.passABIArg(scratch2.ref());
-        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, NativeObject::growSlotsDontReportOOM));
+        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, NativeObject::growSlotsPure));
         masm.mov(ReturnReg, scratch1);
 
         LiveRegisterSet ignore;
         ignore.add(scratch1);
         masm.PopRegsInMaskIgnore(save, ignore);
 
         masm.branchIfFalseBool(scratch1, failure->label());
     }
@@ -1950,17 +1950,17 @@ IonCacheIRCompiler::emitStoreDenseElemen
     LiveRegisterSet save(GeneralRegisterSet::Volatile(), liveVolatileFloatRegs());
     save.takeUnchecked(scratch1);
     masm.PushRegsInMask(save);
 
     masm.setupUnalignedABICall(scratch1);
     masm.loadJSContext(scratch1);
     masm.passABIArg(scratch1);
     masm.passABIArg(obj);
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, NativeObject::addDenseElementDontReportOOM));
+    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, NativeObject::addDenseElementPure));
     masm.mov(ReturnReg, scratch1);
 
     masm.PopRegsInMask(save);
     masm.branchIfFalseBool(scratch1, failure->label());
 
     // Load the reallocated elements pointer.
     masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratch1);
 
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -1596,17 +1596,17 @@ CallNativeSetter(JSContext* cx, HandleFu
     vp[0].setObject(*callee.get());
     vp[1].setObject(*obj.get());
     vp[2].set(rhs);
 
     return natfun(cx, 1, vp.begin());
 }
 
 bool
-EqualStringsHelper(JSString* str1, JSString* str2)
+EqualStringsHelperPure(JSString* str1, JSString* str2)
 {
     // IC code calls this directly so we shouldn't GC.
     AutoUnsafeCallWithABI unsafe;
 
     MOZ_ASSERT(str1->isAtom());
     MOZ_ASSERT(!str2->isAtom());
     MOZ_ASSERT(str1->length() == str2->length());
 
@@ -1627,17 +1627,17 @@ CheckIsCallable(JSContext* cx, HandleVal
         return ThrowCheckIsCallable(cx, kind);
     }
 
     return true;
 }
 
 template <bool HandleMissing>
 static MOZ_ALWAYS_INLINE bool
-GetNativeDataProperty(JSContext* cx, NativeObject* obj, jsid id, Value* vp)
+GetNativeDataPropertyPure(JSContext* cx, NativeObject* obj, jsid id, Value* vp)
 {
     // Fast path used by megamorphic IC stubs. Unlike our other property
     // lookup paths, this is optimized to be as fast as possible for simple
     // data property lookups.
 
     AutoUnsafeCallWithABI unsafe;
 
     MOZ_ASSERT(JSID_IS_ATOM(id) || JSID_IS_SYMBOL(id));
@@ -1672,28 +1672,28 @@ GetNativeDataProperty(JSContext* cx, Nat
             return false;
         }
         obj = &proto->as<NativeObject>();
     }
 }
 
 template <bool HandleMissing>
 bool
-GetNativeDataProperty(JSContext* cx, JSObject* obj, PropertyName* name, Value* vp)
+GetNativeDataPropertyPure(JSContext* cx, JSObject* obj, PropertyName* name, Value* vp)
 {
     // Condition checked by caller.
     MOZ_ASSERT(obj->isNative());
-    return GetNativeDataProperty<HandleMissing>(cx, &obj->as<NativeObject>(), NameToId(name), vp);
+    return GetNativeDataPropertyPure<HandleMissing>(cx, &obj->as<NativeObject>(), NameToId(name), vp);
 }
 
 template bool
-GetNativeDataProperty<true>(JSContext* cx, JSObject* obj, PropertyName* name, Value* vp);
+GetNativeDataPropertyPure<true>(JSContext* cx, JSObject* obj, PropertyName* name, Value* vp);
 
 template bool
-GetNativeDataProperty<false>(JSContext* cx, JSObject* obj, PropertyName* name, Value* vp);
+GetNativeDataPropertyPure<false>(JSContext* cx, JSObject* obj, PropertyName* name, Value* vp);
 
 static MOZ_ALWAYS_INLINE bool
 ValueToAtomOrSymbolPure(JSContext* cx, Value& idVal, jsid* id)
 {
     if (MOZ_LIKELY(idVal.isString())) {
         JSString* s = idVal.toString();
         JSAtom* atom;
         if (s->isAtom()) {
@@ -1736,28 +1736,28 @@ GetNativeDataPropertyByValuePure(JSConte
     // vp[0] contains the id, result will be stored in vp[1].
     Value idVal = vp[0];
     jsid id;
     if (!ValueToAtomOrSymbolPure(cx, idVal, &id)) {
         return false;
     }
 
     Value* res = vp + 1;
-    return GetNativeDataProperty<HandleMissing>(cx, &obj->as<NativeObject>(), id, res);
+    return GetNativeDataPropertyPure<HandleMissing>(cx, &obj->as<NativeObject>(), id, res);
 }
 
 template bool
 GetNativeDataPropertyByValuePure<true>(JSContext* cx, JSObject* obj, Value* vp);
 
 template bool
 GetNativeDataPropertyByValuePure<false>(JSContext* cx, JSObject* obj, Value* vp);
 
 template <bool NeedsTypeBarrier>
 bool
-SetNativeDataProperty(JSContext* cx, JSObject* obj, PropertyName* name, Value* val)
+SetNativeDataPropertyPure(JSContext* cx, JSObject* obj, PropertyName* name, Value* val)
 {
     AutoUnsafeCallWithABI unsafe;
 
     if (MOZ_UNLIKELY(!obj->isNative())) {
         return false;
     }
 
     NativeObject* nobj = &obj->as<NativeObject>();
@@ -1773,23 +1773,23 @@ SetNativeDataProperty(JSContext* cx, JSO
         return false;
     }
 
     nobj->setSlot(shape->slot(), *val);
     return true;
 }
 
 template bool
-SetNativeDataProperty<true>(JSContext* cx, JSObject* obj, PropertyName* name, Value* val);
+SetNativeDataPropertyPure<true>(JSContext* cx, JSObject* obj, PropertyName* name, Value* val);
 
 template bool
-SetNativeDataProperty<false>(JSContext* cx, JSObject* obj, PropertyName* name, Value* val);
+SetNativeDataPropertyPure<false>(JSContext* cx, JSObject* obj, PropertyName* name, Value* val);
 
 bool
-ObjectHasGetterSetter(JSContext* cx, JSObject* objArg, Shape* propShape)
+ObjectHasGetterSetterPure(JSContext* cx, JSObject* objArg, Shape* propShape)
 {
     AutoUnsafeCallWithABI unsafe;
 
     MOZ_ASSERT(propShape->hasGetterObject() || propShape->hasSetterObject());
 
     // Window objects may require outerizing (passing the WindowProxy to the
     // getter/setter), so we don't support them here.
     if (MOZ_UNLIKELY(!objArg->isNative() || IsWindow(objArg))) {
@@ -1888,17 +1888,17 @@ HasNativeDataPropertyPure(JSContext* cx,
 template bool
 HasNativeDataPropertyPure<true>(JSContext* cx, JSObject* obj, Value* vp);
 
 template bool
 HasNativeDataPropertyPure<false>(JSContext* cx, JSObject* obj, Value* vp);
 
 
 bool
-HasNativeElement(JSContext* cx, NativeObject* obj, int32_t index, Value* vp)
+HasNativeElementPure(JSContext* cx, NativeObject* obj, int32_t index, Value* vp)
 {
     AutoUnsafeCallWithABI unsafe;
 
     MOZ_ASSERT(obj->getClass()->isNative());
     MOZ_ASSERT(!obj->getOpsHasProperty());
     MOZ_ASSERT(!obj->getOpsLookupProperty());
     MOZ_ASSERT(!obj->getOpsGetOwnPropertyDescriptor());
 
--- a/js/src/jit/VMFunctions.h
+++ b/js/src/jit/VMFunctions.h
@@ -912,42 +912,42 @@ MOZ_MUST_USE bool
 CallNativeGetter(JSContext* cx, HandleFunction callee, HandleObject obj,
                  MutableHandleValue result);
 
 MOZ_MUST_USE bool
 CallNativeSetter(JSContext* cx, HandleFunction callee, HandleObject obj,
                  HandleValue rhs);
 
 MOZ_MUST_USE bool
-EqualStringsHelper(JSString* str1, JSString* str2);
+EqualStringsHelperPure(JSString* str1, JSString* str2);
 
 MOZ_MUST_USE bool
 CheckIsCallable(JSContext* cx, HandleValue v, CheckIsCallableKind kind);
 
 template <bool HandleMissing>
 bool
-GetNativeDataProperty(JSContext* cx, JSObject* obj, PropertyName* name, Value* vp);
+GetNativeDataPropertyPure(JSContext* cx, JSObject* obj, PropertyName* name, Value* vp);
 
 template <bool HandleMissing>
 bool
 GetNativeDataPropertyByValuePure(JSContext* cx, JSObject* obj, Value* vp);
 
 template <bool HasOwn>
 bool
 HasNativeDataPropertyPure(JSContext* cx, JSObject* obj, Value* vp);
 
 bool
-HasNativeElement(JSContext* cx, NativeObject* obj, int32_t index, Value* vp);
+HasNativeElementPure(JSContext* cx, NativeObject* obj, int32_t index, Value* vp);
 
 template <bool NeedsTypeBarrier>
 bool
-SetNativeDataProperty(JSContext* cx, JSObject* obj, PropertyName* name, Value* val);
+SetNativeDataPropertyPure(JSContext* cx, JSObject* obj, PropertyName* name, Value* val);
 
 bool
-ObjectHasGetterSetter(JSContext* cx, JSObject* obj, Shape* propShape);
+ObjectHasGetterSetterPure(JSContext* cx, JSObject* obj, Shape* propShape);
 
 JSString*
 TypeOfObject(JSObject* obj, JSRuntime* rt);
 
 bool
 GetPrototypeOf(JSContext* cx, HandleObject target, MutableHandleValue rval);
 
 void
--- a/js/src/jsapi-tests/tests.h
+++ b/js/src/jsapi-tests/tests.h
@@ -223,16 +223,18 @@ class JSAPITest
     {
         char location[256];
         snprintf(location, mozilla::ArrayLength(location), "%s:%d:", filename, lineno);
 
         JSAPITestString message(location);
         message += msg;
 
         if (JS_IsExceptionPending(cx)) {
+            message += " -- ";
+
             js::gc::AutoSuppressGC gcoff(cx);
             JS::RootedValue v(cx);
             JS_GetPendingException(cx, &v);
             JS_ClearPendingException(cx);
             JSString* s = JS::ToString(cx, v);
             if (s) {
                 if (JS::UniqueChars bytes = JS_EncodeStringToLatin1(cx, s)) {
                     message += bytes.get();
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -6603,21 +6603,16 @@ JS_SetGlobalJitCompilerOption(JSContext*
             jit::DefaultJitOptions defaultValues;
             value = defaultValues.jumpThreshold;
         }
         jit::JitOptions.jumpThreshold = value;
         break;
       case JSJITCOMPILER_TRACK_OPTIMIZATIONS:
         jit::JitOptions.disableOptimizationTracking = !value;
         break;
-#ifdef JS_TRACE_LOGGING
-      case JSJITCOMPILER_ENABLE_TRACELOGGER:
-        jit::JitOptions.enableTraceLogger = !!value;
-        break;
-#endif
       case JSJITCOMPILER_SPECTRE_INDEX_MASKING:
         jit::JitOptions.spectreIndexMasking = !!value;
         break;
       case JSJITCOMPILER_SPECTRE_OBJECT_MITIGATIONS_BARRIERS:
         jit::JitOptions.spectreObjectMitigationsBarriers = !!value;
         break;
       case JSJITCOMPILER_SPECTRE_OBJECT_MITIGATIONS_MISC:
         jit::JitOptions.spectreObjectMitigationsMisc = !!value;
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -2736,31 +2736,31 @@ extern JS_PUBLIC_API(bool)
 JS_GetArrayLength(JSContext* cx, JS::Handle<JSObject*> obj, uint32_t* lengthp);
 
 extern JS_PUBLIC_API(bool)
 JS_SetArrayLength(JSContext* cx, JS::Handle<JSObject*> obj, uint32_t length);
 
 namespace JS {
 
 /**
- * Returns true and sets |*isMap| indicating whether |obj| is an Map object
- * or a wrapper around one, otherwise returns false on failure.
+ * On success, returns true, setting |*isMap| to true if |obj| is a Map object
+ * or a wrapper around one, or to false if not.  Returns false on failure.
  *
- * This method returns true with |*isMap == false| when passed a proxy whose
- * target is an Map, or when passed a revoked proxy.
+ * This method returns true with |*isMap == false| when passed an ES6 proxy
+ * whose target is a Map, or when passed a revoked proxy.
  */
 extern JS_PUBLIC_API(bool)
 IsMapObject(JSContext* cx, JS::HandleObject obj, bool* isMap);
 
 /**
- * Returns true and sets |*isSet| indicating whether |obj| is an Set object
- * or a wrapper around one, otherwise returns false on failure.
+ * On success, returns true, setting |*isSet| to true if |obj| is a Set object
+ * or a wrapper around one, or to false if not.  Returns false on failure.
  *
- * This method returns true with |*isSet == false| when passed a proxy whose
- * target is an Set, or when passed a revoked proxy.
+ * This method returns true with |*isSet == false| when passed an ES6 proxy
+ * whose target is a Set, or when passed a revoked proxy.
  */
 extern JS_PUBLIC_API(bool)
 IsSetObject(JSContext* cx, JS::HandleObject obj, bool* isSet);
 
 } /* namespace JS */
 
 /**
  * Assign 'undefined' to all of the object's non-reserved slots. Note: this is
@@ -4278,21 +4278,22 @@ SetForEach(JSContext *cx, HandleObject o
 /*
  * Dates.
  */
 
 extern JS_PUBLIC_API(JSObject*)
 JS_NewDateObject(JSContext* cx, int year, int mon, int mday, int hour, int min, int sec);
 
 /**
- * Returns true and sets |*isDate| indicating whether |obj| is a Date object or
- * a wrapper around one, otherwise returns false on failure.
+ * On success, returns true, setting |*isDate| to true if |obj| is a Date
+ * object or a wrapper around one, or to false if not.  Returns false on
+ * failure.
  *
- * This method returns true with |*isDate == false| when passed a proxy whose
- * target is a Date, or when passed a revoked proxy.
+ * This method returns true with |*isDate == false| when passed an ES6 proxy
+ * whose target is a Date, or when passed a revoked proxy.
  */
 extern JS_PUBLIC_API(bool)
 JS_ObjectIsDate(JSContext* cx, JS::HandleObject obj, bool* isDate);
 
 /************************************************************************/
 
 /*
  * Regular Expressions.
@@ -4322,21 +4323,22 @@ JS_ExecuteRegExp(JSContext* cx, JS::Hand
 
 /* RegExp interface for clients without a global object. */
 
 extern JS_PUBLIC_API(bool)
 JS_ExecuteRegExpNoStatics(JSContext* cx, JS::HandleObject reobj, char16_t* chars, size_t length,
                           size_t* indexp, bool test, JS::MutableHandleValue rval);
 
 /**
- * Returns true and sets |*isRegExp| indicating whether |obj| is a RegExp
- * object or a wrapper around one, otherwise returns false on failure.
+ * On success, returns true, setting |*isRegExp| to true if |obj| is a RegExp
+ * object or a wrapper around one, or to false if not.  Returns false on
+ * failure.
  *
- * This method returns true with |*isRegExp == false| when passed a proxy whose
- * target is a RegExp, or when passed a revoked proxy.
+ * This method returns true with |*isRegExp == false| when passed an ES6 proxy
+ * whose target is a RegExp, or when passed a revoked proxy.
  */
 extern JS_PUBLIC_API(bool)
 JS_ObjectIsRegExp(JSContext* cx, JS::HandleObject obj, bool* isRegExp);
 
 extern JS_PUBLIC_API(unsigned)
 JS_GetRegExpFlags(JSContext* cx, JS::HandleObject obj);
 
 extern JS_PUBLIC_API(JSString*)
@@ -4510,17 +4512,16 @@ JS_SetOffthreadIonCompilationEnabled(JSC
     Register(ION_ENABLE, "ion.enable")                                      \
     Register(ION_CHECK_RANGE_ANALYSIS, "ion.check-range-analysis")          \
     Register(ION_FREQUENT_BAILOUT_THRESHOLD, "ion.frequent-bailout-threshold") \
     Register(BASELINE_ENABLE, "baseline.enable")                            \
     Register(OFFTHREAD_COMPILATION_ENABLE, "offthread-compilation.enable")  \
     Register(FULL_DEBUG_CHECKS, "jit.full-debug-checks")                    \
     Register(JUMP_THRESHOLD, "jump-threshold")                              \
     Register(TRACK_OPTIMIZATIONS, "jit.track-optimizations")                \
-    Register(ENABLE_TRACELOGGER, "jit.enable-tracelogger")                  \
     Register(SIMULATOR_ALWAYS_INTERRUPT, "simulator.always-interrupt")      \
     Register(SPECTRE_INDEX_MASKING, "spectre.index-masking")                \
     Register(SPECTRE_OBJECT_MITIGATIONS_BARRIERS, "spectre.object-mitigations.barriers") \
     Register(SPECTRE_OBJECT_MITIGATIONS_MISC, "spectre.object-mitigations.misc") \
     Register(SPECTRE_STRING_MITIGATIONS, "spectre.string-mitigations")      \
     Register(SPECTRE_VALUE_MASKING, "spectre.value-masking")                \
     Register(SPECTRE_JIT_TO_CXX_CALLS, "spectre.jit-to-C++-calls")          \
     Register(WASM_FOLD_OFFSETS, "wasm.fold-offsets")                        \
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -715,17 +715,17 @@ js::Int32ToString(JSContext* cx, int32_t
 
 template JSFlatString*
 js::Int32ToString<CanGC>(JSContext* cx, int32_t si);
 
 template JSFlatString*
 js::Int32ToString<NoGC>(JSContext* cx, int32_t si);
 
 JSFlatString*
-js::Int32ToStringHelper(JSContext* cx, int32_t si)
+js::Int32ToStringHelperPure(JSContext* cx, int32_t si)
 {
     AutoUnsafeCallWithABI unsafe;
     JSFlatString* res = Int32ToString<NoGC>(cx, si);
     if (!res) {
         cx->recoverFromOutOfMemory();
     }
     return res;
 }
@@ -1525,17 +1525,17 @@ js::NumberToString(JSContext* cx, double
 
 template JSString*
 js::NumberToString<CanGC>(JSContext* cx, double d);
 
 template JSString*
 js::NumberToString<NoGC>(JSContext* cx, double d);
 
 JSString*
-js::NumberToStringHelper(JSContext* cx, double d)
+js::NumberToStringHelperPure(JSContext* cx, double d)
 {
     AutoUnsafeCallWithABI unsafe;
     JSString* res = NumberToString<NoGC>(cx, d);
     if (!res) {
         cx->recoverFromOutOfMemory();
     }
     return res;
 }
@@ -1709,17 +1709,17 @@ js::StringToNumber(JSContext* cx, JSStri
     }
 
     return linearStr->hasLatin1Chars()
            ? CharsToNumber(cx, linearStr->latin1Chars(nogc), str->length(), result)
            : CharsToNumber(cx, linearStr->twoByteChars(nogc), str->length(), result);
 }
 
 bool
-js::StringToNumberDontReportOOM(JSContext* cx, JSString* str, double* result)
+js::StringToNumberPure(JSContext* cx, JSString* str, double* result)
 {
     // IC Code calls this directly.
     AutoUnsafeCallWithABI unsafe;
 
     if (!StringToNumber(cx, str, result)) {
         cx->recoverFromOutOfMemory();
         return false;
     }
--- a/js/src/jsnum.h
+++ b/js/src/jsnum.h
@@ -56,27 +56,27 @@ InitNumberClass(JSContext* cx, Handle<Gl
  * ECMA-262-5 section 9.8.1; but note that it handles integers specially for
  * performance.  See also js::NumberToCString().
  */
 template <AllowGC allowGC>
 extern JSString*
 NumberToString(JSContext* cx, double d);
 
 extern JSString*
-NumberToStringHelper(JSContext* cx, double d);
+NumberToStringHelperPure(JSContext* cx, double d);
 
 extern JSAtom*
 NumberToAtom(JSContext* cx, double d);
 
 template <AllowGC allowGC>
 extern JSFlatString*
 Int32ToString(JSContext* cx, int32_t i);
 
 extern JSFlatString*
-Int32ToStringHelper(JSContext* cx, int32_t i);
+Int32ToStringHelperPure(JSContext* cx, int32_t i);
 
 extern JSAtom*
 Int32ToAtom(JSContext* cx, int32_t si);
 
 // ES6 15.7.3.12
 extern bool
 IsInteger(const Value& val);
 
@@ -194,17 +194,17 @@ GetFullInteger(JSContext* cx, const Char
 template <typename CharT>
 extern MOZ_MUST_USE bool
 GetDecimalInteger(JSContext* cx, const CharT* start, const CharT* end, double* dp);
 
 extern MOZ_MUST_USE bool
 StringToNumber(JSContext* cx, JSString* str, double* result);
 
 extern MOZ_MUST_USE bool
-StringToNumberDontReportOOM(JSContext* cx, JSString* str, double* result);
+StringToNumberPure(JSContext* cx, JSString* str, double* result);
 
 /* ES5 9.3 ToNumber, overwriting *vp with the appropriate number value. */
 MOZ_ALWAYS_INLINE MOZ_MUST_USE bool
 ToNumber(JSContext* cx, JS::MutableHandleValue vp)
 {
     if (vp.isNumber()) {
         return true;
     }
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -10516,19 +10516,16 @@ main(int argc, char** argv, char** envp)
         || !op.addStringOption('z', "gc-zeal", "LEVEL(;LEVEL)*[,N]", gc::ZealModeHelpText)
 #else
         || !op.addStringOption('z', "gc-zeal", "LEVEL(;LEVEL)*[,N]", "option ignored in non-gc-zeal builds")
 #endif
         || !op.addStringOption('\0', "module-load-path", "DIR", "Set directory to load modules from")
         || !op.addBoolOption('\0', "no-async-stacks", "Disable async stacks")
         || !op.addMultiStringOption('\0', "dll", "LIBRARY", "Dynamically load LIBRARY")
         || !op.addBoolOption('\0', "suppress-minidump", "Suppress crash minidumps")
-#ifdef JS_TRACE_LOGGING
-        || !op.addBoolOption('\0', "enable-tracelogger","Enable Trace Logging")
-#endif
     )
     {
         return EXIT_FAILURE;
     }
 
     op.setArgTerminatesOptions("script", true);
     op.setArgCapturesRest("scriptArgs");
 
@@ -10582,22 +10579,16 @@ main(int argc, char** argv, char** envp)
         loader.load(path);
         dllPaths.popFront();
     }
 
     if (op.getBoolOption("suppress-minidump")) {
         js::NoteIntentionalCrash();
     }
 
-#ifdef JS_TRACE_LOGGING
-    if (op.getBoolOption("enable-tracelogger")) {
-        jit::JitOptions.enableTraceLogger = true;
-    }
-#endif
-
     if (!InitSharedObjectMailbox()) {
         return 1;
     }
 
     JS::SetProcessBuildIdOp(ShellBuildId);
 
     // The fake CPU count must be set before initializing the Runtime,
     // which spins up the thread pool.
--- a/js/src/vm/ArgumentsObject.cpp
+++ b/js/src/vm/ArgumentsObject.cpp
@@ -380,18 +380,18 @@ ArgumentsObject::createForIon(JSContext*
     MOZ_ASSERT(jit::CalleeTokenIsFunction(token));
     RootedFunction callee(cx, jit::CalleeTokenToFunction(token));
     RootedObject callObj(cx, scopeChain->is<CallObject>() ? scopeChain.get() : nullptr);
     CopyJitFrameArgs copy(frame, callObj);
     return create(cx, callee, frame->numActualArgs(), copy);
 }
 
 /* static */ ArgumentsObject*
-ArgumentsObject::finishForIon(JSContext* cx, jit::JitFrameLayout* frame,
-                              JSObject* scopeChain, ArgumentsObject* obj)
+ArgumentsObject::finishForIonPure(JSContext* cx, jit::JitFrameLayout* frame,
+                                  JSObject* scopeChain, ArgumentsObject* obj)
 {
     // JIT code calls this directly (no callVM), because it's faster, so we're
     // not allowed to GC in here.
     AutoUnsafeCallWithABI unsafe;
 
     JSFunction* callee = jit::CalleeTokenToFunction(frame->calleeToken());
     RootedObject callObj(cx, scopeChain->is<CallObject>() ? scopeChain : nullptr);
     CopyJitFrameArgs copy(frame, callObj);
--- a/js/src/vm/ArgumentsObject.h
+++ b/js/src/vm/ArgumentsObject.h
@@ -205,17 +205,17 @@ class ArgumentsObject : public NativeObj
     static ArgumentsObject* createUnexpected(JSContext* cx, AbstractFramePtr frame);
     static ArgumentsObject* createForIon(JSContext* cx, jit::JitFrameLayout* frame,
                                          HandleObject scopeChain);
 
     /*
      * Allocate ArgumentsData and fill reserved slots after allocating an
      * ArgumentsObject in Ion code.
      */
-    static ArgumentsObject* finishForIon(JSContext* cx, jit::JitFrameLayout* frame,
+    static ArgumentsObject* finishForIonPure(JSContext* cx, jit::JitFrameLayout* frame,
                                          JSObject* scopeChain, ArgumentsObject* obj);
 
     static ArgumentsObject* createTemplateObject(JSContext* cx, bool mapped);
 
     /*
      * Return the initial length of the arguments.  This may differ from the
      * current value of arguments.length!
      */
--- a/js/src/vm/NativeObject.cpp
+++ b/js/src/vm/NativeObject.cpp
@@ -460,30 +460,30 @@ NativeObject::growSlots(JSContext* cx, u
     slots_ = newslots;
 
     Debug_SetSlotRangeToCrashOnTouch(slots_ + oldCount, newCount - oldCount);
 
     return true;
 }
 
 /* static */ bool
-NativeObject::growSlotsDontReportOOM(JSContext* cx, NativeObject* obj, uint32_t newCount)
+NativeObject::growSlotsPure(JSContext* cx, NativeObject* obj, uint32_t newCount)
 {
     // IC code calls this directly.
     AutoUnsafeCallWithABI unsafe;
 
     if (!obj->growSlots(cx, obj->numDynamicSlots(), newCount)) {
         cx->recoverFromOutOfMemory();
         return false;
     }
     return true;
 }
 
 /* static */ bool
-NativeObject::addDenseElementDontReportOOM(JSContext* cx, NativeObject* obj)
+NativeObject::addDenseElementPure(JSContext* cx, NativeObject* obj)
 {
     // IC code calls this directly.
     AutoUnsafeCallWithABI unsafe;
 
     MOZ_ASSERT(obj->getDenseInitializedLength() == obj->getDenseCapacity());
     MOZ_ASSERT(!obj->denseElementsAreCopyOnWrite());
     MOZ_ASSERT(obj->isExtensible());
     MOZ_ASSERT(!obj->isIndexed());
--- a/js/src/vm/NativeObject.h
+++ b/js/src/vm/NativeObject.h
@@ -829,24 +829,24 @@ class NativeObject : public ShapedObject
      */
     bool growSlots(JSContext* cx, uint32_t oldCount, uint32_t newCount);
     void shrinkSlots(JSContext* cx, uint32_t oldCount, uint32_t newCount);
 
     /*
      * This method is static because it's called from JIT code. On OOM, returns
      * false without leaving a pending exception on the context.
      */
-    static bool growSlotsDontReportOOM(JSContext* cx, NativeObject* obj, uint32_t newCount);
+    static bool growSlotsPure(JSContext* cx, NativeObject* obj, uint32_t newCount);
 
     /*
-     * Like growSlotsDontReportOOM but for dense elements. This will return
+     * Like growSlotsPure but for dense elements. This will return
      * false if we failed to allocate a dense element for some reason (OOM, too
      * many dense elements, non-writable array length, etc).
      */
-    static bool addDenseElementDontReportOOM(JSContext* cx, NativeObject* obj);
+    static bool addDenseElementPure(JSContext* cx, NativeObject* obj);
 
     bool hasDynamicSlots() const { return !!slots_; }
 
     /* Compute dynamicSlotsCount() for this object. */
     MOZ_ALWAYS_INLINE uint32_t numDynamicSlots() const;
 
     bool empty() const {
         return lastProperty()->isEmptyShape();
--- a/js/src/vm/TraceLogging.cpp
+++ b/js/src/vm/TraceLogging.cpp
@@ -669,16 +669,17 @@ TraceLoggerThread::startEvent(uint32_t i
                 graph->addTextId(otherId, text);
             } else {
                 TraceLoggerEventPayload *p = traceLoggerState->getPayload(id);
                 if (p) {
                     const char *filename = traceLoggerState->maybeEventText(p);
                     mozilla::Maybe<uint32_t> line   = p->line();
                     mozilla::Maybe<uint32_t> column = p->column();
                     graph->addTextId(otherId, filename, line, column);
+                    p->release();
                 }
             }
         }
     }
 
     log(id);
 }
 
@@ -999,16 +1000,17 @@ TraceLoggerThreadState::init()
         if (strstr(options, "EnableOffThread")) {
             helperThreadEnabled = true;
         }
         if (strstr(options, "EnableGraph")) {
             graphEnabled = true;
         }
         if (strstr(options, "EnableGraphFile")) {
             graphFileEnabled = true;
+            jit::JitOptions.enableTraceLogger = true;
         }
         if (strstr(options, "Errors")) {
             spewErrors = true;
         }
     } else {
             mainThreadEnabled = true;
             helperThreadEnabled = true;
             graphEnabled = false;
@@ -1249,17 +1251,17 @@ JS_PUBLIC_API(void)
 JS::StartTraceLogger(JSContext *cx)
 {
     if (jit::JitOptions.enableTraceLogger || !traceLoggerState)  {
         return;
     }
 
     LockGuard<Mutex> guard(traceLoggerState->lock);
     traceLoggerState->enableTextIdsForProfiler();
-    JS_SetGlobalJitCompilerOption(cx, JSJITCOMPILER_ENABLE_TRACELOGGER, true);
+    jit::JitOptions.enableTraceLogger = true;
 
     // Reset the start time to profile start so it aligns with sampling.
     traceLoggerState->startupTime = rdtsc();
 
     if (cx->traceLogger) {
         cx->traceLogger->enable();
     }
 }
@@ -1268,13 +1270,13 @@ JS_PUBLIC_API(void)
 JS::StopTraceLogger(JSContext *cx)
 {
     if (!jit::JitOptions.enableTraceLogger || !traceLoggerState) {
         return;
     }
 
     LockGuard<Mutex> guard(traceLoggerState->lock);
     traceLoggerState->disableTextIdsForProfiler();
-    JS_SetGlobalJitCompilerOption(cx, JSJITCOMPILER_ENABLE_TRACELOGGER, false);
+    jit::JitOptions.enableTraceLogger = false;
     if (cx->traceLogger) {
         cx->traceLogger->disable();
     }
 }
--- a/js/xpconnect/tests/chrome/chrome.ini
+++ b/js/xpconnect/tests/chrome/chrome.ini
@@ -96,26 +96,23 @@ skip-if = os == 'win' || os == 'mac' || 
 [test_discardSystemSource.xul]
 [test_documentdomain.xul]
 [test_doublewrappedcompartments.xul]
 [test_evalInSandbox.xul]
 [test_evalInWindow.xul]
 [test_exnstack.xul]
 [test_expandosharing.xul]
 [test_exposeInDerived.xul]
-[test_getweakmapkeys.xul]
 [test_localstorage_with_nsEp.xul]
 [test_matches.xul]
 [test_nodelists.xul]
 [test_nsScriptErrorWithStack.html]
 [test_onGarbageCollection.html]
-[test_paris_weakmap_keys.xul]
 [test_precisegc.xul]
 [test_sandboxImport.xul]
 [test_scriptSettings.xul]
 [test_weakmap_keys_preserved.xul]
 [test_weakmap_keys_preserved2.xul]
-[test_weakmaps.xul]
 [test_weakref.xul]
 [test_windowProxyDeadWrapper.html]
 [test_wrappers.xul]
 [test_xrayic.xul]
 [test_xrayToJS.xul]
--- a/js/xpconnect/tests/mochitest/mochitest.ini
+++ b/js/xpconnect/tests/mochitest/mochitest.ini
@@ -96,14 +96,17 @@ support-files =
 [test_bug1094930.html]
 [test_bug1158558.html]
 [test_bug1448048.html]
 [test_crosscompartment_weakmap.html]
 [test_frameWrapping.html]
 # The JS test component we use below is only available in debug builds.
 [test_getWebIDLCaller.html]
 skip-if = (debug == false)
+[test_getweakmapkeys.html]
+[test_paris_weakmap_keys.html]
 [test_nac.xhtml]
 [test_nukeContentWindow.html]
 [test_sameOriginPolicy.html]
 [test_sandbox_fetch.html]
   support-files =
     ../../../../dom/tests/mochitest/fetch/test_fetch_basic.js
+[test_weakmaps.html]
rename from js/xpconnect/tests/chrome/test_getweakmapkeys.xul
rename to js/xpconnect/tests/mochitest/test_getweakmapkeys.html
--- a/js/xpconnect/tests/chrome/test_getweakmapkeys.xul
+++ b/js/xpconnect/tests/mochitest/test_getweakmapkeys.html
@@ -1,40 +1,32 @@
-<?xml version="1.0"?>
-<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
-<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
+<!DOCTYPE HTML>
+<html>
 <!--
 https://bugzilla.mozilla.org/show_bug.cgi?id=688277
 -->
-<window title="Mozilla Bug "
-        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
-  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
-
-  <!-- test results are displayed in the html:body -->
-  <body xmlns="http://www.w3.org/1999/xhtml">
-  <a href="https://bugzilla.mozilla.org/show_bug.cgi?id="
-     target="_blank">Mozilla Bug 688277</a>
-  </body>
-
-  <!-- test code goes here -->
+<head>
+  <meta charset="utf-8">
+  <title>Tests for nondeterministicGetWeakMapKeys</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
   <script type="application/javascript">
-  <![CDATA[
   /** Test for Bug 688277 **/
 
   /* Fail gracefully if junk is passed in. */
-  is(ChromeUtils.nondeterministicGetWeakMapKeys(11), undefined,
+  is(SpecialPowers.nondeterministicGetWeakMapKeys(11), undefined,
     "nondeterministicGetWeakMapKeys should return undefined for non-objects");
-  is(ChromeUtils.nondeterministicGetWeakMapKeys({}), undefined,
+  is(SpecialPowers.nondeterministicGetWeakMapKeys({}), undefined,
     "nondeterministicGetWeakMapKeys should return undefined for non-weakmap objects");
-  is(ChromeUtils.nondeterministicGetWeakMapKeys(null), undefined,
+  is(SpecialPowers.nondeterministicGetWeakMapKeys(null), undefined,
     "nondeterministicGetWeakMapKeys should return undefined for null");
 
   /* return an empty array for an empty WeakMap */
   let mempty = new WeakMap();
-  is(ChromeUtils.nondeterministicGetWeakMapKeys(mempty).length, 0,
+  is(SpecialPowers.nondeterministicGetWeakMapKeys(mempty).length, 0,
     "nondeterministicGetWeakMapKeys should return empty array for empty weakmap");
 
   /* Test freeing/nonfreeing. */
   let m = new WeakMap();
   let liveKeys = new Array();
 
   let add_elements = function () {
     let k1 = {};
@@ -45,21 +37,23 @@ https://bugzilla.mozilla.org/show_bug.cg
     m.set(k2, "dead1");
 
     let k = {};
     m.set(k, k); /* simple cycle */
   };
 
   add_elements();
 
-  Cu.schedulePreciseGC(function () {
-    let keys = ChromeUtils.nondeterministicGetWeakMapKeys(m);
+  SpecialPowers.exactGC(function () {
+    let keys = SpecialPowers.nondeterministicGetWeakMapKeys(m);
     is(liveKeys.length, 1, "Wrong number of live keys.");
     is(keys.length, 1, "Should have one weak map key.");
     is(m.get(keys[0]), "live1", "live1 should be live");
     SimpleTest.finish();
   });
 
   SimpleTest.waitForExplicitFinish();
-
-  ]]>
   </script>
-</window>
+</head>
+<body>
+<p id="display"></p>
+</body>
+</html>
rename from js/xpconnect/tests/chrome/test_paris_weakmap_keys.xul
rename to js/xpconnect/tests/mochitest/test_paris_weakmap_keys.html
--- a/js/xpconnect/tests/chrome/test_paris_weakmap_keys.xul
+++ b/js/xpconnect/tests/mochitest/test_paris_weakmap_keys.html
@@ -1,30 +1,26 @@
-<?xml version="1.0"?>
-<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
-<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
+<!DOCTYPE HTML>
+<html>
 <!--
 https://bugzilla.mozilla.org/show_bug.cgi?id=777385
 -->
-<window title="Mozilla Bug 777385"
-        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
-  <div></div>
-  <div id="mydivname"></div>
-  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+<head>
+  <meta charset="utf-8">
+  <title>Tests for WebIDL objects as weak map keys</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="application/javascript">
 
-  <!-- test results are displayed in the html:body -->
-  <body xmlns="http://www.w3.org/1999/xhtml">
-  <a href="https://bugzilla.mozilla.org/show_bug.cgi?id="
-     target="_blank">Mozilla Bug 777385</a>
-  </body>
+  /** Test for Bug 777385 **/
 
-  <!-- test code goes here -->
-  <script type="application/javascript">
-  <![CDATA[
-  /** Test for Bug 777385 **/
+  SimpleTest.waitForExplicitFinish();
+
+  // We wait to run this until the load event because it needs to access an element.
+  function go() {
 
   let live_map = new WeakMap;
 
   let get_div_style = function () {
     return document.getElementById("mydivname").style;
   }
 
   let make_live_map = function () {
@@ -67,27 +63,31 @@ https://bugzilla.mozilla.org/show_bug.cg
     is(live_map.get(grad), 23456, "Live map should have live DOMPoint with right value before GC.");
   }
 
   add_non_isupports2();
 
 
   /* Set up for running precise GC/CC then check the results. */
 
-  SimpleTest.waitForExplicitFinish();
+  SpecialPowers.exactGC(function () {
+    SpecialPowers.forceCC();
+    SpecialPowers.forceGC();
+    SpecialPowers.forceGC();
 
-  Cu.schedulePreciseGC(function () {
-    SpecialPowers.DOMWindowUtils.cycleCollect();
-    SpecialPowers.DOMWindowUtils.garbageCollect();
-    SpecialPowers.DOMWindowUtils.garbageCollect();
-
-    is(ChromeUtils.nondeterministicGetWeakMapKeys(live_map).length, 2,
+    is(SpecialPowers.nondeterministicGetWeakMapKeys(live_map).length, 2,
        "Live nsISupports new DOM bindings wrappercached native weak map key should not be removed.");
 
     is(live_map.get(get_div_style()), 12345, "Live map should have live style with right value after GC.");
     is(live_map.get(ctx.strokeStyle), 23456, "Live map should have live gradient with right value after GC.");
 
     SimpleTest.finish();
   });
 
-  ]]>
+  }
   </script>
-</window>
+</head>
+<div></div>
+<div id="mydivname"></div>
+<body onload="go()";>
+<p id="display"></p>
+</body>
+</html>
rename from js/xpconnect/tests/chrome/test_weakmaps.xul
rename to js/xpconnect/tests/mochitest/test_weakmaps.html
--- a/js/xpconnect/tests/chrome/test_weakmaps.xul
+++ b/js/xpconnect/tests/mochitest/test_weakmaps.html
@@ -1,39 +1,36 @@
-<?xml version="1.0"?>
-<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
-<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
+<!DOCTYPE HTML>
+<html>
 <!--
 https://bugzilla.mozilla.org/show_bug.cgi?id=668855
 -->
-<window title="Mozilla Bug "
-        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
-  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+<head>
+  <meta charset="utf-8">
+  <title>Test Cross-Compartment DOM WeakMaps</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+<script type="application/javascript">
+  /** Test for Bug 668855 **/
 
-  <!-- test results are displayed in the html:body -->
-  <body xmlns="http://www.w3.org/1999/xhtml">
-  <a href="https://bugzilla.mozilla.org/show_bug.cgi?id="
-     target="_blank">Mozilla Bug 668855</a>
-  </body>
+  SimpleTest.waitForExplicitFinish();
 
-  <!-- test code goes here -->
-  <script type="application/javascript">
-  <![CDATA[
-  /** Test for Bug 668855 **/
+// We wait to run this until the load event because it needs to access an element.
+function go() {
 
   /* Create a weak reference, with a single-element weak map. */
   let make_weak_ref = function (obj) {
     let m = new WeakMap;
     m.set(obj, {});
     return m;
   };
 
   /* Check to see if a weak reference is dead. */
   let weak_ref_dead = function (r) {
-    return ChromeUtils.nondeterministicGetWeakMapKeys(r).length == 0;
+    return SpecialPowers.nondeterministicGetWeakMapKeys(r).length == 0;
   }
 
   /* Deterministically grab an arbitrary DOM element. */
   let get_live_dom = function () {
     let elems = document.getElementsByTagName("a");
     return elems[0];
   };
 
@@ -123,26 +120,26 @@ https://bugzilla.mozilla.org/show_bug.cg
     ok(weak_ref_dead(basic_weak_ref), "Dead value was kept alive.");
     ok(weak_ref_dead(basic_map_weak_ref), "Dead map was kept alive.");
 
     // check the live gray map
     is(live_map.get(live_key).my_key, 'live_live',
       "Live key should have the same value in live map.");
     is(live_map.get(black_key).my_key, 'live_black',
       "Black key should have the same value in live map.");
-    is(ChromeUtils.nondeterministicGetWeakMapKeys(live_map).length, 2,
+    is(SpecialPowers.nondeterministicGetWeakMapKeys(live_map).length, 2,
       "Live map should have two entries.");
 
     // check the live black map
     is(black_map.get(live_key).my_key, 'black_live',
       "Live key should have the same value in black map.");
     is(black_map.get(black_key).my_key, 'black_black',
       "Black key should have the same value in black map.");
-    is(ChromeUtils.nondeterministicGetWeakMapKeys(black_map).length, 2,
-      "Black map should have two entries.");    
+    is(SpecialPowers.nondeterministicGetWeakMapKeys(black_map).length, 2,
+      "Black map should have two entries.");
 
   };
 
 
   /* live gray chained weak map entries, involving the cycle collector. */
   let chainm = new WeakMap;
   let num_chains = 5;
 
@@ -161,17 +158,17 @@ https://bugzilla.mozilla.org/show_bug.cg
   let check_nested_cc_maps = function () {
     let dom = get_live_dom();
     let all_ok = true;
     for(let i = 0; i < num_chains; i++) {
       let k = dom.key;
       all_ok = all_ok && k.count == i;
       dom = chainm.get(k).d.firstChild;
     };
-    ok(all_ok, "Count was invalid on a key in chained weak map entries.");    
+    ok(all_ok, "Count was invalid on a key in chained weak map entries.");
   };
 
   nested_cc_maps();
 
 
   /* black weak map, chained garbage cycle involving DOM */
   let garbage_map = new WeakMap;
 
@@ -224,39 +221,44 @@ https://bugzilla.mozilla.org/show_bug.cg
 
   make_live_map();
 
   // We're out of ideas for unpreservable natives, now that just about
   // everything is on webidl, so just don't test those.
 
   /* set up for running precise GC/CC then checking the results */
 
-  SimpleTest.waitForExplicitFinish();
-
-  Cu.schedulePreciseGC(function () {
-    SpecialPowers.DOMWindowUtils.cycleCollect();
-    SpecialPowers.DOMWindowUtils.garbageCollect();
-    SpecialPowers.DOMWindowUtils.garbageCollect();
+  SpecialPowers.exactGC(function () {
+    SpecialPowers.forceCC();
+    SpecialPowers.forceGC();
+    SpecialPowers.forceGC();
 
     ok(weak_ref_dead(weakref), "Garbage gray cycle should be collected.");
 
     check_nested_cc_maps();
 
-    is(ChromeUtils.nondeterministicGetWeakMapKeys(garbage_map).length, 0, "Chained garbage weak map entries should not leak.");
+    is(SpecialPowers.nondeterministicGetWeakMapKeys(garbage_map).length, 0, "Chained garbage weak map entries should not leak.");
 
     check_basic_unit();
 
     // fixed by Bug 680937
-    is(ChromeUtils.nondeterministicGetWeakMapKeys(wn_garbage_map).length, 0,
+    is(SpecialPowers.nondeterministicGetWeakMapKeys(wn_garbage_map).length, 0,
        "Chained garbage WN weak map entries should not leak.");
 
     // fixed by Bug 680937
-    is(ChromeUtils.nondeterministicGetWeakMapKeys(wn_live_map).length, 1,
+    is(SpecialPowers.nondeterministicGetWeakMapKeys(wn_live_map).length, 1,
        "Live weak map wrapped native key should not be removed.");
 
     ok(wn_live_map.has(get_live_dom()), "Live map should have live dom.");
 
     SimpleTest.finish();
   });
 
-  ]]>
+}
   </script>
-</window>
+</head>
+<div></div>
+<div id="mydivname"></div>
+<body onload="go()";>
+<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=668855" target="_blank">Mozilla Bug 668855</a>
+<p id="display"></p>
+</body>
+</html>
--- a/layout/style/ImageLoader.cpp
+++ b/layout/style/ImageLoader.cpp
@@ -463,24 +463,27 @@ ImageLoader::LoadImage(nsIURI* aURI,
   MOZ_ASSERT(aImage);
   MOZ_ASSERT(aImage->LoadID() != 0);
 
   if (aImage->LoadID() == 0) {
     MOZ_ASSERT_UNREACHABLE("Image should have a valid LoadID");
     return;
   }
 
-  if (sImages->Contains(aImage->LoadID())) {
-    // This css::URLValue has already been loaded.
-    return;
+  ImageTableEntry* entry;
+
+  {
+    auto lookup = sImages->LookupForAdd(aImage->LoadID());
+    if (lookup) {
+      // This css::URLValue has already been loaded.
+      return;
+    }
+    entry = lookup.OrInsert([]() { return new ImageTableEntry(); });
   }
 
-  ImageTableEntry* entry = new ImageTableEntry();
-  sImages->Put(aImage->LoadID(), entry);
-
   if (!aURI) {
     return;
   }
 
   int32_t loadFlags = nsIRequest::LOAD_NORMAL |
                       nsContentUtils::CORSModeToLoadImageFlags(aCorsMode);
 
   RefPtr<imgRequestProxy> request;
--- a/layout/style/nsCSSValue.cpp
+++ b/layout/style/nsCSSValue.cpp
@@ -76,23 +76,16 @@ nsCSSValue::nsCSSValue(const nsString& a
 nsCSSValue::nsCSSValue(nsCSSValue::Array* aValue, nsCSSUnit aUnit)
   : mUnit(aUnit)
 {
   MOZ_ASSERT(UnitHasArrayValue(), "bad unit");
   mValue.mArray = aValue;
   mValue.mArray->AddRef();
 }
 
-nsCSSValue::nsCSSValue(SharedFontList* aValue)
-  : mUnit(eCSSUnit_FontFamilyList)
-{
-  mValue.mFontFamilyList = aValue;
-  mValue.mFontFamilyList->AddRef();
-}
-
 nsCSSValue::nsCSSValue(const nsCSSValue& aCopy)
   : mUnit(aCopy.mUnit)
 {
   if (mUnit <= eCSSUnit_DummyInherit) {
     // nothing to do, but put this important case first
   }
   else if (eCSSUnit_Percent <= mUnit) {
     mValue.mFloat = aCopy.mValue.mFloat;
@@ -112,34 +105,24 @@ nsCSSValue::nsCSSValue(const nsCSSValue&
   else if (eCSSUnit_Pair == mUnit) {
     mValue.mPair = aCopy.mValue.mPair;
     mValue.mPair->AddRef();
   }
   else if (eCSSUnit_List == mUnit) {
     mValue.mList = aCopy.mValue.mList;
     mValue.mList->AddRef();
   }
-  else if (eCSSUnit_ListDep == mUnit) {
-    mValue.mListDependent = aCopy.mValue.mListDependent;
-  }
   else if (eCSSUnit_SharedList == mUnit) {
     mValue.mSharedList = aCopy.mValue.mSharedList;
     mValue.mSharedList->AddRef();
   }
   else if (eCSSUnit_PairList == mUnit) {
     mValue.mPairList = aCopy.mValue.mPairList;
     mValue.mPairList->AddRef();
   }
-  else if (eCSSUnit_PairListDep == mUnit) {
-    mValue.mPairListDependent = aCopy.mValue.mPairListDependent;
-  }
-  else if (eCSSUnit_FontFamilyList == mUnit) {
-    mValue.mFontFamilyList = aCopy.mValue.mFontFamilyList;
-    mValue.mFontFamilyList->AddRef();
-  }
   else if (eCSSUnit_AtomIdent == mUnit) {
     mValue.mAtom = aCopy.mValue.mAtom;
     mValue.mAtom->AddRef();
   }
   else {
     MOZ_ASSERT(false, "unknown unit");
   }
 }
@@ -163,22 +146,16 @@ nsCSSValue::operator=(nsCSSValue&& aOthe
   mValue = aOther.mValue;
   aOther.mUnit = eCSSUnit_Null;
 
   return *this;
 }
 
 bool nsCSSValue::operator==(const nsCSSValue& aOther) const
 {
-  MOZ_ASSERT(mUnit != eCSSUnit_ListDep &&
-             aOther.mUnit != eCSSUnit_ListDep &&
-             mUnit != eCSSUnit_PairListDep &&
-             aOther.mUnit != eCSSUnit_PairListDep,
-             "don't use operator== with dependent lists");
-
   if (mUnit == aOther.mUnit) {
     if (mUnit <= eCSSUnit_DummyInherit) {
       return true;
     }
     else if (UnitHasStringValue()) {
       return (NS_strcmp(GetBufferValue(mValue.mString),
                         GetBufferValue(aOther.mValue.mString)) == 0);
     }
@@ -196,20 +173,16 @@ bool nsCSSValue::operator==(const nsCSSV
     }
     else if (eCSSUnit_SharedList == mUnit) {
       return *mValue.mSharedList == *aOther.mValue.mSharedList;
     }
     else if (eCSSUnit_PairList == mUnit) {
       return nsCSSValuePairList::Equal(mValue.mPairList,
                                        aOther.mValue.mPairList);
     }
-    else if (eCSSUnit_FontFamilyList == mUnit) {
-      return mValue.mFontFamilyList->mNames ==
-             aOther.mValue.mFontFamilyList->mNames;
-    }
     else if (eCSSUnit_AtomIdent == mUnit) {
       return mValue.mAtom == aOther.mValue.mAtom;
     }
     else {
       return mValue.mFloat == aOther.mValue.mFloat;
     }
   }
   return false;
@@ -289,18 +262,16 @@ void nsCSSValue::DoReset()
   } else if (eCSSUnit_Pair == mUnit) {
     DO_RELEASE(mPair);
   } else if (eCSSUnit_List == mUnit) {
     DO_RELEASE(mList);
   } else if (eCSSUnit_SharedList == mUnit) {
     DO_RELEASE(mSharedList);
   } else if (eCSSUnit_PairList == mUnit) {
     DO_RELEASE(mPairList);
-  } else if (eCSSUnit_FontFamilyList == mUnit) {
-    DO_RELEASE(mFontFamilyList);
   } else if (eCSSUnit_AtomIdent == mUnit) {
     DO_RELEASE(mAtom);
   }
   mUnit = eCSSUnit_Null;
 }
 
 #undef DO_RELEASE
 
@@ -587,58 +558,39 @@ nsCSSValue::SizeOfExcludingThis(mozilla:
     case eCSSUnit_Counter:
     case eCSSUnit_Counters:
     case eCSSUnit_Cubic_Bezier:
     case eCSSUnit_Steps:
     case eCSSUnit_Symbols:
     case eCSSUnit_Function:
     case eCSSUnit_Calc:
     case eCSSUnit_Calc_Plus:
-    case eCSSUnit_Calc_Minus:
-    case eCSSUnit_Calc_Times_L:
-    case eCSSUnit_Calc_Times_R:
-    case eCSSUnit_Calc_Divided:
       break;
 
     // Pair
     case eCSSUnit_Pair:
       n += mValue.mPair->SizeOfIncludingThis(aMallocSizeOf);
       break;
 
     // List
     case eCSSUnit_List:
       n += mValue.mList->SizeOfIncludingThis(aMallocSizeOf);
       break;
 
-    // ListDep: not measured because it's non-owning.
-    case eCSSUnit_ListDep:
-      break;
-
     // SharedList
     case eCSSUnit_SharedList:
       // Makes more sense not to measure, since it most cases the list
       // will be shared.
       break;
 
     // PairList
     case eCSSUnit_PairList:
       n += mValue.mPairList->SizeOfIncludingThis(aMallocSizeOf);
       break;
 
-    // PairListDep: not measured because it's non-owning.
-    case eCSSUnit_PairListDep:
-      break;
-
-    case eCSSUnit_FontFamilyList:
-      // The SharedFontList is a refcounted object, but is unique per
-      // declaration. We don't measure the references from computed
-      // values.
-      n += mValue.mFontFamilyList->SizeOfIncludingThis(aMallocSizeOf);
-      break;
-
     // Atom is always shared, and thus should not be counted.
     case eCSSUnit_AtomIdent:
       break;
 
     // Int: nothing extra to measure.
     case eCSSUnit_Integer:
     case eCSSUnit_Enumerated:
       break;
--- a/layout/style/nsCSSValue.h
+++ b/layout/style/nsCSSValue.h
@@ -290,32 +290,22 @@ enum nsCSSUnit {
   // eCSSUnit_Calc has an array with exactly 1 element.  eCSSUnit_Calc
   // exists so we can distinguish calc(2em) from 2em as specified values
   // (but we drop this distinction for nsStyleCoord when we store
   // computed values).
   eCSSUnit_Calc         = 30,     // (nsCSSValue::Array*) calc() value
   // Plus, Minus, Times_* and Divided have arrays with exactly 2
   // elements.  a + b + c + d is grouped as ((a + b) + c) + d
   eCSSUnit_Calc_Plus    = 31,     // (nsCSSValue::Array*) + node within calc()
-  eCSSUnit_Calc_Minus   = 32,     // (nsCSSValue::Array*) - within calc
-  eCSSUnit_Calc_Times_L = 33,     // (nsCSSValue::Array*) num * val within calc
-  eCSSUnit_Calc_Times_R = 34,     // (nsCSSValue::Array*) val * num within calc
-  eCSSUnit_Calc_Divided = 35,     // (nsCSSValue::Array*) / within calc
 
   eCSSUnit_Pair         = 50,     // (nsCSSValuePair*) pair of values
   eCSSUnit_List         = 53,     // (nsCSSValueList*) list of values
-  eCSSUnit_ListDep      = 54,     // (nsCSSValueList*) same as List
-                                  //   but does not own the list
   eCSSUnit_SharedList   = 55,     // (nsCSSValueSharedList*) same as list
                                   //   but reference counted and shared
   eCSSUnit_PairList     = 56,     // (nsCSSValuePairList*) list of value pairs
-  eCSSUnit_PairListDep  = 57,     // (nsCSSValuePairList*) same as PairList
-                                  //   but does not own the list
-
-  eCSSUnit_FontFamilyList = 58,   // (SharedFontList*) value
 
   // Atom units
   eCSSUnit_AtomIdent    = 60,     // (nsAtom*) for its string as an identifier
 
   eCSSUnit_Integer      = 70,     // (int) simple value
   eCSSUnit_Enumerated   = 71,     // (int) value has enumerated meaning
 
   eCSSUnit_Percent      = 100,     // (float) 1.0 == 100%) value is percentage of something
@@ -380,17 +370,16 @@ public:
   {
     MOZ_ASSERT(aUnit <= eCSSUnit_DummyInherit, "not a valueless unit");
   }
 
   nsCSSValue(int32_t aValue, nsCSSUnit aUnit);
   nsCSSValue(float aValue, nsCSSUnit aUnit);
   nsCSSValue(const nsString& aValue, nsCSSUnit aUnit);
   nsCSSValue(Array* aArray, nsCSSUnit aUnit);
-  explicit nsCSSValue(mozilla::SharedFontList* aValue);
   nsCSSValue(const nsCSSValue& aCopy);
   nsCSSValue(nsCSSValue&& aOther)
     : mUnit(aOther.mUnit)
     , mValue(aOther.mValue)
   {
     aOther.mUnit = eCSSUnit_Null;
   }
   template<typename T,
@@ -445,22 +434,22 @@ public:
     { return eCSSUnit_Number <= aUnit; }
   bool      IsAngularUnit() const
     { return eCSSUnit_Degree <= mUnit && mUnit <= eCSSUnit_Turn; }
   bool      IsFrequencyUnit() const
     { return eCSSUnit_Hertz <= mUnit && mUnit <= eCSSUnit_Kilohertz; }
   bool      IsTimeUnit() const
     { return eCSSUnit_Seconds <= mUnit && mUnit <= eCSSUnit_Milliseconds; }
   bool      IsCalcUnit() const
-    { return eCSSUnit_Calc <= mUnit && mUnit <= eCSSUnit_Calc_Divided; }
+    { return eCSSUnit_Calc <= mUnit && mUnit <= eCSSUnit_Calc_Plus; }
 
   bool      UnitHasStringValue() const
     { return eCSSUnit_String <= mUnit && mUnit <= eCSSUnit_Element; }
   bool      UnitHasArrayValue() const
-    { return eCSSUnit_Array <= mUnit && mUnit <= eCSSUnit_Calc_Divided; }
+    { return eCSSUnit_Array <= mUnit && mUnit <= eCSSUnit_Calc_Plus; }
 
   int32_t GetIntValue() const
   {
     MOZ_ASSERT(mUnit == eCSSUnit_Integer ||
                mUnit == eCSSUnit_Enumerated,
                "not an int value");
     return mValue.mInt;
   }
@@ -519,25 +508,16 @@ public:
   }
 
   nsCSSValueSharedList* GetSharedListValue() const
   {
     MOZ_ASSERT(mUnit == eCSSUnit_SharedList, "not a shared list value");
     return mValue.mSharedList;
   }
 
-  mozilla::NotNull<mozilla::SharedFontList*> GetFontFamilyListValue() const
-  {
-    MOZ_ASSERT(mUnit == eCSSUnit_FontFamilyList,
-               "not a font family list value");
-    NS_ASSERTION(mValue.mFontFamilyList != nullptr,
-                 "font family list value should never be null");
-    return mozilla::WrapNotNull(mValue.mFontFamilyList);
-  }
-
   // bodies of these are below
   inline nsCSSValuePair& GetPairValue();
   inline const nsCSSValuePair& GetPairValue() const;
 
   inline nsCSSValueList* GetListValue();
   inline const nsCSSValueList* GetListValue() const;
 
   inline nsCSSValuePairList* GetPairListValue();
@@ -580,17 +560,16 @@ public:
   }
   void SetPercentValue(float aValue);
   void SetFloatValue(float aValue, nsCSSUnit aUnit);
   void SetStringValue(const nsString& aValue, nsCSSUnit aUnit);
   void SetAtomIdentValue(already_AddRefed<nsAtom> aValue);
   // converts the nscoord to pixels
   void SetIntegerCoordValue(nscoord aCoord);
   void SetArrayValue(nsCSSValue::Array* aArray, nsCSSUnit aUnit);
-  void SetFontFamilyListValue(already_AddRefed<mozilla::SharedFontList> aFontListValue);
   void SetPairValue(const nsCSSValuePair* aPair);
   void SetPairValue(const nsCSSValue& xValue, const nsCSSValue& yValue);
   void SetSharedListValue(nsCSSValueSharedList* aList);
   void SetNoneValue();
 
   nsStyleCoord::CalcValue GetCalcValue() const;
   void SetCalcValue(const nsStyleCoord::CalcValue&);
 
@@ -599,19 +578,16 @@ public:
   nsCSSValueList* SetListValue();
   nsCSSValuePairList* SetPairListValue();
 
   // Returns an already addrefed buffer.  Guaranteed to return non-null.
   // (Will abort on allocation failure.)
   static already_AddRefed<nsStringBuffer>
     BufferFromString(const nsString& aValue);
 
-  // Convert the given Ident value into AtomIdent.
-  void AtomizeIdentValue();
-
   size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
 
   static void
   AppendAlignJustifyValueToString(int32_t aValue, nsAString& aResult);
 
 private:
   static const char16_t* GetBufferValue(nsStringBuffer* aBuffer) {
     return static_cast<char16_t*>(aBuffer->Data());
@@ -624,21 +600,18 @@ protected:
     float      mFloat;
     // Note: the capacity of the buffer may exceed the length of the string.
     // If we're of a string type, mString is not null.
     nsStringBuffer* MOZ_OWNING_REF mString;
     nsAtom* MOZ_OWNING_REF mAtom;
     Array* MOZ_OWNING_REF mArray;
     nsCSSValuePair_heap* MOZ_OWNING_REF mPair;
     nsCSSValueList_heap* MOZ_OWNING_REF mList;
-    nsCSSValueList* mListDependent;
     nsCSSValueSharedList* MOZ_OWNING_REF mSharedList;
     nsCSSValuePairList_heap* MOZ_OWNING_REF mPairList;
-    nsCSSValuePairList* mPairListDependent;
-    mozilla::SharedFontList* MOZ_OWNING_REF mFontFamilyList;
   } mValue;
 };
 
 struct nsCSSValue::Array final {
 
   // return |Array| with reference count of zero
   static Array* Create(size_t aItemCount) {
     return new (aItemCount) Array(aItemCount);
@@ -795,38 +768,28 @@ public:
   bool operator!=(const nsCSSValueSharedList& aOther) const
   { return !(*this == aOther); }
 
   size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
 
   nsCSSValueList* mHead;
 };
 
-// This has to be here so that the relationship between nsCSSValueList
-// and nsCSSValueList_heap is visible.
 inline nsCSSValueList*
 nsCSSValue::GetListValue()
 {
-  if (mUnit == eCSSUnit_List)
-    return mValue.mList;
-  else {
-    MOZ_ASSERT(mUnit == eCSSUnit_ListDep, "not a list value");
-    return mValue.mListDependent;
-  }
+  MOZ_DIAGNOSTIC_ASSERT(mUnit == eCSSUnit_List, "not a list value");
+  return mValue.mList;
 }
 
 inline const nsCSSValueList*
 nsCSSValue::GetListValue() const
 {
-  if (mUnit == eCSSUnit_List)
-    return mValue.mList;
-  else {
-    MOZ_ASSERT(mUnit == eCSSUnit_ListDep, "not a list value");
-    return mValue.mListDependent;
-  }
+  MOZ_DIAGNOSTIC_ASSERT(mUnit == eCSSUnit_List, "not a list value");
+  return mValue.mList;
 }
 
 struct nsCSSValuePair {
   nsCSSValuePair()
   {
     MOZ_COUNT_CTOR(nsCSSValuePair);
   }
   explicit nsCSSValuePair(nsCSSUnit aUnit)
@@ -972,29 +935,21 @@ private:
   }
 };
 
 // This has to be here so that the relationship between nsCSSValuePairList
 // and nsCSSValuePairList_heap is visible.
 inline nsCSSValuePairList*
 nsCSSValue::GetPairListValue()
 {
-  if (mUnit == eCSSUnit_PairList)
-    return mValue.mPairList;
-  else {
-    MOZ_ASSERT (mUnit == eCSSUnit_PairListDep, "not a pairlist value");
-    return mValue.mPairListDependent;
-  }
+  MOZ_DIAGNOSTIC_ASSERT(mUnit == eCSSUnit_PairList, "not a pairlist value");
+  return mValue.mPairList;
 }
 
 inline const nsCSSValuePairList*
 nsCSSValue::GetPairListValue() const
 {
-  if (mUnit == eCSSUnit_PairList)
-    return mValue.mPairList;
-  else {
-    MOZ_ASSERT (mUnit == eCSSUnit_PairListDep, "not a pairlist value");
-    return mValue.mPairListDependent;
-  }
+  MOZ_DIAGNOSTIC_ASSERT(mUnit == eCSSUnit_PairList, "not a pairlist value");
+  return mValue.mPairList;
 }
 
 #endif /* nsCSSValue_h___ */
 
deleted file mode 100644
--- a/layout/tools/reftest/Makefile.in
+++ /dev/null
@@ -1,14 +0,0 @@
-# vim: set shiftwidth=8 tabstop=8 autoindent noexpandtab copyindent:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-_DEST_DIR = $(DEPTH)/_tests/reftest
-
-include $(topsrcdir)/config/rules.mk
-
-# copy harness and the reftest extension bits to $(_DEST_DIR)
-# This needs to happen after jar.mn handling from rules.mk included above.
-# The order of the :: rules ensures that.
-libs::
-	(cd $(DIST)/xpi-stage && tar $(TAR_CREATE_FLAGS) - reftest) | (cd $(_DEST_DIR) && tar -xf -)
--- a/layout/tools/reftest/reftestcommandline.py
+++ b/layout/tools/reftest/reftestcommandline.py
@@ -308,27 +308,27 @@ class ReftestArgumentsParser(argparse.Ar
                 self.error("--xre-path '%s' not found" % options.xrePath)
             if not os.path.isdir(options.xrePath):
                 self.error("--xre-path '%s' is not a directory" %
                            options.xrePath)
             options.xrePath = reftest.getFullPath(options.xrePath)
 
         if options.reftestExtensionPath is None:
             if self.build_obj is not None:
-                reftestExtensionPath = os.path.join(self.build_obj.topobjdir, "_tests",
-                                                    "reftest", "reftest")
+                reftestExtensionPath = os.path.join(self.build_obj.distdir,
+                                                    "xpi-stage", "reftest")
             else:
                 reftestExtensionPath = os.path.join(here, "reftest")
             options.reftestExtensionPath = os.path.normpath(reftestExtensionPath)
 
         if (options.specialPowersExtensionPath is None and
             options.suite in ["crashtest", "jstestbrowser"]):
             if self.build_obj is not None:
-                specialPowersExtensionPath = os.path.join(self.build_obj.topobjdir, "_tests",
-                                                          "reftest", "specialpowers")
+                specialPowersExtensionPath = os.path.join(self.build_obj.distdir,
+                                                          "xpi-stage", "specialpowers")
             else:
                 specialPowersExtensionPath = os.path.join(here, "specialpowers")
             options.specialPowersExtensionPath = os.path.normpath(specialPowersExtensionPath)
 
         options.leakThresholds = {
             "default": options.defaultLeakThreshold,
             "tab": options.defaultLeakThreshold,
         }
--- a/mobile/android/app/geckoview-prefs.js
+++ b/mobile/android/app/geckoview-prefs.js
@@ -13,11 +13,17 @@ pref("dom.ipc.processPrelaunch.enabled",
 
 // Tell Telemetry that we're in GeckoView mode.
 pref("toolkit.telemetry.isGeckoViewMode", true);
 // Disable the Telemetry Event Ping
 pref("toolkit.telemetry.eventping.enabled", false);
 
 pref("geckoview.console.enabled", false);
 
+#ifdef RELEASE_OR_BETA
+pref("geckoview.logging", "Warn");
+#else
+pref("geckoview.logging", "Debug");
+#endif
+
 // Disable Web Push until we get it working
 pref("dom.push.enabled", false);
 
--- a/mobile/android/chrome/geckoview/ErrorPageEventHandler.js
+++ b/mobile/android/chrome/geckoview/ErrorPageEventHandler.js
@@ -2,17 +2,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 ChromeUtils.import("resource://gre/modules/GeckoViewUtils.jsm");
 
 /* global debug:false, warn:false */
-GeckoViewUtils.initLogging("GeckoView.ErrorPageEventHandler", this);
+GeckoViewUtils.initLogging("ErrorPageEventHandler", this);
 
 ChromeUtils.defineModuleGetter(this, "SSLExceptions",
                                "resource://gre/modules/SSLExceptions.jsm");
 
 XPCOMUtils.defineLazyModuleGetters(this, {
   Services: "resource://gre/modules/Services.jsm",
 });
 
--- a/mobile/android/chrome/geckoview/geckoview.js
+++ b/mobile/android/chrome/geckoview/geckoview.js
@@ -224,17 +224,17 @@ class ModuleInfo {
   _loadPhase(aPhase) {
     if (!aPhase) {
       return;
     }
 
     if (aPhase.resource && !this._impl) {
       const scope = {};
       const global = ChromeUtils.import(aPhase.resource, scope);
-      const tag = this._name.replace("GeckoView", "GeckoView.");
+      const tag = this._name.replace("GeckoView", "");
       GeckoViewUtils.initLogging(tag, global);
       this._impl = new scope[this._name](this);
     }
 
     if (aPhase.frameScript && !this._contentModuleLoaded) {
       if (this._impl) {
         this._impl.onLoadContentModule();
       }
@@ -303,17 +303,17 @@ function createBrowser() {
   const browser = window.browser = document.createElement("browser");
   browser.setAttribute("type", "content");
   browser.setAttribute("primary", "true");
   browser.setAttribute("flex", "1");
   return browser;
 }
 
 function startup() {
-  GeckoViewUtils.initLogging("GeckoView.XUL", window);
+  GeckoViewUtils.initLogging("XUL", window);
 
   const browser = createBrowser();
   ModuleManager.init(browser, [{
     name: "GeckoViewAccessibility",
     onInit: {
       resource: "resource://gre/modules/GeckoViewAccessibility.jsm",
     },
   }, {
--- a/mobile/android/components/geckoview/GeckoViewExternalAppService.js
+++ b/mobile/android/components/geckoview/GeckoViewExternalAppService.js
@@ -3,17 +3,17 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 ChromeUtils.import("resource://gre/modules/GeckoViewUtils.jsm");
 
 /* global debug:false, warn:false */
-GeckoViewUtils.initLogging("GeckoView.ExternalAppService", this);
+GeckoViewUtils.initLogging("ExternalAppService", this);
 
 ChromeUtils.defineModuleGetter(this, "EventDispatcher",
   "resource://gre/modules/Messaging.jsm");
 
 function ExternalAppService() {
   this.wrappedJSObject = this;
 }
 
--- a/mobile/android/components/geckoview/GeckoViewStartup.js
+++ b/mobile/android/components/geckoview/GeckoViewStartup.js
@@ -1,25 +1,26 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
+ChromeUtils.import("resource://gre/modules/GeckoViewUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetters(this, {
   ActorManagerParent: "resource://gre/modules/ActorManagerParent.jsm",
   EventDispatcher: "resource://gre/modules/Messaging.jsm",
   FileSource: "resource://gre/modules/L10nRegistry.jsm",
   GeckoViewTelemetryController: "resource://gre/modules/GeckoViewTelemetryController.jsm",
-  GeckoViewUtils: "resource://gre/modules/GeckoViewUtils.jsm",
   L10nRegistry: "resource://gre/modules/L10nRegistry.jsm",
   Services: "resource://gre/modules/Services.jsm",
 });
 
-const {debug, warn} = GeckoViewUtils.initLogging("GeckoViewStartup", this);
+/* global debug:false, warn:false */
+GeckoViewUtils.initLogging("Startup", this);
 
 function GeckoViewStartup() {
 }
 
 GeckoViewStartup.prototype = {
   classID: Components.ID("{8e993c34-fdd6-432c-967e-f995d888777f}"),
 
   QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver]),
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/SessionAccessibility.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/SessionAccessibility.java
@@ -700,17 +700,17 @@ public class SessionAccessibility {
             if (bundle == null) {
                 return false;
             }
             rootId = currentId;
             currentId = bundle.getInt("parent", View.NO_ID);
         }
 
         if (DEBUG) {
-            Log.d(LOGTAG, "performAutoFill(" + id + ", " + value + ')');
+            Log.d(LOGTAG, "performAutoFill(" + id + ')');
         }
 
         final EventCallback callback = mAutoFillRoots.get(rootId);
         if (callback == null) {
             return false;
         }
 
         final GeckoBundle response = new GeckoBundle(1);
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/SessionTextInput.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/SessionTextInput.java
@@ -531,18 +531,17 @@ public final class SessionTextInput {
         GeckoBundle response = null;
         EventCallback callback = null;
 
         for (int i = 0; i < values.size(); i++) {
             final int id = values.keyAt(i);
             final CharSequence value = values.valueAt(i);
 
             if (DEBUG) {
-                Log.d(LOGTAG,
-                      "performAutoFill(" + id + ", " + values + ')');
+                Log.d(LOGTAG, "performAutoFill(" + id + ')');
             }
             int rootId = id;
             for (int currentId = id; currentId != View.NO_ID; ) {
                 final GeckoBundle bundle = mAutoFillNodes.get(currentId);
                 if (bundle == null) {
                     return;
                 }
                 rootId = currentId;
--- a/mobile/android/modules/geckoview/GeckoViewAutoFill.jsm
+++ b/mobile/android/modules/geckoview/GeckoViewAutoFill.jsm
@@ -109,17 +109,17 @@ class GeckoViewAutoFill {
     const rootInfo = getInfo(aFormLike.rootElement, null, undefined);
     rootInfo.root = rootInfo.id;
     rootInfo.children = aFormLike.elements.map(
         element => getInfo(element, rootInfo.id, rootInfo.id));
 
     this._eventDispatcher.dispatch("GeckoView:AddAutoFill", rootInfo, {
       onSuccess: responses => {
         // `responses` is an object with IDs as keys.
-        debug `Performing auto-fill ${responses}`;
+        debug `Performing auto-fill ${Object.keys(responses)}`;
 
         const AUTOFILL_STATE = "-moz-autofill";
         const winUtils = window.windowUtils;
 
         for (let id in responses) {
           const entry = this._autoFillElements &&
                         this._autoFillElements.get(+id);
           const element = entry && entry.get();
--- a/mobile/android/modules/geckoview/GeckoViewConsole.jsm
+++ b/mobile/android/modules/geckoview/GeckoViewConsole.jsm
@@ -7,17 +7,17 @@ var EXPORTED_SYMBOLS = ["GeckoViewConsol
 
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 ChromeUtils.import("resource://gre/modules/GeckoViewUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetters(this, {
   Services: "resource://gre/modules/Services.jsm"
 });
 
-GeckoViewUtils.initLogging("GeckoViewConsole", this);
+GeckoViewUtils.initLogging("Console", this);
 
 const LOG_EVENT_TOPIC = "console-api-log-event";
 
 var GeckoViewConsole = {
   _isEnabled: false,
 
   get enabled() {
     return this._isEnabled;
--- a/mobile/android/modules/geckoview/GeckoViewContentModule.jsm
+++ b/mobile/android/modules/geckoview/GeckoViewContentModule.jsm
@@ -3,22 +3,22 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 var EXPORTED_SYMBOLS = ["GeckoViewContentModule"];
 
 ChromeUtils.import("resource://gre/modules/GeckoViewUtils.jsm");
 
-GeckoViewUtils.initLogging("GeckoView.Module.[C]", this);
+GeckoViewUtils.initLogging("Module[C]", this);
 
 class GeckoViewContentModule {
   static initLogging(aModuleName) {
     this._moduleName = aModuleName;
-    const tag = aModuleName.replace("GeckoView", "GeckoView.") + ".[C]";
+    const tag = aModuleName.replace("GeckoView", "") + "[C]";
     return GeckoViewUtils.initLogging(tag, {});
   }
 
   static create(aGlobal, aModuleName) {
     return new this(aModuleName || this._moduleName, aGlobal);
   }
 
   constructor(aModuleName, aGlobal) {
--- a/mobile/android/modules/geckoview/GeckoViewModule.jsm
+++ b/mobile/android/modules/geckoview/GeckoViewModule.jsm
@@ -3,17 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 var EXPORTED_SYMBOLS = ["GeckoViewModule"];
 
 ChromeUtils.import("resource://gre/modules/GeckoViewUtils.jsm");
 
-GeckoViewUtils.initLogging("GeckoView.Module", this);
+GeckoViewUtils.initLogging("Module", this);
 
 class GeckoViewModule {
   constructor(aModuleInfo) {
     this._info = aModuleInfo;
 
     this._isContentLoaded = false;
     this._eventProxy = new EventProxy(this, this.eventDispatcher);
 
--- a/mobile/android/modules/geckoview/GeckoViewRemoteDebugger.jsm
+++ b/mobile/android/modules/geckoview/GeckoViewRemoteDebugger.jsm
@@ -18,17 +18,17 @@ XPCOMUtils.defineLazyGetter(this, "requi
   return require;
 });
 
 XPCOMUtils.defineLazyGetter(this, "DebuggerServer", () => {
   const { DebuggerServer } = require("devtools/server/main");
   return DebuggerServer;
 });
 
-GeckoViewUtils.initLogging("GeckoView.RemoteDebugger", this);
+GeckoViewUtils.initLogging("RemoteDebugger", this);
 
 var GeckoViewRemoteDebugger = {
   observe(aSubject, aTopic, aData) {
     if (aTopic !== "nsPref:changed") {
       return;
     }
 
     if (Services.prefs.getBoolPref(aData, false)) {
--- a/mobile/android/modules/geckoview/GeckoViewUtils.jsm
+++ b/mobile/android/modules/geckoview/GeckoViewUtils.jsm
@@ -370,40 +370,43 @@ var GeckoViewUtils = {
    *   let bar = 42;
    *   do_something(bar); // No log.
    *   do_something(debug.foo = bar); // Output "foo = 42" to the log.
    *
    * @param aTag Name of the Log.jsm logger to forward logs to.
    * @param aScope Scope to add the logging functions to.
    */
   initLogging: function(aTag, aScope) {
+    const tag = "GeckoView." + aTag.replace(/^GeckoView\.?/, "");
+
     // Only provide two levels for simplicity.
     // For "info", use "debug" instead.
     // For "error", throw an actual JS error instead.
     for (const level of ["DEBUG", "WARN"]) {
       const log = (strings, ...exprs) =>
           this._log(log.logger, level, strings, exprs);
 
       XPCOMUtils.defineLazyGetter(log, "logger", _ => {
-        const logger = Log.repository.getLogger(aTag);
+        const logger = Log.repository.getLogger(tag);
         logger.parent = this.rootLogger;
         return logger;
       });
 
       aScope[level.toLowerCase()] = new Proxy(log, {
         set: (obj, prop, value) => obj([prop + " = ", ""], value) || true,
       });
     }
     return aScope;
   },
 
   get rootLogger() {
     if (!this._rootLogger) {
       this._rootLogger = Log.repository.getLogger("GeckoView");
       this._rootLogger.addAppender(new AndroidAppender());
+      this._rootLogger.manageLevelFromPref("geckoview.logging");
     }
     return this._rootLogger;
   },
 
   _log: function(aLogger, aLevel, aStrings, aExprs) {
     if (!Array.isArray(aStrings)) {
       const [, file, line] =
           (new Error()).stack.match(/.*\n.*\n.*@(.*):(\d+):/);
--- a/python/mozbuild/mozbuild/action/test_archive.py
+++ b/python/mozbuild/mozbuild/action/test_archive.py
@@ -404,17 +404,29 @@ ARCHIVE_FILES = {
         {
             'source': buildconfig.topsrcdir,
             'base': '',
             'manifests': [
                 'layout/reftests/reftest.list',
                 'testing/crashtest/crashtests.list',
             ],
             'dest': 'reftest/tests',
-        }
+        },
+        {
+            'source': buildconfig.topobjdir,
+            'base': 'dist/xpi-stage',
+            'pattern': 'reftest/**',
+            'dest': 'reftest'
+        },
+        {
+            'source': buildconfig.topobjdir,
+            'base': 'dist/xpi-stage',
+            'pattern': 'specialpowers/**',
+            'dest': 'reftest'
+        },
     ],
     'talos': [
         {
             'source': buildconfig.topsrcdir,
             'base': 'testing',
             'pattern': 'talos/**',
         },
         {
--- a/python/mozbuild/mozbuild/mach_commands.py
+++ b/python/mozbuild/mozbuild/mach_commands.py
@@ -2697,16 +2697,19 @@ class Vendor(MachCommandBase):
         default=False)
     def vendor_aom(self, **kwargs):
         from mozbuild.vendor_aom import VendorAOM
         vendor_command = self._spawn(VendorAOM)
         vendor_command.vendor(**kwargs)
 
     @SubCommand('vendor', 'python',
                 description='Vendor Python packages from pypi.org into third_party/python')
+    @CommandArgument('--with-windows-wheel', action='store_true',
+        help='Vendor a wheel for Windows along with the source package',
+        default=False)
     @CommandArgument('packages', default=None, nargs='*', help='Packages to vendor. If omitted, packages and their dependencies defined in Pipfile.lock will be vendored. If Pipfile has been modified, then Pipfile.lock will be regenerated. Note that transient dependencies may be updated when running this command.')
     def vendor_python(self, **kwargs):
         from mozbuild.vendor_python import VendorPython
         vendor_command = self._spawn(VendorPython)
         vendor_command.vendor(**kwargs)
 
     @SubCommand('vendor', 'manifest',
                 description='Vendor externally hosted repositories into this '
--- a/python/mozbuild/mozbuild/vendor_python.py
+++ b/python/mozbuild/mozbuild/vendor_python.py
@@ -12,24 +12,26 @@ import mozfile
 import mozpack.path as mozpath
 from mozbuild.base import MozbuildObject
 from mozfile import NamedTemporaryFile, TemporaryDirectory
 from mozpack.files import FileFinder
 
 
 class VendorPython(MozbuildObject):
 
-    def vendor(self, packages=None):
+    def vendor(self, packages=None, with_windows_wheel=False):
         self.populate_logger()
         self.log_manager.enable_unstructured()
 
         vendor_dir = mozpath.join(
             self.topsrcdir, os.path.join('third_party', 'python'))
 
         packages = packages or []
+        if with_windows_wheel and len(packages) != 1:
+            raise Exception('--with-windows-wheel is only supported for a single package!')
 
         self._activate_virtualenv()
         pip_compile = os.path.join(self.virtualenv_manager.bin_path, 'pip-compile')
         if not os.path.exists(pip_compile):
             path = os.path.normpath(os.path.join(self.topsrcdir, 'third_party', 'python', 'pip-tools'))
             self.virtualenv_manager.install_pip_package(path, vendored=True)
         spec = os.path.join(vendor_dir, 'requirements.in')
         requirements = os.path.join(vendor_dir, 'requirements.txt')
@@ -51,16 +53,31 @@ class VendorPython(MozbuildObject):
                 # use requirements.txt to download archived source distributions of all packages
                 self.virtualenv_manager._run_pip([
                     'download',
                     '-r', requirements,
                     '--no-deps',
                     '--dest', tmp,
                     '--no-binary', ':all:',
                     '--disable-pip-version-check'])
+                if with_windows_wheel:
+                    # This is hardcoded to CPython 2.7 for win64, which is good
+                    # enough for what we need currently. If we need psutil for Python 3
+                    # in the future that coudl be added here as well.
+                    self.virtualenv_manager._run_pip([
+                        'download',
+                        '--dest', tmp,
+                        '--no-deps',
+                        '--only-binary', ':all:',
+                        '--platform', 'win_amd64',
+                        '--implementation', 'cp',
+                        '--python-version', '27',
+                        '--abi', 'none',
+                        '--disable-pip-version-check',
+                        packages[0]])
                 self._extract(tmp, vendor_dir)
 
             shutil.copyfile(tmpspec.name, spec)
             self.repository.add_remove_files(vendor_dir)
 
     def _update_packages(self, spec, packages):
         for package in packages:
             if not all(package.partition('==')):
@@ -78,13 +95,36 @@ class VendorPython(MozbuildObject):
         with open(spec, 'w') as f:
             for name, version in sorted(requirements.items()):
                 f.write('{}=={}\n'.format(name, version))
 
     def _extract(self, src, dest):
         """extract source distribution into vendor directory"""
         finder = FileFinder(src)
         for path, _ in finder.find('*'):
-            # packages extract into package-version directory name and we strip the version
-            tld = mozfile.extract(os.path.join(finder.base, path), dest)[0]
-            target = os.path.join(dest, tld.rpartition('-')[0])
-            mozfile.remove(target)  # remove existing version of vendored package
-            mozfile.move(tld, target)
+            base, ext = os.path.splitext(path)
+            if ext == '.whl':
+                # Wheels would extract into a directory with the name of the package, but
+                # we want the platform signifiers, minus the version number.
+                # Wheel filenames look like:
+                # {distribution}-{version}(-{build tag})?-{python tag}-{abi tag}-{platform tag}
+                bits = base.split('-')
+
+                # Remove the version number.
+                bits.pop(1)
+                target = os.path.join(dest, '-'.join(bits))
+                mozfile.remove(target)  # remove existing version of vendored package
+                os.mkdir(target)
+                mozfile.extract(os.path.join(finder.base, path), target)
+            else:
+                # packages extract into package-version directory name and we strip the version
+                tld = mozfile.extract(os.path.join(finder.base, path), dest)[0]
+                target = os.path.join(dest, tld.rpartition('-')[0])
+                mozfile.remove(target)  # remove existing version of vendored package
+                mozfile.move(tld, target)
+            # If any files inside the vendored package were symlinks, turn them into normal files
+            # because hg.mozilla.org forbids symlinks in the repository.
+            link_finder = FileFinder(target)
+            for _, f in link_finder.find('**'):
+                if os.path.islink(f.path):
+                    link_target = os.path.realpath(f.path)
+                    os.unlink(f.path)
+                    shutil.copyfile(link_target, f.path)
--- a/python/mozbuild/mozbuild/virtualenv.py
+++ b/python/mozbuild/mozbuild/virtualenv.py
@@ -249,16 +249,22 @@ class VirtualenvManager(object):
         packages.txt -- Denotes that the specified path is a child manifest. It
             will be read and processed as if its contents were concatenated
             into the manifest being read.
 
         objdir -- Denotes a relative path in the object directory to add to the
             search path. e.g. "objdir:build" will add $topobjdir/build to the
             search path.
 
+        windows -- This denotes that the action should only be taken when run
+            on Windows.
+
+        !windows -- This denotes that the action should only be taken when run
+            on non-Windows systems.
+
         Note that the Python interpreter running this function should be the
         one from the virtualenv. If it is the system Python or if the
         environment is not configured properly, packages could be installed
         into the wrong place. This is how virtualenv's work.
         """
         packages = self.packages()
         python_lib = distutils.sysconfig.get_python_lib()
 
@@ -318,16 +324,23 @@ class VirtualenvManager(object):
                     handle_package(package[1:])
                     return True
                 except:
                     print('Error processing command. Ignoring', \
                         'because optional. (%s)' % ':'.join(package),
                         file=self.log_handle)
                     return False
 
+            if package[0] in ('windows', '!windows'):
+                for_win = not package[0].startswith('!')
+                is_win = sys.platform == 'win32'
+                if is_win == for_win:
+                    handle_package(package[1:])
+                return True
+
             if package[0] == 'objdir':
                 assert len(package) == 2
                 path = os.path.join(self.topobjdir, package[1])
 
                 with open(os.path.join(python_lib, 'objdir.pth'), 'a') as f:
                     f.write('%s\n' % path)
 
                 return True
--- a/python/mozlint/mozlint/pathutils.py
+++ b/python/mozlint/mozlint/pathutils.py
@@ -4,20 +4,25 @@
 
 from __future__ import unicode_literals, absolute_import
 
 import os
 
 from mozpack import path as mozpath
 from mozpack.files import FileFinder
 
+try:
+    from os import scandir, walk
+except ImportError:
+    from scandir import scandir, walk
+
 
 class FilterPath(object):
     """Helper class to make comparing and matching file paths easier."""
-    def __init__(self, path, exclude=None):
+    def __init__(self, path):
         self.path = os.path.normpath(path)
         self._finder = None
 
     @property
     def finder(self):
         if self._finder:
             return self._finder
         self._finder = FileFinder(mozpath.normsep(self.path))
@@ -62,16 +67,73 @@ class FilterPath(object):
         if b.startswith(a):
             return True
         return False
 
     def __repr__(self):
         return repr(self.path)
 
 
+def collapse(paths, base=None, dotfiles=False):
+    """Given an iterable of paths, collapse them into the smallest possible set
+    of paths that contain the original set (without containing any extra paths).
+
+    For example, if directory 'a' contains two files b.txt and c.txt, calling:
+
+        collapse(['a/b.txt', 'a/c.txt'])
+
+    returns ['a']. But if a third file d.txt also exists, then it will return
+    ['a/b.txt', 'a/c.txt'] since ['a'] would also include that extra file.
+
+    :param paths: An iterable of paths (files and directories) to collapse.
+    :returns: The smallest set of paths (files and directories) that contain
+              the original set of paths and only the original set.
+    """
+    if not paths:
+        if not base:
+            return []
+
+        # Need to test whether directory chain is empty. If it is then bubble
+        # the base back up so that it counts as 'covered'.
+        for _, _, names in walk(base):
+            if names:
+                return []
+        return [base]
+
+    if not base:
+        paths = map(mozpath.abspath, paths)
+        base = mozpath.commonprefix(paths)
+
+        if not os.path.isdir(base):
+            base = os.path.dirname(base)
+
+    covered = set()
+    full = set()
+    for entry in scandir(base):
+        if not dotfiles and entry.name[0] == '.':
+            continue
+
+        path = mozpath.normpath(entry.path)
+        full.add(path)
+
+        if path in paths:
+            # This path was explicitly specified, so just bubble it back up
+            # without recursing down into it (if it was a directory).
+            covered.add(path)
+        elif entry.is_dir():
+            new_paths = [p for p in paths if p.startswith(path)]
+            covered.update(collapse(new_paths, base=path, dotfiles=dotfiles))
+
+    if full == covered:
+        # Every file under this base was covered, so we can collapse them all
+        # up into the base path.
+        return [base]
+    return covered
+
+
 def filterpaths(paths, linter, **lintargs):
     """Filters a list of paths.
 
     Given a list of paths, and a linter definition plus extra
     arguments, return the set of paths that should be linted.
 
     :param paths: A starting list of paths to possibly lint.
     :param linter: A linter definition.
@@ -138,17 +200,17 @@ def filterpaths(paths, linter, **lintarg
 
         # Next expand excludes with globs in them so we can add them to
         # the set of files to discard.
         for pattern in excludeglobs:
             for p, f in path.finder.find(pattern):
                 discard.add(path.join(p))
 
     # Only pass paths we couldn't exclude here to the underlying linter
-    lintargs['exclude'] = [f.path for f in discard]
+    lintargs['exclude'] = collapse([f.path for f in discard])
     return [f.path for f in keep]
 
 
 def findobject(path):
     """
     Find a Python object given a path of the form <modulepath>:<objectpath>.
     Conceptually equivalent to
 
--- a/python/mozlint/test/test_pathutils.py
+++ b/python/mozlint/test/test_pathutils.py
@@ -1,16 +1,17 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-from __future__ import absolute_import
+from __future__ import absolute_import, print_function
 
 import os
 from copy import deepcopy
+from fnmatch import fnmatch
 
 import mozunit
 import pytest
 
 from mozlint import pathutils
 
 here = os.path.abspath(os.path.dirname(__file__))
 root = os.path.join(here, 'filter')
@@ -97,10 +98,34 @@ TEST_CASES = (
 @pytest.mark.parametrize('test', TEST_CASES)
 def test_filterpaths(filterpaths, test):
     expected = test.pop('expected')
 
     paths = filterpaths(**test)
     assert_paths(paths, expected)
 
 
+@pytest.mark.parametrize('paths,expected', [
+    (['subdir1/*'], ['subdir1']),
+    (['subdir2/*'], ['subdir2']),
+    (['subdir1/*.*', 'subdir1/subdir3/*', 'subdir2/*'], ['subdir1', 'subdir2']),
+    ([root + '/*', 'subdir1/*.*', 'subdir1/subdir3/*', 'subdir2/*'], [root]),
+    (['subdir1/b.py', 'subdir1/subdir3'], ['subdir1/b.py', 'subdir1/subdir3']),
+    (['subdir1/b.py', 'subdir1/b.js'], ['subdir1/b.py', 'subdir1/b.js']),
+])
+def test_collapse(paths, expected):
+    inputs = []
+    for path in paths:
+        base, name = os.path.split(path)
+        if '*' in name:
+            for n in os.listdir(base):
+                if not fnmatch(n, name):
+                    continue
+                inputs.append(os.path.join(base, n))
+        else:
+            inputs.append(path)
+
+    print("inputs: {}".format(inputs))
+    assert_paths(pathutils.collapse(inputs), expected)
+
+
 if __name__ == '__main__':
     mozunit.main()
--- a/servo/components/style/gecko_bindings/sugar/ns_css_value.rs
+++ b/servo/components/style/gecko_bindings/sugar/ns_css_value.rs
@@ -55,17 +55,17 @@ impl nsCSSValue {
         unsafe { *self.mValue.mFloat.as_ref() }
     }
 
     /// Returns this nsCSSValue as a nsCSSValue::Array, unchecked in release
     /// builds.
     pub unsafe fn array_unchecked(&self) -> &nsCSSValue_Array {
         debug_assert!(
             nsCSSUnit::eCSSUnit_Array as u32 <= self.mUnit as u32 &&
-                self.mUnit as u32 <= nsCSSUnit::eCSSUnit_Calc_Divided as u32
+                self.mUnit as u32 <= nsCSSUnit::eCSSUnit_Calc_Plus as u32
         );
         let array = *self.mValue.mArray.as_ref();
         debug_assert!(!array.is_null());
         &*array
     }
 
     /// Sets LengthOrPercentage value to this nsCSSValue.
     pub unsafe fn set_lop(&mut self, lop: LengthOrPercentage) {
--- a/taskcluster/ci/static-analysis/kind.yml
+++ b/taskcluster/ci/static-analysis/kind.yml
@@ -43,18 +43,18 @@ jobs:
             options: [append-env-variables-from-configs]
             script: mozharness/scripts/fx_desktop_build.py
             config:
                 - builds/releng_base_firefox.py
                 - builds/taskcluster_base_windows.py
                 - builds/taskcluster_base_win32.py
                 - builds/taskcluster_sub_win32/clang_debug.py
         toolchains:
-            - win32-clang-cl-st-an
-            - win32-rust
+            - win64-clang-cl-st-an
+            - win64-rust
             - win64-cbindgen
             - win64-sccache
             - win64-node
 
     win32-st-an/opt:
         description: "Win32 Static Analysis Opt (clang-cl)"
         index:
             product: firefox
@@ -74,18 +74,18 @@ jobs:
             options: [append-env-variables-from-configs]
             script: mozharness/scripts/fx_desktop_build.py
             config:
                 - builds/releng_base_firefox.py
                 - builds/taskcluster_base_windows.py
                 - builds/taskcluster_base_win32.py
                 - builds/taskcluster_sub_win32/clang.py
         toolchains:
-            - win32-clang-cl-st-an
-            - win32-rust
+            - win64-clang-cl-st-an
+            - win64-rust
             - win64-cbindgen
             - win64-sccache
             - win64-node
 
     win64-st-an/debug:
         description: "Win64 Static Analysis Debug (clang-cl)"
         index:
             product: firefox
--- a/taskcluster/ci/test/mochitest.yml
+++ b/taskcluster/ci/test/mochitest.yml
@@ -106,16 +106,17 @@ mochitest-browser-chrome:
     description: "Mochitest browser-chrome run"
     suite: mochitest/browser-chrome-chunked
     treeherder-symbol: M(bc)
     loopback-video: true
     chunks:
         by-test-platform:
             linux.*/debug: 16
             linux64-asan/opt: 16
+            macosx64/debug: 12
             default: 7
     max-run-time:
         by-test-platform:
             linux64-.*cov/opt: 7200
             windows10-64-ccov/debug: 7200
             macosx64-ccov/debug: 10800
             linux.*/debug: 5400
             default: 3600
--- a/taskcluster/ci/toolchain/windows.yml
+++ b/taskcluster/ci/toolchain/windows.yml
@@ -18,37 +18,16 @@ win64-clang-cl:
         using: toolchain-script
         script: build-clang64-windows.sh
         resources:
             - 'build/build-clang/build-clang.py'
             - 'build/build-clang/clang-win64.json'
             - 'taskcluster/scripts/misc/build-clang-windows-helper64.sh'
         toolchain-artifact: public/build/clang.tar.bz2
 
-win32-clang-cl-st-an:
-    description: "Clang-cl static analysis toolchain build"
-    treeherder:
-        kind: build
-        platform: toolchains/opt
-        symbol: TW32(clang-cl-st-an)
-        tier: 1
-    worker-type: aws-provisioner-v1/gecko-{level}-b-win2012
-    worker:
-        max-run-time: 7200
-        env:
-            TOOLTOOL_MANIFEST: "browser/config/tooltool-manifests/win32/build-clang-cl.manifest"
-    run:
-        using: toolchain-script
-        script: build-clang32-st-an-windows.sh
-        resources:
-            - 'build/build-clang/build-clang.py'
-            - 'build/build-clang/clang-win32-st-an.json'
-            - 'taskcluster/scripts/misc/build-clang-windows-helper32.sh'
-        toolchain-artifact: public/build/clang.tar.bz2
-
 win64-clang-cl-st-an:
     description: "Clang-cl static analysis toolchain build"
     treeherder:
         kind: build
         platform: toolchains/opt
         symbol: TW64(clang-cl-st-an)
         tier: 1
     worker-type: aws-provisioner-v1/gecko-{level}-b-win2012
@@ -204,40 +183,16 @@ win64-node:
         docker-image: {in-tree: toolchain-build}
         max-run-time: 1800
     run:
         using: toolchain-script
         script: repack-node.sh
         arguments: ['win64']
         toolchain-artifact: public/build/node.tar.bz2
 
-win32-rust-1.29:
-    description: "rust repack"
-    treeherder:
-        kind: build
-        platform: toolchains/opt
-        symbol: TW32(rust)
-        tier: 1
-    worker-type: aws-provisioner-v1/gecko-{level}-b-linux
-    worker:
-        docker-image: {in-tree: toolchain-build}
-        max-run-time: 7200
-        env:
-            UPLOAD_DIR: artifacts
-    run:
-        using: toolchain-script
-        script: repack_rust.py
-        arguments: [
-            '--channel', '1.29.0',
-            '--host', 'i686-pc-windows-msvc',
-            '--target', 'i686-pc-windows-msvc',
-        ]
-        toolchain-alias: win32-rust
-        toolchain-artifact: public/build/rustc.tar.bz2
-
 mingw32-rust-1.29:
     description: "rust repack"
     treeherder:
         kind: build
         platform: toolchains/opt
         symbol: TMW(rust)
         tier: 1
     worker-type: aws-provisioner-v1/gecko-{level}-b-linux
deleted file mode 100755
--- a/taskcluster/scripts/misc/build-clang32-st-an-windows.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/bash
-
-source build/src/taskcluster/scripts/misc/build-clang-windows-helper32.sh clang-win32-st-an.json
--- a/testing/mochitest/tests/Harness_sanity/mochitest.ini
+++ b/testing/mochitest/tests/Harness_sanity/mochitest.ini
@@ -38,8 +38,9 @@ subsuite = clipboard
 skip-if = toolkit == 'android'  # bug 688052
 [test_sanity_manifest.html]
 skip-if = toolkit == 'android' # we use the old manifest style on android
 fail-if = true
 [test_sanity_manifest_pf.html]
 skip-if = toolkit == 'android' # we use the old manifest style on android
 fail-if = true
 [test_sanity_waitForCondition.html]
+[test_getweakmapkeys.html]
new file mode 100644
--- /dev/null
+++ b/testing/mochitest/tests/Harness_sanity/test_getweakmapkeys.html
@@ -0,0 +1,26 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test for SpecialPowers.nondeterministicGetWeakMapKeys</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+
+<div id="content" class="testbody">
+  <script type="text/javascript">
+    var emptyMap = new WeakMap;
+    is(SpecialPowers.nondeterministicGetWeakMapKeys(emptyMap).length, 0, "Empty map has no keys");
+    var twoMap = new WeakMap;
+    var x = {};
+    var y = {};
+    twoMap.set(x, 1);
+    twoMap.set(y, 2);
+    var twoMapKeys = SpecialPowers.nondeterministicGetWeakMapKeys(twoMap);
+    is(twoMapKeys.length, 2, "Map with two things should have two keys");
+    ok(twoMapKeys[0] == x || twoMapKeys[1] == x, "One of the keys should be x");
+    ok(twoMapKeys[0] == y || twoMapKeys[1] == y, "One of the keys should be y");
+  </script>
+</div>
+</body>
+</html>
--- a/testing/specialpowers/Makefile.in
+++ b/testing/specialpowers/Makefile.in
@@ -1,18 +1,6 @@
 #
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-TEST_EXTENSIONS_DIR = $(DEPTH)/testing/specialpowers
 XPI_PKGNAME = specialpowers@mozilla.org
-
-include $(topsrcdir)/config/rules.mk
-
-libs-preqs = \
-  $(call mkdir_deps,$(TEST_EXTENSIONS_DIR)) \
-  $(NULL)
-
-libs:: $(libs-preqs)
-	(cd $(DIST)/xpi-stage && tar $(TAR_CREATE_FLAGS) - $(XPI_NAME)) | (cd $(TEST_EXTENSIONS_DIR) && tar -xf -)
-	$(NSINSTALL) -D $(DEPTH)/_tests/reftest/specialpowers
-	cp -RL $(DEPTH)/testing/specialpowers/specialpowers $(DEPTH)/_tests/reftest
--- a/testing/specialpowers/content/specialpowersAPI.js
+++ b/testing/specialpowers/content/specialpowersAPI.js
@@ -1607,16 +1607,20 @@ SpecialPowersAPI.prototype = {
           cb();
         }
       };
     }
 
     Cu.schedulePreciseGC(genGCCallback(callback));
   },
 
+  nondeterministicGetWeakMapKeys(m) {
+    return ChromeUtils.nondeterministicGetWeakMapKeys(m);
+  },
+
   getMemoryReports() {
     try {
       Cc["@mozilla.org/memory-reporter-manager;1"]
         .getService(Ci.nsIMemoryReporterManager)
         .getReports(() => {}, null, () => {}, null, false);
     } catch (e) { }
   },
 
--- a/testing/web-platform/mach_commands.py
+++ b/testing/web-platform/mach_commands.py
@@ -22,22 +22,28 @@ from mach.decorators import (
 
 from mach_commands_base import WebPlatformTestsRunner, create_parser_wpt
 
 
 class WebPlatformTestsRunnerSetup(MozbuildObject):
     default_log_type = "mach"
 
     def kwargs_common(self, kwargs):
+        from mozrunner.devices.android_device import verify_android_device
         build_path = os.path.join(self.topobjdir, 'build')
         here = os.path.split(__file__)[0]
         tests_src_path = os.path.join(here, "tests")
         if build_path not in sys.path:
             sys.path.append(build_path)
 
+        if kwargs["product"] == "fennec":
+            verify_android_device(self, install=True, verbose=False, xre=True)
+            if kwargs["certutil_binary"] is None:
+                kwargs["certutil_binary"] = os.path.join(os.environ.get('MOZ_HOST_BIN'), "certutil")
+
         if kwargs["config"] is None:
             kwargs["config"] = os.path.join(self.topobjdir, '_tests', 'web-platform', 'wptrunner.local.ini')
 
         if kwargs["prefs_root"] is None:
             kwargs["prefs_root"] = os.path.join(self.topsrcdir, 'testing', 'profiles')
 
         if kwargs["stackfix_dir"] is None:
             kwargs["stackfix_dir"] = self.bindir
new file mode 100644
--- /dev/null
+++ b/third_party/python/psutil-cp27-none-win_amd64/psutil-5.4.3.dist-info/DESCRIPTION.rst
@@ -0,0 +1,472 @@
+.. image:: https://img.shields.io/travis/giampaolo/psutil/master.svg?maxAge=3600&label=Linux%20/%20OSX
+    :target: https://travis-ci.org/giampaolo/psutil
+    :alt: Linux tests (Travis)
+
+.. image:: https://img.shields.io/appveyor/ci/giampaolo/psutil/master.svg?maxAge=3600&label=Windows
+    :target: https://ci.appveyor.com/project/giampaolo/psutil
+    :alt: Windows tests (Appveyor)
+
+.. image:: https://coveralls.io/repos/github/giampaolo/psutil/badge.svg?branch=master
+    :target: https://coveralls.io/github/giampaolo/psutil?branch=master
+    :alt: Test coverage (coverall.io)
+
+.. image:: https://readthedocs.org/projects/psutil/badge/?version=latest
+    :target: http://psutil.readthedocs.io/en/latest/?badge=latest
+    :alt: Documentation Status
+
+.. image:: https://img.shields.io/pypi/v/psutil.svg?label=pypi
+    :target: https://pypi.python.org/pypi/psutil/
+    :alt: Latest version
+
+.. image:: https://img.shields.io/github/stars/giampaolo/psutil.svg
+    :target: https://github.com/giampaolo/psutil/
+    :alt: Github stars
+
+.. image:: https://img.shields.io/pypi/l/psutil.svg
+    :target: https://pypi.python.org/pypi/psutil/
+    :alt: License
+
+===========
+Quick links
+===========
+
+- `Home page <https://github.com/giampaolo/psutil>`_
+- `Install <https://github.com/giampaolo/psutil/blob/master/INSTALL.rst>`_
+- `Documentation <http://psutil.readthedocs.io>`_
+- `Download <https://pypi.python.org/pypi?:action=display&name=psutil#downloads>`_
+- `Forum <http://groups.google.com/group/psutil/topics>`_
+- `Blog <http://grodola.blogspot.com/search/label/psutil>`_
+- `Development guide <https://github.com/giampaolo/psutil/blob/master/DEVGUIDE.rst>`_
+- `What's new <https://github.com/giampaolo/psutil/blob/master/HISTORY.rst>`_
+
+=======
+Summary
+=======
+
+psutil (process and system utilities) is a cross-platform library for
+retrieving information on **running processes** and **system utilization**
+(CPU, memory, disks, network, sensors) in Python.
+It is useful mainly for **system monitoring**, **profiling and limiting process
+resources** and **management of running processes**.
+It implements many functionalities offered by UNIX command line tools such as:
+ps, top, lsof, netstat, ifconfig, who, df, kill, free, nice, ionice, iostat,
+iotop, uptime, pidof, tty, taskset, pmap.
+psutil currently supports the following platforms:
+
+- **Linux**
+- **Windows**
+- **OSX**,
+- **FreeBSD, OpenBSD**, **NetBSD**
+- **Sun Solaris**
+- **AIX**
+
+...both **32-bit** and **64-bit** architectures, with Python
+versions from **2.6 to 3.6**.
+`PyPy <http://pypy.org/>`__ is also known to work.
+
+====================
+Example applications
+====================
+
++------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------+
+| .. image:: https://github.com/giampaolo/psutil/blob/master/docs/_static/procinfo-small.png     | .. image:: https://github.com/giampaolo/psutil/blob/master/docs/_static/top-small.png      |
+|    :target: https://github.com/giampaolo/psutil/blob/master/docs/_static/procinfo.png          |     :target: https://github.com/giampaolo/psutil/blob/master/docs/_static/top.png          |
++------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------+
+| .. image:: https://github.com/giampaolo/psutil/blob/master/docs/_static/procsmem-small.png     | .. image:: https://github.com/giampaolo/psutil/blob/master/docs/_static/pmap-small.png     |
+|     :target: https://github.com/giampaolo/psutil/blob/master/docs/_static/procsmem.png         |     :target: https://github.com/giampaolo/psutil/blob/master/docs/_static/pmap.png         |
++------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------+
+
+Also see `scripts directory <https://github.com/giampaolo/psutil/tree/master/scripts>`__
+and `doc recipes <http://psutil.readthedocs.io/#recipes/>`__.
+
+=====================
+Projects using psutil
+=====================
+
+At the time of writing psutil has roughly
+`2.9 milion downloads <https://github.com/giampaolo/psutil/issues/1053#issuecomment-340166262>`__
+per month and there are over
+`6000 open source projects <https://libraries.io/pypi/psutil/dependent_repositories?page=1>`__
+on github which depend from psutil.
+Here's some I find particularly interesting:
+
+- https://github.com/facebook/osquery/
+- https://github.com/nicolargo/glances
+- https://github.com/google/grr
+- https://github.com/Jahaja/psdash
+- https://github.com/ajenti/ajenti
+- https://github.com/home-assistant/home-assistant/
+
+========
+Portings
+========
+
+- Go: https://github.com/shirou/gopsutil
+- C: https://github.com/hamon-in/cpslib
+- Node: https://github.com/christkv/node-psutil
+- Rust: https://github.com/borntyping/rust-psutil
+- Ruby: https://github.com/spacewander/posixpsutil
+- Nim: https://github.com/johnscillieri/psutil-nim
+
+==============
+Example usages
+==============
+
+CPU
+===
+
+.. code-block:: python
+
+    >>> import psutil
+    >>> psutil.cpu_times()
+    scputimes(user=3961.46, nice=169.729, system=2150.659, idle=16900.540, iowait=629.59, irq=0.0, softirq=19.42, steal=0.0, guest=0, nice=0.0)
+    >>>
+    >>> for x in range(3):
+    ...     psutil.cpu_percent(interval=1)
+    ...
+    4.0
+    5.9
+    3.8
+    >>>
+    >>> for x in range(3):
+    ...     psutil.cpu_percent(interval=1, percpu=True)
+    ...
+    [4.0, 6.9, 3.7, 9.2]
+    [7.0, 8.5, 2.4, 2.1]
+    [1.2, 9.0, 9.9, 7.2]
+    >>>
+    >>> for x in range(3):
+    ...     psutil.cpu_times_percent(interval=1, percpu=False)
+    ...
+    scputimes(user=1.5, nice=0.0, system=0.5, idle=96.5, iowait=1.5, irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0)
+    scputimes(user=1.0, nice=0.0, system=0.0, idle=99.0, iowait=0.0, irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0)
+    scputimes(user=2.0, nice=0.0, system=0.0, idle=98.0, iowait=0.0, irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0)
+    >>>
+    >>> psutil.cpu_count()
+    4
+    >>> psutil.cpu_count(logical=False)
+    2
+    >>>
+    >>> psutil.cpu_stats()
+    scpustats(ctx_switches=20455687, interrupts=6598984, soft_interrupts=2134212, syscalls=0)
+    >>>
+    >>> psutil.cpu_freq()
+    scpufreq(current=931.42925, min=800.0, max=3500.0)
+    >>>
+
+Memory
+======
+
+.. code-block:: python
+
+    >>> import psutil
+    >>> psutil.virtual_memory()
+    svmem(total=10367352832, available=6472179712, percent=37.6, used=8186245120, free=2181107712, active=4748992512, inactive=2758115328, buffers=790724608, cached=3500347392, shared=787554304)
+    >>> psutil.swap_memory()
+    sswap(total=2097147904, used=296128512, free=1801019392, percent=14.1, sin=304193536, sout=677842944)
+    >>>
+
+Disks
+=====
+
+.. code-block:: python
+
+    >>> import psutil
+    >>> psutil.disk_partitions()
+    [sdiskpart(device='/dev/sda1', mountpoint='/', fstype='ext4', opts='rw,nosuid'),
+     sdiskpart(device='/dev/sda2', mountpoint='/home', fstype='ext, opts='rw')]
+    >>>
+    >>> psutil.disk_usage('/')
+    sdiskusage(total=21378641920, used=4809781248, free=15482871808, percent=22.5)
+    >>>
+    >>> psutil.disk_io_counters(perdisk=False)
+    sdiskio(read_count=719566, write_count=1082197, read_bytes=18626220032, write_bytes=24081764352, read_time=5023392, write_time=63199568, read_merged_count=619166, write_merged_count=812396, busy_time=4523412)
+    >>>
+
+Network
+=======
+
+.. code-block:: python
+
+    >>> import psutil
+    >>> psutil.net_io_counters(pernic=True)
+    {'eth0': netio(bytes_sent=485291293, bytes_recv=6004858642, packets_sent=3251564, packets_recv=4787798, errin=0, errout=0, dropin=0, dropout=0),
+     'lo': netio(bytes_sent=2838627, bytes_recv=2838627, packets_sent=30567, packets_recv=30567, errin=0, errout=0, dropin=0, dropout=0)}
+    >>>
+    >>> psutil.net_connections()
+    [sconn(fd=115, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=48776), raddr=addr(ip='93.186.135.91', port=80), status='ESTABLISHED', pid=1254),
+     sconn(fd=117, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=43761), raddr=addr(ip='72.14.234.100', port=80), status='CLOSING', pid=2987),
+     sconn(fd=-1, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=60759), raddr=addr(ip='72.14.234.104', port=80), status='ESTABLISHED', pid=None),
+     sconn(fd=-1, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=51314), raddr=addr(ip='72.14.234.83', port=443), status='SYN_SENT', pid=None)
+     ...]
+    >>>
+    >>> psutil.net_if_addrs()
+    {'lo': [snic(family=<AddressFamily.AF_INET: 2>, address='127.0.0.1', netmask='255.0.0.0', broadcast='127.0.0.1', ptp=None),
+            snic(family=<AddressFamily.AF_INET6: 10>, address='::1', netmask='ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff', broadcast=None, ptp=None),
+            snic(family=<AddressFamily.AF_LINK: 17>, address='00:00:00:00:00:00', netmask=None, broadcast='00:00:00:00:00:00', ptp=None)],
+     'wlan0': [snic(family=<AddressFamily.AF_INET: 2>, address='192.168.1.3', netmask='255.255.255.0', broadcast='192.168.1.255', ptp=None),
+               snic(family=<AddressFamily.AF_INET6: 10>, address='fe80::c685:8ff:fe45:641%wlan0', netmask='ffff:ffff:ffff:ffff::', broadcast=None, ptp=None),
+               snic(family=<AddressFamily.AF_LINK: 17>, address='c4:85:08:45:06:41', netmask=None, broadcast='ff:ff:ff:ff:ff:ff', ptp=None)]}
+    >>>
+    >>> psutil.net_if_stats()
+    {'eth0': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_FULL: 2>, speed=100, mtu=1500),
+     'lo': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_UNKNOWN: 0>, speed=0, mtu=65536)}
+    >>>
+
+Sensors
+=======
+
+.. code-block:: python
+
+    >>> import psutil
+    >>> psutil.sensors_temperatures()
+    {'acpitz': [shwtemp(label='', current=47.0, high=103.0, critical=103.0)],
+     'asus': [shwtemp(label='', current=47.0, high=None, critical=None)],
+     'coretemp': [shwtemp(label='Physical id 0', current=52.0, high=100.0, critical=100.0),
+                  shwtemp(label='Core 0', current=45.0, high=100.0, critical=100.0),
+                  shwtemp(label='Core 1', current=52.0, high=100.0, critical=100.0),
+                  shwtemp(label='Core 2', current=45.0, high=100.0, critical=100.0),
+                  shwtemp(label='Core 3', current=47.0, high=100.0, critical=100.0)]}
+    >>>
+    >>> psutil.sensors_fans()
+    {'asus': [sfan(label='cpu_fan', current=3200)]}
+    >>>
+    >>> psutil.sensors_battery()
+    sbattery(percent=93, secsleft=16628, power_plugged=False)
+    >>>
+
+Other system info
+=================
+
+.. code-block:: python
+
+    >>> import psutil
+    >>> psutil.users()
+    [suser(name='giampaolo', terminal='pts/2', host='localhost', started=1340737536.0, pid=1352),
+     suser(name='giampaolo', terminal='pts/3', host='localhost', started=1340737792.0, pid=1788)]
+    >>>
+    >>> psutil.boot_time()
+    1365519115.0
+    >>>
+
+Process management
+==================
+
+.. code-block:: python
+
+    >>> import psutil
+    >>> psutil.pids()
+    [1, 2, 3, 4, 5, 6, 7, 46, 48, 50, 51, 178, 182, 222, 223, 224, 268, 1215, 1216, 1220, 1221, 1243, 1244,
+     1301, 1601, 2237, 2355, 2637, 2774, 3932, 4176, 4177, 4185, 4187, 4189, 4225, 4243, 4245, 4263, 4282,
+     4306, 4311, 4312, 4313, 4314, 4337, 4339, 4357, 4358, 4363, 4383, 4395, 4408, 4433, 4443, 4445, 4446,
+     5167, 5234, 5235, 5252, 5318, 5424, 5644, 6987, 7054, 7055, 7071]
+    >>>
+    >>> p = psutil.Process(7055)
+    >>> p.name()
+    'python'
+    >>> p.exe()
+    '/usr/bin/python'
+    >>> p.cwd()
+    '/home/giampaolo'
+    >>> p.cmdline()
+    ['/usr/bin/python', 'main.py']
+    >>>
+    >>> p.pid
+    7055
+    >>> p.ppid()
+    7054
+    >>> p.parent()
+    <psutil.Process(pid=7054, name='bash') at 140008329539408>
+    >>> p.children()
+    [<psutil.Process(pid=8031, name='python') at 14020832451977>,
+     <psutil.Process(pid=8044, name='python') at 19229444921932>]
+    >>>
+    >>> p.status()
+    'running'
+    >>> p.username()
+    'giampaolo'
+    >>> p.create_time()
+    1267551141.5019531
+    >>> p.terminal()
+    '/dev/pts/0'
+    >>>
+    >>> p.uids()
+    puids(real=1000, effective=1000, saved=1000)
+    >>> p.gids()
+    pgids(real=1000, effective=1000, saved=1000)
+    >>>
+    >>> p.cpu_times()
+    pcputimes(user=1.02, system=0.31, children_user=0.32, children_system=0.1)
+    >>> p.cpu_percent(interval=1.0)
+    12.1
+    >>> p.cpu_affinity()
+    [0, 1, 2, 3]
+    >>> p.cpu_affinity([0, 1])  # set
+    >>> p.cpu_num()
+    1
+    >>>
+    >>> p.memory_info()
+    pmem(rss=10915840, vms=67608576, shared=3313664, text=2310144, lib=0, data=7262208, dirty=0)
+    >>> p.memory_full_info()  # "real" USS memory usage (Linux, OSX, Win only)
+    pfullmem(rss=10199040, vms=52133888, shared=3887104, text=2867200, lib=0, data=5967872, dirty=0, uss=6545408, pss=6872064, swap=0)
+    >>> p.memory_percent()
+    0.7823
+    >>> p.memory_maps()
+    [pmmap_grouped(path='/lib/x8664-linux-gnu/libutil-2.15.so', rss=32768, size=2125824, pss=32768, shared_clean=0, shared_dirty=0, private_clean=20480, private_dirty=12288, referenced=32768, anonymous=12288, swap=0),
+     pmmap_grouped(path='/lib/x8664-linux-gnu/libc-2.15.so', rss=3821568, size=3842048, pss=3821568, shared_clean=0, shared_dirty=0, private_clean=0, private_dirty=3821568, referenced=3575808, anonymous=3821568, swap=0),
+     pmmap_grouped(path='/lib/x8664-linux-gnu/libcrypto.so.0.1', rss=34124, rss=32768, size=2134016, pss=15360, shared_clean=24576, shared_dirty=0, private_clean=0, private_dirty=8192, referenced=24576, anonymous=8192, swap=0),
+     pmmap_grouped(path='[heap]',  rss=32768, size=139264, pss=32768, shared_clean=0, shared_dirty=0, private_clean=0, private_dirty=32768, referenced=32768, anonymous=32768, swap=0),
+     pmmap_grouped(path='[stack]', rss=2465792, size=2494464, pss=2465792, shared_clean=0, shared_dirty=0, private_clean=0, private_dirty=2465792, referenced=2277376, anonymous=2465792, swap=0),
+     ...]
+    >>>
+    >>> p.io_counters()
+    pio(read_count=478001, write_count=59371, read_bytes=700416, write_bytes=69632, read_chars=456232, write_chars=517543)
+    >>>
+    >>> p.open_files()
+    [popenfile(path='/home/giampaolo/svn/psutil/setup.py', fd=3, position=0, mode='r', flags=32768),
+     popenfile(path='/var/log/monitd', fd=4, position=235542, mode='a', flags=33793)]
+    >>>
+    >>> p.connections()
+    [pconn(fd=115, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=48776), raddr=addr(ip='93.186.135.91', port=80), status='ESTABLISHED'),
+     pconn(fd=117, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=43761), raddr=addr(ip='72.14.234.100', port=80), status='CLOSING'),
+     pconn(fd=119, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=60759), raddr=addr(ip='72.14.234.104', port=80), status='ESTABLISHED'),
+     pconn(fd=123, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=51314), raddr=addr(ip='72.14.234.83', port=443), status='SYN_SENT')]
+    >>>
+    >>> p.num_threads()
+    4
+    >>> p.num_fds()
+    8
+    >>> p.threads()
+    [pthread(id=5234, user_time=22.5, system_time=9.2891),
+     pthread(id=5235, user_time=0.0, system_time=0.0),
+     pthread(id=5236, user_time=0.0, system_time=0.0),
+     pthread(id=5237, user_time=0.0707, system_time=1.1)]
+    >>>
+    >>> p.num_ctx_switches()
+    pctxsw(voluntary=78, involuntary=19)
+    >>>
+    >>> p.nice()
+    0
+    >>> p.nice(10)  # set
+    >>>
+    >>> p.ionice(psutil.IOPRIO_CLASS_IDLE)  # IO priority (Win and Linux only)
+    >>> p.ionice()
+    pionice(ioclass=<IOPriority.IOPRIO_CLASS_IDLE: 3>, value=0)
+    >>>
+    >>> p.rlimit(psutil.RLIMIT_NOFILE, (5, 5))  # set resource limits (Linux only)
+    >>> p.rlimit(psutil.RLIMIT_NOFILE)
+    (5, 5)
+    >>>
+    >>> p.environ()
+    {'LC_PAPER': 'it_IT.UTF-8', 'SHELL': '/bin/bash', 'GREP_OPTIONS': '--color=auto',
+    'XDG_CONFIG_DIRS': '/etc/xdg/xdg-ubuntu:/usr/share/upstart/xdg:/etc/xdg', 'COLORTERM': 'gnome-terminal',
+     ...}
+    >>>
+    >>> p.as_dict()
+    {'status': 'running', 'num_ctx_switches': pctxsw(voluntary=63, involuntary=1), 'pid': 5457, ...}
+    >>> p.is_running()
+    True
+    >>> p.suspend()
+    >>> p.resume()
+    >>>
+    >>> p.terminate()
+    >>> p.wait(timeout=3)
+    0
+    >>>
+    >>> psutil.test()
+    USER         PID %CPU %MEM     VSZ     RSS TTY        START    TIME  COMMAND
+    root           1  0.0  0.0   24584    2240            Jun17   00:00  init
+    root           2  0.0  0.0       0       0            Jun17   00:00  kthreadd
+    root           3  0.0  0.0       0       0            Jun17   00:05  ksoftirqd/0
+    ...
+    giampaolo  31475  0.0  0.0   20760    3024 /dev/pts/0 Jun19   00:00  python2.4
+    giampaolo  31721  0.0  2.2  773060  181896            00:04   10:30  chrome
+    root       31763  0.0  0.0       0       0            00:05   00:00  kworker/0:1
+    >>>
+
+Further process APIs
+====================
+
+.. code-block:: python
+
+    >>> import psutil
+    >>> for proc in psutil.process_iter(attrs=['pid', 'name']):
+    ...     print(proc.info)
+    ...
+    {'pid': 1, 'name': 'systemd'}
+    {'pid': 2, 'name': 'kthreadd'}
+    {'pid': 3, 'name': 'ksoftirqd/0'}
+    ...
+    >>>
+    >>> psutil.pid_exists(3)
+    True
+    >>>
+    >>> def on_terminate(proc):
+    ...     print("process {} terminated".format(proc))
+    ...
+    >>> # waits for multiple processes to terminate
+    >>> gone, alive = psutil.wait_procs(procs_list, timeout=3, callback=on_terminate)
+    >>>
+
+Popen wrapper:
+
+.. code-block:: python
+
+    >>> import psutil
+    >>> from subprocess import PIPE
+    >>> p = psutil.Popen(["/usr/bin/python", "-c", "print('hello')"], stdout=PIPE)
+    >>> p.name()
+    'python'
+    >>> p.username()
+    'giampaolo'
+    >>> p.communicate()
+    ('hello\n', None)
+    >>> p.wait(timeout=2)
+    0
+    >>>
+
+Windows services
+================
+
+.. code-block:: python
+
+    >>> list(psutil.win_service_iter())
+    [<WindowsService(name='AeLookupSvc', display_name='Application Experience') at 38850096>,
+     <WindowsService(name='ALG', display_name='Application Layer Gateway Service') at 38850128>,
+     <WindowsService(name='APNMCP', display_name='Ask Update Service') at 38850160>,
+     <WindowsService(name='AppIDSvc', display_name='Application Identity') at 38850192>,
+     ...]
+    >>> s = psutil.win_service_get('alg')
+    >>> s.as_dict()
+    {'binpath': 'C:\\Windows\\System32\\alg.exe',
+     'description': 'Provides support for 3rd party protocol plug-ins for Internet Connection Sharing',
+     'display_name': 'Application Layer Gateway Service',
+     'name': 'alg',
+     'pid': None,
+     'start_type': 'manual',
+     'status': 'stopped',
+     'username': 'NT AUTHORITY\\LocalService'}
+
+Other samples
+=============
+
+See `doc recipes <http://psutil.readthedocs.io/#recipes>`__.
+
+======
+Author
+======
+
+psutil was created and is maintained by
+`Giampaolo Rodola' <http://grodola.blogspot.com/p/about.html>`__.
+A lot of time and effort went into making psutil as it is right now.
+If you feel psutil is useful to you or your business and want to support its
+future development please consider donating me
+(`Giampaolo <http://grodola.blogspot.com/p/about.html>`__) some money.
+
+.. image:: http://www.paypal.com/en_US/i/btn/x-click-but04.gif
+    :target: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A9ZS7PKKRM3S8
+    :alt: Donate via PayPal
+
+Don't want to donate money? Then maybe you could `write me a recommendation on Linkedin <https://www.linkedin.com/in/grodola>`_.
+
+
new file mode 100644
--- /dev/null
+++ b/third_party/python/psutil-cp27-none-win_amd64/psutil-5.4.3.dist-info/METADATA
@@ -0,0 +1,524 @@
+Metadata-Version: 2.0
+Name: psutil
+Version: 5.4.3
+Summary: Cross-platform lib for process and system monitoring in Python.
+Home-page: https://github.com/giampaolo/psutil
+Author: Giampaolo Rodola
+Author-email: g.rodola@gmail.com
+License: BSD
+Keywords: ps,top,kill,free,lsof,netstat,nice,tty,ionice,uptime,taskmgr,process,df,iotop,iostat,ifconfig,taskset,who,pidof,pmap,smem,pstree,monitoring,ulimit,prlimit,smem
+Platform: Platform Independent
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Environment :: Console
+Classifier: Environment :: Win32 (MS Windows)
+Classifier: Intended Audience :: Developers
+Classifier: Intended Audience :: Information Technology
+Classifier: Intended Audience :: System Administrators
+Classifier: License :: OSI Approved :: BSD License
+Classifier: Operating System :: MacOS :: MacOS X
+Classifier: Operating System :: Microsoft :: Windows :: Windows NT/2000
+Classifier: Operating System :: Microsoft
+Classifier: Operating System :: OS Independent
+Classifier: Operating System :: POSIX :: BSD :: FreeBSD
+Classifier: Operating System :: POSIX :: BSD :: NetBSD
+Classifier: Operating System :: POSIX :: BSD :: OpenBSD
+Classifier: Operating System :: POSIX :: BSD
+Classifier: Operating System :: POSIX :: Linux
+Classifier: Operating System :: POSIX :: SunOS/Solaris
+Classifier: Operating System :: POSIX
+Classifier: Programming Language :: C
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 2.6
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.4
+Classifier: Programming Language :: Python :: 3.5
+Classifier: Programming Language :: Python :: 3.6
+Classifier: Programming Language :: Python :: Implementation :: CPython
+Classifier: Programming Language :: Python :: Implementation :: PyPy
+Classifier: Programming Language :: Python
+Classifier: Topic :: Software Development :: Libraries :: Python Modules
+Classifier: Topic :: Software Development :: Libraries
+Classifier: Topic :: System :: Benchmark
+Classifier: Topic :: System :: Hardware
+Classifier: Topic :: System :: Monitoring
+Classifier: Topic :: System :: Networking :: Monitoring
+Classifier: Topic :: System :: Networking
+Classifier: Topic :: System :: Operating System
+Classifier: Topic :: System :: Systems Administration
+Classifier: Topic :: Utilities
+Provides-Extra: enum
+Requires-Dist: enum34; extra == 'enum'
+
+.. image:: https://img.shields.io/travis/giampaolo/psutil/master.svg?maxAge=3600&label=Linux%20/%20OSX
+    :target: https://travis-ci.org/giampaolo/psutil
+    :alt: Linux tests (Travis)
+
+.. image:: https://img.shields.io/appveyor/ci/giampaolo/psutil/master.svg?maxAge=3600&label=Windows
+    :target: https://ci.appveyor.com/project/giampaolo/psutil
+    :alt: Windows tests (Appveyor)
+
+.. image:: https://coveralls.io/repos/github/giampaolo/psutil/badge.svg?branch=master
+    :target: https://coveralls.io/github/giampaolo/psutil?branch=master
+    :alt: Test coverage (coverall.io)
+
+.. image:: https://readthedocs.org/projects/psutil/badge/?version=latest
+    :target: http://psutil.readthedocs.io/en/latest/?badge=latest
+    :alt: Documentation Status
+
+.. image:: https://img.shields.io/pypi/v/psutil.svg?label=pypi
+    :target: https://pypi.python.org/pypi/psutil/
+    :alt: Latest version
+
+.. image:: https://img.shields.io/github/stars/giampaolo/psutil.svg
+    :target: https://github.com/giampaolo/psutil/
+    :alt: Github stars
+
+.. image:: https://img.shields.io/pypi/l/psutil.svg
+    :target: https://pypi.python.org/pypi/psutil/
+    :alt: License
+
+===========
+Quick links
+===========
+
+- `Home page <https://github.com/giampaolo/psutil>`_
+- `Install <https://github.com/giampaolo/psutil/blob/master/INSTALL.rst>`_
+- `Documentation <http://psutil.readthedocs.io>`_
+- `Download <https://pypi.python.org/pypi?:action=display&name=psutil#downloads>`_
+- `Forum <http://groups.google.com/group/psutil/topics>`_
+- `Blog <http://grodola.blogspot.com/search/label/psutil>`_
+- `Development guide <https://github.com/giampaolo/psutil/blob/master/DEVGUIDE.rst>`_
+- `What's new <https://github.com/giampaolo/psutil/blob/master/HISTORY.rst>`_
+
+=======
+Summary
+=======
+
+psutil (process and system utilities) is a cross-platform library for
+retrieving information on **running processes** and **system utilization**
+(CPU, memory, disks, network, sensors) in Python.
+It is useful mainly for **system monitoring**, **profiling and limiting process
+resources** and **management of running processes**.
+It implements many functionalities offered by UNIX command line tools such as:
+ps, top, lsof, netstat, ifconfig, who, df, kill, free, nice, ionice, iostat,
+iotop, uptime, pidof, tty, taskset, pmap.
+psutil currently supports the following platforms:
+
+- **Linux**
+- **Windows**
+- **OSX**,
+- **FreeBSD, OpenBSD**, **NetBSD**
+- **Sun Solaris**
+- **AIX**
+
+...both **32-bit** and **64-bit** architectures, with Python
+versions from **2.6 to 3.6**.
+`PyPy <http://pypy.org/>`__ is also known to work.
+
+====================
+Example applications
+====================
+
++------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------+
+| .. image:: https://github.com/giampaolo/psutil/blob/master/docs/_static/procinfo-small.png     | .. image:: https://github.com/giampaolo/psutil/blob/master/docs/_static/top-small.png      |
+|    :target: https://github.com/giampaolo/psutil/blob/master/docs/_static/procinfo.png          |     :target: https://github.com/giampaolo/psutil/blob/master/docs/_static/top.png          |
++------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------+
+| .. image:: https://github.com/giampaolo/psutil/blob/master/docs/_static/procsmem-small.png     | .. image:: https://github.com/giampaolo/psutil/blob/master/docs/_static/pmap-small.png     |
+|     :target: https://github.com/giampaolo/psutil/blob/master/docs/_static/procsmem.png         |     :target: https://github.com/giampaolo/psutil/blob/master/docs/_static/pmap.png         |
++------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------+
+
+Also see `scripts directory <https://github.com/giampaolo/psutil/tree/master/scripts>`__
+and `doc recipes <http://psutil.readthedocs.io/#recipes/>`__.
+
+=====================
+Projects using psutil
+=====================
+
+At the time of writing psutil has roughly
+`2.9 milion downloads <https://github.com/giampaolo/psutil/issues/1053#issuecomment-340166262>`__
+per month and there are over
+`6000 open source projects <https://libraries.io/pypi/psutil/dependent_repositories?page=1>`__
+on github which depend from psutil.
+Here's some I find particularly interesting:
+
+- https://github.com/facebook/osquery/
+- https://github.com/nicolargo/glances
+- https://github.com/google/grr
+- https://github.com/Jahaja/psdash
+- https://github.com/ajenti/ajenti
+- https://github.com/home-assistant/home-assistant/
+
+========
+Portings
+========
+
+- Go: https://github.com/shirou/gopsutil
+- C: https://github.com/hamon-in/cpslib
+- Node: https://github.com/christkv/node-psutil
+- Rust: https://github.com/borntyping/rust-psutil
+- Ruby: https://github.com/spacewander/posixpsutil
+- Nim: https://github.com/johnscillieri/psutil-nim
+
+==============
+Example usages
+==============
+
+CPU
+===
+
+.. code-block:: python
+
+    >>> import psutil
+    >>> psutil.cpu_times()
+    scputimes(user=3961.46, nice=169.729, system=2150.659, idle=16900.540, iowait=629.59, irq=0.0, softirq=19.42, steal=0.0, guest=0, nice=0.0)
+    >>>
+    >>> for x in range(3):
+    ...     psutil.cpu_percent(interval=1)
+    ...
+    4.0
+    5.9
+    3.8
+    >>>
+    >>> for x in range(3):
+    ...     psutil.cpu_percent(interval=1, percpu=True)
+    ...
+    [4.0, 6.9, 3.7, 9.2]
+    [7.0, 8.5, 2.4, 2.1]
+    [1.2, 9.0, 9.9, 7.2]
+    >>>
+    >>> for x in range(3):
+    ...     psutil.cpu_times_percent(interval=1, percpu=False)
+    ...
+    scputimes(user=1.5, nice=0.0, system=0.5, idle=96.5, iowait=1.5, irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0)
+    scputimes(user=1.0, nice=0.0, system=0.0, idle=99.0, iowait=0.0, irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0)
+    scputimes(user=2.0, nice=0.0, system=0.0, idle=98.0, iowait=0.0, irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0)
+    >>>
+    >>> psutil.cpu_count()
+    4
+    >>> psutil.cpu_count(logical=False)
+    2
+    >>>
+    >>> psutil.cpu_stats()
+    scpustats(ctx_switches=20455687, interrupts=6598984, soft_interrupts=2134212, syscalls=0)
+    >>>
+    >>> psutil.cpu_freq()
+    scpufreq(current=931.42925, min=800.0, max=3500.0)
+    >>>
+
+Memory
+======
+
+.. code-block:: python
+
+    >>> import psutil
+    >>> psutil.virtual_memory()
+    svmem(total=10367352832, available=6472179712, percent=37.6, used=8186245120, free=2181107712, active=4748992512, inactive=2758115328, buffers=790724608, cached=3500347392, shared=787554304)
+    >>> psutil.swap_memory()
+    sswap(total=2097147904, used=296128512, free=1801019392, percent=14.1, sin=304193536, sout=677842944)
+    >>>
+
+Disks
+=====
+
+.. code-block:: python
+
+    >>> import psutil
+    >>> psutil.disk_partitions()
+    [sdiskpart(device='/dev/sda1', mountpoint='/', fstype='ext4', opts='rw,nosuid'),
+     sdiskpart(device='/dev/sda2', mountpoint='/home', fstype='ext, opts='rw')]
+    >>>
+    >>> psutil.disk_usage('/')
+    sdiskusage(total=21378641920, used=4809781248, free=15482871808, percent=22.5)
+    >>>
+    >>> psutil.disk_io_counters(perdisk=False)
+    sdiskio(read_count=719566, write_count=1082197, read_bytes=18626220032, write_bytes=24081764352, read_time=5023392, write_time=63199568, read_merged_count=619166, write_merged_count=812396, busy_time=4523412)
+    >>>
+
+Network
+=======
+
+.. code-block:: python
+
+    >>> import psutil
+    >>> psutil.net_io_counters(pernic=True)
+    {'eth0': netio(bytes_sent=485291293, bytes_recv=6004858642, packets_sent=3251564, packets_recv=4787798, errin=0, errout=0, dropin=0, dropout=0),
+     'lo': netio(bytes_sent=2838627, bytes_recv=2838627, packets_sent=30567, packets_recv=30567, errin=0, errout=0, dropin=0, dropout=0)}
+    >>>
+    >>> psutil.net_connections()
+    [sconn(fd=115, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=48776), raddr=addr(ip='93.186.135.91', port=80), status='ESTABLISHED', pid=1254),
+     sconn(fd=117, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=43761), raddr=addr(ip='72.14.234.100', port=80), status='CLOSING', pid=2987),
+     sconn(fd=-1, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=60759), raddr=addr(ip='72.14.234.104', port=80), status='ESTABLISHED', pid=None),
+     sconn(fd=-1, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=51314), raddr=addr(ip='72.14.234.83', port=443), status='SYN_SENT', pid=None)
+     ...]
+    >>>
+    >>> psutil.net_if_addrs()
+    {'lo': [snic(family=<AddressFamily.AF_INET: 2>, address='127.0.0.1', netmask='255.0.0.0', broadcast='127.0.0.1', ptp=None),
+            snic(family=<AddressFamily.AF_INET6: 10>, address='::1', netmask='ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff', broadcast=None, ptp=None),
+            snic(family=<AddressFamily.AF_LINK: 17>, address='00:00:00:00:00:00', netmask=None, broadcast='00:00:00:00:00:00', ptp=None)],
+     'wlan0': [snic(family=<AddressFamily.AF_INET: 2>, address='192.168.1.3', netmask='255.255.255.0', broadcast='192.168.1.255', ptp=None),
+               snic(family=<AddressFamily.AF_INET6: 10>, address='fe80::c685:8ff:fe45:641%wlan0', netmask='ffff:ffff:ffff:ffff::', broadcast=None, ptp=None),
+               snic(family=<AddressFamily.AF_LINK: 17>, address='c4:85:08:45:06:41', netmask=None, broadcast='ff:ff:ff:ff:ff:ff', ptp=None)]}
+    >>>
+    >>> psutil.net_if_stats()
+    {'eth0': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_FULL: 2>, speed=100, mtu=1500),
+     'lo': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_UNKNOWN: 0>, speed=0, mtu=65536)}
+    >>>
+
+Sensors
+=======
+
+.. code-block:: python
+
+    >>> import psutil
+    >>> psutil.sensors_temperatures()
+    {'acpitz': [shwtemp(label='', current=47.0, high=103.0, critical=103.0)],
+     'asus': [shwtemp(label='', current=47.0, high=None, critical=None)],
+     'coretemp': [shwtemp(label='Physical id 0', current=52.0, high=100.0, critical=100.0),
+                  shwtemp(label='Core 0', current=45.0, high=100.0, critical=100.0),
+                  shwtemp(label='Core 1', current=52.0, high=100.0, critical=100.0),
+                  shwtemp(label='Core 2', current=45.0, high=100.0, critical=100.0),
+                  shwtemp(label='Core 3', current=47.0, high=100.0, critical=100.0)]}
+    >>>
+    >>> psutil.sensors_fans()
+    {'asus': [sfan(label='cpu_fan', current=3200)]}
+    >>>
+    >>> psutil.sensors_battery()
+    sbattery(percent=93, secsleft=16628, power_plugged=False)
+    >>>
+
+Other system info
+=================
+
+.. code-block:: python
+
+    >>> import psutil
+    >>> psutil.users()
+    [suser(name='giampaolo', terminal='pts/2', host='localhost', started=1340737536.0, pid=1352),
+     suser(name='giampaolo', terminal='pts/3', host='localhost', started=1340737792.0, pid=1788)]
+    >>>
+    >>> psutil.boot_time()
+    1365519115.0
+    >>>
+
+Process management
+==================
+
+.. code-block:: python
+
+    >>> import psutil
+    >>> psutil.pids()
+    [1, 2, 3, 4, 5, 6, 7, 46, 48, 50, 51, 178, 182, 222, 223, 224, 268, 1215, 1216, 1220, 1221, 1243, 1244,
+     1301, 1601, 2237, 2355, 2637, 2774, 3932, 4176, 4177, 4185, 4187, 4189, 4225, 4243, 4245, 4263, 4282,
+     4306, 4311, 4312, 4313, 4314, 4337, 4339, 4357, 4358, 4363, 4383, 4395, 4408, 4433, 4443, 4445, 4446,
+     5167, 5234, 5235, 5252, 5318, 5424, 5644, 6987, 7054, 7055, 7071]
+    >>>
+    >>> p = psutil.Process(7055)
+    >>> p.name()
+    'python'
+    >>> p.exe()
+    '/usr/bin/python'
+    >>> p.cwd()
+    '/home/giampaolo'
+    >>> p.cmdline()
+    ['/usr/bin/python', 'main.py']
+    >>>
+    >>> p.pid
+    7055
+    >>> p.ppid()
+    7054
+    >>> p.parent()
+    <psutil.Process(pid=7054, name='bash') at 140008329539408>
+    >>> p.children()
+    [<psutil.Process(pid=8031, name='python') at 14020832451977>,
+     <psutil.Process(pid=8044, name='python') at 19229444921932>]
+    >>>
+    >>> p.status()
+    'running'
+    >>> p.username()
+    'giampaolo'
+    >>> p.create_time()
+    1267551141.5019531
+    >>> p.terminal()
+    '/dev/pts/0'
+    >>>
+    >>> p.uids()
+    puids(real=1000, effective=1000, saved=1000)
+    >>> p.gids()
+    pgids(real=1000, effective=1000, saved=1000)
+    >>>
+    >>> p.cpu_times()
+    pcputimes(user=1.02, system=0.31, children_user=0.32, children_system=0.1)
+    >>> p.cpu_percent(interval=1.0)
+    12.1
+    >>> p.cpu_affinity()
+    [0, 1, 2, 3]
+    >>> p.cpu_affinity([0, 1])  # set
+    >>> p.cpu_num()
+    1
+    >>>
+    >>> p.memory_info()
+    pmem(rss=10915840, vms=67608576, shared=3313664, text=2310144, lib=0, data=7262208, dirty=0)
+    >>> p.memory_full_info()  # "real" USS memory usage (Linux, OSX, Win only)
+    pfullmem(rss=10199040, vms=52133888, shared=3887104, text=2867200, lib=0, data=5967872, dirty=0, uss=6545408, pss=6872064, swap=0)
+    >>> p.memory_percent()
+    0.7823
+    >>> p.memory_maps()
+    [pmmap_grouped(path='/lib/x8664-linux-gnu/libutil-2.15.so', rss=32768, size=2125824, pss=32768, shared_clean=0, shared_dirty=0, private_clean=20480, private_dirty=12288, referenced=32768, anonymous=12288, swap=0),
+     pmmap_grouped(path='/lib/x8664-linux-gnu/libc-2.15.so', rss=3821568, size=3842048, pss=3821568, shared_clean=0, shared_dirty=0, private_clean=0, private_dirty=3821568, referenced=3575808, anonymous=3821568, swap=0),
+     pmmap_grouped(path='/lib/x8664-linux-gnu/libcrypto.so.0.1', rss=34124, rss=32768, size=2134016, pss=15360, shared_clean=24576, shared_dirty=0, private_clean=0, private_dirty=8192, referenced=24576, anonymous=8192, swap=0),
+     pmmap_grouped(path='[heap]',  rss=32768, size=139264, pss=32768, shared_clean=0, shared_dirty=0, private_clean=0, private_dirty=32768, referenced=32768, anonymous=32768, swap=0),
+     pmmap_grouped(path='[stack]', rss=2465792, size=2494464, pss=2465792, shared_clean=0, shared_dirty=0, private_clean=0, private_dirty=2465792, referenced=2277376, anonymous=2465792, swap=0),
+     ...]
+    >>>
+    >>> p.io_counters()
+    pio(read_count=478001, write_count=59371, read_bytes=700416, write_bytes=69632, read_chars=456232, write_chars=517543)
+    >>>
+    >>> p.open_files()
+    [popenfile(path='/home/giampaolo/svn/psutil/setup.py', fd=3, position=0, mode='r', flags=32768),
+     popenfile(path='/var/log/monitd', fd=4, position=235542, mode='a', flags=33793)]
+    >>>
+    >>> p.connections()
+    [pconn(fd=115, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=48776), raddr=addr(ip='93.186.135.91', port=80), status='ESTABLISHED'),
+     pconn(fd=117, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=43761), raddr=addr(ip='72.14.234.100', port=80), status='CLOSING'),
+     pconn(fd=119, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=60759), raddr=addr(ip='72.14.234.104', port=80), status='ESTABLISHED'),
+     pconn(fd=123, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=51314), raddr=addr(ip='72.14.234.83', port=443), status='SYN_SENT')]
+    >>>
+    >>> p.num_threads()
+    4
+    >>> p.num_fds()
+    8
+    >>> p.threads()
+    [pthread(id=5234, user_time=22.5, system_time=9.2891),
+     pthread(id=5235, user_time=0.0, system_time=0.0),
+     pthread(id=5236, user_time=0.0, system_time=0.0),
+     pthread(id=5237, user_time=0.0707, system_time=1.1)]
+    >>>
+    >>> p.num_ctx_switches()
+    pctxsw(voluntary=78, involuntary=19)
+    >>>
+    >>> p.nice()
+    0
+    >>> p.nice(10)  # set
+    >>>
+    >>> p.ionice(psutil.IOPRIO_CLASS_IDLE)  # IO priority (Win and Linux only)
+    >>> p.ionice()
+    pionice(ioclass=<IOPriority.IOPRIO_CLASS_IDLE: 3>, value=0)
+    >>>
+    >>> p.rlimit(psutil.RLIMIT_NOFILE, (5, 5))  # set resource limits (Linux only)
+    >>> p.rlimit(psutil.RLIMIT_NOFILE)
+    (5, 5)
+    >>>
+    >>> p.environ()
+    {'LC_PAPER': 'it_IT.UTF-8', 'SHELL': '/bin/bash', 'GREP_OPTIONS': '--color=auto',
+    'XDG_CONFIG_DIRS': '/etc/xdg/xdg-ubuntu:/usr/share/upstart/xdg:/etc/xdg', 'COLORTERM': 'gnome-terminal',
+     ...}
+    >>>
+    >>> p.as_dict()
+    {'status': 'running', 'num_ctx_switches': pctxsw(voluntary=63, involuntary=1), 'pid': 5457, ...}
+    >>> p.is_running()
+    True
+    >>> p.suspend()
+    >>> p.resume()
+    >>>
+    >>> p.terminate()
+    >>> p.wait(timeout=3)
+    0
+    >>>
+    >>> psutil.test()
+    USER         PID %CPU %MEM     VSZ     RSS TTY        START    TIME  COMMAND
+    root           1  0.0  0.0   24584    2240            Jun17   00:00  init
+    root           2  0.0  0.0       0       0            Jun17   00:00  kthreadd
+    root           3  0.0  0.0       0       0            Jun17   00:05  ksoftirqd/0
+    ...
+    giampaolo  31475  0.0  0.0   20760    3024 /dev/pts/0 Jun19   00:00  python2.4
+    giampaolo  31721  0.0  2.2  773060  181896            00:04   10:30  chrome
+    root       31763  0.0  0.0       0       0            00:05   00:00  kworker/0:1
+    >>>
+
+Further process APIs
+====================
+
+.. code-block:: python
+
+    >>> import psutil
+    >>> for proc in psutil.process_iter(attrs=['pid', 'name']):
+    ...     print(proc.info)
+    ...
+    {'pid': 1, 'name': 'systemd'}
+    {'pid': 2, 'name': 'kthreadd'}
+    {'pid': 3, 'name': 'ksoftirqd/0'}
+    ...
+    >>>
+    >>> psutil.pid_exists(3)
+    True
+    >>>
+    >>> def on_terminate(proc):
+    ...     print("process {} terminated".format(proc))
+    ...
+    >>> # waits for multiple processes to terminate
+    >>> gone, alive = psutil.wait_procs(procs_list, timeout=3, callback=on_terminate)
+    >>>
+
+Popen wrapper:
+
+.. code-block:: python
+
+    >>> import psutil
+    >>> from subprocess import PIPE
+    >>> p = psutil.Popen(["/usr/bin/python", "-c", "print('hello')"], stdout=PIPE)
+    >>> p.name()
+    'python'
+    >>> p.username()
+    'giampaolo'
+    >>> p.communicate()
+    ('hello\n', None)
+    >>> p.wait(timeout=2)
+    0
+    >>>
+
+Windows services
+================
+
+.. code-block:: python
+
+    >>> list(psutil.win_service_iter())
+    [<WindowsService(name='AeLookupSvc', display_name='Application Experience') at 38850096>,
+     <WindowsService(name='ALG', display_name='Application Layer Gateway Service') at 38850128>,
+     <WindowsService(name='APNMCP', display_name='Ask Update Service') at 38850160>,
+     <WindowsService(name='AppIDSvc', display_name='Application Identity') at 38850192>,
+     ...]
+    >>> s = psutil.win_service_get('alg')
+    >>> s.as_dict()
+    {'binpath': 'C:\\Windows\\System32\\alg.exe',
+     'description': 'Provides support for 3rd party protocol plug-ins for Internet Connection Sharing',
+     'display_name': 'Application Layer Gateway Service',
+     'name': 'alg',
+     'pid': None,
+     'start_type': 'manual',
+     'status': 'stopped',
+     'username': 'NT AUTHORITY\\LocalService'}
+
+Other samples
+=============
+
+See `doc recipes <http://psutil.readthedocs.io/#recipes>`__.
+
+======
+Author
+======
+
+psutil was created and is maintained by
+`Giampaolo Rodola' <http://grodola.blogspot.com/p/about.html>`__.
+A lot of time and effort went into making psutil as it is right now.
+If you feel psutil is useful to you or your business and want to support its
+future development please consider donating me
+(`Giampaolo <http://grodola.blogspot.com/p/about.html>`__) some money.
+
+.. image:: http://www.paypal.com/en_US/i/btn/x-click-but04.gif
+    :target: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A9ZS7PKKRM3S8
+    :alt: Donate via PayPal
+
+Don't want to donate money? Then maybe you could `write me a recommendation on Linkedin <https://www.linkedin.com/in/grodola>`_.
+
+
new file mode 100644
--- /dev/null
+++ b/third_party/python/psutil-cp27-none-win_amd64/psutil-5.4.3.dist-info/RECORD
@@ -0,0 +1,34 @@
+psutil/__init__.py,sha256=220_B4k7vC9eoVP_OW8SFcaXCSBGpj_nacxvfBQ5O2o,84989
+psutil/_common.py,sha256=df5J2HqrWvGoFdumxDL1q9fgJOOYyiCmV0EFxb4ghuY,17852
+psutil/_compat.py,sha256=0VqlfcCGD5tZRBW-mFroguS0J7YNw6y3LjEcX5ChXDc,8170
+psutil/_exceptions.py,sha256=37eRgLuwTy7X4tjovePfZfYif-veW6LFeRlPqsgnNBU,3009
+psutil/_psaix.py,sha256=uAqwhQHS0upGc8OIk8Qa5PScCwXNvaMkoIdltZZ0n8A,19376
+psutil/_psbsd.py,sha256=ewmj2_DfzZpQZEcRvo1xvjVFhQqJidnENLgS8jrBb68,30244
+psutil/_pslinux.py,sha256=ME3wEgxfOWSFxgKXpTKbFw29ur1toMT4DdkKLJGkaD4,74850
+psutil/_psosx.py,sha256=X2WzhpuGjffjzFt3B3hphX7piPRCrPsjJrk6p6vu96w,17213
+psutil/_psposix.py,sha256=AmpZmKnvzCFcf7RpYypiUxOxKoRdXHRy2p9hFEIAJVc,6345
+psutil/_pssunos.py,sha256=uEsntvZPXplCuP9ER2W1QaGXjOqUZx_qFx2iLeyc5V8,25650
+psutil/_psutil_windows.pyd,sha256=wbQ_dSXTvdmCyQV02P7uCk95MwDkZ_D1g5r4G7IiYr8,59904
+psutil/_pswindows.py,sha256=_KYB-Vyhnz2A3l8I7tuXvFSrBPqKIb9slcwh5Azj0QU,33121
+psutil/tests/__init__.py,sha256=hkGHtLQNHjKrqhuV3Sk0kkHir17Mlam-amZBkLdfGwA,37656
+psutil/tests/__main__.py,sha256=dssAzXI-sAHkObtruDvc1cYUFNWOi-ZXETQgwaLKJS0,2784
+psutil/tests/test_aix.py,sha256=_ItFqb-CmYHlnlcduSKbgsPBw_xEIfE5v_pOr_YD8gw,4483
+psutil/tests/test_bsd.py,sha256=aif308A3TRnPZGY1tmNlH25YCweeSMpwbkah2K13wZs,17785
+psutil/tests/test_connections.py,sha256=eXOPOkusHO6Xc8gNrDxPBhq1Ni2fYYe0AAzeGU4gijQ,20676
+psutil/tests/test_contracts.py,sha256=ryPd7QDkQKxh8Mjcl-iPflXw5OTi8TWWLzQjIJ4EW2w,24136
+psutil/tests/test_linux.py,sha256=_gQBxUSiRSygoGfFXn-2m5XpXJQMQSiurVobrwkaAgc,78746
+psutil/tests/test_memory_leaks.py,sha256=v-RmU0BAzH05pkQ1dUV1hUXxlMva7943GFvT9Erl6J4,18259
+psutil/tests/test_misc.py,sha256=4qu61Sdmvzbaz2heOXKlg_PveYrzamBIUJ5QlLIYmSQ,37821
+psutil/tests/test_osx.py,sha256=UL3sovPp-5f0LIjNqjHu12NnpXF2uuv8Z62wbeAJj2c,9652
+psutil/tests/test_posix.py,sha256=4gm2VeCYoPYnstn_2GMG18c6xvMV7APXA26W5Dcm99s,16397
+psutil/tests/test_process.py,sha256=IE-v3DHKIje6Kwnas8kzfsbz15L4-0dpI555lXg7-NE,60495
+psutil/tests/test_sunos.py,sha256=UNywEx_qlSOyUHV48lMKqmnu8RKPBDCQrO0llulCUHY,1322
+psutil/tests/test_system.py,sha256=fv3otFKJVOn3VpRrD5IMivbI-hfajL6wmzVQF_JJqDI,34885
+psutil/tests/test_unicode.py,sha256=M0VTr_kGgmDKiNq6nSvraaw-711pRXe_6R948qHAr8I,12913
+psutil/tests/test_windows.py,sha256=AG2Feks59VOahEW_hJs_o4f5wt20vS1jxxaUCijcwAQ,32609
+psutil-5.4.3.dist-info/DESCRIPTION.rst,sha256=oATWrkVX56oC_b77TIXQsrm1CxSgD93PM71km6ud5G4,19853
+psutil-5.4.3.dist-info/METADATA,sha256=neLhT7NMfWptGzaSxueDDYqVDOR0C9cNvE8pAK14C2c,22835
+psutil-5.4.3.dist-info/RECORD,,
+psutil-5.4.3.dist-info/WHEEL,sha256=oT-jJdPOIfRdvpqTJO9X6OjCsyUImH2THoT54KREdwI,106
+psutil-5.4.3.dist-info/metadata.json,sha256=RqO1wxtF8F5B2HqYztzUkdKh5XmF8Wq_PxB9l571GM0,2492
+psutil-5.4.3.dist-info/top_level.txt,sha256=gCNhn57wzksDjSAISmgMJ0aiXzQulk0GJhb2-BAyYgw,7
new file mode 100644
--- /dev/null
+++ b/third_party/python/psutil-cp27-none-win_amd64/psutil-5.4.3.dist-info/WHEEL
@@ -0,0 +1,5 @@
+Wheel-Version: 1.0
+Generator: bdist_wheel (0.30.0)
+Root-Is-Purelib: false
+Tag: cp27-cp27m-win_amd64
+
new file mode 100644
--- /dev/null
+++ b/third_party/python/psutil-cp27-none-win_amd64/psutil-5.4.3.dist-info/metadata.json
@@ -0,0 +1,1 @@
+{"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Console", "Environment :: Win32 (MS Windows)", "Intended Audience :: Developers", "Intended Audience :: Information Technology", "Intended Audience :: System Administrators", "License :: OSI Approved :: BSD License", "Operating System :: MacOS :: MacOS X", "Operating System :: Microsoft :: Windows :: Windows NT/2000", "Operating System :: Microsoft", "Operating System :: OS Independent", "Operating System :: POSIX :: BSD :: FreeBSD", "Operating System :: POSIX :: BSD :: NetBSD", "Operating System :: POSIX :: BSD :: OpenBSD", "Operating System :: POSIX :: BSD", "Operating System :: POSIX :: Linux", "Operating System :: POSIX :: SunOS/Solaris", "Operating System :: POSIX", "Programming Language :: C", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Programming Language :: Python", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: Software Development :: Libraries", "Topic :: System :: Benchmark", "Topic :: System :: Hardware", "Topic :: System :: Monitoring", "Topic :: System :: Networking :: Monitoring", "Topic :: System :: Networking", "Topic :: System :: Operating System", "Topic :: System :: Systems Administration", "Topic :: Utilities"], "extensions": {"python.details": {"contacts": [{"email": "g.rodola@gmail.com", "name": "Giampaolo Rodola", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst"}, "project_urls": {"Home": "https://github.com/giampaolo/psutil"}}}, "extras": ["enum"], "generator": "bdist_wheel (0.30.0)", "keywords": ["ps", "top", "kill", "free", "lsof", "netstat", "nice", "tty", "ionice", "uptime", "taskmgr", "process", "df", "iotop", "iostat", "ifconfig", "taskset", "who", "pidof", "pmap", "smem", "pstree", "monitoring", "ulimit", "prlimit", "smem"], "license": "BSD", "metadata_version": "2.0", "name": "psutil", "platform": "Platform Independent", "run_requires": [{"extra": "enum", "requires": ["enum34"]}], "summary": "Cross-platform lib for process and system monitoring in Python.", "test_requires": [{"requires": ["ipaddress", "mock"]}], "version": "5.4.3"}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/third_party/python/psutil-cp27-none-win_amd64/psutil-5.4.3.dist-info/top_level.txt
@@ -0,0 +1,1 @@
+psutil
new file mode 100644
--- /dev/null
+++ b/third_party/python/psutil-cp27-none-win_amd64/psutil/__init__.py
@@ -0,0 +1,2349 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""psutil is a cross-platform library for retrieving information on
+running processes and system utilization (CPU, memory, disks, network,
+sensors) in Python. Supported platforms:
+
+ - Linux
+ - Windows
+ - OSX
+ - FreeBSD
+ - OpenBSD
+ - NetBSD
+ - Sun Solaris
+ - AIX
+
+Works with Python versions from 2.6 to 3.X.
+"""
+
+from __future__ import division
+
+import collections
+import contextlib
+import datetime
+import errno
+import functools
+import os
+import signal
+import subprocess
+import sys
+import time
+import traceback
+try:
+    import pwd
+except ImportError:
+    pwd = None
+
+from . import _common
+from ._common import deprecated_method
+from ._common import memoize
+from ._common import memoize_when_activated
+from ._common import wrap_numbers as _wrap_numbers
+from ._compat import callable
+from ._compat import long
+from ._compat import PY3 as _PY3
+
+from ._common import STATUS_DEAD
+from ._common import STATUS_DISK_SLEEP
+from ._common import STATUS_IDLE  # bsd
+from ._common import STATUS_LOCKED
+from ._common import STATUS_RUNNING
+from ._common import STATUS_SLEEPING
+from ._common import STATUS_STOPPED
+from ._common import STATUS_TRACING_STOP
+from ._common import STATUS_WAITING  # bsd
+from ._common import STATUS_WAKING
+from ._common import STATUS_ZOMBIE
+
+from ._common import CONN_CLOSE
+from ._common import CONN_CLOSE_WAIT
+from ._common import CONN_CLOSING
+from ._common import CONN_ESTABLISHED
+from ._common import CONN_FIN_WAIT1
+from ._common import CONN_FIN_WAIT2
+from ._common import CONN_LAST_ACK
+from ._common import CONN_LISTEN
+from ._common import CONN_NONE
+from ._common import CONN_SYN_RECV
+from ._common import CONN_SYN_SENT
+from ._common import CONN_TIME_WAIT
+from ._common import NIC_DUPLEX_FULL
+from ._common import NIC_DUPLEX_HALF
+from ._common import NIC_DUPLEX_UNKNOWN
+
+from ._common import AIX
+from ._common import BSD
+from ._common import FREEBSD  # NOQA
+from ._common import LINUX
+from ._common import NETBSD  # NOQA
+from ._common import OPENBSD  # NOQA
+from ._common import OSX
+from ._common import POSIX  # NOQA
+from ._common import SUNOS
+from ._common import WINDOWS
+
+from ._exceptions import AccessDenied
+from ._exceptions import Error
+from ._exceptions import NoSuchProcess
+from ._exceptions import TimeoutExpired
+from ._exceptions import ZombieProcess
+
+if LINUX:
+    # This is public API and it will be retrieved from _pslinux.py
+    # via sys.modules.
+    PROCFS_PATH = "/proc"
+
+    from . import _pslinux as _psplatform
+
+    from ._pslinux import IOPRIO_CLASS_BE  # NOQA
+    from ._pslinux import IOPRIO_CLASS_IDLE  # NOQA
+    from ._pslinux import IOPRIO_CLASS_NONE  # NOQA
+    from ._pslinux import IOPRIO_CLASS_RT  # NOQA
+    # Linux >= 2.6.36
+    if _psplatform.HAS_PRLIMIT:
+        from ._psutil_linux import RLIM_INFINITY  # NOQA
+        from ._psutil_linux import RLIMIT_AS  # NOQA
+        from ._psutil_linux import RLIMIT_CORE  # NOQA
+        from ._psutil_linux import RLIMIT_CPU  # NOQA
+        from ._psutil_linux import RLIMIT_DATA  # NOQA
+        from ._psutil_linux import RLIMIT_FSIZE  # NOQA
+        from ._psutil_linux import RLIMIT_LOCKS  # NOQA
+        from ._psutil_linux import RLIMIT_MEMLOCK  # NOQA
+        from ._psutil_linux import RLIMIT_NOFILE  # NOQA
+        from ._psutil_linux import RLIMIT_NPROC  # NOQA
+        from ._psutil_linux import RLIMIT_RSS  # NOQA
+        from ._psutil_linux import RLIMIT_STACK  # NOQA
+        # Kinda ugly but considerably faster than using hasattr() and
+        # setattr() against the module object (we are at import time:
+        # speed matters).
+        from . import _psutil_linux
+        try:
+            RLIMIT_MSGQUEUE = _psutil_linux.RLIMIT_MSGQUEUE
+        except AttributeError:
+            pass
+        try:
+            RLIMIT_NICE = _psutil_linux.RLIMIT_NICE
+        except AttributeError:
+            pass
+        try:
+            RLIMIT_RTPRIO = _psutil_linux.RLIMIT_RTPRIO
+        except AttributeError:
+            pass
+        try:
+            RLIMIT_RTTIME = _psutil_linux.RLIMIT_RTTIME
+        except AttributeError:
+            pass
+        try:
+            RLIMIT_SIGPENDING = _psutil_linux.RLIMIT_SIGPENDING
+        except AttributeError:
+            pass
+
+elif WINDOWS:
+    from . import _pswindows as _psplatform
+    from ._psutil_windows import ABOVE_NORMAL_PRIORITY_CLASS  # NOQA
+    from ._psutil_windows import BELOW_NORMAL_PRIORITY_CLASS  # NOQA
+    from ._psutil_windows import HIGH_PRIORITY_CLASS  # NOQA
+    from ._psutil_windows import IDLE_PRIORITY_CLASS  # NOQA
+    from ._psutil_windows import NORMAL_PRIORITY_CLASS  # NOQA
+    from ._psutil_windows import REALTIME_PRIORITY_CLASS  # NOQA
+    from ._pswindows import CONN_DELETE_TCB  # NOQA
+
+elif OSX:
+    from . import _psosx as _psplatform
+
+elif BSD:
+    from . import _psbsd as _psplatform
+
+elif SUNOS:
+    from . import _pssunos as _psplatform
+    from ._pssunos import CONN_BOUND  # NOQA
+    from ._pssunos import CONN_IDLE  # NOQA
+
+    # This is public writable API which is read from _pslinux.py and
+    # _pssunos.py via sys.modules.
+    PROCFS_PATH = "/proc"
+
+elif AIX:
+    from . import _psaix as _psplatform
+
+    # This is public API and it will be retrieved from _pslinux.py
+    # via sys.modules.
+    PROCFS_PATH = "/proc"
+
+else:  # pragma: no cover
+    raise NotImplementedError('platform %s is not supported' % sys.platform)
+
+
+__all__ = [
+    # exceptions
+    "Error", "NoSuchProcess", "ZombieProcess", "AccessDenied",
+    "TimeoutExpired",
+
+    # constants
+    "version_info", "__version__",
+
+    "STATUS_RUNNING", "STATUS_IDLE", "STATUS_SLEEPING", "STATUS_DISK_SLEEP",
+    "STATUS_STOPPED", "STATUS_TRACING_STOP", "STATUS_ZOMBIE", "STATUS_DEAD",
+    "STATUS_WAKING", "STATUS_LOCKED", "STATUS_WAITING", "STATUS_LOCKED",
+
+    "CONN_ESTABLISHED", "CONN_SYN_SENT", "CONN_SYN_RECV", "CONN_FIN_WAIT1",
+    "CONN_FIN_WAIT2", "CONN_TIME_WAIT", "CONN_CLOSE", "CONN_CLOSE_WAIT",
+    "CONN_LAST_ACK", "CONN_LISTEN", "CONN_CLOSING", "CONN_NONE",
+
+    "AF_LINK",
+
+    "NIC_DUPLEX_FULL", "NIC_DUPLEX_HALF", "NIC_DUPLEX_UNKNOWN",
+
+    "POWER_TIME_UNKNOWN", "POWER_TIME_UNLIMITED",
+
+    "BSD", "FREEBSD", "LINUX", "NETBSD", "OPENBSD", "OSX", "POSIX", "SUNOS",
+    "WINDOWS", "AIX",
+
+    # classes
+    "Process", "Popen",
+
+    # functions
+    "pid_exists", "pids", "process_iter", "wait_procs",             # proc
+    "virtual_memory", "swap_memory",                                # memory
+    "cpu_times", "cpu_percent", "cpu_times_percent", "cpu_count",   # cpu
+    "cpu_stats",  # "cpu_freq",
+    "net_io_counters", "net_connections", "net_if_addrs",           # network
+    "net_if_stats",
+    "disk_io_counters", "disk_partitions", "disk_usage",            # disk
+    # "sensors_temperatures", "sensors_battery", "sensors_fans"     # sensors
+    "users", "boot_time",                                           # others
+]
+__all__.extend(_psplatform.__extra__all__)
+__author__ = "Giampaolo Rodola'"
+__version__ = "5.4.3"
+version_info = tuple([int(num) for num in __version__.split('.')])
+AF_LINK = _psplatform.AF_LINK
+POWER_TIME_UNLIMITED = _common.POWER_TIME_UNLIMITED
+POWER_TIME_UNKNOWN = _common.POWER_TIME_UNKNOWN
+_TOTAL_PHYMEM = None
+_timer = getattr(time, 'monotonic', time.time)
+
+
+# Sanity check in case the user messed up with psutil installation
+# or did something weird with sys.path. In this case we might end
+# up importing a python module using a C extension module which
+# was compiled for a different version of psutil.
+# We want to prevent that by failing sooner rather than later.
+# See: https://github.com/giampaolo/psutil/issues/564
+if (int(__version__.replace('.', '')) !=
+        getattr(_psplatform.cext, 'version', None)):
+    msg = "version conflict: %r C extension module was built for another " \
+          "version of psutil" % getattr(_psplatform.cext, "__file__")
+    if hasattr(_psplatform.cext, 'version'):
+        msg += " (%s instead of %s)" % (
+            '.'.join([x for x in str(_psplatform.cext.version)]), __version__)
+    else:
+        msg += " (different than %s)" % __version__
+    msg += "; you may try to 'pip uninstall psutil', manually remove %s" % (
+        getattr(_psplatform.cext, "__file__",
+                "the existing psutil install directory"))
+    msg += " or clean the virtual env somehow, then reinstall"
+    raise ImportError(msg)
+
+
+# =====================================================================
+# --- Utils
+# =====================================================================
+
+
+if hasattr(_psplatform, 'ppid_map'):
+    # Faster version (Windows and Linux).
+    _ppid_map = _psplatform.ppid_map
+else:
+    def _ppid_map():
+        """Return a {pid: ppid, ...} dict for all running processes in
+        one shot. Used to speed up Process.children().
+        """
+        ret = {}
+        for pid in pids():
+            try:
+                proc = _psplatform.Process(pid)
+                ppid = proc.ppid()
+            except (NoSuchProcess, AccessDenied):
+                # Note: AccessDenied is unlikely to happen.
+                pass
+            else:
+                ret[pid] = ppid
+        return ret
+
+
+def _assert_pid_not_reused(fun):
+    """Decorator which raises NoSuchProcess in case a process is no
+    longer running or its PID has been reused.
+    """
+    @functools.wraps(fun)
+    def wrapper(self, *args, **kwargs):
+        if not self.is_running():
+            raise NoSuchProcess(self.pid, self._name)
+        return fun(self, *args, **kwargs)
+    return wrapper
+
+
+def _pprint_secs(secs):
+    """Format seconds in a human readable form."""
+    now = time.time()
+    secs_ago = int(now - secs)
+    if secs_ago < 60 * 60 * 24:
+        fmt = "%H:%M:%S"
+    else:
+        fmt = "%Y-%m-%d %H:%M:%S"
+    return datetime.datetime.fromtimestamp(secs).strftime(fmt)
+
+
+# =====================================================================
+# --- Process class
+# =====================================================================
+
+
+class Process(object):
+    """Represents an OS process with the given PID.
+    If PID is omitted current process PID (os.getpid()) is used.
+    Raise NoSuchProcess if PID does not exist.
+
+    Note that most of the methods of this class do not make sure
+    the PID of the process being queried has been reused over time.
+    That means you might end up retrieving an information referring
+    to another process in case the original one this instance
+    refers to is gone in the meantime.
+
+    The only exceptions for which process identity is pre-emptively
+    checked and guaranteed are:
+
+     - parent()
+     - children()
+     - nice() (set)
+     - ionice() (set)
+     - rlimit() (set)
+     - cpu_affinity (set)
+     - suspend()
+     - resume()
+     - send_signal()
+     - terminate()
+     - kill()
+
+    To prevent this problem for all other methods you can:
+     - use is_running() before querying the process
+     - if you're continuously iterating over a set of Process
+       instances use process_iter() which pre-emptively checks
+     process identity for every yielded instance
+    """
+
+    def __init__(self, pid=None):
+        self._init(pid)
+
+    def _init(self, pid, _ignore_nsp=False):
+        if pid is None:
+            pid = os.getpid()
+        else:
+            if not _PY3 and not isinstance(pid, (int, long)):
+                raise TypeError('pid must be an integer (got %r)' % pid)
+            if pid < 0:
+                raise ValueError('pid must be a positive integer (got %s)'
+                                 % pid)
+        self._pid = pid
+        self._name = None
+        self._exe = None
+        self._create_time = None
+        self._gone = False
+        self._hash = None
+        self._oneshot_inctx = False
+        # used for caching on Windows only (on POSIX ppid may change)
+        self._ppid = None
+        # platform-specific modules define an _psplatform.Process
+        # implementation class
+        self._proc = _psplatform.Process(pid)
+        self._last_sys_cpu_times = None
+        self._last_proc_cpu_times = None
+        # cache creation time for later use in is_running() method
+        try:
+            self.create_time()
+        except AccessDenied:
+            # We should never get here as AFAIK we're able to get
+            # process creation time on all platforms even as a
+            # limited user.
+            pass
+        except ZombieProcess:
+            # Zombies can still be queried by this class (although
+            # not always) and pids() return them so just go on.
+            pass
+        except NoSuchProcess:
+            if not _ignore_nsp:
+                msg = 'no process found with pid %s' % pid
+                raise NoSuchProcess(pid, None, msg)
+            else:
+                self._gone = True
+        # This pair is supposed to indentify a Process instance
+        # univocally over time (the PID alone is not enough as
+        # it might refer to a process whose PID has been reused).
+        # This will be used later in __eq__() and is_running().
+        self._ident = (self.pid, self._create_time)
+
+    def __str__(self):
+        try:
+            info = collections.OrderedDict()
+        except AttributeError:
+            info = {}  # Python 2.6
+        info["pid"] = self.pid
+        try:
+            info["name"] = self.name()
+            if self._create_time:
+                info['started'] = _pprint_secs(self._create_time)
+        except ZombieProcess:
+            info["status"] = "zombie"
+        except NoSuchProcess:
+            info["status"] = "terminated"
+        except AccessDenied:
+            pass
+        return "%s.%s(%s)" % (
+            self.__class__.__module__,
+            self.__class__.__name__,
+            ", ".join(["%s=%r" % (k, v) for k, v in info.items()]))
+
+    __repr__ = __str__
+
+    def __eq__(self, other):
+        # Test for equality with another Process object based
+        # on PID and creation time.
+        if not isinstance(other, Process):
+            return NotImplemented
+        return self._ident == other._ident
+
+    def __ne__(self, other):
+        return not self == other
+
+    def __hash__(self):
+        if self._hash is None:
+            self._hash = hash(self._ident)
+        return self._hash
+
+    @property
+    def pid(self):
+        """The process PID."""
+        return self._pid
+
+    # --- utility methods
+
+    @contextlib.contextmanager
+    def oneshot(self):
+        """Utility context manager which considerably speeds up the
+        retrieval of multiple process information at the same time.
+
+        Internally different process info (e.g. name, ppid, uids,
+        gids, ...) may be fetched by using the same routine, but
+        only one information is returned and the others are discarded.
+        When using this context manager the internal routine is
+        executed once (in the example below on name()) and the
+        other info are cached.
+
+        The cache is cleared when exiting the context manager block.
+        The advice is to use this every time you retrieve more than
+        one information about the process. If you're lucky, you'll
+        get a hell of a speedup.
+
+        >>> import psutil
+        >>> p = psutil.Process()
+        >>> with p.oneshot():
+        ...     p.name()  # collect multiple info
+        ...     p.cpu_times()  # return cached value
+        ...     p.cpu_percent()  # return cached value
+        ...     p.create_time()  # return cached value
+        ...
+        >>>
+        """
+        if self._oneshot_inctx:
+            # NOOP: this covers the use case where the user enters the
+            # context twice. Since as_dict() internally uses oneshot()
+            # I expect that the code below will be a pretty common
+            # "mistake" that the user will make, so let's guard
+            # against that:
+            #
+            # >>> with p.oneshot():
+            # ...    p.as_dict()
+            # ...
+            yield
+        else:
+            self._oneshot_inctx = True
+            try:
+                # cached in case cpu_percent() is used
+                self.cpu_times.cache_activate()
+                # cached in case memory_percent() is used
+                self.memory_info.cache_activate()
+                # cached in case parent() is used
+                self.ppid.cache_activate()
+                # cached in case username() is used
+                if POSIX:
+                    self.uids.cache_activate()
+                # specific implementation cache
+                self._proc.oneshot_enter()
+                yield
+            finally:
+                self.cpu_times.cache_deactivate()
+                self.memory_info.cache_deactivate()
+                self.ppid.cache_deactivate()
+                if POSIX:
+                    self.uids.cache_deactivate()
+                self._proc.oneshot_exit()
+                self._oneshot_inctx = False
+
+    def as_dict(self, attrs=None, ad_value=None):
+        """Utility method returning process information as a
+        hashable dictionary.
+        If *attrs* is specified it must be a list of strings
+        reflecting available Process class' attribute names
+        (e.g. ['cpu_times', 'name']) else all public (read
+        only) attributes are assumed.
+        *ad_value* is the value which gets assigned in case
+        AccessDenied or ZombieProcess exception is raised when
+        retrieving that particular process information.
+        """
+        valid_names = _as_dict_attrnames
+        if attrs is not None:
+            if not isinstance(attrs, (list, tuple, set, frozenset)):
+                raise TypeError("invalid attrs type %s" % type(attrs))
+            attrs = set(attrs)
+            invalid_names = attrs - valid_names
+            if invalid_names:
+                raise ValueError("invalid attr name%s %s" % (
+                    "s" if len(invalid_names) > 1 else "",
+                    ", ".join(map(repr, invalid_names))))
+
+        retdict = dict()
+        ls = attrs or valid_names
+        with self.oneshot():
+            for name in ls:
+                try:
+                    if name == 'pid':
+                        ret = self.pid
+                    else:
+                        meth = getattr(self, name)
+                        ret = meth()
+                except (AccessDenied, ZombieProcess):
+                    ret = ad_value
+                except NotImplementedError:
+                    # in case of not implemented functionality (may happen
+                    # on old or exotic systems) we want to crash only if
+                    # the user explicitly asked for that particular attr
+                    if attrs:
+                        raise
+                    continue
+                retdict[name] = ret
+        return retdict
+
+    def parent(self):
+        """Return the parent process as a Process object pre-emptively
+        checking whether PID has been reused.
+        If no parent is known return None.
+        """
+        ppid = self.ppid()
+        if ppid is not None:
+            ctime = self.create_time()
+            try:
+                parent = Process(ppid)
+                if parent.create_time() <= ctime:
+                    return parent
+                # ...else ppid has been reused by another process
+            except NoSuchProcess:
+                pass
+
+    def is_running(self):
+        """Return whether this process is running.
+        It also checks if PID has been reused by another process in
+        which case return False.
+        """
+        if self._gone:
+            return False
+        try:
+            # Checking if PID is alive is not enough as the PID might
+            # have been reused by another process: we also want to
+            # verify process identity.
+            # Process identity / uniqueness over time is guaranteed by
+            # (PID + creation time) and that is verified in __eq__.
+            return self == Process(self.pid)
+        except ZombieProcess:
+            # We should never get here as it's already handled in
+            # Process.__init__; here just for extra safety.
+            return True
+        except NoSuchProcess:
+            self._gone = True
+            return False
+
+    # --- actual API
+
+    @memoize_when_activated
+    def ppid(self):
+        """The process parent PID.
+        On Windows the return value is cached after first call.
+        """
+        # On POSIX we don't want to cache the ppid as it may unexpectedly
+        # change to 1 (init) in case this process turns into a zombie:
+        # https://github.com/giampaolo/psutil/issues/321
+        # http://stackoverflow.com/questions/356722/
+
+        # XXX should we check creation time here rather than in
+        # Process.parent()?
+        if POSIX:
+            return self._proc.ppid()
+        else:  # pragma: no cover
+            self._ppid = self._ppid or self._proc.ppid()
+            return self._ppid
+
+    def name(self):
+        """The process name. The return value is cached after first call."""
+        # Process name is only cached on Windows as on POSIX it may
+        # change, see:
+        # https://github.com/giampaolo/psutil/issues/692
+        if WINDOWS and self._name is not None:
+            return self._name
+        name = self._proc.name()
+        if POSIX and len(name) >= 15:
+            # On UNIX the name gets truncated to the first 15 characters.
+            # If it matches the first part of the cmdline we return that
+            # one instead because it's usually more explicative.
+            # Examples are "gnome-keyring-d" vs. "gnome-keyring-daemon".
+            try:
+                cmdline = self.cmdline()
+            except AccessDenied:
+                pass
+            else:
+                if cmdline:
+                    extended_name = os.path.basename(cmdline[0])
+                    if extended_name.startswith(name):
+                        name = extended_name
+        self._name = name
+        self._proc._name = name
+        return name
+
+    def exe(self):
+        """The process executable as an absolute path.
+        May also be an empty string.
+        The return value is cached after first call.
+        """
+        def guess_it(fallback):
+            # try to guess exe from cmdline[0] in absence of a native
+            # exe representation
+            cmdline = self.cmdline()
+            if cmdline and hasattr(os, 'access') and hasattr(os, 'X_OK'):
+                exe = cmdline[0]  # the possible exe
+                # Attempt to guess only in case of an absolute path.
+                # It is not safe otherwise as the process might have
+                # changed cwd.
+                if (os.path.isabs(exe) and
+                        os.path.isfile(exe) and
+                        os.access(exe, os.X_OK)):
+                    return exe
+            if isinstance(fallback, AccessDenied):
+                raise fallback
+            return fallback
+
+        if self._exe is None:
+            try:
+                exe = self._proc.exe()
+            except AccessDenied as err:
+                return guess_it(fallback=err)
+            else:
+                if not exe:
+                    # underlying implementation can legitimately return an
+                    # empty string; if that's the case we don't want to
+                    # raise AD while guessing from the cmdline
+                    try:
+                        exe = guess_it(fallback=exe)
+                    except AccessDenied:
+                        pass
+                self._exe = exe
+        return self._exe
+
+    def cmdline(self):
+        """The command line this process has been called with."""
+        return self._proc.cmdline()
+
+    def status(self):
+        """The process current status as a STATUS_* constant."""
+        try:
+            return self._proc.status()
+        except ZombieProcess:
+            return STATUS_ZOMBIE
+
+    def username(self):
+        """The name of the user that owns the process.
+        On UNIX this is calculated by using *real* process uid.
+        """
+        if POSIX:
+            if pwd is None:
+                # might happen if python was installed from sources
+                raise ImportError(
+                    "requires pwd module shipped with standard python")
+            real_uid = self.uids().real
+            try:
+                return pwd.getpwuid(real_uid).pw_name
+            except KeyError:
+                # the uid can't be resolved by the system
+                return str(real_uid)
+        else:
+            return self._proc.username()
+
+    def create_time(self):
+        """The process creation time as a floating point number
+        expressed in seconds since the epoch, in UTC.
+        The return value is cached after first call.
+        """
+        if self._create_time is None:
+            self._create_time = self._proc.create_time()
+        return self._create_time
+
+    def cwd(self):
+        """Process current working directory as an absolute path."""
+        return self._proc.cwd()
+
+    def nice(self, value=None):
+        """Get or set process niceness (priority)."""
+        if value is None:
+            return self._proc.nice_get()
+        else:
+            if not self.is_running():
+                raise NoSuchProcess(self.pid, self._name)
+            self._proc.nice_set(value)
+
+    if POSIX:
+
+        @memoize_when_activated
+        def uids(self):
+            """Return process UIDs as a (real, effective, saved)
+            namedtuple.
+            """
+            return self._proc.uids()
+
+        def gids(self):
+            """Return process GIDs as a (real, effective, saved)
+            namedtuple.
+            """
+            return self._proc.gids()
+
+        def terminal(self):
+            """The terminal associated with this process, if any,
+            else None.
+            """
+            return self._proc.terminal()
+
+        def num_fds(self):
+            """Return the number of file descriptors opened by this
+            process (POSIX only).
+            """
+            return self._proc.num_fds()
+
+    # Linux, BSD, AIX and Windows only
+    if hasattr(_psplatform.Process, "io_counters"):
+
+        def io_counters(self):
+            """Return process I/O statistics as a
+            (read_count, write_count, read_bytes, write_bytes)
+            namedtuple.
+            Those are the number of read/write calls performed and the
+            amount of bytes read and written by the process.
+            """
+            return self._proc.io_counters()
+
+    # Linux and Windows >= Vista only
+    if hasattr(_psplatform.Process, "ionice_get"):
+
+        def ionice(self, ioclass=None, value=None):
+            """Get or set process I/O niceness (priority).
+
+            On Linux *ioclass* is one of the IOPRIO_CLASS_* constants.
+            *value* is a number which goes from 0 to 7. The higher the
+            value, the lower the I/O priority of the process.
+
+            On Windows only *ioclass* is used and it can be set to 2
+            (normal), 1 (low) or 0 (very low).
+
+            Available on Linux and Windows > Vista only.
+            """
+            if ioclass is None:
+                if value is not None:
+                    raise ValueError("'ioclass' argument must be specified")
+                return self._proc.ionice_get()
+            else:
+                return self._proc.ionice_set(ioclass, value)
+
+    # Linux only
+    if hasattr(_psplatform.Process, "rlimit"):
+
+        def rlimit(self, resource, limits=None):
+            """Get or set process resource limits as a (soft, hard)
+            tuple.
+
+            *resource* is one of the RLIMIT_* constants.
+            *limits* is supposed to be a (soft, hard)  tuple.
+
+            See "man prlimit" for further info.
+            Available on Linux only.
+            """
+            if limits is None:
+                return self._proc.rlimit(resource)
+            else:
+                return self._proc.rlimit(resource, limits)
+
+    # Windows, Linux and FreeBSD only
+    if hasattr(_psplatform.Process, "cpu_affinity_get"):
+
+        def cpu_affinity(self, cpus=None):
+            """Get or set process CPU affinity.
+            If specified, *cpus* must be a list of CPUs for which you
+            want to set the affinity (e.g. [0, 1]).
+            If an empty list is passed, all egible CPUs are assumed
+            (and set).
+            (Windows, Linux and BSD only).
+            """
+            # Automatically remove duplicates both on get and
+            # set (for get it's not really necessary, it's
+            # just for extra safety).
+            if cpus is None:
+                return list(set(self._proc.cpu_affinity_get()))
+            else:
+                if not cpus:
+                    if hasattr(self._proc, "_get_eligible_cpus"):
+                        cpus = self._proc._get_eligible_cpus()
+                    else:
+                        cpus = tuple(range(len(cpu_times(percpu=True))))
+                self._proc.cpu_affinity_set(list(set(cpus)))
+
+    # Linux, FreeBSD, SunOS
+    if hasattr(_psplatform.Process, "cpu_num"):
+
+        def cpu_num(self):
+            """Return what CPU this process is currently running on.
+            The returned number should be <= psutil.cpu_count()
+            and <= len(psutil.cpu_percent(percpu=True)).
+            It may be used in conjunction with
+            psutil.cpu_percent(percpu=True) to observe the system
+            workload distributed across CPUs.
+            """
+            return self._proc.cpu_num()
+
+    # Linux, OSX and Windows only
+    if hasattr(_psplatform.Process, "environ"):
+
+        def environ(self):
+            """The environment variables of the process as a dict.  Note: this
+            might not reflect changes made after the process started.  """
+            return self._proc.environ()
+
+    if WINDOWS:
+
+        def num_handles(self):
+            """Return the number of handles opened by this process
+            (Windows only).
+            """
+            return self._proc.num_handles()
+
+    def num_ctx_switches(self):
+        """Return the number of voluntary and involuntary context
+        switches performed by this process.
+        """
+        return self._proc.num_ctx_switches()
+
+    def num_threads(self):
+        """Return the number of threads used by this process."""
+        return self._proc.num_threads()
+
+    if hasattr(_psplatform.Process, "threads"):
+
+        def threads(self):
+            """Return threads opened by process as a list of
+            (id, user_time, system_time) namedtuples representing
+            thread id and thread CPU times (user/system).
+            On OpenBSD this method requires root access.
+            """
+            return self._proc.threads()
+
+    @_assert_pid_not_reused
+    def children(self, recursive=False):
+        """Return the children of this process as a list of Process
+        instances, pre-emptively checking whether PID has been reused.
+        If *recursive* is True return all the parent descendants.
+
+        Example (A == this process):
+
+         A ─┐
+            │
+            ├─ B (child) ─┐
+            │             └─ X (grandchild) ─┐
+            │                                └─ Y (great grandchild)
+            ├─ C (child)
+            └─ D (child)
+
+        >>> import psutil
+        >>> p = psutil.Process()
+        >>> p.children()
+        B, C, D
+        >>> p.children(recursive=True)
+        B, X, Y, C, D
+
+        Note that in the example above if process X disappears
+        process Y won't be listed as the reference to process A
+        is lost.
+        """
+        ppid_map = _ppid_map()
+        ret = []
+        if not recursive:
+            for pid, ppid in ppid_map.items():
+                if ppid == self.pid:
+                    try:
+                        child = Process(pid)
+                        # if child happens to be older than its parent
+                        # (self) it means child's PID has been reused
+                        if self.create_time() <= child.create_time():
+                            ret.append(child)
+                    except (NoSuchProcess, ZombieProcess):
+                        pass
+        else:
+            # Construct a {pid: [child pids]} dict
+            reverse_ppid_map = collections.defaultdict(list)
+            for pid, ppid in ppid_map.items():
+                reverse_ppid_map[ppid].append(pid)
+            # Recursively traverse that dict, starting from self.pid,
+            # such that we only call Process() on actual children
+            seen = set()
+            stack = [self.pid]
+            while stack:
+                pid = stack.pop()
+                if pid in seen:
+                    # Since pids can be reused while the ppid_map is
+                    # constructed, there may be rare instances where
+                    # there's a cycle in the recorded process "tree".
+                    continue
+                seen.add(pid)
+                for child_pid in reverse_ppid_map[pid]:
+                    try:
+                        child = Process(child_pid)
+                        # if child happens to be older than its parent
+                        # (self) it means child's PID has been reused
+                        intime = self.create_time() <= child.create_time()
+                        if intime:
+                            ret.append(child)
+                            stack.append(child_pid)
+                    except (NoSuchProcess, ZombieProcess):
+                        pass
+        return ret
+
+    def cpu_percent(self, interval=None):
+        """Return a float representing the current process CPU
+        utilization as a percentage.
+
+        When *interval* is 0.0 or None (default) compares process times
+        to system CPU times elapsed since last call, returning
+        immediately (non-blocking). That means that the first time
+        this is called it will return a meaningful 0.0 value.
+
+        When *interval* is > 0.0 compares process times to system CPU
+        times elapsed before and after the interval (blocking).
+
+        In this case is recommended for accuracy that this function
+        be called with at least 0.1 seconds between calls.
+
+        A value > 100.0 can be returned in case of processes running
+        multiple threads on different CPU cores.
+
+        The returned value is explicitly NOT split evenly between
+        all available logical CPUs. This means that a busy loop process
+        running on a system with 2 logical CPUs will be reported as
+        having 100% CPU utilization instead of 50%.
+
+        Examples:
+
+          >>> import psutil
+          >>> p = psutil.Process(os.getpid())
+          >>> # blocking
+          >>> p.cpu_percent(interval=1)
+          2.0
+          >>> # non-blocking (percentage since last call)
+          >>> p.cpu_percent(interval=None)
+          2.9
+          >>>
+        """
+        blocking = interval is not None and interval > 0.0
+        if interval is not None and interval < 0:
+            raise ValueError("interval is not positive (got %r)" % interval)
+        num_cpus = cpu_count() or 1
+
+        def timer():
+            return _timer() * num_cpus
+
+        if blocking:
+            st1 = timer()
+            pt1 = self._proc.cpu_times()
+            time.sleep(interval)
+            st2 = timer()
+            pt2 = self._proc.cpu_times()
+        else:
+            st1 = self._last_sys_cpu_times
+            pt1 = self._last_proc_cpu_times
+            st2 = timer()
+            pt2 = self._proc.cpu_times()
+            if st1 is None or pt1 is None:
+                self._last_sys_cpu_times = st2
+                self._last_proc_cpu_times = pt2
+                return 0.0
+
+        delta_proc = (pt2.user - pt1.user) + (pt2.system - pt1.system)
+        delta_time = st2 - st1
+        # reset values for next call in case of interval == None
+        self._last_sys_cpu_times = st2
+        self._last_proc_cpu_times = pt2
+
+        try:
+            # This is the utilization split evenly between all CPUs.
+            # E.g. a busy loop process on a 2-CPU-cores system at this
+            # point is reported as 50% instead of 100%.
+            overall_cpus_percent = ((delta_proc / delta_time) * 100)
+        except ZeroDivisionError:
+            # interval was too low
+            return 0.0
+        else:
+            # Note 1:
+            # in order to emulate "top" we multiply the value for the num
+            # of CPU cores. This way the busy process will be reported as
+            # having 100% (or more) usage.
+            #
+            # Note 2:
+            # taskmgr.exe on Windows differs in that it will show 50%
+            # instead.
+            #
+            # Note 3:
+            # a percentage > 100 is legitimate as it can result from a
+            # process with multiple threads running on different CPU
+            # cores (top does the same), see:
+            # http://stackoverflow.com/questions/1032357
+            # https://github.com/giampaolo/psutil/issues/474
+            single_cpu_percent = overall_cpus_percent * num_cpus
+            return round(single_cpu_percent, 1)
+
+    @memoize_when_activated
+    def cpu_times(self):
+        """Return a (user, system, children_user, children_system)
+        namedtuple representing the accumulated process time, in
+        seconds.
+        This is similar to os.times() but per-process.
+        On OSX and Windows children_user and children_system are
+        always set to 0.
+        """
+        return self._proc.cpu_times()
+
+    @memoize_when_activated
+    def memory_info(self):
+        """Return a namedtuple with variable fields depending on the
+        platform, representing memory information about the process.
+
+        The "portable" fields available on all plaforms are `rss` and `vms`.
+
+        All numbers are expressed in bytes.
+        """
+        return self._proc.memory_info()
+
+    @deprecated_method(replacement="memory_info")
+    def memory_info_ex(self):
+        return self.memory_info()
+
+    def memory_full_info(self):
+        """This method returns the same information as memory_info(),
+        plus, on some platform (Linux, OSX, Windows), also provides
+        additional metrics (USS, PSS and swap).
+        The additional metrics provide a better representation of actual
+        process memory usage.
+
+        Namely USS is the memory which is unique to a process and which
+        would be freed if the process was terminated right now.
+
+        It does so by passing through the whole process address.
+        As such it usually requires higher user privileges than
+        memory_info() and is considerably slower.
+        """
+        return self._proc.memory_full_info()
+
+    def memory_percent(self, memtype="rss"):
+        """Compare process memory to total physical system memory and
+        calculate process memory utilization as a percentage.
+        *memtype* argument is a string that dictates what type of
+        process memory you want to compare against (defaults to "rss").
+        The list of available strings can be obtained like this:
+
+        >>> psutil.Process().memory_info()._fields
+        ('rss', 'vms', 'shared', 'text', 'lib', 'data', 'dirty', 'uss', 'pss')
+        """
+        valid_types = list(_psplatform.pfullmem._fields)
+        if memtype not in valid_types:
+            raise ValueError("invalid memtype %r; valid types are %r" % (
+                memtype, tuple(valid_types)))
+        fun = self.memory_info if memtype in _psplatform.pmem._fields else \
+            self.memory_full_info
+        metrics = fun()
+        value = getattr(metrics, memtype)
+
+        # use cached value if available
+        total_phymem = _TOTAL_PHYMEM or virtual_memory().total
+        if not total_phymem > 0:
+            # we should never get here
+            raise ValueError(
+                "can't calculate process memory percent because "
+                "total physical system memory is not positive (%r)"
+                % total_phymem)
+        return (value / float(total_phymem)) * 100
+
+    if hasattr(_psplatform.Process, "memory_maps"):
+        # Available everywhere except OpenBSD and NetBSD.
+        def memory_maps(self, grouped=True):
+            """Return process' mapped memory regions as a list of namedtuples
+            whose fields are variable depending on the platform.
+
+            If *grouped* is True the mapped regions with the same 'path'
+            are grouped together and the different memory fields are summed.
+
+            If *grouped* is False every mapped region is shown as a single
+            entity and the namedtuple will also include the mapped region's
+            address space ('addr') and permission set ('perms').
+            """
+            it = self._proc.memory_maps()
+            if grouped:
+                d = {}
+                for tupl in it:
+                    path = tupl[2]
+                    nums = tupl[3:]
+                    try:
+                        d[path] = map(lambda x, y: x + y, d[path], nums)
+                    except KeyError:
+                        d[path] = nums
+                nt = _psplatform.pmmap_grouped
+                return [nt(path, *d[path]) for path in d]  # NOQA
+            else:
+                nt = _psplatform.pmmap_ext
+                return [nt(*x) for x in it]
+
+    def open_files(self):
+        """Return files opened by process as a list of
+        (path, fd) namedtuples including the absolute file name
+        and file descriptor number.
+        """
+        return self._proc.open_files()
+
+    def connections(self, kind='inet'):
+        """Return socket connections opened by process as a list of
+        (fd, family, type, laddr, raddr, status) namedtuples.
+        The *kind* parameter filters for connections that match the
+        following criteria:
+
+        +------------+----------------------------------------------------+
+        | Kind Value | Connections using                                  |
+        +------------+----------------------------------------------------+
+        | inet       | IPv4 and IPv6                                      |
+        | inet4      | IPv4                                               |
+        | inet6      | IPv6                                               |
+        | tcp        | TCP                                                |
+        | tcp4       | TCP over IPv4                                      |
+        | tcp6       | TCP over IPv6                                      |
+        | udp        | UDP                                                |
+        | udp4       | UDP over IPv4                                      |
+        | udp6       | UDP over IPv6                                      |
+        | unix       | UNIX socket (both UDP and TCP protocols)           |
+        | all        | the sum of all the possible families and protocols |
+        +------------+----------------------------------------------------+
+        """
+        return self._proc.connections(kind)
+
+    # --- signals
+
+    if POSIX:
+        def _send_signal(self, sig):
+            assert not self.pid < 0, self.pid
+            if self.pid == 0:
+                # see "man 2 kill"
+                raise ValueError(
+                    "preventing sending signal to process with PID 0 as it "
+                    "would affect every process in the process group of the "
+                    "calling process (os.getpid()) instead of PID 0")
+            try:
+                os.kill(self.pid, sig)
+            except OSError as err:
+                if err.errno == errno.ESRCH:
+                    if OPENBSD and pid_exists(self.pid):
+                        # We do this because os.kill() lies in case of
+                        # zombie processes.
+                        raise ZombieProcess(self.pid, self._name, self._ppid)
+                    else:
+                        self._gone = True
+                        raise NoSuchProcess(self.pid, self._name)
+                if err.errno in (errno.EPERM, errno.EACCES):
+                    raise AccessDenied(self.pid, self._name)
+                raise
+
+    @_assert_pid_not_reused
+    def send_signal(self, sig):
+        """Send a signal *sig* to process pre-emptively checking
+        whether PID has been reused (see signal module constants) .
+        On Windows only SIGTERM is valid and is treated as an alias
+        for kill().
+        """
+        if POSIX:
+            self._send_signal(sig)
+        else:  # pragma: no cover
+            if sig == signal.SIGTERM:
+                self._proc.kill()
+            # py >= 2.7
+            elif sig in (getattr(signal, "CTRL_C_EVENT", object()),
+                         getattr(signal, "CTRL_BREAK_EVENT", object())):
+                self._proc.send_signal(sig)
+            else:
+                raise ValueError(
+                    "only SIGTERM, CTRL_C_EVENT and CTRL_BREAK_EVENT signals "
+                    "are supported on Windows")
+
+    @_assert_pid_not_reused
+    def suspend(self):
+        """Suspend process execution with SIGSTOP pre-emptively checking
+        whether PID has been reused.
+        On Windows this has the effect ot suspending all process threads.
+        """
+        if POSIX:
+            self._send_signal(signal.SIGSTOP)
+        else:  # pragma: no cover
+            self._proc.suspend()
+
+    @_assert_pid_not_reused
+    def resume(self):
+        """Resume process execution with SIGCONT pre-emptively checking
+        whether PID has been reused.
+        On Windows this has the effect of resuming all process threads.
+        """
+        if POSIX:
+            self._send_signal(signal.SIGCONT)
+        else:  # pragma: no cover
+            self._proc.resume()
+
+    @_assert_pid_not_reused
+    def terminate(self):
+        """Terminate the process with SIGTERM pre-emptively checking
+        whether PID has been reused.
+        On Windows this is an alias for kill().
+        """
+        if POSIX:
+            self._send_signal(signal.SIGTERM)
+        else:  # pragma: no cover
+            self._proc.kill()
+
+    @_assert_pid_not_reused
+    def kill(self):
+        """Kill the current process with SIGKILL pre-emptively checking
+        whether PID has been reused.
+        """
+        if POSIX:
+            self._send_signal(signal.SIGKILL)
+        else:  # pragma: no cover
+            self._proc.kill()
+
+    def wait(self, timeout=None):
+        """Wait for process to terminate and, if process is a children
+        of os.getpid(), also return its exit code, else None.
+
+        If the process is already terminated immediately return None
+        instead of raising NoSuchProcess.
+
+        If *timeout* (in seconds) is specified and process is still
+        alive raise TimeoutExpired.
+
+        To wait for multiple Process(es) use psutil.wait_procs().
+        """
+        if timeout is not None and not timeout >= 0:
+            raise ValueError("timeout must be a positive integer")
+        return self._proc.wait(timeout)
+
+
+# =====================================================================
+# --- Popen class
+# =====================================================================
+
+
+class Popen(Process):
+    """A more convenient interface to stdlib subprocess.Popen class.
+    It starts a sub process and deals with it exactly as when using
+    subprocess.Popen class but in addition also provides all the
+    properties and methods of psutil.Process class as a unified
+    interface:
+
+      >>> import psutil
+      >>> from subprocess import PIPE
+      >>> p = psutil.Popen(["python", "-c", "print 'hi'"], stdout=PIPE)
+      >>> p.name()
+      'python'
+      >>> p.uids()
+      user(real=1000, effective=1000, saved=1000)
+      >>> p.username()
+      'giampaolo'
+      >>> p.communicate()
+      ('hi\n', None)
+      >>> p.terminate()
+      >>> p.wait(timeout=2)
+      0
+      >>>
+
+    For method names common to both classes such as kill(), terminate()
+    and wait(), psutil.Process implementation takes precedence.
+
+    Unlike subprocess.Popen this class pre-emptively checks whether PID
+    has been reused on send_signal(), terminate() and kill() so that
+    you don't accidentally terminate another process, fixing
+    http://bugs.python.org/issue6973.
+
+    For a complete documentation refer to:
+    http://docs.python.org/library/subprocess.html
+    """
+
+    def __init__(self, *args, **kwargs):
+        # Explicitly avoid to raise NoSuchProcess in case the process
+        # spawned by subprocess.Popen terminates too quickly, see:
+        # https://github.com/giampaolo/psutil/issues/193
+        self.__subproc = subprocess.Popen(*args, **kwargs)
+        self._init(self.__subproc.pid, _ignore_nsp=True)
+
+    def __dir__(self):
+        return sorted(set(dir(Popen) + dir(subprocess.Popen)))
+
+    def __enter__(self):
+        if hasattr(self.__subproc, '__enter__'):
+            self.__subproc.__enter__()
+        return self
+
+    def __exit__(self, *args, **kwargs):
+        if hasattr(self.__subproc, '__exit__'):
+            return self.__subproc.__exit__(*args, **kwargs)
+        else:
+            if self.stdout:
+                self.stdout.close()
+            if self.stderr:
+                self.stderr.close()
+            try:
+                # Flushing a BufferedWriter may raise an error.
+                if self.stdin:
+                    self.stdin.close()
+            finally:
+                # Wait for the process to terminate, to avoid zombies.
+                self.wait()
+
+    def __getattribute__(self, name):
+        try:
+            return object.__getattribute__(self, name)
+        except AttributeError:
+            try:
+                return object.__getattribute__(self.__subproc, name)
+            except AttributeError:
+                raise AttributeError("%s instance has no attribute '%s'"
+                                     % (self.__class__.__name__, name))
+
+    def wait(self, timeout=None):
+        if self.__subproc.returncode is not None:
+            return self.__subproc.returncode
+        ret = super(Popen, self).wait(timeout)
+        self.__subproc.returncode = ret
+        return ret
+
+
+# The valid attr names which can be processed by Process.as_dict().
+_as_dict_attrnames = set(
+    [x for x in dir(Process) if not x.startswith('_') and x not in
+     ['send_signal', 'suspend', 'resume', 'terminate', 'kill', 'wait',
+      'is_running', 'as_dict', 'parent', 'children', 'rlimit',
+      'memory_info_ex', 'oneshot']])
+
+
+# =====================================================================
+# --- system processes related functions
+# =====================================================================
+
+
+def pids():
+    """Return a list of current running PIDs."""
+    return _psplatform.pids()
+
+
+def pid_exists(pid):
+    """Return True if given PID exists in the current process list.
+    This is faster than doing "pid in psutil.pids()" and
+    should be preferred.
+    """
+    if pid < 0:
+        return False
+    elif pid == 0 and POSIX:
+        # On POSIX we use os.kill() to determine PID existence.
+        # According to "man 2 kill" PID 0 has a special meaning
+        # though: it refers to <<every process in the process
+        # group of the calling process>> and that is not we want
+        # to do here.
+        return pid in pids()
+    else:
+        return _psplatform.pid_exists(pid)
+
+
+_pmap = {}
+
+
+def process_iter(attrs=None, ad_value=None):
+    """Return a generator yielding a Process instance for all
+    running processes.
+
+    Every new Process instance is only created once and then cached
+    into an internal table which is updated every time this is used.
+
+    Cached Process instances are checked for identity so that you're
+    safe in case a PID has been reused by another process, in which
+    case the cached instance is updated.
+
+    The sorting order in which processes are yielded is based on
+    their PIDs.
+
+    *attrs* and *ad_value* have the same meaning as in
+    Process.as_dict(). If *attrs* is specified as_dict() is called
+    and the resulting dict is stored as a 'info' attribute attached
+    to returned Process instance.
+    If *attrs* is an empty list it will retrieve all process info
+    (slow).
+    """
+    def add(pid):
+        proc = Process(pid)
+        if attrs is not None:
+            proc.info = proc.as_dict(attrs=attrs, ad_value=ad_value)
+        _pmap[proc.pid] = proc
+        return proc
+
+    def remove(pid):
+        _pmap.pop(pid, None)
+
+    a = set(pids())
+    b = set(_pmap.keys())
+    new_pids = a - b
+    gone_pids = b - a
+
+    for pid in gone_pids:
+        remove(pid)
+    for pid, proc in sorted(list(_pmap.items()) +
+                            list(dict.fromkeys(new_pids).items())):
+        try:
+            if proc is None:  # new process
+                yield add(pid)
+            else:
+                # use is_running() to check whether PID has been reused by
+                # another process in which case yield a new Process instance
+                if proc.is_running():
+                    if attrs is not None:
+                        proc.info = proc.as_dict(
+                            attrs=attrs, ad_value=ad_value)
+                    yield proc
+                else:
+                    yield add(pid)
+        except NoSuchProcess:
+            remove(pid)
+        except AccessDenied:
+            # Process creation time can't be determined hence there's
+            # no way to tell whether the pid of the cached process
+            # has been reused. Just return the cached version.
+            if proc is None and pid in _pmap:
+                try:
+                    yield _pmap[pid]
+                except KeyError:
+                    # If we get here it is likely that 2 threads were
+                    # using process_iter().
+                    pass
+            else:
+                raise
+
+
+def wait_procs(procs, timeout=None, callback=None):
+    """Convenience function which waits for a list of processes to
+    terminate.
+
+    Return a (gone, alive) tuple indicating which processes
+    are gone and which ones are still alive.
+
+    The gone ones will have a new *returncode* attribute indicating
+    process exit status (may be None).
+
+    *callback* is a function which gets called every time a process
+    terminates (a Process instance is passed as callback argument).
+
+    Function will return as soon as all processes terminate or when
+    *timeout* occurs.
+    Differently from Process.wait() it will not raise TimeoutExpired if
+    *timeout* occurs.
+
+    Typical use case is:
+
+     - send SIGTERM to a list of processes
+     - give them some time to terminate
+     - send SIGKILL to those ones which are still alive
+
+    Example:
+
+    >>> def on_terminate(proc):
+    ...     print("process {} terminated".format(proc))
+    ...
+    >>> for p in procs:
+    ...    p.terminate()
+    ...
+    >>> gone, alive = wait_procs(procs, timeout=3, callback=on_terminate)
+    >>> for p in alive:
+    ...     p.kill()
+    """
+    def check_gone(proc, timeout):
+        try:
+            returncode = proc.wait(timeout=timeout)
+        except TimeoutExpired:
+            pass
+        else:
+            if returncode is not None or not proc.is_running():
+                proc.returncode = returncode
+                gone.add(proc)
+                if callback is not None:
+                    callback(proc)
+
+    if timeout is not None and not timeout >= 0:
+        msg = "timeout must be a positive integer, got %s" % timeout
+        raise ValueError(msg)
+    gone = set()
+    alive = set(procs)
+    if callback is not None and not callable(callback):
+        raise TypeError("callback %r is not a callable" % callable)
+    if timeout is not None:
+        deadline = _timer() + timeout
+
+    while alive:
+        if timeout is not None and timeout <= 0:
+            break
+        for proc in alive:
+            # Make sure that every complete iteration (all processes)
+            # will last max 1 sec.
+            # We do this because we don't want to wait too long on a
+            # single process: in case it terminates too late other
+            # processes may disappear in the meantime and their PID
+            # reused.
+            max_timeout = 1.0 / len(alive)
+            if timeout is not None:
+                timeout = min((deadline - _timer()), max_timeout)
+                if timeout <= 0:
+                    break
+                check_gone(proc, timeout)
+            else:
+                check_gone(proc, max_timeout)
+        alive = alive - gone
+
+    if alive:
+        # Last attempt over processes survived so far.
+        # timeout == 0 won't make this function wait any further.
+        for proc in alive:
+            check_gone(proc, 0)
+        alive = alive - gone
+
+    return (list(gone), list(alive))
+
+
+# =====================================================================
+# --- CPU related functions
+# =====================================================================
+
+
+def cpu_count(logical=True):
+    """Return the number of logical CPUs in the system (same as
+    os.cpu_count() in Python 3.4).
+
+    If *logical* is False return the number of physical cores only
+    (e.g. hyper thread CPUs are excluded).
+
+    Return None if undetermined.
+
+    The return value is cached after first call.
+    If desired cache can be cleared like this:
+
+    >>> psutil.cpu_count.cache_clear()
+    """
+    if logical:
+        ret = _psplatform.cpu_count_logical()
+    else:
+        ret = _psplatform.cpu_count_physical()
+    if ret is not None and ret < 1:
+        ret = None
+    return ret
+
+
+def cpu_times(percpu=False):
+    """Return system-wide CPU times as a namedtuple.
+    Every CPU time represents the seconds the CPU has spent in the
+    given mode. The namedtuple's fields availability varies depending on the
+    platform:
+
+     - user
+     - system
+     - idle
+     - nice (UNIX)
+     - iowait (Linux)
+     - irq (Linux, FreeBSD)
+     - softirq (Linux)
+     - steal (Linux >= 2.6.11)
+     - guest (Linux >= 2.6.24)
+     - guest_nice (Linux >= 3.2.0)
+
+    When *percpu* is True return a list of namedtuples for each CPU.
+    First element of the list refers to first CPU, second element
+    to second CPU and so on.
+    The order of the list is consistent across calls.
+    """
+    if not percpu:
+        return _psplatform.cpu_times()
+    else:
+        return _psplatform.per_cpu_times()
+
+
+try:
+    _last_cpu_times = cpu_times()
+except Exception:
+    # Don't want to crash at import time.
+    _last_cpu_times = None
+    traceback.print_exc()
+
+try:
+    _last_per_cpu_times = cpu_times(percpu=True)
+except Exception:
+    # Don't want to crash at import time.
+    _last_per_cpu_times = None
+    traceback.print_exc()
+
+
+def _cpu_tot_time(times):
+    """Given a cpu_time() ntuple calculates the total CPU time
+    (including idle time).
+    """
+    tot = sum(times)
+    if LINUX:
+        # On Linux guest times are already accounted in "user" or
+        # "nice" times, so we subtract them from total.
+        # Htop does the same. References:
+        # https://github.com/giampaolo/psutil/pull/940
+        # http://unix.stackexchange.com/questions/178045
+        # https://github.com/torvalds/linux/blob/
+        #     447976ef4fd09b1be88b316d1a81553f1aa7cd07/kernel/sched/
+        #     cputime.c#L158
+        tot -= getattr(times, "guest", 0)  # Linux 2.6.24+
+        tot -= getattr(times, "guest_nice", 0)  # Linux 3.2.0+
+    return tot
+
+
+def _cpu_busy_time(times):
+    """Given a cpu_time() ntuple calculates the busy CPU time.
+    We do so by subtracting all idle CPU times.
+    """
+    busy = _cpu_tot_time(times)
+    busy -= times.idle
+    # Linux: "iowait" is time during which the CPU does not do anything
+    # (waits for IO to complete). On Linux IO wait is *not* accounted
+    # in "idle" time so we subtract it. Htop does the same.
+    # References:
+    # https://github.com/torvalds/linux/blob/
+    #     447976ef4fd09b1be88b316d1a81553f1aa7cd07/kernel/sched/cputime.c#L244
+    busy -= getattr(times, "iowait", 0)
+    return busy
+
+
+def cpu_percent(interval=None, percpu=False):
+    """Return a float representing the current system-wide CPU
+    utilization as a percentage.
+
+    When *interval* is > 0.0 compares system CPU times elapsed before
+    and after the interval (blocking).
+
+    When *interval* is 0.0 or None compares system CPU times elapsed
+    since last call or module import, returning immediately (non
+    blocking). That means the first time this is called it will
+    return a meaningless 0.0 value which you should ignore.
+    In this case is recommended for accuracy that this function be
+    called with at least 0.1 seconds between calls.
+
+    When *percpu* is True returns a list of floats representing the
+    utilization as a percentage for each CPU.
+    First element of the list refers to first CPU, second element
+    to second CPU and so on.
+    The order of the list is consistent across calls.
+
+    Examples:
+
+      >>> # blocking, system-wide
+      >>> psutil.cpu_percent(interval=1)
+      2.0
+      >>>
+      >>> # blocking, per-cpu
+      >>> psutil.cpu_percent(interval=1, percpu=True)
+      [2.0, 1.0]
+      >>>
+      >>> # non-blocking (percentage since last call)
+      >>> psutil.cpu_percent(interval=None)
+      2.9
+      >>>
+    """
+    global _last_cpu_times
+    global _last_per_cpu_times
+    blocking = interval is not None and interval > 0.0
+    if interval is not None and interval < 0:
+        raise ValueError("interval is not positive (got %r)" % interval)
+
+    def calculate(t1, t2):
+        t1_all = _cpu_tot_time(t1)
+        t1_busy = _cpu_busy_time(t1)
+
+        t2_all = _cpu_tot_time(t2)
+        t2_busy = _cpu_busy_time(t2)
+
+        # this usually indicates a float precision issue
+        if t2_busy <= t1_busy:
+            return 0.0
+
+        busy_delta = t2_busy - t1_busy
+        all_delta = t2_all - t1_all
+        try:
+            busy_perc = (busy_delta / all_delta) * 100
+        except ZeroDivisionError:
+            return 0.0
+        else:
+            return round(busy_perc, 1)
+
+    # system-wide usage
+    if not percpu:
+        if blocking:
+            t1 = cpu_times()
+            time.sleep(interval)
+        else:
+            t1 = _last_cpu_times
+            if t1 is None:
+                # Something bad happened at import time. We'll
+                # get a meaningful result on the next call. See:
+                # https://github.com/giampaolo/psutil/pull/715
+                t1 = cpu_times()
+        _last_cpu_times = cpu_times()
+        return calculate(t1, _last_cpu_times)
+    # per-cpu usage
+    else:
+        ret = []
+        if blocking:
+            tot1 = cpu_times(percpu=True)
+            time.sleep(interval)
+        else:
+            tot1 = _last_per_cpu_times
+            if tot1 is None:
+                # Something bad happened at import time. We'll
+                # get a meaningful result on the next call. See:
+                # https://github.com/giampaolo/psutil/pull/715
+                tot1 = cpu_times(percpu=True)
+        _last_per_cpu_times = cpu_times(percpu=True)
+        for t1, t2 in zip(tot1, _last_per_cpu_times):
+            ret.append(calculate(t1, t2))
+        return ret
+
+
+# Use separate global vars for cpu_times_percent() so that it's
+# independent from cpu_percent() and they can both be used within
+# the same program.
+_last_cpu_times_2 = _last_cpu_times
+_last_per_cpu_times_2 = _last_per_cpu_times
+
+
+def cpu_times_percent(interval=None, percpu=False):
+    """Same as cpu_percent() but provides utilization percentages
+    for each specific CPU time as is returned by cpu_times().
+    For instance, on Linux we'll get:
+
+      >>> cpu_times_percent()
+      cpupercent(user=4.8, nice=0.0, system=4.8, idle=90.5, iowait=0.0,
+                 irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0)
+      >>>
+
+    *interval* and *percpu* arguments have the same meaning as in
+    cpu_percent().
+    """
+    global _last_cpu_times_2
+    global _last_per_cpu_times_2
+    blocking = interval is not None and interval > 0.0
+    if interval is not None and interval < 0:
+        raise ValueError("interval is not positive (got %r)" % interval)
+
+    def calculate(t1, t2):
+        nums = []
+        all_delta = _cpu_tot_time(t2) - _cpu_tot_time(t1)
+        for field in t1._fields:
+            field_delta = getattr(t2, field) - getattr(t1, field)
+            try:
+                field_perc = (100 * field_delta) / all_delta
+            except ZeroDivisionError:
+                field_perc = 0.0
+            field_perc = round(field_perc, 1)
+            # CPU times are always supposed to increase over time
+            # or at least remain the same and that's because time
+            # cannot go backwards.
+            # Surprisingly sometimes this might not be the case (at
+            # least on Windows and Linux), see:
+            # https://github.com/giampaolo/psutil/issues/392
+            # https://github.com/giampaolo/psutil/issues/645
+            # I really don't know what to do about that except
+            # forcing the value to 0 or 100.
+            if field_perc > 100.0:
+                field_perc = 100.0
+            # `<=` because `-0.0 == 0.0` evaluates to True
+            elif field_perc <= 0.0:
+                field_perc = 0.0
+            nums.append(field_perc)
+        return _psplatform.scputimes(*nums)
+
+    # system-wide usage
+    if not percpu:
+        if blocking:
+            t1 = cpu_times()
+            time.sleep(interval)
+        else:
+            t1 = _last_cpu_times_2
+            if t1 is None:
+                # Something bad happened at import time. We'll
+                # get a meaningful result on the next call. See:
+                # https://github.com/giampaolo/psutil/pull/715
+                t1 = cpu_times()
+        _last_cpu_times_2 = cpu_times()
+        return calculate(t1, _last_cpu_times_2)
+    # per-cpu usage
+    else:
+        ret = []
+        if blocking:
+            tot1 = cpu_times(percpu=True)
+            time.sleep(interval)
+        else:
+            tot1 = _last_per_cpu_times_2
+            if tot1 is None:
+                # Something bad happened at import time. We'll
+                # get a meaningful result on the next call. See:
+                # https://github.com/giampaolo/psutil/pull/715
+                tot1 = cpu_times(percpu=True)
+        _last_per_cpu_times_2 = cpu_times(percpu=True)
+        for t1, t2 in zip(tot1, _last_per_cpu_times_2):
+            ret.append(calculate(t1, t2))
+        return ret
+
+
+def cpu_stats():
+    """Return CPU statistics."""
+    return _psplatform.cpu_stats()
+
+
+if hasattr(_psplatform, "cpu_freq"):
+
+    def cpu_freq(percpu=False):
+        """Return CPU frequency as a nameduple including current,
+        min and max frequency expressed in Mhz.
+
+        If *percpu* is True and the system supports per-cpu frequency
+        retrieval (Linux only) a list of frequencies is returned for
+        each CPU. If not a list with one element is returned.
+        """
+        ret = _psplatform.cpu_freq()
+        if percpu:
+            return ret
+        else:
+            num_cpus = float(len(ret))
+            if num_cpus == 0:
+                return None
+            elif num_cpus == 1:
+                return ret[0]
+            else:
+                currs, mins, maxs = 0.0, 0.0, 0.0
+                for cpu in ret:
+                    currs += cpu.current
+                    mins += cpu.min
+                    maxs += cpu.max
+                current = currs / num_cpus
+                min_ = mins / num_cpus
+                max_ = maxs / num_cpus
+                return _common.scpufreq(current, min_, max_)
+
+    __all__.append("cpu_freq")
+
+
+# =====================================================================
+# --- system memory related functions
+# =====================================================================
+
+
+def virtual_memory():
+    """Return statistics about system memory usage as a namedtuple
+    including the following fields, expressed in bytes:
+
+     - total:
+       total physical memory available.
+
+     - available:
+       the memory that can be given instantly to processes without the
+       system going into swap.
+       This is calculated by summing different memory values depending
+       on the platform and it is supposed to be used to monitor actual
+       memory usage in a cross platform fashion.
+
+     - percent:
+       the percentage usage calculated as (total - available) / total * 100
+
+     - used:
+        memory used, calculated differently depending on the platform and
+        designed for informational purposes only:
+        OSX: active + inactive + wired
+        BSD: active + wired + cached
+        LINUX: total - free
+
+     - free:
+       memory not being used at all (zeroed) that is readily available;
+       note that this doesn't reflect the actual memory available
+       (use 'available' instead)
+
+    Platform-specific fields:
+
+     - active (UNIX):
+       memory currently in use or very recently used, and so it is in RAM.
+
+     - inactive (UNIX):
+       memory that is marked as not used.
+
+     - buffers (BSD, Linux):
+       cache for things like file system metadata.
+
+     - cached (BSD, OSX):
+       cache for various things.
+
+     - wired (OSX, BSD):
+       memory that is marked to always stay in RAM. It is never moved to disk.
+
+     - shared (BSD):
+       memory that may be simultaneously accessed by multiple processes.
+
+    The sum of 'used' and 'available' does not necessarily equal total.
+    On Windows 'available' and 'free' are the same.
+    """
+    global _TOTAL_PHYMEM
+    ret = _psplatform.virtual_memory()
+    # cached for later use in Process.memory_percent()
+    _TOTAL_PHYMEM = ret.total
+    return ret
+
+
+def swap_memory():
+    """Return system swap memory statistics as a namedtuple including
+    the following fields:
+
+     - total:   total swap memory in bytes
+     - used:    used swap memory in bytes
+     - free:    free swap memory in bytes
+     - percent: the percentage usage
+     - sin:     no. of bytes the system has swapped in from disk (cumulative)
+     - sout:    no. of bytes the system has swapped out from disk (cumulative)
+
+    'sin' and 'sout' on Windows are meaningless and always set to 0.
+    """
+    return _psplatform.swap_memory()
+
+
+# =====================================================================
+# --- disks/paritions related functions
+# =====================================================================
+
+
+def disk_usage(path):
+    """Return disk usage statistics about the given *path* as a
+    namedtuple including total, used and free space expressed in bytes
+    plus the percentage usage.
+    """
+    return _psplatform.disk_usage(path)
+
+
+def disk_partitions(all=False):
+    """Return mounted partitions as a list of
+    (device, mountpoint, fstype, opts) namedtuple.
+    'opts' field is a raw string separated by commas indicating mount
+    options which may vary depending on the platform.
+
+    If *all* parameter is False return physical devices only and ignore
+    all others.
+    """
+    return _psplatform.disk_partitions(all)
+
+
+def disk_io_counters(perdisk=False, nowrap=True):
+    """Return system disk I/O statistics as a namedtuple including
+    the following fields:
+
+     - read_count:  number of reads
+     - write_count: number of writes
+     - read_bytes:  number of bytes read
+     - write_bytes: number of bytes written
+     - read_time:   time spent reading from disk (in ms)
+     - write_time:  time spent writing to disk (in ms)
+
+    Platform specific:
+
+     - busy_time: (Linux, FreeBSD) time spent doing actual I/Os (in ms)
+     - read_merged_count (Linux): number of merged reads
+     - write_merged_count (Linux): number of merged writes
+
+    If *perdisk* is True return the same information for every
+    physical disk installed on the system as a dictionary
+    with partition names as the keys and the namedtuple
+    described above as the values.
+
+    If *nowrap* is True it detects and adjust the numbers which overflow
+    and wrap (restart from 0) and add "old value" to "new value" so that
+    the returned numbers will always be increasing or remain the same,
+    but never decrease.
+    "disk_io_counters.cache_clear()" can be used to invalidate the
+    cache.
+
+    On recent Windows versions 'diskperf -y' command may need to be
+    executed first otherwise this function won't find any disk.
+    """
+    rawdict = _psplatform.disk_io_counters()
+    if not rawdict:
+        return {} if perdisk else None
+    if nowrap:
+        rawdict = _wrap_numbers(rawdict, 'psutil.disk_io_counters')
+    nt = getattr(_psplatform, "sdiskio", _common.sdiskio)
+    if perdisk:
+        for disk, fields in rawdict.items():
+            rawdict[disk] = nt(*fields)
+        return rawdict
+    else:
+        return nt(*[sum(x) for x in zip(*rawdict.values())])
+
+
+disk_io_counters.cache_clear = functools.partial(
+    _wrap_numbers.cache_clear, 'psutil.disk_io_counters')
+disk_io_counters.cache_clear.__doc__ = "Clears nowrap argument cache"
+
+
+# =====================================================================
+# --- network related functions
+# =====================================================================
+
+
+def net_io_counters(pernic=False, nowrap=True):
+    """Return network I/O statistics as a namedtuple including
+    the following fields:
+
+     - bytes_sent:   number of bytes sent
+     - bytes_recv:   number of bytes received
+     - packets_sent: number of packets sent
+     - packets_recv: number of packets received
+     - errin:        total number of errors while receiving
+     - errout:       total number of errors while sending
+     - dropin:       total number of incoming packets which were dropped
+     - dropout:      total number of outgoing packets which were dropped
+                     (always 0 on OSX and BSD)
+
+    If *pernic* is True return the same information for every
+    network interface installed on the system as a dictionary
+    with network interface names as the keys and the namedtuple
+    described above as the values.
+
+    If *nowrap* is True it detects and adjust the numbers which overflow
+    and wrap (restart from 0) and add "old value" to "new value" so that
+    the returned numbers will always be increasing or remain the same,
+    but never decrease.
+    "disk_io_counters.cache_clear()" can be used to invalidate the
+    cache.
+    """
+    rawdict = _psplatform.net_io_counters()
+    if not rawdict:
+        return {} if pernic else None
+    if nowrap:
+        rawdict = _wrap_numbers(rawdict, 'psutil.net_io_counters')
+    if pernic:
+        for nic, fields in rawdict.items():
+            rawdict[nic] = _common.snetio(*fields)
+        return rawdict
+    else:
+        return _common.snetio(*[sum(x) for x in zip(*rawdict.values())])
+
+
+net_io_counters.cache_clear = functools.partial(
+    _wrap_numbers.cache_clear, 'psutil.net_io_counters')
+net_io_counters.cache_clear.__doc__ = "Clears nowrap argument cache"
+
+
+def net_connections(kind='inet'):
+    """Return system-wide socket connections as a list of
+    (fd, family, type, laddr, raddr, status, pid) namedtuples.
+    In case of limited privileges 'fd' and 'pid' may be set to -1
+    and None respectively.
+    The *kind* parameter filters for connections that fit the
+    following criteria:
+
+    +------------+----------------------------------------------------+
+    | Kind Value | Connections using                                  |
+    +------------+----------------------------------------------------+
+    | inet       | IPv4 and IPv6                                      |
+    | inet4      | IPv4                                               |
+    | inet6      | IPv6                                               |
+    | tcp        | TCP                                                |
+    | tcp4       | TCP over IPv4                                      |
+    | tcp6       | TCP over IPv6                                      |
+    | udp        | UDP                                                |
+    | udp4       | UDP over IPv4                                      |
+    | udp6       | UDP over IPv6                                      |
+    | unix       | UNIX socket (both UDP and TCP protocols)           |
+    | all        | the sum of all the possible families and protocols |
+    +------------+----------------------------------------------------+
+
+    On OSX this function requires root privileges.
+    """
+    return _psplatform.net_connections(kind)
+
+
+def net_if_addrs():
+    """Return the addresses associated to each NIC (network interface
+    card) installed on the system as a dictionary whose keys are the
+    NIC names and value is a list of namedtuples for each address
+    assigned to the NIC. Each namedtuple includes 5 fields:
+
+     - family: can be either socket.AF_INET, socket.AF_INET6 or
+               psutil.AF_LINK, which refers to a MAC address.
+     - address: is the primary address and it is always set.
+     - netmask: and 'broadcast' and 'ptp' may be None.
+     - ptp: stands for "point to point" and references the
+            destination address on a point to point interface
+            (typically a VPN).
+     - broadcast: and *ptp* are mutually exclusive.
+
+    Note: you can have more than one address of the same family
+    associated with each interface.
+    """
+    has_enums = sys.version_info >= (3, 4)
+    if has_enums:
+        import socket
+    rawlist = _psplatform.net_if_addrs()
+    rawlist.sort(key=lambda x: x[1])  # sort by family
+    ret = collections.defaultdict(list)
+    for name, fam, addr, mask, broadcast, ptp in rawlist:
+        if has_enums:
+            try:
+                fam = socket.AddressFamily(fam)
+            except ValueError:
+                if WINDOWS and fam == -1:
+                    fam = _psplatform.AF_LINK
+                elif (hasattr(_psplatform, "AF_LINK") and
+                        _psplatform.AF_LINK == fam):
+                    # Linux defines AF_LINK as an alias for AF_PACKET.
+                    # We re-set the family here so that repr(family)
+                    # will show AF_LINK rather than AF_PACKET
+                    fam = _psplatform.AF_LINK
+        if fam == _psplatform.AF_LINK:
+            # The underlying C function may return an incomplete MAC
+            # address in which case we fill it with null bytes, see:
+            # https://github.com/giampaolo/psutil/issues/786
+            separator = ":" if POSIX else "-"
+            while addr.count(separator) < 5:
+                addr += "%s00" % separator
+        ret[name].append(_common.snic(fam, addr, mask, broadcast, ptp))
+    return dict(ret)
+
+
+def net_if_stats():
+    """Return information about each NIC (network interface card)
+    installed on the system as a dictionary whose keys are the
+    NIC names and value is a namedtuple with the following fields:
+
+     - isup: whether the interface is up (bool)
+     - duplex: can be either NIC_DUPLEX_FULL, NIC_DUPLEX_HALF or
+               NIC_DUPLEX_UNKNOWN
+     - speed: the NIC speed expressed in mega bits (MB); if it can't
+              be determined (e.g. 'localhost') it will be set to 0.
+     - mtu: the maximum transmission unit expressed in bytes.
+    """
+    return _psplatform.net_if_stats()
+
+
+# =====================================================================
+# --- sensors
+# =====================================================================
+
+
+# Linux
+if hasattr(_psplatform, "sensors_temperatures"):
+
+    def sensors_temperatures(fahrenheit=False):
+        """Return hardware temperatures. Each entry is a namedtuple
+        representing a certain hardware sensor (it may be a CPU, an
+        hard disk or something else, depending on the OS and its
+        configuration).
+        All temperatures are expressed in celsius unless *fahrenheit*
+        is set to True.
+        """
+        def convert(n):
+            if n is not None:
+                return (float(n) * 9 / 5) + 32 if fahrenheit else n
+
+        ret = collections.defaultdict(list)
+        rawdict = _psplatform.sensors_temperatures()
+
+        for name, values in rawdict.items():
+            while values:
+                label, current, high, critical = values.pop(0)
+                current = convert(current)
+                high = convert(high)
+                critical = convert(critical)
+
+                if high and not critical:
+                    critical = high
+                elif critical and not high:
+                    high = critical
+
+                ret[name].append(
+                    _common.shwtemp(label, current, high, critical))
+
+        return dict(ret)
+
+    __all__.append("sensors_temperatures")
+
+
+# Linux
+if hasattr(_psplatform, "sensors_fans"):
+
+    def sensors_fans():
+        """Return fans speed. Each entry is a namedtuple
+        representing a certain hardware sensor.
+        All speed are expressed in RPM (rounds per minute).
+        """
+        return _psplatform.sensors_fans()
+
+    __all__.append("sensors_fans")
+
+
+# Linux, Windows, FreeBSD, OSX
+if hasattr(_psplatform, "sensors_battery"):
+
+    def sensors_battery():
+        """Return battery information. If no battery is installed
+        returns None.
+
+         - percent: battery power left as a percentage.
+         - secsleft: a rough approximation of how many seconds are left
+                     before the battery runs out of power. May be
+                     POWER_TIME_UNLIMITED or POWER_TIME_UNLIMITED.
+         - power_plugged: True if the AC power cable is connected.
+        """
+        return _psplatform.sensors_battery()
+
+    __all__.append("sensors_battery")
+
+
+# =====================================================================
+# --- other system related functions
+# =====================================================================
+
+
+def boot_time():
+    """Return the system boot time expressed in seconds since the epoch."""
+    # Note: we are not caching this because it is subject to
+    # system clock updates.
+    return _psplatform.boot_time()
+
+
+def users():
+    """Return users currently connected on the system as a list of
+    namedtuples including the following fields.
+
+     - user: the name of the user
+     - terminal: the tty or pseudo-tty associated with the user, if any.
+     - host: the host name associated with the entry, if any.
+     - started: the creation time as a floating point number expressed in
+       seconds since the epoch.
+    """
+    return _psplatform.users()
+
+
+# =====================================================================
+# --- Windows services
+# =====================================================================
+
+
+if WINDOWS:
+
+    def win_service_iter():
+        """Return a generator yielding a WindowsService instance for all
+        Windows services installed.
+        """
+        return _psplatform.win_service_iter()
+
+    def win_service_get(name):
+        """Get a Windows service by *name*.
+        Raise NoSuchProcess if no service with such name exists.
+        """
+        return _psplatform.win_service_get(name)
+
+
+# =====================================================================
+
+
+def test():  # pragma: no cover
+    """List info of all currently running processes emulating ps aux
+    output.
+    """
+    today_day = datetime.date.today()
+    templ = "%-10s %5s %4s %7s %7s %-13s %5s %7s  %s"
+    attrs = ['pid', 'memory_percent', 'name', 'cpu_times', 'create_time',
+             'memory_info']
+    if POSIX:
+        attrs.append('uids')
+        attrs.append('terminal')
+    print(templ % ("USER", "PID", "%MEM", "VSZ", "RSS", "TTY", "START", "TIME",
+                   "COMMAND"))
+    for p in process_iter(attrs=attrs, ad_value=''):
+        if p.info['create_time']:
+            ctime = datetime.datetime.fromtimestamp(p.info['create_time'])
+            if ctime.date() == today_day:
+                ctime = ctime.strftime("%H:%M")
+            else:
+                ctime = ctime.strftime("%b%d")
+        else:
+            ctime = ''
+        cputime = time.strftime("%M:%S",
+                                time.localtime(sum(p.info['cpu_times'])))
+        try:
+            user = p.username()
+        except Error:
+            user = ''
+        if WINDOWS and '\\' in user:
+            user = user.split('\\')[1]
+        vms = p.info['memory_info'] and \
+            int(p.info['memory_info'].vms / 1024) or '?'
+        rss = p.info['memory_info'] and \
+            int(p.info['memory_info'].rss / 1024) or '?'
+        memp = p.info['memory_percent'] and \
+            round(p.info['memory_percent'], 1) or '?'
+        print(templ % (
+            user[:10],
+            p.info['pid'],
+            memp,
+            vms,
+            rss,
+            p.info.get('terminal', '') or '?',
+            ctime,
+            cputime,
+            p.info['name'].strip() or '?'))
+
+
+del memoize, memoize_when_activated, division, deprecated_method
+if sys.version_info[0] < 3:
+    del num, x
+
+if __name__ == "__main__":
+    test()
new file mode 100644
--- /dev/null
+++ b/third_party/python/psutil-cp27-none-win_amd64/psutil/_common.py
@@ -0,0 +1,575 @@
+# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Common objects shared by __init__.py and _ps*.py modules."""
+
+# Note: this module is imported by setup.py so it should not import
+# psutil or third-party modules.
+
+from __future__ import division
+
+import contextlib
+import errno
+import functools
+import os
+import socket
+import stat
+import sys
+import threading
+import warnings
+from collections import defaultdict
+from collections import namedtuple
+from socket import AF_INET
+from socket import SOCK_DGRAM
+from socket import SOCK_STREAM
+try:
+    from socket import AF_INET6
+except ImportError:
+    AF_INET6 = None
+try:
+    from socket import AF_UNIX
+except ImportError:
+    AF_UNIX = None
+
+if sys.version_info >= (3, 4):
+    import enum
+else:
+    enum = None
+
+# can't take it from _common.py as this script is imported by setup.py
+PY3 = sys.version_info[0] == 3
+
+__all__ = [
+    # constants
+    'FREEBSD', 'BSD', 'LINUX', 'NETBSD', 'OPENBSD', 'OSX', 'POSIX', 'SUNOS',
+    'WINDOWS',
+    'ENCODING', 'ENCODING_ERRS', 'AF_INET6',
+    # connection constants
+    'CONN_CLOSE', 'CONN_CLOSE_WAIT', 'CONN_CLOSING', 'CONN_ESTABLISHED',
+    'CONN_FIN_WAIT1', 'CONN_FIN_WAIT2', 'CONN_LAST_ACK', 'CONN_LISTEN',
+    'CONN_NONE', 'CONN_SYN_RECV', 'CONN_SYN_SENT', 'CONN_TIME_WAIT',
+    # net constants
+    'NIC_DUPLEX_FULL', 'NIC_DUPLEX_HALF', 'NIC_DUPLEX_UNKNOWN',
+    # process status constants
+    'STATUS_DEAD', 'STATUS_DISK_SLEEP', 'STATUS_IDLE', 'STATUS_LOCKED',
+    'STATUS_RUNNING', 'STATUS_SLEEPING', 'STATUS_STOPPED', 'STATUS_SUSPENDED',
+    'STATUS_TRACING_STOP', 'STATUS_WAITING', 'STATUS_WAKE_KILL',
+    'STATUS_WAKING', 'STATUS_ZOMBIE',
+    # named tuples
+    'pconn', 'pcputimes', 'pctxsw', 'pgids', 'pio', 'pionice', 'popenfile',
+    'pthread', 'puids', 'sconn', 'scpustats', 'sdiskio', 'sdiskpart',
+    'sdiskusage', 'snetio', 'snic', 'snicstats', 'sswap', 'suser',
+    # utility functions
+    'conn_tmap', 'deprecated_method', 'isfile_strict', 'memoize',
+    'parse_environ_block', 'path_exists_strict', 'usage_percent',
+    'supports_ipv6', 'sockfam_to_enum', 'socktype_to_enum', "wrap_numbers",
+]
+
+
+# ===================================================================
+# --- OS constants
+# ===================================================================
+
+
+POSIX = os.name == "posix"
+WINDOWS = os.name == "nt"
+LINUX = sys.platform.startswith("linux")
+OSX = sys.platform.startswith("darwin")
+FREEBSD = sys.platform.startswith("freebsd")
+OPENBSD = sys.platform.startswith("openbsd")
+NETBSD = sys.platform.startswith("netbsd")
+BSD = FREEBSD or OPENBSD or NETBSD
+SUNOS = sys.platform.startswith("sunos") or sys.platform.startswith("solaris")
+AIX = sys.platform.startswith("aix")
+
+
+# ===================================================================
+# --- API constants
+# ===================================================================
+
+
+# Process.status()
+STATUS_RUNNING = "running"
+STATUS_SLEEPING = "sleeping"
+STATUS_DISK_SLEEP = "disk-sleep"
+STATUS_STOPPED = "stopped"
+STATUS_TRACING_STOP = "tracing-stop"
+STATUS_ZOMBIE = "zombie"
+STATUS_DEAD = "dead"
+STATUS_WAKE_KILL = "wake-kill"
+STATUS_WAKING = "waking"
+STATUS_IDLE = "idle"  # FreeBSD, OSX
+STATUS_LOCKED = "locked"  # FreeBSD
+STATUS_WAITING = "waiting"  # FreeBSD
+STATUS_SUSPENDED = "suspended"  # NetBSD
+
+# Process.connections() and psutil.net_connections()
+CONN_ESTABLISHED = "ESTABLISHED"
+CONN_SYN_SENT = "SYN_SENT"
+CONN_SYN_RECV = "SYN_RECV"
+CONN_FIN_WAIT1 = "FIN_WAIT1"
+CONN_FIN_WAIT2 = "FIN_WAIT2"
+CONN_TIME_WAIT = "TIME_WAIT"
+CONN_CLOSE = "CLOSE"
+CONN_CLOSE_WAIT = "CLOSE_WAIT"
+CONN_LAST_ACK = "LAST_ACK"
+CONN_LISTEN = "LISTEN"
+CONN_CLOSING = "CLOSING"
+CONN_NONE = "NONE"
+
+# net_if_stats()
+if enum is None:
+    NIC_DUPLEX_FULL = 2
+    NIC_DUPLEX_HALF = 1
+    NIC_DUPLEX_UNKNOWN = 0
+else:
+    class NicDuplex(enum.IntEnum):
+        NIC_DUPLEX_FULL = 2
+        NIC_DUPLEX_HALF = 1
+        NIC_DUPLEX_UNKNOWN = 0
+
+    globals().update(NicDuplex.__members__)
+
+# sensors_battery()
+if enum is None:
+    POWER_TIME_UNKNOWN = -1
+    POWER_TIME_UNLIMITED = -2
+else:
+    class BatteryTime(enum.IntEnum):
+        POWER_TIME_UNKNOWN = -1
+        POWER_TIME_UNLIMITED = -2
+
+    globals().update(BatteryTime.__members__)
+
+# --- others
+
+ENCODING = sys.getfilesystemencoding()
+if not PY3:
+    ENCODING_ERRS = "replace"
+else:
+    try:
+        ENCODING_ERRS = sys.getfilesystemencodeerrors()  # py 3.6
+    except AttributeError:
+        ENCODING_ERRS = "surrogateescape" if POSIX else "replace"
+
+
+# ===================================================================
+# --- namedtuples
+# ===================================================================
+
+# --- for system functions
+
+# psutil.swap_memory()
+sswap = namedtuple('sswap', ['total', 'used', 'free', 'percent', 'sin',
+                             'sout'])
+# psutil.disk_usage()
+sdiskusage = namedtuple('sdiskusage', ['total', 'used', 'free', 'percent'])
+# psutil.disk_io_counters()
+sdiskio = namedtuple('sdiskio', ['read_count', 'write_count',
+                                 'read_bytes', 'write_bytes',
+                                 'read_time', 'write_time'])
+# psutil.disk_partitions()
+sdiskpart = namedtuple('sdiskpart', ['device', 'mountpoint', 'fstype', 'opts'])
+# psutil.net_io_counters()
+snetio = namedtuple('snetio', ['bytes_sent', 'bytes_recv',
+                               'packets_sent', 'packets_recv',
+                               'errin', 'errout',
+                               'dropin', 'dropout'])
+# psutil.users()
+suser = namedtuple('suser', ['name', 'terminal', 'host', 'started', 'pid'])
+# psutil.net_connections()
+sconn = namedtuple('sconn', ['fd', 'family', 'type', 'laddr', 'raddr',
+                             'status', 'pid'])
+# psutil.net_if_addrs()
+snic = namedtuple('snic', ['family', 'address', 'netmask', 'broadcast', 'ptp'])
+# psutil.net_if_stats()
+snicstats = namedtuple('snicstats', ['isup', 'duplex', 'speed', 'mtu'])
+# psutil.cpu_stats()
+scpustats = namedtuple(
+    'scpustats', ['ctx_switches', 'interrupts', 'soft_interrupts', 'syscalls'])
+# psutil.cpu_freq()
+scpufreq = namedtuple('scpufreq', ['current', 'min', 'max'])
+# psutil.sensors_temperatures()
+shwtemp = namedtuple(
+    'shwtemp', ['label', 'current', 'high', 'critical'])
+# psutil.sensors_battery()
+sbattery = namedtuple('sbattery', ['percent', 'secsleft', 'power_plugged'])
+# psutil.sensors_battery()
+sfan = namedtuple('sfan', ['label', 'current'])
+
+# --- for Process methods
+
+# psutil.Process.cpu_times()
+pcputimes = namedtuple('pcputimes',
+                       ['user', 'system', 'children_user', 'children_system'])
+# psutil.Process.open_files()
+popenfile = namedtuple('popenfile', ['path', 'fd'])
+# psutil.Process.threads()
+pthread = namedtuple('pthread', ['id', 'user_time', 'system_time'])
+# psutil.Process.uids()
+puids = namedtuple('puids', ['real', 'effective', 'saved'])
+# psutil.Process.gids()
+pgids = namedtuple('pgids', ['real', 'effective', 'saved'])
+# psutil.Process.io_counters()
+pio = namedtuple('pio', ['read_count', 'write_count',
+                         'read_bytes', 'write_bytes'])
+# psutil.Process.ionice()
+pionice = namedtuple('pionice', ['ioclass', 'value'])
+# psutil.Process.ctx_switches()
+pctxsw = namedtuple('pctxsw', ['voluntary', 'involuntary'])
+# psutil.Process.connections()
+pconn = namedtuple('pconn', ['fd', 'family', 'type', 'laddr', 'raddr',
+                             'status'])
+
+# psutil.connections() and psutil.Process.connections()
+addr = namedtuple('addr', ['ip', 'port'])
+
+
+# ===================================================================
+# --- Process.connections() 'kind' parameter mapping
+# ===================================================================
+
+
+conn_tmap = {
+    "all": ([AF_INET, AF_INET6, AF_UNIX], [SOCK_STREAM, SOCK_DGRAM]),
+    "tcp": ([AF_INET, AF_INET6], [SOCK_STREAM]),
+    "tcp4": ([AF_INET], [SOCK_STREAM]),
+    "udp": ([AF_INET, AF_INET6], [SOCK_DGRAM]),
+    "udp4": ([AF_INET], [SOCK_DGRAM]),
+    "inet": ([AF_INET, AF_INET6], [SOCK_STREAM, SOCK_DGRAM]),
+    "inet4": ([AF_INET], [SOCK_STREAM, SOCK_DGRAM]),
+    "inet6": ([AF_INET6], [SOCK_STREAM, SOCK_DGRAM]),
+}
+
+if AF_INET6 is not None:
+    conn_tmap.update({
+        "tcp6": ([AF_INET6], [SOCK_STREAM]),
+        "udp6": ([AF_INET6], [SOCK_DGRAM]),
+    })
+
+if AF_UNIX is not None:
+    conn_tmap.update({
+        "unix": ([AF_UNIX], [SOCK_STREAM, SOCK_DGRAM]),
+    })
+
+del AF_INET, AF_UNIX, SOCK_STREAM, SOCK_DGRAM
+
+
+# ===================================================================
+# --- utils
+# ===================================================================
+
+
+def usage_percent(used, total, _round=None):
+    """Calculate percentage usage of 'used' against 'total'."""
+    try:
+        ret = (used / total) * 100
+    except ZeroDivisionError:
+        ret = 0.0 if isinstance(used, float) or isinstance(total, float) else 0
+    if _round is not None:
+        return round(ret, _round)
+    else:
+        return ret
+
+
+def memoize(fun):
+    """A simple memoize decorator for functions supporting (hashable)
+    positional arguments.
+    It also provides a cache_clear() function for clearing the cache:
+
+    >>> @memoize
+    ... def foo()
+    ...     return 1
+        ...
+    >>> foo()
+    1
+    >>> foo.cache_clear()
+    >>>
+    """
+    @functools.wraps(fun)
+    def wrapper(*args, **kwargs):
+        key = (args, frozenset(sorted(kwargs.items())))
+        try:
+            return cache[key]
+        except KeyError:
+            ret = cache[key] = fun(*args, **kwargs)
+            return ret
+
+    def cache_clear():
+        """Clear cache."""
+        cache.clear()
+
+    cache = {}
+    wrapper.cache_clear = cache_clear
+    return wrapper
+
+
+def memoize_when_activated(fun):
+    """A memoize decorator which is disabled by default. It can be
+    activated and deactivated on request.
+    For efficiency reasons it can be used only against class methods
+    accepting no arguments.
+
+    >>> class Foo:
+    ...     @memoize
+    ...     def foo()
+    ...         print(1)
+    ...
+    >>> f = Foo()
+    >>> # deactivated (default)
+    >>> foo()
+    1
+    >>> foo()
+    1
+    >>>
+    >>> # activated
+    >>> foo.cache_activate()
+    >>> foo()
+    1
+    >>> foo()
+    >>> foo()
+    >>>
+    """
+    @functools.wraps(fun)
+    def wrapper(self):
+        if not wrapper.cache_activated:
+            return fun(self)
+        else:
+            try:
+                ret = cache[fun]
+            except KeyError:
+                ret = cache[fun] = fun(self)
+            return ret
+
+    def cache_activate():
+        """Activate cache."""
+        wrapper.cache_activated = True
+
+    def cache_deactivate():
+        """Deactivate and clear cache."""
+        wrapper.cache_activated = False
+        cache.clear()
+
+    cache = {}
+    wrapper.cache_activated = False
+    wrapper.cache_activate = cache_activate
+    wrapper.cache_deactivate = cache_deactivate
+    return wrapper
+
+
+def isfile_strict(path):
+    """Same as os.path.isfile() but does not swallow EACCES / EPERM
+    exceptions, see:
+    http://mail.python.org/pipermail/python-dev/2012-June/120787.html
+    """
+    try:
+        st = os.stat(path)
+    except OSError as err:
+        if err.errno in (errno.EPERM, errno.EACCES):
+            raise
+        return False
+    else:
+        return stat.S_ISREG(st.st_mode)
+
+
+def path_exists_strict(path):
+    """Same as os.path.exists() but does not swallow EACCES / EPERM
+    exceptions, see:
+    http://mail.python.org/pipermail/python-dev/2012-June/120787.html
+    """
+    try:
+        os.stat(path)
+    except OSError as err:
+        if err.errno in (errno.EPERM, errno.EACCES):
+            raise
+        return False
+    else:
+        return True
+
+
+@memoize
+def supports_ipv6():
+    """Return True if IPv6 is supported on this platform."""
+    if not socket.has_ipv6 or AF_INET6 is None:
+        return False
+    try:
+        sock = socket.socket(AF_INET6, socket.SOCK_STREAM)
+        with contextlib.closing(sock):
+            sock.bind(("::1", 0))
+        return True
+    except socket.error:
+        return False
+
+
+def parse_environ_block(data):
+    """Parse a C environ block of environment variables into a dictionary."""
+    # The block is usually raw data from the target process.  It might contain
+    # trailing garbage and lines that do not look like assignments.
+    ret = {}
+    pos = 0
+
+    # localize global variable to speed up access.
+    WINDOWS_ = WINDOWS
+    while True:
+        next_pos = data.find("\0", pos)
+        # nul byte at the beginning or double nul byte means finish
+        if next_pos <= pos:
+            break
+        # there might not be an equals sign
+        equal_pos = data.find("=", pos, next_pos)
+        if equal_pos > pos:
+            key = data[pos:equal_pos]
+            value = data[equal_pos + 1:next_pos]
+            # Windows expects environment variables to be uppercase only
+            if WINDOWS_:
+                key = key.upper()
+            ret[key] = value
+        pos = next_pos + 1
+
+    return ret
+
+
+def sockfam_to_enum(num):
+    """Convert a numeric socket family value to an IntEnum member.
+    If it's not a known member, return the numeric value itself.
+    """
+    if enum is None:
+        return num
+    else:  # pragma: no cover
+        try:
+            return socket.AddressFamily(num)
+        except (ValueError, AttributeError):
+            return num
+
+
+def socktype_to_enum(num):
+    """Convert a numeric socket type value to an IntEnum member.
+    If it's not a known member, return the numeric value itself.
+    """
+    if enum is None:
+        return num
+    else:  # pragma: no cover
+        try:
+            return socket.AddressType(num)
+        except (ValueError, AttributeError):
+            return num
+
+
+def deprecated_method(replacement):
+    """A decorator which can be used to mark a method as deprecated
+    'replcement' is the method name which will be called instead.
+    """
+    def outer(fun):
+        msg = "%s() is deprecated and will be removed; use %s() instead" % (
+            fun.__name__, replacement)
+        if fun.__doc__ is None:
+            fun.__doc__ = msg
+
+        @functools.wraps(fun)
+        def inner(self, *args, **kwargs):
+            warnings.warn(msg, category=FutureWarning, stacklevel=2)
+            return getattr(self, replacement)(*args, **kwargs)
+        return inner
+    return outer
+
+
+class _WrapNumbers:
+    """Watches numbers so that they don't overflow and wrap
+    (reset to zero).
+    """
+
+    def __init__(self):
+        self.lock = threading.Lock()
+        self.cache = {}
+        self.reminders = {}
+        self.reminder_keys = {}
+
+    def _add_dict(self, input_dict, name):
+        assert name not in self.cache
+        assert name not in self.reminders
+        assert name not in self.reminder_keys
+        self.cache[name] = input_dict
+        self.reminders[name] = defaultdict(int)
+        self.reminder_keys[name] = defaultdict(set)
+
+    def _remove_dead_reminders(self, input_dict, name):
+        """In case the number of keys changed between calls (e.g. a
+        disk disappears) this removes the entry from self.reminders.
+        """
+        old_dict = self.cache[name]
+        gone_keys = set(old_dict.keys()) - set(input_dict.keys())
+        for gone_key in gone_keys:
+            for remkey in self.reminder_keys[name][gone_key]:
+                del self.reminders[name][remkey]
+            del self.reminder_keys[name][gone_key]
+
+    def run(self, input_dict, name):
+        """Cache dict and sum numbers which overflow and wrap.
+        Return an updated copy of `input_dict`
+        """
+        if name not in self.cache:
+            # This was the first call.
+            self._add_dict(input_dict, name)
+            return input_dict
+
+        self._remove_dead_reminders(input_dict, name)
+
+        old_dict = self.cache[name]
+        new_dict = {}
+        for key in input_dict.keys():
+            input_tuple = input_dict[key]
+            try:
+                old_tuple = old_dict[key]
+            except KeyError:
+                # The input dict has a new key (e.g. a new disk or NIC)
+                # which didn't exist in the previous call.
+                new_dict[key] = input_tuple
+                continue
+
+            bits = []
+            for i in range(len(input_tuple)):
+                input_value = input_tuple[i]
+                old_value = old_tuple[i]
+                remkey = (key, i)
+                if input_value < old_value:
+                    # it wrapped!
+                    self.reminders[name][remkey] += old_value
+                    self.reminder_keys[name][key].add(remkey)
+                bits.append(input_value + self.reminders[name][remkey])
+
+            new_dict[key] = tuple(bits)
+
+        self.cache[name] = input_dict
+        return new_dict
+
+    def cache_clear(self, name=None):
+        """Clear the internal cache, optionally only for function 'name'."""
+        with self.lock:
+            if name is None:
+                self.cache.clear()
+                self.reminders.clear()
+                self.reminder_keys.clear()
+            else:
+                self.cache.pop(name, None)
+                self.reminders.pop(name, None)
+                self.reminder_keys.pop(name, None)
+
+    def cache_info(self):
+        """Return internal cache dicts as a tuple of 3 elements."""
+        with self.lock:
+            return (self.cache, self.reminders, self.reminder_keys)
+
+
+def wrap_numbers(input_dict, name):
+    """Given an `input_dict` and a function `name`, adjust the numbers
+    which "wrap" (restart from zero) across different calls by adding
+    "old value" to "new value" and return an updated dict.
+    """
+    with _wn.lock:
+        return _wn.run(input_dict, name)
+
+
+_wn = _WrapNumbers()
+wrap_numbers.cache_clear = _wn.cache_clear
+wrap_numbers.cache_info = _wn.cache_info
new file mode 100644
--- /dev/null
+++ b/third_party/python/psutil-cp27-none-win_amd64/psutil/_compat.py
@@ -0,0 +1,249 @@
+# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Module which provides compatibility with older Python versions."""
+
+import collections
+import functools
+import os
+import sys
+
+__all__ = ["PY3", "long", "xrange", "unicode", "basestring", "u", "b",
+           "callable", "lru_cache", "which"]
+
+PY3 = sys.version_info[0] == 3
+
+if PY3:
+    long = int
+    xrange = range
+    unicode = str
+    basestring = str
+
+    def u(s):
+        return s
+
+    def b(s):
+        return s.encode("latin-1")
+else:
+    long = long
+    xrange = xrange
+    unicode = unicode
+    basestring = basestring
+
+    def u(s):
+        return unicode(s, "unicode_escape")
+
+    def b(s):
+        return s
+
+
+# removed in 3.0, reintroduced in 3.2
+try:
+    callable = callable
+except NameError:
+    def callable(obj):
+        return any("__call__" in klass.__dict__ for klass in type(obj).__mro__)
+
+
+# --- stdlib additions
+
+
+# py 3.2 functools.lru_cache
+# Taken from: http://code.activestate.com/recipes/578078
+# Credit: Raymond Hettinger
+try:
+    from functools import lru_cache
+except ImportError:
+    try:
+        from threading import RLock
+    except ImportError:
+        from dummy_threading import RLock
+
+    _CacheInfo = collections.namedtuple(
+        "CacheInfo", ["hits", "misses", "maxsize", "currsize"])
+
+    class _HashedSeq(list):
+        __slots__ = 'hashvalue'
+
+        def __init__(self, tup, hash=hash):
+            self[:] = tup
+            self.hashvalue = hash(tup)
+
+        def __hash__(self):
+            return self.hashvalue
+
+    def _make_key(args, kwds, typed,
+                  kwd_mark=(object(), ),
+                  fasttypes=set((int, str, frozenset, type(None))),
+                  sorted=sorted, tuple=tuple, type=type, len=len):
+        key = args
+        if kwds:
+            sorted_items = sorted(kwds.items())
+            key += kwd_mark
+            for item in sorted_items:
+                key += item
+        if typed:
+            key += tuple(type(v) for v in args)
+            if kwds:
+                key += tuple(type(v) for k, v in sorted_items)
+        elif len(key) == 1 and type(key[0]) in fasttypes:
+            return key[0]
+        return _HashedSeq(key)
+
+    def lru_cache(maxsize=100, typed=False):
+        """Least-recently-used cache decorator, see:
+        http://docs.python.org/3/library/functools.html#functools.lru_cache
+        """
+        def decorating_function(user_function):
+            cache = dict()
+            stats = [0, 0]
+            HITS, MISSES = 0, 1
+            make_key = _make_key
+            cache_get = cache.get
+            _len = len
+            lock = RLock()
+            root = []
+            root[:] = [root, root, None, None]
+            nonlocal_root = [root]
+            PREV, NEXT, KEY, RESULT = 0, 1, 2, 3
+            if maxsize == 0:
+                def wrapper(*args, **kwds):
+                    result = user_function(*args, **kwds)
+                    stats[MISSES] += 1
+                    return result
+            elif maxsize is None:
+                def wrapper(*args, **kwds):
+                    key = make_key(args, kwds, typed)
+                    result = cache_get(key, root)
+                    if result is not root:
+                        stats[HITS] += 1
+                        return result
+                    result = user_function(*args, **kwds)
+                    cache[key] = result
+                    stats[MISSES] += 1
+                    return result
+            else:
+                def wrapper(*args, **kwds):
+                    if kwds or typed:
+                        key = make_key(args, kwds, typed)
+                    else:
+                        key = args
+                    lock.acquire()
+                    try:
+                        link = cache_get(key)
+                        if link is not None:
+                            root, = nonlocal_root
+                            link_prev, link_next, key, result = link
+                            link_prev[NEXT] = link_next
+                            link_next[PREV] = link_prev
+                            last = root[PREV]
+                            last[NEXT] = root[PREV] = link
+                            link[PREV] = last
+                            link[NEXT] = root
+                            stats[HITS] += 1
+                            return result
+                    finally:
+                        lock.release()
+                    result = user_function(*args, **kwds)
+                    lock.acquire()
+                    try:
+                        root, = nonlocal_root
+                        if key in cache:
+                            pass
+                        elif _len(cache) >= maxsize:
+                            oldroot = root
+                            oldroot[KEY] = key
+                            oldroot[RESULT] = result
+                            root = nonlocal_root[0] = oldroot[NEXT]
+                            oldkey = root[KEY]
+                            root[KEY] = root[RESULT] = None
+                            del cache[oldkey]
+                            cache[key] = oldroot
+                        else:
+                            last = root[PREV]
+                            link = [last, root, key, result]
+                            last[NEXT] = root[PREV] = cache[key] = link
+                        stats[MISSES] += 1
+                    finally:
+                        lock.release()
+                    return result
+
+            def cache_info():
+                """Report cache statistics"""
+                lock.acquire()
+                try:
+                    return _CacheInfo(stats[HITS], stats[MISSES], maxsize,
+                                      len(cache))
+                finally:
+                    lock.release()
+
+            def cache_clear():
+                """Clear the cache and cache statistics"""
+                lock.acquire()
+                try:
+                    cache.clear()
+                    root = nonlocal_root[0]
+                    root[:] = [root, root, None, None]
+                    stats[:] = [0, 0]
+                finally:
+                    lock.release()
+
+            wrapper.__wrapped__ = user_function
+            wrapper.cache_info = cache_info
+            wrapper.cache_clear = cache_clear
+            return functools.update_wrapper(wrapper, user_function)
+
+        return decorating_function
+
+
+# python 3.3
+try:
+    from shutil import which
+except ImportError:
+    def which(cmd, mode=os.F_OK | os.X_OK, path=None):
+        """Given a command, mode, and a PATH string, return the path which
+        conforms to the given mode on the PATH, or None if there is no such
+        file.
+
+        `mode` defaults to os.F_OK | os.X_OK. `path` defaults to the result
+        of os.environ.get("PATH"), or can be overridden with a custom search
+        path.
+        """
+        def _access_check(fn, mode):
+            return (os.path.exists(fn) and os.access(fn, mode) and
+                    not os.path.isdir(fn))
+
+        if os.path.dirname(cmd):
+            if _access_check(cmd, mode):
+                return cmd
+            return None
+
+        if path is None:
+            path = os.environ.get("PATH", os.defpath)
+        if not path:
+            return None
+        path = path.split(os.pathsep)
+
+        if sys.platform == "win32":
+            if os.curdir not in path:
+                path.insert(0, os.curdir)
+
+            pathext = os.environ.get("PATHEXT", "").split(os.pathsep)
+            if any(cmd.lower().endswith(ext.lower()) for ext in pathext):
+                files = [cmd]
+            else:
+                files = [cmd + ext for ext in pathext]
+        else:
+            files = [cmd]
+
+        seen = set()
+        for dir in path:
+            normdir = os.path.normcase(dir)
+            if normdir not in seen:
+                seen.add(normdir)
+                for thefile in files:
+                    name = os.path.join(dir, thefile)
+                    if _access_check(name, mode):
+                        return name
+        return None
new file mode 100644
--- /dev/null
+++ b/third_party/python/psutil-cp27-none-win_amd64/psutil/_exceptions.py
@@ -0,0 +1,94 @@
+# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+
+class Error(Exception):
+    """Base exception class. All other psutil exceptions inherit
+    from this one.
+    """
+
+    def __init__(self, msg=""):
+        Exception.__init__(self, msg)
+        self.msg = msg
+
+    def __repr__(self):
+        ret = "psutil.%s %s" % (self.__class__.__name__, self.msg)
+        return ret.strip()
+
+    __str__ = __repr__
+
+
+class NoSuchProcess(Error):
+    """Exception raised when a process with a certain PID doesn't
+    or no longer exists.
+    """
+
+    def __init__(self, pid, name=None, msg=None):
+        Error.__init__(self, msg)
+        self.pid = pid
+        self.name = name
+        self.msg = msg
+        if msg is None:
+            if name:
+                details = "(pid=%s, name=%s)" % (self.pid, repr(self.name))
+            else:
+                details = "(pid=%s)" % self.pid
+            self.msg = "process no longer exists " + details
+
+
+class ZombieProcess(NoSuchProcess):
+    """Exception raised when querying a zombie process. This is
+    raised on OSX, BSD and Solaris only, and not always: depending
+    on the query the OS may be able to succeed anyway.
+    On Linux all zombie processes are querable (hence this is never
+    raised). Windows doesn't have zombie processes.
+    """
+
+    def __init__(self, pid, name=None, ppid=None, msg=None):
+        NoSuchProcess.__init__(self, msg)
+        self.pid = pid
+        self.ppid = ppid
+        self.name = name
+        self.msg = msg
+        if msg is None:
+            args = ["pid=%s" % pid]
+            if name:
+                args.append("name=%s" % repr(self.name))
+            if ppid:
+                args.append("ppid=%s" % self.ppid)
+            details = "(%s)" % ", ".join(args)
+            self.msg = "process still exists but it's a zombie " + details
+
+
+class AccessDenied(Error):
+    """Exception raised when permission to perform an action is denied."""
+
+    def __init__(self, pid=None, name=None, msg=None):
+        Error.__init__(self, msg)
+        self.pid = pid
+        self.name = name
+        self.msg = msg
+        if msg is None:
+            if (pid is not None) and (name is not None):
+                self.msg = "(pid=%s, name=%s)" % (pid, repr(name))
+            elif (pid is not None):
+                self.msg = "(pid=%s)" % self.pid
+            else:
+                self.msg = ""
+
+
+class TimeoutExpired(Error):
+    """Raised on Process.wait(timeout) if timeout expires and process
+    is still alive.
+    """
+
+    def __init__(self, seconds, pid=None, name=None):
+        Error.__init__(self, "timeout after %s seconds" % seconds)
+        self.seconds = seconds
+        self.pid = pid
+        self.name = name
+        if (pid is not None) and (name is not None):
+            self.msg += " (pid=%s, name=%s)" % (pid, repr(name))
+        elif (pid is not None):
+            self.msg += " (pid=%s)" % self.pid
new file mode 100644
--- /dev/null
+++ b/third_party/python/psutil-cp27-none-win_amd64/psutil/_psaix.py
@@ -0,0 +1,573 @@
+# Copyright (c) 2009, Giampaolo Rodola'
+# Copyright (c) 2017, Arnon Yaari
+# All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""AIX platform implementation."""
+
+import errno
+import glob
+import os
+import re
+import subprocess
+import sys
+from collections import namedtuple
+from socket import AF_INET
+
+from . import _common
+from . import _psposix
+from . import _psutil_aix as cext
+from . import _psutil_posix as cext_posix
+from ._common import AF_INET6
+from ._common import memoize_when_activated
+from ._common import NIC_DUPLEX_FULL
+from ._common import NIC_DUPLEX_HALF
+from ._common import NIC_DUPLEX_UNKNOWN
+from ._common import sockfam_to_enum
+from ._common import socktype_to_enum
+from ._common import usage_percent
+from ._compat import PY3
+from ._exceptions import AccessDenied
+from ._exceptions import NoSuchProcess
+from ._exceptions import ZombieProcess
+
+
+__extra__all__ = ["PROCFS_PATH"]
+
+
+# =====================================================================
+# --- globals
+# =====================================================================
+
+
+HAS_THREADS = hasattr(cext, "proc_threads")
+
+PAGE_SIZE = os.sysconf('SC_PAGE_SIZE')
+AF_LINK = cext_posix.AF_LINK
+
+PROC_STATUSES = {
+    cext.SIDL: _common.STATUS_IDLE,
+    cext.SZOMB: _common.STATUS_ZOMBIE,
+    cext.SACTIVE: _common.STATUS_RUNNING,
+    cext.SSWAP: _common.STATUS_RUNNING,      # TODO what status is this?
+    cext.SSTOP: _common.STATUS_STOPPED,
+}
+
+TCP_STATUSES = {
+    cext.TCPS_ESTABLISHED: _common.CONN_ESTABLISHED,
+    cext.TCPS_SYN_SENT: _common.CONN_SYN_SENT,
+    cext.TCPS_SYN_RCVD: _common.CONN_SYN_RECV,
+    cext.TCPS_FIN_WAIT_1: _common.CONN_FIN_WAIT1,
+    cext.TCPS_FIN_WAIT_2: _common.CONN_FIN_WAIT2,
+    cext.TCPS_TIME_WAIT: _common.CONN_TIME_WAIT,
+    cext.TCPS_CLOSED: _common.CONN_CLOSE,
+    cext.TCPS_CLOSE_WAIT: _common.CONN_CLOSE_WAIT,
+    cext.TCPS_LAST_ACK: _common.CONN_LAST_ACK,
+    cext.TCPS_LISTEN: _common.CONN_LISTEN,
+    cext.TCPS_CLOSING: _common.CONN_CLOSING,
+    cext.PSUTIL_CONN_NONE: _common.CONN_NONE,
+}
+
+proc_info_map = dict(
+    ppid=0,
+    rss=1,
+    vms=2,
+    create_time=3,
+    nice=4,
+    num_threads=5,
+    status=6,
+    ttynr=7)
+
+
+# =====================================================================
+# --- named tuples
+# =====================================================================
+
+
+# psutil.Process.memory_info()
+pmem = namedtuple('pmem', ['rss', 'vms'])
+# psutil.Process.memory_full_info()
+pfullmem = pmem
+# psutil.Process.cpu_times()
+scputimes = namedtuple('scputimes', ['user', 'system', 'idle', 'iowait'])
+# psutil.virtual_memory()
+svmem = namedtuple('svmem', ['total', 'available', 'percent', 'used', 'free'])
+# psutil.Process.memory_maps(grouped=True)
+pmmap_grouped = namedtuple('pmmap_grouped', ['path', 'rss', 'anon', 'locked'])
+# psutil.Process.memory_maps(grouped=False)
+pmmap_ext = namedtuple(
+    'pmmap_ext', 'addr perms ' + ' '.join(pmmap_grouped._fields))
+
+
+# =====================================================================
+# --- utils
+# =====================================================================
+
+
+def get_procfs_path():
+    """Return updated psutil.PROCFS_PATH constant."""
+    return sys.modules['psutil'].PROCFS_PATH
+
+
+# =====================================================================
+# --- memory
+# =====================================================================
+
+
+def virtual_memory():
+    total, avail, free, pinned, inuse = cext.virtual_mem()
+    percent = usage_percent((total - avail), total, _round=1)
+    return svmem(total, avail, percent, inuse, free)
+
+
+def swap_memory():
+    """Swap system memory as a (total, used, free, sin, sout) tuple."""
+    total, free, sin, sout = cext.swap_mem()
+    used = total - free
+    percent = usage_percent(used, total, _round=1)
+    return _common.sswap(total, used, free, percent, sin, sout)
+
+
+# =====================================================================
+# --- CPU
+# =====================================================================
+
+
+def cpu_times():
+    """Return system-wide CPU times as a named tuple"""
+    ret = cext.per_cpu_times()
+    return scputimes(*[sum(x) for x in zip(*ret)])
+
+
+def per_cpu_times():
+    """Return system per-CPU times as a list of named tuples"""
+    ret = cext.per_cpu_times()
+    return [scputimes(*x) for x in ret]
+
+
+def cpu_count_logical():
+    """Return the number of logical CPUs in the system."""
+    try:
+        return os.sysconf("SC_NPROCESSORS_ONLN")
+    except ValueError:
+        # mimic os.cpu_count() behavior
+        return None
+
+
+def cpu_count_physical():
+    cmd = "lsdev -Cc processor"
+    p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,
+                         stderr=subprocess.PIPE)
+    stdout, stderr = p.communicate()
+    if PY3:
+        stdout, stderr = [x.decode(sys.stdout.encoding)
+                          for x in (stdout, stderr)]
+    if p.returncode != 0:
+        raise RuntimeError("%r command error\n%s" % (cmd, stderr))
+    processors = stdout.strip().splitlines()
+    return len(processors) or None
+
+
+def cpu_stats():
+    """Return various CPU stats as a named tuple."""
+    ctx_switches, interrupts, soft_interrupts, syscalls = cext.cpu_stats()
+    return _common.scpustats(
+        ctx_switches, interrupts, soft_interrupts, syscalls)
+
+
+# =====================================================================
+# --- disks
+# =====================================================================
+
+
+disk_io_counters = cext.disk_io_counters
+disk_usage = _psposix.disk_usage
+
+
+def disk_partitions(all=False):
+    """Return system disk partitions."""
+    # TODO - the filtering logic should be better checked so that
+    # it tries to reflect 'df' as much as possible
+    retlist = []
+    partitions = cext.disk_partitions()
+    for partition in partitions:
+        device, mountpoint, fstype, opts = partition
+        if device == 'none':
+            device = ''
+        if not all:
+            # Differently from, say, Linux, we don't have a list of
+            # common fs types so the best we can do, AFAIK, is to
+            # filter by filesystem having a total size > 0.
+            if not disk_usage(mountpoint).total:
+                continue
+        ntuple = _common.sdiskpart(device, mountpoint, fstype, opts)
+        retlist.append(ntuple)
+    return retlist
+
+
+# =====================================================================
+# --- network
+# =====================================================================
+
+
+net_if_addrs = cext_posix.net_if_addrs
+net_io_counters = cext.net_io_counters
+
+
+def net_connections(kind, _pid=-1):
+    """Return socket connections.  If pid == -1 return system-wide
+    connections (as opposed to connections opened by one process only).
+    """
+    cmap = _common.conn_tmap
+    if kind not in cmap:
+        raise ValueError("invalid %r kind argument; choose between %s"
+                         % (kind, ', '.join([repr(x) for x in cmap])))
+    families, types = _common.conn_tmap[kind]
+    rawlist = cext.net_connections(_pid)
+    ret = set()
+    for item in rawlist:
+        fd, fam, type_, laddr, raddr, status, pid = item
+        if fam not in families:
+            continue
+        if type_ not in types:
+            continue
+        status = TCP_STATUSES[status]
+        if fam in (AF_INET, AF_INET6):
+            if laddr:
+                laddr = _common.addr(*laddr)
+            if raddr:
+                raddr = _common.addr(*raddr)
+        fam = sockfam_to_enum(fam)
+        type_ = socktype_to_enum(type_)
+        if _pid == -1:
+            nt = _common.sconn(fd, fam, type_, laddr, raddr, status, pid)
+        else:
+            nt = _common.pconn(fd, fam, type_, laddr, raddr, status)
+        ret.add(nt)
+    return list(ret)
+
+
+def net_if_stats():
+    """Get NIC stats (isup, duplex, speed, mtu)."""
+    duplex_map = {"Full": NIC_DUPLEX_FULL,
+                  "Half": NIC_DUPLEX_HALF}
+    names = set([x[0] for x in net_if_addrs()])
+    ret = {}
+    for name in names:
+        isup, mtu = cext.net_if_stats(name)
+
+        # try to get speed and duplex
+        # TODO: rewrite this in C (entstat forks, so use truss -f to follow.
+        # looks like it is using an undocumented ioctl?)
+        duplex = ""
+        speed = 0
+        p = subprocess.Popen(["/usr/bin/entstat", "-d", name],
+                             stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+        stdout, stderr = p.communicate()
+        if PY3:
+            stdout, stderr = [x.decode(sys.stdout.encoding)
+                              for x in (stdout, stderr)]
+        if p.returncode == 0:
+            re_result = re.search("Running: (\d+) Mbps.*?(\w+) Duplex", stdout)
+            if re_result is not None:
+                speed = int(re_result.group(1))
+                duplex = re_result.group(2)
+
+        duplex = duplex_map.get(duplex, NIC_DUPLEX_UNKNOWN)
+        ret[name] = _common.snicstats(isup, duplex, speed, mtu)
+    return ret
+
+
+# =====================================================================
+# --- other system functions
+# =====================================================================
+
+
+def boot_time():
+    """The system boot time expressed in seconds since the epoch."""
+    return cext.boot_time()
+
+
+def users():
+    """Return currently connected users as a list of namedtuples."""
+    retlist = []
+    rawlist = cext.users()
+    localhost = (':0.0', ':0')
+    for item in rawlist:
+        user, tty, hostname, tstamp, user_process, pid = item
+        # note: the underlying C function includes entries about
+        # system boot, run level and others.  We might want
+        # to use them in the future.
+        if not user_process:
+            continue
+        if hostname in localhost:
+            hostname = 'localhost'
+        nt = _common.suser(user, tty, hostname, tstamp, pid)
+        retlist.append(nt)
+    return retlist
+
+
+# =====================================================================
+# --- processes
+# =====================================================================
+
+
+def pids():
+    """Returns a list of PIDs currently running on the system."""
+    return [int(x) for x in os.listdir(get_procfs_path()) if x.isdigit()]
+
+
+def pid_exists(pid):
+    """Check for the existence of a unix pid."""
+    return os.path.exists(os.path.join(get_procfs_path(), str(pid), "psinfo"))
+
+
+def wrap_exceptions(fun):
+    """Call callable into a try/except clause and translate ENOENT,
+    EACCES and EPERM in NoSuchProcess or AccessDenied exceptions.
+    """
+
+    def wrapper(self, *args, **kwargs):
+        try:
+            return fun(self, *args, **kwargs)
+        except EnvironmentError as err:
+            # support for private module import
+            if (NoSuchProcess is None or AccessDenied is None or
+                    ZombieProcess is None):
+                raise
+            # ENOENT (no such file or directory) gets raised on open().
+            # ESRCH (no such process) can get raised on read() if
+            # process is gone in meantime.
+            if err.errno in (errno.ENOENT, errno.ESRCH):
+                if not pid_exists(self.pid):
+                    raise NoSuchProcess(self.pid, self._name)
+                else:
+                    raise ZombieProcess(self.pid, self._name, self._ppid)
+            if err.errno in (errno.EPERM, errno.EACCES):
+                raise AccessDenied(self.pid, self._name)
+            raise
+    return wrapper
+
+
+class Process(object):
+    """Wrapper class around underlying C implementation."""
+
+    __slots__ = ["pid", "_name", "_ppid", "_procfs_path"]
+
+    def __init__(self, pid):
+        self.pid = pid
+        self._name = None
+        self._ppid = None
+        self._procfs_path = get_procfs_path()
+
+    def oneshot_enter(self):
+        self._proc_name_and_args.cache_activate()
+        self._proc_basic_info.cache_activate()
+        self._proc_cred.cache_activate()
+
+    def oneshot_exit(self):
+        self._proc_name_and_args.cache_deactivate()
+        self._proc_basic_info.cache_deactivate()
+        self._proc_cred.cache_deactivate()
+
+    @memoize_when_activated
+    def _proc_name_and_args(self):
+        return cext.proc_name_and_args(self.pid, self._procfs_path)
+
+    @memoize_when_activated
+    def _proc_basic_info(self):
+        return cext.proc_basic_info(self.pid, self._procfs_path)
+
+    @memoize_when_activated
+    def _proc_cred(self):
+        return cext.proc_cred(self.pid, self._procfs_path)
+
+    @wrap_exceptions
+    def name(self):
+        if self.pid == 0:
+            return "swapper"
+        # note: this is limited to 15 characters
+        return self._proc_name_and_args()[0].rstrip("\x00")
+
+    @wrap_exceptions
+    def exe(self):
+        # there is no way to get executable path in AIX other than to guess,
+        # and guessing is more complex than what's in the wrapping class
+        exe = self.cmdline()[0]
+        if os.path.sep in exe:
+            # relative or absolute path
+            if not os.path.isabs(exe):
+                # if cwd has changed, we're out of luck - this may be wrong!
+                exe = os.path.abspath(os.path.join(self.cwd(), exe))
+            if (os.path.isabs(exe) and
+               os.path.isfile(exe) and
+               os.access(exe, os.X_OK)):
+                return exe
+            # not found, move to search in PATH using basename only
+            exe = os.path.basename(exe)
+        # search for exe name PATH
+        for path in os.environ["PATH"].split(":"):
+            possible_exe = os.path.abspath(os.path.join(path, exe))
+            if (os.path.isfile(possible_exe) and
+               os.access(possible_exe, os.X_OK)):
+                return possible_exe
+        return ''
+
+    @wrap_exceptions
+    def cmdline(self):
+        return self._proc_name_and_args()[1].split(' ')
+
+    @wrap_exceptions
+    def create_time(self):
+        return self._proc_basic_info()[proc_info_map['create_time']]
+
+    @wrap_exceptions
+    def num_threads(self):
+        return self._proc_basic_info()[proc_info_map['num_threads']]
+
+    if HAS_THREADS:
+        @wrap_exceptions
+        def threads(self):
+            rawlist = cext.proc_threads(self.pid)
+            retlist = []
+            for thread_id, utime, stime in rawlist:
+                ntuple = _common.pthread(thread_id, utime, stime)
+                retlist.append(ntuple)
+            # The underlying C implementation retrieves all OS threads
+            # and filters them by PID.  At this point we can't tell whether
+            # an empty list means there were no connections for process or
+            # process is no longer active so we force NSP in case the PID
+            # is no longer there.
+            if not retlist:
+                # will raise NSP if process is gone
+                os.stat('%s/%s' % (self._procfs_path, self.pid))
+            return retlist
+
+    @wrap_exceptions
+    def connections(self, kind='inet'):
+        ret = net_connections(kind, _pid=self.pid)
+        # The underlying C implementation retrieves all OS connections
+        # and filters them by PID.  At this point we can't tell whether
+        # an empty list means there were no connections for process or
+        # process is no longer active so we force NSP in case the PID
+        # is no longer there.
+        if not ret:
+            # will raise NSP if process is gone
+            os.stat('%s/%s' % (self._procfs_path, self.pid))
+        return ret
+
+    @wrap_exceptions
+    def nice_get(self):
+        return cext_posix.getpriority(self.pid)
+
+    @wrap_exceptions
+    def nice_set(self, value):
+        return cext_posix.setpriority(self.pid, value)
+
+    @wrap_exceptions
+    def ppid(self):
+        self._ppid = self._proc_basic_info()[proc_info_map['ppid']]
+        return self._ppid
+
+    @wrap_exceptions
+    def uids(self):
+        real, effective, saved, _, _, _ = self._proc_cred()
+        return _common.puids(real, effective, saved)
+
+    @wrap_exceptions
+    def gids(self):
+        _, _, _, real, effective, saved = self._proc_cred()
+        return _common.puids(real, effective, saved)
+
+    @wrap_exceptions
+    def cpu_times(self):
+        cpu_times = cext.proc_cpu_times(self.pid, self._procfs_path)
+        return _common.pcputimes(*cpu_times)
+
+    @wrap_exceptions
+    def terminal(self):
+        ttydev = self._proc_basic_info()[proc_info_map['ttynr']]
+        # convert from 64-bit dev_t to 32-bit dev_t and then map the device
+        ttydev = (((ttydev & 0x0000FFFF00000000) >> 16) | (ttydev & 0xFFFF))
+        # try to match rdev of /dev/pts/* files ttydev
+        for dev in glob.glob("/dev/**/*"):
+            if os.stat(dev).st_rdev == ttydev:
+                return dev
+        return None
+
+    @wrap_exceptions
+    def cwd(self):
+        procfs_path = self._procfs_path
+        try:
+            result = os.readlink("%s/%s/cwd" % (procfs_path, self.pid))
+            return result.rstrip('/')
+        except OSError as err:
+            if err.errno == errno.ENOENT:
+                os.stat("%s/%s" % (procfs_path, self.pid))  # raise NSP or AD
+                return None
+            raise
+
+    @wrap_exceptions
+    def memory_info(self):
+        ret = self._proc_basic_info()
+        rss = ret[proc_info_map['rss']] * 1024
+        vms = ret[proc_info_map['vms']] * 1024
+        return pmem(rss, vms)
+
+    memory_full_info = memory_info
+
+    @wrap_exceptions
+    def status(self):
+        code = self._proc_basic_info()[proc_info_map['status']]
+        # XXX is '?' legit? (we're not supposed to return it anyway)
+        return PROC_STATUSES.get(code, '?')
+
+    def open_files(self):
+        # TODO rewrite without using procfiles (stat /proc/pid/fd/* and then
+        # find matching name of the inode)
+        p = subprocess.Popen(["/usr/bin/procfiles", "-n", str(self.pid)],
+                             stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+        stdout, stderr = p.communicate()
+        if PY3:
+            stdout, stderr = [x.decode(sys.stdout.encoding)
+                              for x in (stdout, stderr)]
+        if "no such process" in stderr.lower():
+            raise NoSuchProcess(self.pid, self._name)
+        procfiles = re.findall("(\d+): S_IFREG.*\s*.*name:(.*)\n", stdout)
+        retlist = []
+        for fd, path in procfiles:
+            path = path.strip()
+            if path.startswith("//"):
+                path = path[1:]
+            if path.lower() == "cannot be retrieved":
+                continue
+            retlist.append(_common.popenfile(path, int(fd)))
+        return retlist
+
+    @wrap_exceptions
+    def num_fds(self):
+        if self.pid == 0:       # no /proc/0/fd
+            return 0
+        return len(os.listdir("%s/%s/fd" % (self._procfs_path, self.pid)))
+
+    @wrap_exceptions
+    def num_ctx_switches(self):
+        return _common.pctxsw(
+            *cext.proc_num_ctx_switches(self.pid))
+
+    @wrap_exceptions
+    def wait(self, timeout=None):
+        return _psposix.wait_pid(self.pid, timeout, self._name)
+
+    @wrap_exceptions
+    def io_counters(self):
+        try:
+            rc, wc, rb, wb = cext.proc_io_counters(self.pid)
+        except OSError:
+            # if process is terminated, proc_io_counters returns OSError
+            # instead of NSP
+            if not pid_exists(self.pid):
+                raise NoSuchProcess(self.pid, self._name)
+            raise
+        return _common.pio(rc, wc, rb, wb)
new file mode 100644
--- /dev/null
+++ b/third_party/python/psutil-cp27-none-win_amd64/psutil/_psbsd.py
@@ -0,0 +1,873 @@
+# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""FreeBSD, OpenBSD and NetBSD platforms implementation."""
+
+import contextlib
+import errno
+import functools
+import os
+import xml.etree.ElementTree as ET
+from collections import namedtuple
+from socket import AF_INET
+
+from . import _common
+from . import _psposix
+from . import _psutil_bsd as cext
+from . import _psutil_posix as cext_posix
+from ._common import AF_INET6
+from ._common import conn_tmap
+from ._common import FREEBSD
+from ._common import memoize
+from ._common import memoize_when_activated
+from ._common import NETBSD
+from ._common import OPENBSD
+from ._common import sockfam_to_enum
+from ._common import socktype_to_enum
+from ._common import usage_percent
+from ._compat import which
+from ._exceptions import AccessDenied
+from ._exceptions import NoSuchProcess
+from ._exceptions import ZombieProcess
+
+__extra__all__ = []
+
+
+# =====================================================================
+# --- globals
+# =====================================================================
+
+
+if FREEBSD:
+    PROC_STATUSES = {
+        cext.SIDL: _common.STATUS_IDLE,
+        cext.SRUN: _common.STATUS_RUNNING,
+        cext.SSLEEP: _common.STATUS_SLEEPING,
+        cext.SSTOP: _common.STATUS_STOPPED,
+        cext.SZOMB: _common.STATUS_ZOMBIE,
+        cext.SWAIT: _common.STATUS_WAITING,
+        cext.SLOCK: _common.STATUS_LOCKED,
+    }
+elif OPENBSD or NETBSD:
+    PROC_STATUSES = {
+        cext.SIDL: _common.STATUS_IDLE,
+        cext.SSLEEP: _common.STATUS_SLEEPING,
+        cext.SSTOP: _common.STATUS_STOPPED,
+        # According to /usr/include/sys/proc.h SZOMB is unused.
+        # test_zombie_process() shows that SDEAD is the right
+        # equivalent. Also it appears there's no equivalent of
+        # psutil.STATUS_DEAD. SDEAD really means STATUS_ZOMBIE.
+        # cext.SZOMB: _common.STATUS_ZOMBIE,
+        cext.SDEAD: _common.STATUS_ZOMBIE,
+        cext.SZOMB: _common.STATUS_ZOMBIE,
+        # From http://www.eecs.harvard.edu/~margo/cs161/videos/proc.h.txt
+        # OpenBSD has SRUN and SONPROC: SRUN indicates that a process
+        # is runnable but *not* yet running, i.e. is on a run queue.
+        # SONPROC indicates that the process is actually executing on
+        # a CPU, i.e. it is no longer on a run queue.
+        # As such we'll map SRUN to STATUS_WAKING and SONPROC to
+        # STATUS_RUNNING
+        cext.SRUN: _common.STATUS_WAKING,
+        cext.SONPROC: _common.STATUS_RUNNING,
+    }
+elif NETBSD:
+    PROC_STATUSES = {
+        cext.SIDL: _common.STATUS_IDLE,
+        cext.SACTIVE: _common.STATUS_RUNNING,
+        cext.SDYING: _common.STATUS_ZOMBIE,
+        cext.SSTOP: _common.STATUS_STOPPED,
+        cext.SZOMB: _common.STATUS_ZOMBIE,
+        cext.SDEAD: _common.STATUS_DEAD,
+        cext.SSUSPENDED: _common.STATUS_SUSPENDED,  # unique to NetBSD
+    }
+
+TCP_STATUSES = {
+    cext.TCPS_ESTABLISHED: _common.CONN_ESTABLISHED,
+    cext.TCPS_SYN_SENT: _common.CONN_SYN_SENT,
+    cext.TCPS_SYN_RECEIVED: _common.CONN_SYN_RECV,
+    cext.TCPS_FIN_WAIT_1: _common.CONN_FIN_WAIT1,
+    cext.TCPS_FIN_WAIT_2: _common.CONN_FIN_WAIT2,
+    cext.TCPS_TIME_WAIT: _common.CONN_TIME_WAIT,
+    cext.TCPS_CLOSED: _common.CONN_CLOSE,
+    cext.TCPS_CLOSE_WAIT: _common.CONN_CLOSE_WAIT,
+    cext.TCPS_LAST_ACK: _common.CONN_LAST_ACK,
+    cext.TCPS_LISTEN: _common.CONN_LISTEN,
+    cext.TCPS_CLOSING: _common.CONN_CLOSING,
+    cext.PSUTIL_CONN_NONE: _common.CONN_NONE,
+}
+
+if NETBSD:
+    PAGESIZE = os.sysconf("SC_PAGESIZE")
+else:
+    PAGESIZE = os.sysconf("SC_PAGE_SIZE")
+AF_LINK = cext_posix.AF_LINK
+
+kinfo_proc_map = dict(
+    ppid=0,
+    status=1,
+    real_uid=2,
+    effective_uid=3,
+    saved_uid=4,
+    real_gid=5,
+    effective_gid=6,
+    saved_gid=7,
+    ttynr=8,
+    create_time=9,
+    ctx_switches_vol=10,
+    ctx_switches_unvol=11,
+    read_io_count=12,
+    write_io_count=13,
+    user_time=14,
+    sys_time=15,
+    ch_user_time=16,
+    ch_sys_time=17,
+    rss=18,
+    vms=19,
+    memtext=20,
+    memdata=21,
+    memstack=22,
+    cpunum=23,
+    name=24,
+)
+
+
+# =====================================================================
+# --- named tuples
+# =====================================================================
+
+
+# psutil.virtual_memory()
+svmem = namedtuple(
+    'svmem', ['total', 'available', 'percent', 'used', 'free',
+              'active', 'inactive', 'buffers', 'cached', 'shared', 'wired'])
+# psutil.cpu_times()
+scputimes = namedtuple(
+    'scputimes', ['user', 'nice', 'system', 'idle', 'irq'])
+# psutil.Process.memory_info()
+pmem = namedtuple('pmem', ['rss', 'vms', 'text', 'data', 'stack'])
+# psutil.Process.memory_full_info()
+pfullmem = pmem
+# psutil.Process.cpu_times()
+pcputimes = namedtuple('pcputimes',
+                       ['user', 'system', 'children_user', 'children_system'])
+# psutil.Process.memory_maps(grouped=True)
+pmmap_grouped = namedtuple(
+    'pmmap_grouped', 'path rss, private, ref_count, shadow_count')
+# psutil.Process.memory_maps(grouped=False)
+pmmap_ext = namedtuple(
+    'pmmap_ext', 'addr, perms path rss, private, ref_count, shadow_count')
+# psutil.disk_io_counters()
+if FREEBSD:
+    sdiskio = namedtuple('sdiskio', ['read_count', 'write_count',
+                                     'read_bytes', 'write_bytes',
+                                     'read_time', 'write_time',
+                                     'busy_time'])
+else:
+    sdiskio = namedtuple('sdiskio', ['read_count', 'write_count',
+                                     'read_bytes', 'write_bytes'])
+
+
+# =====================================================================
+# --- memory
+# =====================================================================
+
+
+def virtual_memory():
+    """System virtual memory as a namedtuple."""
+    mem = cext.virtual_mem()
+    total, free, active, inactive, wired, cached, buffers, shared = mem
+    if NETBSD:
+        # On NetBSD buffers and shared mem is determined via /proc.
+        # The C ext set them to 0.
+        with open('/proc/meminfo', 'rb') as f:
+            for line in f:
+                if line.startswith(b'Buffers:'):
+                    buffers = int(line.split()[1]) * 1024
+                elif line.startswith(b'MemShared:'):
+                    shared = int(line.split()[1]) * 1024
+    avail = inactive + cached + free
+    used = active + wired + cached
+    percent = usage_percent((total - avail), total, _round=1)
+    return svmem(total, avail, percent, used, free,
+                 active, inactive, buffers, cached, shared, wired)
+
+
+def swap_memory():
+    """System swap memory as (total, used, free, sin, sout) namedtuple."""
+    total, used, free, sin, sout = cext.swap_mem()
+    percent = usage_percent(used, total, _round=1)
+    return _common.sswap(total, used, free, percent, sin, sout)
+
+
+# =====================================================================
+# --- CPU