Merge mozilla-central to mozilla-inbound
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Thu, 01 Jun 2017 13:56:11 +0200
changeset 361796 980375a7b0292f0b7fcdc4bb47d117fe0f51e158
parent 361795 7abafd0fead900aec67b0de342f71ec856f561cf (current diff)
parent 361760 0bcea6bac1797e14b00af45cc7c368d12460ab7f (diff)
child 361797 675c893a028dfe609ee6812cba0d1e86b2853d23
push id31943
push userryanvm@gmail.com
push dateThu, 01 Jun 2017 15:54:45 +0000
treeherdermozilla-central@62005e6aecdf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone55.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 mozilla-central to mozilla-inbound
modules/libpref/init/all.js
third_party/rust/serde-0.9.9/.cargo-checksum.json
third_party/rust/serde-0.9.9/.cargo-ok
third_party/rust/serde-0.9.9/Cargo.toml
third_party/rust/serde-0.9.9/LICENSE-APACHE
third_party/rust/serde-0.9.9/LICENSE-MIT
third_party/rust/serde-0.9.9/README.md
third_party/rust/serde-0.9.9/src/bytes.rs
third_party/rust/serde-0.9.9/src/de/content.rs
third_party/rust/serde-0.9.9/src/de/from_primitive.rs
third_party/rust/serde-0.9.9/src/de/impls.rs
third_party/rust/serde-0.9.9/src/de/mod.rs
third_party/rust/serde-0.9.9/src/de/private.rs
third_party/rust/serde-0.9.9/src/de/value.rs
third_party/rust/serde-0.9.9/src/error.rs
third_party/rust/serde-0.9.9/src/export.rs
third_party/rust/serde-0.9.9/src/iter.rs
third_party/rust/serde-0.9.9/src/lib.rs
third_party/rust/serde-0.9.9/src/macros.rs
third_party/rust/serde-0.9.9/src/ser/content.rs
third_party/rust/serde-0.9.9/src/ser/impls.rs
third_party/rust/serde-0.9.9/src/ser/impossible.rs
third_party/rust/serde-0.9.9/src/ser/mod.rs
third_party/rust/serde-0.9.9/src/ser/private.rs
third_party/rust/serde-0.9.9/src/utils.rs
third_party/rust/serde/src/de/ignored_any.rs
third_party/rust/serde/src/de/utf8.rs
third_party/rust/serde/src/private/de.rs
third_party/rust/serde/src/private/macros.rs
third_party/rust/serde/src/private/mod.rs
third_party/rust/serde/src/private/ser.rs
third_party/rust/serde_test/.cargo-checksum.json
third_party/rust/serde_test/.cargo-ok
third_party/rust/serde_test/Cargo.toml
third_party/rust/serde_test/LICENSE-APACHE
third_party/rust/serde_test/LICENSE-MIT
third_party/rust/serde_test/README.md
third_party/rust/serde_test/src/assert.rs
third_party/rust/serde_test/src/de.rs
third_party/rust/serde_test/src/error.rs
third_party/rust/serde_test/src/lib.rs
third_party/rust/serde_test/src/ser.rs
third_party/rust/serde_test/src/token.rs
third_party/rust/unicode-bidi-0.2.5/.cargo-checksum.json
third_party/rust/unicode-bidi-0.2.5/.cargo-ok
third_party/rust/unicode-bidi-0.2.5/.gitignore
third_party/rust/unicode-bidi-0.2.5/.travis.yml
third_party/rust/unicode-bidi-0.2.5/AUTHORS
third_party/rust/unicode-bidi-0.2.5/COPYRIGHT
third_party/rust/unicode-bidi-0.2.5/Cargo.toml
third_party/rust/unicode-bidi-0.2.5/LICENSE-APACHE
third_party/rust/unicode-bidi-0.2.5/LICENSE-MIT
third_party/rust/unicode-bidi-0.2.5/README.md
third_party/rust/unicode-bidi-0.2.5/src/lib.rs
third_party/rust/unicode-bidi-0.2.5/src/tables.rs
third_party/rust/unicode-bidi-0.2.5/tools/generate.py
third_party/rust/unicode-bidi/benches/udhr.rs
third_party/rust/unicode-bidi/src/char_data/mod.rs
third_party/rust/unicode-bidi/src/explicit.rs
third_party/rust/unicode-bidi/src/format_chars.rs
third_party/rust/unicode-bidi/src/implicit.rs
third_party/rust/unicode-bidi/src/prepare.rs
third_party/rust/unicode-bidi/tests/conformance_tests.rs
third_party/rust/url/rust-url-todo
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1038,17 +1038,17 @@ pref("security.sandbox.windows.log.stack
 // SetSecurityLevelForGPUProcess() in
 // security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp
 pref("security.sandbox.gpu.level", 0);
 #endif
 
 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX) && defined(MOZ_CONTENT_SANDBOX)
 // This pref is discussed in bug 1083344, the naming is inspired from its
 // Windows counterpart, but on Mac it's an integer which means:
-// 0 -> "no sandbox"
+// 0 -> "no sandbox" (nightly only)
 // 1 -> "preliminary content sandboxing enabled: write access to
 //       home directory is prevented"
 // 2 -> "preliminary content sandboxing enabled with profile protection:
 //       write access to home directory is prevented, read and write access
 //       to ~/Library and profile directories are prevented (excluding
 //       $PROFILE/{extensions,weave})"
 // This setting is read when the content process is started. On Mac the content
 // process is killed when all windows are closed, so a change will take effect
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -108,17 +108,17 @@ panelview {
   transition: transform var(--panelui-subview-transition-duration);
 }
 
 panelview:not([mainview]):not([current]) {
   transition: visibility 0s linear var(--panelui-subview-transition-duration);
   visibility: collapse;
 }
 
-panelview:not([title]) > .panel-header {
+panelview[mainview] > .panel-header {
   display: none;
 }
 
 tabbrowser {
   -moz-binding: url("chrome://browser/content/tabbrowser.xml#tabbrowser");
 }
 
 .tabbrowser-tabs {
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -606,16 +606,17 @@
                 accesskey="&selectAllCmd.accesskey;"
                 cmd="cmd_selectAll"/>
       <menuseparator/>
       <menuitem label="&syncSyncNowItem.label;"
                 accesskey="&syncSyncNowItem.accesskey;"
                 id="syncedTabsRefreshFilter"/>
     </menupopup>
   </popupset>
+  <box id="appMenu-viewCache" hidden="true"/>
 
 #ifdef CAN_DRAW_IN_TITLEBAR
 <vbox id="titlebar">
   <hbox id="titlebar-content">
     <spacer id="titlebar-spacer" flex="1"/>
     <hbox id="titlebar-buttonbox-container">
 #ifdef XP_WIN
       <hbox id="private-browsing-indicator-titlebar">
@@ -1189,16 +1190,21 @@
                      ondragenter="newWindowButtonObserver.onDragOver(event)"
                      ondragexit="newWindowButtonObserver.onDragExit(event)"/>
 
       <toolbarbutton id="fullscreen-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
                      observes="View:FullScreen"
                      type="checkbox"
                      label="&fullScreenCmd.label;"
                      tooltip="dynamic-shortcut-tooltip"/>
+#ifdef MOZ_PHOTON_THEME
+      <toolbarbutton id="library-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
+                     oncommand="PanelUI.showSubView('appMenu-libraryView', this, null, true);"
+                     label="&places.library.title;"/>
+#endif
     </toolbarpalette>
   </toolbox>
 
   <hbox id="fullscr-toggler" hidden="true"/>
 
   <deck id="content-deck" flex="1">
     <hbox flex="1" id="browser">
       <vbox id="browser-border-start" hidden="true" layer="true"/>
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -4105,30 +4105,42 @@
             },
 
             // This function is called after all the main state changes to
             // make sure we display the right tab.
             updateDisplay() {
               let requestedTabState = this.getTabState(this.requestedTab);
               let requestedBrowser = this.requestedTab.linkedBrowser;
 
-              // It is more desirable to show a blank tab when appropriate than
+              // It is often more desirable to show a blank tab when appropriate than
               // the tab switch spinner - especially since the spinner is usually
               // preceded by a perceived lag of TAB_SWITCH_TIMEOUT ms in the
               // tab switch. We can hide this lag, and hide the time being spent
               // constructing TabChild's, layer trees, etc, by showing a blank
               // tab instead and focusing it immediately.
               let shouldBeBlank = false;
               if (requestedBrowser.isRemoteBrowser) {
-                // If a tab is remote, we can show a blank tab instead of a
-                // spinner if we know it has never presented before, or if it
-                // has just crashed and we haven't started showing the tab crashed
-                // page yet.
+                // If a tab is remote and the window is not minimized, we can show a
+                // blank tab instead of a spinner in the following cases:
+                //
+                // 1. The tab has just crashed, and we haven't started showing the
+                //    tab crashed page yet (in this case, the TabParent is null)
+                // 2. The tab has never presented, and has not finished loading
+                //    a non-blank page.
+                //
+                // For (2), "finished loading a non-blank page" is determined by
+                // looking at the loaded URI and the busy state on the tab element.
+                let hasSufficientlyLoaded =
+                  !this.requestedTab.hasAttribute("busy") &&
+                  requestedBrowser.currentURI.spec != "about:blank";
+
                 let fl = requestedBrowser.frameLoader;
-                shouldBeBlank = !this.minimized && (!fl.tabParent || !fl.tabParent.hasPresented);
+                shouldBeBlank = !this.minimized &&
+                                (!fl.tabParent ||
+                                 (!hasSufficientlyLoaded && !fl.tabParent.hasPresented));
               }
 
               this.log("Tab should be blank: " + shouldBeBlank);
               this.log("Requested tab is remote?: " + requestedBrowser.isRemoteBrowser);
 
               // Figure out which tab we actually want visible right now.
               let showTab = null;
               if (requestedTabState != this.STATE_LOADED &&
@@ -4623,17 +4635,16 @@
                 this.switchInProgress = false;
               }
             },
 
             spinnerDisplayed() {
               this.assert(!this.spinnerTab);
               let browser = this.requestedTab.linkedBrowser;
               this.assert(browser.isRemoteBrowser);
-              this.assert(browser.frameLoader.tabParent.hasPresented);
               TelemetryStopwatch.start("FX_TAB_SWITCH_SPINNER_VISIBLE_MS", window);
               // We have a second, similar probe for capturing recordings of
               // when the spinner is displayed for very long periods.
               TelemetryStopwatch.start("FX_TAB_SWITCH_SPINNER_VISIBLE_LONG_MS", window);
               this.addMarker("AsyncTabSwitch:SpinnerShown");
             },
 
             spinnerHidden() {
--- a/browser/components/customizableui/PanelMultiView.jsm
+++ b/browser/components/customizableui/PanelMultiView.jsm
@@ -242,16 +242,21 @@ this.PanelMultiView = class {
       document.getAnonymousElementByAttribute(this.node, "anonid", "viewContainer");
     this._mainViewContainer =
       document.getAnonymousElementByAttribute(this.node, "anonid", "mainViewContainer");
     this._subViews =
       document.getAnonymousElementByAttribute(this.node, "anonid", "subViews");
     this._viewStack =
       document.getAnonymousElementByAttribute(this.node, "anonid", "viewStack");
 
+    XPCOMUtils.defineLazyGetter(this, "_panelViewCache", () => {
+      let viewCacheId = this.node.getAttribute("viewCacheId");
+      return viewCacheId ? document.getElementById(viewCacheId) : null;
+    });
+
     this._panel.addEventListener("popupshowing", this);
     this._panel.addEventListener("popuphidden", this);
     this._panel.addEventListener("popupshown", this);
     if (this.panelViews) {
       let cs = window.getComputedStyle(document.documentElement);
       // Set CSS-determined attributes now to prevent a layout flush when we do
       // it when transitioning between panels.
       this._dir = cs.direction;
@@ -283,47 +288,76 @@ this.PanelMultiView = class {
       Object.defineProperty(this.node, method, {
         enumerable: true,
         value: (...args) => this[method](...args)
       });
     });
   }
 
   destructor() {
+    // Guard against re-entrancy.
+    if (!this.node)
+      return;
+
     if (this._mainView) {
-      this._mainView.removeAttribute("mainview");
+      let mainView = this._mainView;
+      if (this._panelViewCache)
+        this._panelViewCache.appendChild(mainView);
+      mainView.removeAttribute("mainview");
     }
+    if (this._subViews)
+      this._moveOutKids(this._subViews);
+
     if (this.panelViews) {
+      this._moveOutKids(this._viewStack);
       this.panelViews.clear();
     } else {
       this._clickCapturer.removeEventListener("click", this);
     }
     this._panel.removeEventListener("popupshowing", this);
     this._panel.removeEventListener("popupshown", this);
     this._panel.removeEventListener("popuphidden", this);
     this.node = this._clickCapturer = this._viewContainer = this._mainViewContainer =
-      this._subViews = this._viewStack = this.__dwu = null;
+      this._subViews = this._viewStack = this.__dwu = this._panelViewCache = null;
+  }
+
+  /**
+   * Remove any child subviews into the panelViewCache, to ensure
+   * they remain usable even if this panelmultiview instance is removed
+   * from the DOM.
+   * @param viewNodeContainer the container from which to remove subviews
+   */
+  _moveOutKids(viewNodeContainer) {
+    if (!this._panelViewCache)
+      return;
+
+    // Node.children and Node.childNodes is live to DOM changes like the
+    // ones we're about to do, so iterate over a static copy:
+    let subviews = Array.from(viewNodeContainer.childNodes);
+    for (let subview of subviews) {
+      // XBL lists the 'children' XBL element explicitly. :-(
+      if (subview.nodeName != "children")
+        this._panelViewCache.appendChild(subview);
+    }
   }
 
   goBack(target) {
     let [current, previous] = this.panelViews.back();
     return this.showSubView(current, target, previous);
   }
 
   /**
-   * Checks whether it is possible to navigate backwards currently.
-   * Since the visibility of the back button is dependent - right now - on the
-   * fact that there's a view title set, we use that heuristic to determine this
-   * capability.
+   * Checks whether it is possible to navigate backwards currently. Returns
+   * false if this is the panelmultiview's mainview, true otherwise.
    *
    * @param  {panelview} view View to check, defaults to the currently active view.
    * @return {Boolean}
    */
   _canGoBack(view = this._currentSubView) {
-    return !!view.getAttribute("title");
+    return view != this._mainView;
   }
 
   setMainView(aNewMainView) {
     if (this._mainView) {
       if (!this.panelViews)
         this._subViews.appendChild(this._mainView);
       this._mainView.removeAttribute("mainview");
     }
@@ -355,17 +389,17 @@ this.PanelMultiView = class {
           this.node.setAttribute("viewtype", "main");
         });
       }
 
       this._shiftMainView();
     }
   }
 
-  showSubView(aViewId, aAnchor, aPreviousView, aAdopted = false) {
+  showSubView(aViewId, aAnchor, aPreviousView) {
     const {document, window} = this;
     return (async () => {
       // Support passing in the node directly.
       let viewNode = typeof aViewId == "string" ? this.node.querySelector("#" + aViewId) : aViewId;
       if (!viewNode) {
         viewNode = document.getElementById(aViewId);
         if (viewNode) {
           if (this.panelViews) {
@@ -410,17 +444,17 @@ this.PanelMultiView = class {
       let detail = {
         blockers: new Set(),
         addBlocker(aPromise) {
           this.blockers.add(aPromise);
         },
       };
 
       // Make sure that new panels always have a title set.
-      if (this.panelViews && aAdopted && aAnchor) {
+      if (this.panelViews && aAnchor) {
         if (aAnchor && !viewNode.hasAttribute("title"))
           viewNode.setAttribute("title", aAnchor.getAttribute("label"));
         viewNode.classList.add("PanelUI-subView");
         let custWidget = CustomizableWidgets.find(widget => widget.viewId == viewNode.id);
         if (custWidget) {
           if (custWidget.onInit)
             custWidget.onInit(aAnchor);
           custWidget.onViewShowing({ target: aAnchor, detail });
--- a/browser/components/customizableui/content/panelUI.inc.xul
+++ b/browser/components/customizableui/content/panelUI.inc.xul
@@ -4,17 +4,18 @@
 
 <panel id="PanelUI-popup"
        role="group"
        type="arrow"
        hidden="true"
        flip="slide"
        position="bottomcenter topright"
        noautofocus="true">
-  <panelmultiview id="PanelUI-multiView" mainViewId="PanelUI-mainView">
+  <panelmultiview id="PanelUI-multiView" mainViewId="PanelUI-mainView"
+                  viewCacheId="appMenu-viewCache">
     <panelview id="PanelUI-mainView" context="customizationPanelContextMenu">
       <vbox id="PanelUI-contents-scroller">
         <vbox id="PanelUI-contents" class="panelUI-grid"/>
       </vbox>
 
       <footer id="PanelUI-footer">
         <vbox id="PanelUI-footer-addons"></vbox>
         <toolbarbutton class="panel-banner-item"
@@ -498,17 +499,19 @@
 <panel id="appMenu-popup"
        class="cui-widget-panel"
        role="group"
        type="arrow"
        hidden="true"
        flip="slide"
        position="bottomcenter topright"
        noautofocus="true">
-  <photonpanelmultiview id="appMenu-multiView" mainViewId="appMenu-mainView" descriptionheightworkaround="true">
+  <photonpanelmultiview id="appMenu-multiView" mainViewId="appMenu-mainView"
+                        descriptionheightworkaround="true"
+                        viewCacheId="appMenu-viewCache">
     <panelview id="appMenu-mainView" class="PanelUI-subView">
       <vbox class="panel-subview-body">
         <vbox id="appMenu-addon-banners"/>
         <toolbarbutton class="panel-banner-item"
                        label-update-available="&updateAvailable.panelUI.label;"
                        label-update-manual="&updateManual.panelUI.label;"
                        label-update-restart="&updateRestart.panelUI.label2;"
                        oncommand="PanelUI._onBannerItemSelected(event)"
@@ -561,16 +564,45 @@
                          command="cmd_copy"
                          tooltip="dynamic-shortcut-tooltip"/>
           <toolbarbutton id="appMenu-paste-button"
                          class="subviewbutton subviewbutton-iconic"
                          command="cmd_paste"
                          tooltip="dynamic-shortcut-tooltip"/>
         </toolbaritem>
         <toolbarseparator/>
+        <toolbarbutton id="appMenu-library-button"
+                       class="subviewbutton subviewbutton-iconic subviewbutton-nav"
+                       label="&places.library.title;"
+                       closemenu="none"
+                       oncommand="PanelUI.showSubView('appMenu-libraryView', this)"/>
+        <toolbarbutton id="appMenu-addons-button"
+                       class="subviewbutton subviewbutton-iconic"
+                       label="&addons.label;"
+                       key="key_openAddons"
+                       command="Tools:Addons"
+                       />
+        <toolbarbutton id="appMenu-preferences-button"
+                       class="subviewbutton subviewbutton-iconic"
+#ifdef XP_WIN
+                       label="&preferencesCmd2.label;"
+#else
+                       label="&preferencesCmdUnix.label;"
+#ifdef XP_MACOSX
+                       key="key_preferencesCmdMac"
+#endif
+#endif
+                       oncommand="openPreferences()"
+                       />
+        <toolbarbutton id="appMenu-customize-button"
+                       class="subviewbutton subviewbutton-iconic"
+                       label="&viewCustomizeToolbar.label;"
+                       command="cmd_CustomizeToolbars"
+                       />
+        <toolbarseparator/>
         <toolbarbutton id="appMenu-open-file-button"
                        class="subviewbutton"
                        label="&openFileCmd.label;"
                        key="openFileKb"
                        command="Browser:OpenFile"
                        />
         <toolbarbutton id="appMenu-save-file-button"
                        class="subviewbutton"
@@ -589,65 +621,36 @@
                        key="printKb"
 #ifdef XP_MACOSX
                        command="cmd_print"
 #else
                        command="cmd_printPreview"
 #endif
                        />
         <toolbarseparator/>
-        <toolbarbutton id="appMenu-library-button"
-                       class="subviewbutton subviewbutton-iconic"
-                       label="&places.library.title;"
-                       command="Browser:ShowAllBookmarks"
-                       />
-        <toolbarbutton id="appMenu-addons-button"
-                       class="subviewbutton subviewbutton-iconic"
-                       label="&addons.label;"
-                       key="key_openAddons"
-                       command="Tools:Addons"
-                       />
-        <toolbarbutton id="appMenu-preferences-button"
-                       class="subviewbutton subviewbutton-iconic"
-#ifdef XP_WIN
-                       label="&preferencesCmd2.label;"
-#else
-                       label="&preferencesCmdUnix.label;"
-#ifdef XP_MACOSX
-                       key="key_preferencesCmdMac"
-#endif
-#endif
-                       oncommand="openPreferences()"
-                       />
-        <toolbarbutton id="appMenu-customize-button"
-                       class="subviewbutton subviewbutton-iconic"
-                       label="&viewCustomizeToolbar.label;"
-                       command="cmd_CustomizeToolbars"
-                       />
-        <toolbarseparator/>
         <toolbarbutton id="appMenu-find-button"
                        class="subviewbutton subviewbutton-iconic"
                        label="&findOnCmd.label;"
                        key="key_find"
                        command="cmd_find"/>
         <toolbarbutton id="appMenu-more-button"
                        class="subviewbutton subviewbutton-nav"
                        label="&moreMenu.label;"
                        closemenu="none"
                        oncommand="PanelUI.showSubView('appMenu-moreView', this)"/>
         <toolbarbutton id="appMenu-developer-button"
                        class="subviewbutton subviewbutton-nav"
                        label="&webDeveloperMenu.label;"
                        closemenu="none"
-                       oncommand="PanelUI.showSubView('PanelUI-developer', this, null, true)"/>
+                       oncommand="PanelUI.showSubView('PanelUI-developer', this)"/>
         <toolbarbutton id="appMenu-help-button"
                        class="subviewbutton subviewbutton-iconic subviewbutton-nav"
                        label="&appMenuHelp.label;"
                        closemenu="none"
-                       oncommand="PanelUI.showSubView('PanelUI-helpView', this, null, true)"/>
+                       oncommand="PanelUI.showSubView('PanelUI-helpView', this)"/>
 #ifndef XP_MACOSX
         <toolbarseparator/>
         <toolbarbutton id="appMenu-quit-button"
                        class="subviewbutton subviewbutton-iconic"
 #ifdef XP_WIN
                        label="&quitApplicationCmdWin2.label;"
                        tooltiptext="&quitApplicationCmdWin2.tooltip;"
 #else
@@ -659,19 +662,33 @@
       </vbox>
     </panelview>
     <panelview id="appMenu-moreView" title="&moreMenu.label;" class="PanelUI-subView">
       <vbox class="panel-subview-body">
         <toolbarbutton id="appMenu-characterencoding-button"
                        class="subviewbutton subviewbutton-nav"
                        label="&charsetMenu2.label;"
                        closemenu="none"
-                       oncommand="PanelUI.showSubView('PanelUI-characterEncodingView', this, null, true)"/>
+                       oncommand="PanelUI.showSubView('PanelUI-characterEncodingView', this)"/>
         <toolbarbutton id="appMenu-workoffline-button"
                        class="subviewbutton"
                        label="&goOfflineCmd.label;"
                        type="checkbox"
                        observes="workOfflineMenuitemState"
                        oncommand="BrowserOffline.toggleOfflineStatus();"/>
       </vbox>
     </panelview>
+    <panelview id="appMenu-libraryView" class="PanelUI-subView">
+      <vbox class="panel-subview-body">
+        <toolbarbutton id="appMenu-library-history-button"
+                       class="subviewbutton subviewbutton-iconic subviewbutton-nav"
+                       label="&historyMenu.label;"
+                       closemenu="none"
+                       oncommand="PanelUI.showSubView('PanelUI-history', this)"/>
+        <toolbarbutton id="appMenu-library-remotetabs-button"
+                       class="subviewbutton subviewbutton-iconic subviewbutton-nav"
+                       label="&appMenuRemoteTabs.label;"
+                       closemenu="none"
+                       oncommand="PanelUI.showSubView('PanelUI-remotetabs', this)"/>
+      </vbox>
+    </panelview>
   </photonpanelmultiview>
 </panel>
--- a/browser/components/customizableui/content/panelUI.js
+++ b/browser/components/customizableui/content/panelUI.js
@@ -439,32 +439,32 @@ const PanelUI = {
 
   /**
    * Shows a subview in the panel with a given ID.
    *
    * @param aViewId the ID of the subview to show.
    * @param aAnchor the element that spawned the subview.
    * @param aPlacementArea the CustomizableUI area that aAnchor is in.
    */
-  async showSubView(aViewId, aAnchor, aPlacementArea, aAdopted = false) {
+  async showSubView(aViewId, aAnchor, aPlacementArea) {
     this._ensureEventListenersAdded();
     let viewNode = document.getElementById(aViewId);
     if (!viewNode) {
       Cu.reportError("Could not show panel subview with id: " + aViewId);
       return;
     }
 
     if (!aAnchor) {
       Cu.reportError("Expected an anchor when opening subview with id: " + aViewId);
       return;
     }
 
     let container = aAnchor.closest("panelmultiview,photonpanelmultiview");
     if (container) {
-      container.showSubView(aViewId, aAnchor, null, aAdopted);
+      container.showSubView(aViewId, aAnchor);
     } else if (!aAnchor.open) {
       aAnchor.open = true;
 
       let tempPanel = document.createElement("panel");
       tempPanel.setAttribute("type", "arrow");
       tempPanel.setAttribute("id", "customizationui-widget-panel");
       tempPanel.setAttribute("class", "cui-widget-panel");
       tempPanel.setAttribute("viewId", aViewId);
@@ -475,19 +475,24 @@ const PanelUI = {
         tempPanel.setAttribute("animate", "false");
       }
       tempPanel.setAttribute("context", "");
       document.getElementById(CustomizableUI.AREA_NAVBAR).appendChild(tempPanel);
       // If the view has a footer, set a convenience class on the panel.
       tempPanel.classList.toggle("cui-widget-panelWithFooter",
                                  viewNode.querySelector(".panel-subview-footer"));
 
-      let multiView = document.createElement("panelmultiview");
+      let multiView = document.createElement(gPhotonStructure ? "photonpanelmultiview" : "panelmultiview");
       multiView.setAttribute("id", "customizationui-widget-multiview");
       multiView.setAttribute("nosubviews", "true");
+      multiView.setAttribute("viewCacheId", "appMenu-viewCache");
+      if (gPhotonStructure) {
+        multiView.setAttribute("mainViewId", viewNode.id);
+        multiView.appendChild(viewNode);
+      }
       tempPanel.appendChild(multiView);
       multiView.setAttribute("mainViewIsSubView", "true");
       multiView.setMainView(viewNode);
       viewNode.classList.add("cui-widget-panelview");
 
       let viewShown = false;
       let panelRemover = () => {
         viewNode.classList.remove("cui-widget-panelview");
@@ -495,17 +500,19 @@ const PanelUI = {
           CustomizableUI.removePanelCloseListeners(tempPanel);
           tempPanel.removeEventListener("popuphidden", panelRemover);
 
           let evt = new CustomEvent("ViewHiding", {detail: viewNode});
           viewNode.dispatchEvent(evt);
         }
         aAnchor.open = false;
 
-        this.multiView.appendChild(viewNode);
+        // Ensure we run the destructor:
+        multiView.instance.destructor();
+
         tempPanel.remove();
       };
 
       // Emit the ViewShowing event so that the widget definition has a chance
       // to lazily populate the subview with things.
       let detail = {
         blockers: new Set(),
         addBlocker(aPromise) {
--- a/browser/extensions/pdfjs/content/PdfJs.jsm
+++ b/browser/extensions/pdfjs/content/PdfJs.jsm
@@ -62,20 +62,20 @@ function getIntPref(aPref, aDefaultValue
   try {
     return Services.prefs.getIntPref(aPref);
   } catch (ex) {
     return aDefaultValue;
   }
 }
 
 function isDefaultHandler() {
- if (Services.appinfo.processType === Services.appinfo.PROCESS_TYPE_CONTENT) {
-   return PdfjsContentUtils.isDefaultHandlerApp();
- }
- return PdfjsChromeUtils.isDefaultHandlerApp();
+  if (Services.appinfo.processType !== Services.appinfo.PROCESS_TYPE_DEFAULT) {
+    throw new Error("isDefaultHandler should only get called in the parent process.");
+  }
+  return PdfjsChromeUtils.isDefaultHandlerApp();
 }
 
 function initializeDefaultPreferences() {
   var DEFAULT_PREFERENCES =
 {
   "showPreviousViewOnLoad": true,
   "defaultZoomValue": "",
   "sidebarViewOnLoad": 0,
@@ -264,23 +264,24 @@ var PdfJs = {
     categoryManager.getService(Ci.nsICategoryManager).
                     deleteCategoryEntry("Gecko-Content-Viewers",
                                         PDF_CONTENT_TYPE,
                                         false);
   },
 
   // nsIObserver
   observe: function observe(aSubject, aTopic, aData) {
+    if (Services.appinfo.processType !== Services.appinfo.PROCESS_TYPE_DEFAULT) {
+      throw new Error("Only the parent process should be observing PDF handler changes.");
+    }
+
     this.updateRegistration();
-    if (Services.appinfo.processType ===
-        Services.appinfo.PROCESS_TYPE_DEFAULT) {
-      let jsm = "resource://pdf.js/PdfjsChromeUtils.jsm";
-      let PdfjsChromeUtils = Components.utils.import(jsm, {}).PdfjsChromeUtils;
-      PdfjsChromeUtils.notifyChildOfSettingsChange();
-    }
+    let jsm = "resource://pdf.js/PdfjsChromeUtils.jsm";
+    let PdfjsChromeUtils = Components.utils.import(jsm, {}).PdfjsChromeUtils;
+    PdfjsChromeUtils.notifyChildOfSettingsChange(this.enabled);
   },
 
   /**
    * 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() {
--- a/browser/extensions/pdfjs/content/PdfjsChromeUtils.jsm
+++ b/browser/extensions/pdfjs/content/PdfjsChromeUtils.jsm
@@ -119,25 +119,25 @@ var PdfjsChromeUtils = {
   },
 
   /*
    * Called by the main module when preference changes are picked up
    * in the parent process. Observers don't propagate so we need to
    * instruct the child to refresh its configuration and (possibly)
    * the module's registration.
    */
-  notifyChildOfSettingsChange() {
+  notifyChildOfSettingsChange(enabled) {
     if (Services.appinfo.processType ===
         Services.appinfo.PROCESS_TYPE_DEFAULT && this._ppmm) {
       // XXX kinda bad, we want to get the parent process mm associated
       // with the content process. _ppmm is currently the global process
       // manager, which means this is going to fire to every child process
       // we have open. Unfortunately I can't find a way to get at that
       // process specific mm from js.
-      this._ppmm.broadcastAsyncMessage("PDFJS:Child:refreshSettings", {});
+      this._ppmm.broadcastAsyncMessage("PDFJS:Child:updateSettings", {enabled});
     }
   },
 
   /*
    * Events
    */
 
   observe(aSubject, aTopic, aData) {
--- a/browser/extensions/pdfjs/content/PdfjsContentUtils.jsm
+++ b/browser/extensions/pdfjs/content/PdfjsContentUtils.jsm
@@ -38,25 +38,25 @@ var PdfjsContentUtils = {
   },
 
   init() {
     // child *process* mm, or when loaded into the parent for in-content
     // support the psuedo child process mm 'child PPMM'.
     if (!this._mm) {
       this._mm = Cc["@mozilla.org/childprocessmessagemanager;1"].
         getService(Ci.nsISyncMessageSender);
-      this._mm.addMessageListener("PDFJS:Child:refreshSettings", this);
+      this._mm.addMessageListener("PDFJS:Child:updateSettings", this);
 
       Services.obs.addObserver(this, "quit-application");
     }
   },
 
   uninit() {
     if (this._mm) {
-      this._mm.removeMessageListener("PDFJS:Child:refreshSettings", this);
+      this._mm.removeMessageListener("PDFJS:Child:updateSettings", this);
       Services.obs.removeObserver(this, "quit-application");
     }
     this._mm = null;
   },
 
   /*
    * prefs utilities - the child does not have write access to prefs.
    * note, the pref names here are cross-checked against a list of
@@ -93,24 +93,16 @@ var PdfjsContentUtils = {
   setStringPref(aPrefName, aPrefValue) {
     this._mm.sendSyncMessage("PDFJS:Parent:setStringPref", {
       name: aPrefName,
       value: aPrefValue
     });
   },
 
   /*
-   * Forwards default app query to the parent where we check various
-   * handler app settings only available in the parent process.
-   */
-  isDefaultHandlerApp() {
-    return this._mm.sendSyncMessage("PDFJS:Parent:isDefaultHandlerApp")[0];
-  },
-
-  /*
    * Request the display of a notification warning in the associated window
    * when the renderer isn't sure a pdf displayed correctly.
    */
   displayWarning(aWindow, aMessage, aLabel, aAccessKey) {
     // the child's dom frame mm associated with the window.
     let winmm = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                        .getInterface(Ci.nsIDocShell)
                        .QueryInterface(Ci.nsIInterfaceRequestor)
@@ -129,21 +121,25 @@ var PdfjsContentUtils = {
   observe(aSubject, aTopic, aData) {
     if (aTopic === "quit-application") {
       this.uninit();
     }
   },
 
   receiveMessage(aMsg) {
     switch (aMsg.name) {
-      case "PDFJS:Child:refreshSettings":
+      case "PDFJS:Child:updateSettings":
         // Only react to this if we are remote.
         if (Services.appinfo.processType ===
             Services.appinfo.PROCESS_TYPE_CONTENT) {
           let jsm = "resource://pdf.js/PdfJs.jsm";
           let pdfjs = Components.utils.import(jsm, {}).PdfJs;
-          pdfjs.updateRegistration();
+          if (aMsg.data.enabled) {
+            pdfjs.ensureRegistered();
+          } else {
+            pdfjs.ensureUnregistered();
+          }
         }
         break;
     }
   }
 };
 
--- a/browser/extensions/pocket/content/main.js
+++ b/browser/extensions/pocket/content/main.js
@@ -546,17 +546,17 @@ var pktUI = (function() {
             frame.setAttribute("type", "content");
             frameParent.appendChild(frame);
         }
         return frame;
     }
 
     function getSubview() {
         var view = document.getElementById("PanelUI-pocketView");
-        if (view && view.getAttribute("current") == "true")
+        if (view && view.getAttribute("current") == "true" && !view.getAttribute("mainview"))
             return view;
         return null;
     }
 
     function isInOverflowMenu() {
         var subview = getSubview();
         return !!subview;
     }
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -746,19 +746,19 @@
 @RESPATH@/chrome/pippki.manifest
 @RESPATH@/components/pipnss.xpt
 @RESPATH@/components/pippki.xpt
 
 ; For process sandboxing
 #if defined(MOZ_SANDBOX)
 #if defined(XP_LINUX)
 @BINPATH@/@DLL_PREFIX@mozsandbox@DLL_SUFFIX@
+#endif
 @RESPATH@/components/sandbox.xpt
 #endif
-#endif
 
 ; for Solaris SPARC
 #ifdef SOLARIS
 bin/libfreebl_32fpu_3.so
 bin/libfreebl_32int_3.so
 bin/libfreebl_32int64_3.so
 #endif
 
--- a/browser/themes/shared/browser.inc
+++ b/browser/themes/shared/browser.inc
@@ -1,16 +1,16 @@
 %filter substitution
 
 % Note that zoom-reset-button is a bit different since it doesn't use an image and thus has the image with display: none.
 %define nestedButtons #zoom-out-button, #zoom-reset-button, #zoom-in-button, #cut-button, #copy-button, #paste-button
 %define primaryToolbarButtons #back-button, #forward-button, #home-button, #print-button, #downloads-button, #bookmarks-menu-button, #new-tab-button, #new-window-button, #fullscreen-button, #sync-button, #feed-button, #social-share-button, #open-file-button, #find-button, #developer-button, #preferences-button, #privatebrowsing-button, #save-page-button, #add-ons-button, #history-panelmenu, #nav-bar-overflow-button, #PanelUI-menu-button, #characterencoding-button, #email-link-button, #sidebar-button, @nestedButtons@, #e10s-button, #panic-button, #webide-button, #containers-panelmenu
 
 %ifdef MOZ_PHOTON_THEME
-%define primaryToolbarButtons @primaryToolbarButtons@, #reload-button, #stop-button
+%define primaryToolbarButtons @primaryToolbarButtons@, #reload-button, #stop-button, #library-button
 %endif
 
 %ifdef XP_MACOSX
 % Prior to 10.7 there wasn't a native fullscreen button so we use #restore-button to exit fullscreen
 % and want it to behave like other toolbar buttons.
 %define primaryToolbarButtons @primaryToolbarButtons@, #restore-button
 %endif
 
--- a/browser/themes/shared/toolbarbutton-icons.inc.css
+++ b/browser/themes/shared/toolbarbutton-icons.inc.css
@@ -191,8 +191,12 @@ toolbar:not([brighttext]) #bookmarks-men
 
 #panic-button[cui-areatype="toolbar"][open] {
   fill: rgb(213, 32, 20);
 }
 
 #webide-button[cui-areatype="toolbar"] {
   list-style-image: url("chrome://browser/skin/webIDE.svg");
 }
+
+#library-button {
+  list-style-image: url("chrome://browser/skin/library.svg");
+}
--- a/browser/tools/mozscreenshots/mozscreenshots/extension/TestRunner.jsm
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/TestRunner.jsm
@@ -85,16 +85,22 @@ this.TestRunner = {
     // Setup some prefs
     Services.prefs.setCharPref("browser.aboutHomeSnippets.updateUrl",
                                "data:text/html;charset=utf-8,Generated by mozscreenshots");
     Services.prefs.setCharPref("extensions.ui.lastCategory", "addons://list/extension");
     // Don't let the caret blink since it causes false positives for image diffs
     Services.prefs.setIntPref("ui.caretBlinkTime", -1);
 
     let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+
+    // When being automated through Marionette, Firefox shows a prominent indication
+    // in the urlbar and identity block. We don't want this to show when testing browser UI.
+    // Note that this doesn't prevent subsequently opened windows from showing the automation UI.
+    browserWindow.document.getElementById("main-window").removeAttribute("remotecontrol");
+
     let selectedBrowser = browserWindow.gBrowser.selectedBrowser;
     await BrowserTestUtils.loadURI(selectedBrowser, HOME_PAGE);
     await BrowserTestUtils.browserLoaded(selectedBrowser);
 
     for (let i = 0; i < this.combos.length; i++) {
       this.currentComboIndex = i;
       await this._performCombo(this.combos.item(this.currentComboIndex));
     }
--- a/devtools/server/tests/mochitest/test_getProcess.html
+++ b/devtools/server/tests/mochitest/test_getProcess.html
@@ -111,16 +111,17 @@ function runTests() {
       let actor = response.form;
       is(actor, firstActor,
          "Second call to getProcess with the same id returns the same form");
       closeClient();
     });
   }
 
   function processScript() {
+    Components.utils.import("resource://gre/modules/Services.jsm");
     let listener = function () {
       Services.obs.removeObserver(listener, "sdk:loader:destroy");
       sendAsyncMessage("test:getProcess-destroy", null);
     };
     Services.obs.addObserver(listener, "sdk:loader:destroy");
   }
 
   function closeClient() {
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -73,16 +73,17 @@
 #include "imgLoader.h"
 #include "GMPServiceChild.h"
 
 #ifdef MOZ_GECKO_PROFILER
 #include "ChildProfilerController.h"
 #endif
 
 #if defined(MOZ_CONTENT_SANDBOX)
+#include "mozilla/SandboxSettings.h"
 #if defined(XP_WIN)
 #define TARGET_SANDBOX_EXPORTS
 #include "mozilla/sandboxTarget.h"
 #elif defined(XP_LINUX)
 #include "mozilla/Sandbox.h"
 #include "mozilla/SandboxInfo.h"
 
 // Remove this include with Bug 1104619
@@ -1337,17 +1338,17 @@ GetDirectoryPath(const char *aPath) {
   }
   return directoryPath;
 }
 #endif // DEBUG
 
 static bool
 StartMacOSContentSandbox()
 {
-  int sandboxLevel = Preferences::GetInt("security.sandbox.content.level");
+  int sandboxLevel = GetEffectiveContentSandboxLevel();
   if (sandboxLevel < 1) {
     return false;
   }
 
   nsAutoCString appPath, appBinaryPath, appDir;
   if (!GetAppPaths(appPath, appBinaryPath, appDir)) {
     MOZ_CRASH("Error resolving child process path");
   }
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -224,21 +224,24 @@
 #include "mozilla/RemoteSpellCheckEngineParent.h"
 
 #include "Crypto.h"
 
 #ifdef MOZ_WEBSPEECH
 #include "mozilla/dom/SpeechSynthesisParent.h"
 #endif
 
-#if defined(MOZ_CONTENT_SANDBOX) && defined(XP_LINUX)
+#if defined(MOZ_CONTENT_SANDBOX)
+#include "mozilla/SandboxSettings.h"
+#if defined(XP_LINUX)
 #include "mozilla/SandboxInfo.h"
 #include "mozilla/SandboxBroker.h"
 #include "mozilla/SandboxBrokerPolicyFactory.h"
 #endif
+#endif
 
 #ifdef MOZ_TOOLKIT_SEARCH
 #include "nsIBrowserSearchService.h"
 #endif
 
 #ifdef XP_WIN
 #include "mozilla/widget/AudioSession.h"
 #endif
@@ -2310,17 +2313,17 @@ ContentParent::InitInternal(ProcessPrior
   bool shouldSandbox = true;
   MaybeFileDesc brokerFd = void_t();
 #ifdef XP_LINUX
   // XXX: Checking the pref here makes it possible to enable/disable sandboxing
   // during an active session. Currently the pref is only used for testing
   // purpose. If the decision is made to permanently rely on the pref, this
   // should be changed so that it is required to restart firefox for the change
   // of value to take effect.
-  shouldSandbox = (Preferences::GetInt("security.sandbox.content.level") > 0) &&
+  shouldSandbox = (GetEffectiveContentSandboxLevel() > 0) &&
     !PR_GetEnv("MOZ_DISABLE_CONTENT_SANDBOX");
 
   if (shouldSandbox) {
     MOZ_ASSERT(!mSandboxBroker);
     UniquePtr<SandboxBroker::Policy> policy =
       sSandboxBrokerPolicyFactory->GetContentPolicy(Pid());
     if (policy) {
       brokerFd = FileDescriptor();
--- a/dom/ipc/ContentProcess.cpp
+++ b/dom/ipc/ContentProcess.cpp
@@ -10,33 +10,34 @@
 #include "ContentPrefs.h"
 
 #if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
 #include <stdlib.h>
 #endif
 
 #if (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
 #include "mozilla/Preferences.h"
+#include "mozilla/SandboxSettings.h"
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsDirectoryService.h"
 #include "nsDirectoryServiceDefs.h"
 #endif
 
 using mozilla::ipc::IOThreadChild;
 
 namespace mozilla {
 namespace dom {
 
 #if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
 static bool
 IsSandboxTempDirRequired()
 {
   // On Windows, a sandbox-writable temp directory is only used
   // when sandbox pref level >= 1.
-  return Preferences::GetInt("security.sandbox.content.level") >= 1;
+  return GetEffectiveContentSandboxLevel() >= 1;
 }
 
 static void
 SetTmpEnvironmentVariable(nsIFile* aValue)
 {
   // Save the TMP environment variable so that is is picked up by GetTempPath().
   // Note that we specifically write to the TMP variable, as that is the first
   // variable that is checked by GetTempPath() to determine its output.
@@ -52,17 +53,17 @@ SetTmpEnvironmentVariable(nsIFile* aValu
 }
 #endif
 
 #if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
 static bool
 IsSandboxTempDirRequired()
 {
   // On OSX, use the sandbox-writable temp when the pref level >= 1.
-  return (Preferences::GetInt("security.sandbox.content.level") >= 1);
+  return (GetEffectiveContentSandboxLevel() >= 1);
 }
 
 static void
 SetTmpEnvironmentVariable(nsIFile* aValue)
 {
   nsAutoCString fullTmpPath;
   nsresult rv = aValue->GetNativePath(fullTmpPath);
   if (NS_WARN_IF(NS_FAILED(rv))) {
--- a/dom/locales/en-US/chrome/dom/dom.properties
+++ b/dom/locales/en-US/chrome/dom/dom.properties
@@ -142,20 +142,20 @@ MediaCannotInitializePulseAudio=Unable t
 # LOCALIZATION NOTE: Do not translate "MediaRecorder".
 MediaRecorderMultiTracksNotSupported=MediaRecorder does not support recording multiple tracks of the same type at this time.
 # LOCALIZATION NOTE: %S is the ID of the MediaStreamTrack passed to MediaStream.addTrack(). Do not translate "MediaStreamTrack" and "AudioChannel".
 MediaStreamAddTrackDifferentAudioChannel=MediaStreamTrack %S could not be added since it belongs to a different AudioChannel.
 # LOCALIZATION NOTE: Do not translate "MediaStream", "stop()" and "MediaStreamTrack"
 MediaStreamStopDeprecatedWarning=MediaStream.stop() is deprecated and will soon be removed. Use MediaStreamTrack.stop() instead.
 # LOCALIZATION NOTE: %S is the URL of the web page which is not served on HTTPS and thus is not encrypted and considered insecure.
 MediaEMEInsecureContextDeprecatedWarning=Using Encrypted Media Extensions at %S on an insecure (i.e. non-HTTPS) context is deprecated and will soon be removed. You should consider switching to a secure origin such as HTTPS.
-# LOCALIZATION NOTE: %S is the URL of the web page which is calling web APIs without passing data (either an audioCapabilities or a videoCapabilities) that will soon be required.
+# LOCALIZATION NOTE: %S is the URL of the web page which is calling web APIs without passing data (either an audioCapabilities or a videoCapabilities) that will soon be required. See https://bugzilla.mozilla.org/show_bug.cgi?id=1368583#c21 for explanation of this string.
 MediaEMENoCapabilitiesDeprecatedWarning=Calling navigator.requestMediaKeySystemAccess() (at %S) without passing a candidate MediaKeySystemConfiguration containing audioCapabilities or videoCapabilities is deprecated and will soon become unsupported.
-# LOCALIZATION NOTE: %S is the URL of the web page which is calling web APIs without passing data (a "codecs" string in the "contentType") that will soon be required.
-MediaEMENoCodecsDeprecatedWarning=Calling navigator.requestMediaKeySystemAccess() (at %S) without passing a candidate MediaKeySystemConfiguration containing audioCapabilities or videoCapabilities without a contentType with a “codecs” string is deprecated and will soon become unsupported.
+# LOCALIZATION NOTE: %S is the URL of the web page which is calling web APIs without passing data (a "codecs" string in the "contentType") that will soon be required. See https://bugzilla.mozilla.org/show_bug.cgi?id=1368583#c21 for explanation of this string.
+MediaEMENoCodecsDeprecatedWarning=Calling navigator.requestMediaKeySystemAccess() (at %S) passing a candidate MediaKeySystemConfiguration containing audioCapabilities or videoCapabilities without a contentType with a “codecs” string is deprecated and will soon become unsupported.
 # LOCALIZATION NOTE: Do not translate "DOMException", "code" and "name"
 DOMExceptionCodeWarning=Use of DOMException’s code attribute is deprecated. Use name instead.
 # LOCALIZATION NOTE: Do not translate "__exposedProps__"
 NoExposedPropsWarning=Exposing chrome JS objects to content without __exposedProps__ is insecure and deprecated. See https://developer.mozilla.org/en/XPConnect_wrappers for more information.
 # LOCALIZATION NOTE: Do not translate "Mutation Event" and "MutationObserver"
 MutationEventWarning=Use of Mutation Events is deprecated. Use MutationObserver instead.
 # LOCALIZATION NOTE: Do not translate "Components"
 ComponentsWarning=The Components object is deprecated. It will soon be removed.
--- a/dom/media/BufferMediaResource.h
+++ b/dom/media/BufferMediaResource.h
@@ -70,17 +70,20 @@ private:
   }
   int64_t Tell() override { return mOffset; }
 
   void Pin() override {}
   void Unpin() override {}
   double GetDownloadRate(bool* aIsReliable) override { *aIsReliable = false; return 0.; }
   int64_t GetLength() override { return mLength; }
   int64_t GetNextCachedData(int64_t aOffset) override { return aOffset; }
-  int64_t GetCachedDataEnd(int64_t aOffset) override { return mLength; }
+  int64_t GetCachedDataEnd(int64_t aOffset) override
+  {
+    return std::max(aOffset, int64_t(mLength));
+  }
   bool IsDataCachedToEndOfResource(int64_t aOffset) override { return true; }
   bool IsSuspendedByCache() override { return false; }
   bool IsSuspended() override { return false; }
   nsresult ReadFromCache(char* aBuffer,
                          int64_t aOffset,
                          uint32_t aCount) override
   {
     if (aOffset < 0) {
--- a/dom/media/MediaPrefs.h
+++ b/dom/media/MediaPrefs.h
@@ -81,16 +81,19 @@ private:
     {
       AssertMainThread();
       PrefAddVarCache(&mValue, aPreference, mValue);
     }
   };
 
   // This is where DECL_MEDIA_PREF for each of the preferences should go.
 
+  // Cache sizes.
+  DECL_MEDIA_PREF("media.cache.resource-index",               MediaResourceIndexCache, uint32_t, 8192);
+
   // AudioSink
   DECL_MEDIA_PREF("accessibility.monoaudio.enable",           MonoAudio, bool, false);
   DECL_MEDIA_PREF("media.resampling.enabled",                 AudioSinkResampling, bool, false);
   DECL_MEDIA_PREF("media.resampling.rate",                    AudioSinkResampleRate, uint32_t, 48000);
 #if defined(XP_WIN) || defined(XP_DARWIN) || defined(MOZ_PULSEAUDIO)
   // libcubeb backend implement .get_preferred_channel_layout
   DECL_MEDIA_PREF("media.forcestereo.enabled",                AudioSinkForceStereo, bool, false);
 #else
--- a/dom/media/MediaResource.cpp
+++ b/dom/media/MediaResource.cpp
@@ -30,22 +30,30 @@
 #include "nsHostObjectProtocolHandler.h"
 #include <algorithm>
 #include "nsProxyRelease.h"
 #include "nsIContentPolicy.h"
 
 using mozilla::media::TimeUnit;
 
 #undef LOG
+#undef ILOG
 
 mozilla::LazyLogModule gMediaResourceLog("MediaResource");
 // Debug logging macro with object pointer and class name.
 #define LOG(msg, ...) MOZ_LOG(gMediaResourceLog, mozilla::LogLevel::Debug, \
   ("%p " msg, this, ##__VA_ARGS__))
 
+mozilla::LazyLogModule gMediaResourceIndexLog("MediaResourceIndex");
+// Debug logging macro with object pointer and class name.
+#define ILOG(msg, ...)                                                         \
+  MOZ_LOG(gMediaResourceIndexLog,                                              \
+          mozilla::LogLevel::Debug,                                            \
+          ("%p " msg, this, ##__VA_ARGS__))
+
 static const uint32_t HTTP_OK_CODE = 200;
 static const uint32_t HTTP_PARTIAL_RESPONSE_CODE = 206;
 
 namespace mozilla {
 
 void
 MediaResource::Destroy()
 {
@@ -1638,32 +1646,347 @@ MediaResourceIndex::Read(char* aBuffer, 
   nsresult rv = ReadAt(mOffset, aBuffer, aCount, aBytes);
   if (NS_FAILED(rv)) {
     return rv;
   }
   mOffset += *aBytes;
   return NS_OK;
 }
 
+static nsCString
+ResultName(nsresult aResult)
+{
+  nsCString name;
+  GetErrorName(aResult, name);
+  return name;
+}
+
 nsresult
-MediaResourceIndex::ReadAt(int64_t aOffset, char* aBuffer,
-                           uint32_t aCount, uint32_t* aBytes) const
+MediaResourceIndex::ReadAt(int64_t aOffset,
+                           char* aBuffer,
+                           uint32_t aCount,
+                           uint32_t* aBytes)
+{
+  if (mCacheBlockSize == 0) {
+    return UncachedReadAt(aOffset, aBuffer, aCount, aBytes);
+  }
+
+  *aBytes = 0;
+
+  if (aCount == 0) {
+    return NS_OK;
+  }
+
+  const int64_t endOffset = aOffset + aCount;
+  const int64_t lastBlockOffset = CacheOffsetContaining(endOffset - 1);
+
+  if (mCachedBytes != 0 && mCachedOffset + mCachedBytes >= aOffset &&
+      mCachedOffset < endOffset) {
+    // There is data in the cache that is not completely before aOffset and not
+    // completely after endOffset, so it could be usable (with potential top-up).
+    if (aOffset < mCachedOffset) {
+      // We need to read before the cached data.
+      const uint32_t toRead = uint32_t(mCachedOffset - aOffset);
+      MOZ_ASSERT(toRead > 0);
+      MOZ_ASSERT(toRead < aCount);
+      uint32_t read = 0;
+      nsresult rv = UncachedReadAt(aOffset, aBuffer, toRead, &read);
+      if (NS_FAILED(rv)) {
+        ILOG("ReadAt(%" PRIu32 "@%" PRId64
+             ") uncached read before cache -> %s, %" PRIu32,
+             aCount,
+             aOffset,
+             ResultName(rv).get(),
+             *aBytes);
+        return rv;
+      }
+      *aBytes = read;
+      if (read < toRead) {
+        // Could not read everything we wanted, we're done.
+        ILOG("ReadAt(%" PRIu32 "@%" PRId64
+             ") uncached read before cache, incomplete -> OK, %" PRIu32,
+             aCount,
+             aOffset,
+             *aBytes);
+        return NS_OK;
+      }
+      ILOG("ReadAt(%" PRIu32 "@%" PRId64
+           ") uncached read before cache: %" PRIu32 ", remaining: %" PRIu32
+           "@%" PRId64 "...",
+           aCount,
+           aOffset,
+           read,
+           aCount - read,
+           aOffset + read);
+      aOffset += read;
+      aBuffer += read;
+      aCount -= read;
+      // We should have reached the cache.
+      MOZ_ASSERT(aOffset == mCachedOffset);
+    }
+    MOZ_ASSERT(aOffset >= mCachedOffset);
+
+    // We've reached our cache.
+    const uint32_t toCopy =
+      std::min(aCount, uint32_t(mCachedOffset + mCachedBytes - aOffset));
+    // Note that we could in fact be just after the last byte of the cache, in
+    // which case we can't actually read from it! (But we will top-up next.)
+    if (toCopy != 0) {
+      memcpy(aBuffer, &mCachedBlock[IndexInCache(aOffset)], toCopy);
+      *aBytes += toCopy;
+      aCount -= toCopy;
+      if (aCount == 0) {
+        // All done!
+        ILOG("ReadAt(%" PRIu32 "@%" PRId64 ") copied everything (%" PRIu32
+             ") from cache(%" PRIu32 "@%" PRId64 ") :-D -> OK, %" PRIu32,
+             aCount,
+             aOffset,
+             toCopy,
+             mCachedBytes,
+             mCachedOffset,
+             *aBytes);
+        return NS_OK;
+      }
+      aOffset += toCopy;
+      aBuffer += toCopy;
+      ILOG("ReadAt(%" PRIu32 "@%" PRId64 ") copied %" PRIu32
+           " from cache(%" PRIu32 "@%" PRId64 ") :-), remaining: %" PRIu32
+           "@%" PRId64 "...",
+           aCount + toCopy,
+           aOffset - toCopy,
+           toCopy,
+           mCachedBytes,
+           mCachedOffset,
+           aCount,
+           aOffset);
+    }
+
+    if (aOffset - 1 >= lastBlockOffset) {
+      // We were already reading cached data from the last block, we need more
+      // from it -> try to top-up, read what we can, and we'll be done.
+      MOZ_ASSERT(aOffset == mCachedOffset + mCachedBytes);
+      MOZ_ASSERT(endOffset <= lastBlockOffset + mCacheBlockSize);
+      return CacheOrReadAt(aOffset, aBuffer, aCount, aBytes);
+    }
+
+    // We were not in the last block (but we may just have crossed the line now)
+    MOZ_ASSERT(aOffset <= lastBlockOffset);
+    // Continue below...
+  } else if (aOffset >= lastBlockOffset) {
+    // There was nothing we could get from the cache.
+    // But we're already in the last block -> Cache or read what we can.
+    // Make sure to invalidate the cache first.
+    mCachedBytes = 0;
+    return CacheOrReadAt(aOffset, aBuffer, aCount, aBytes);
+  }
+
+  // If we're here, either there was nothing usable in the cache, or we've just
+  // read what was in the cache but there's still more to read.
+
+  if (aOffset < lastBlockOffset) {
+    // We need to read before the last block.
+    // Start with an uncached read up to the last block.
+    const uint32_t toRead = uint32_t(lastBlockOffset - aOffset);
+    MOZ_ASSERT(toRead > 0);
+    MOZ_ASSERT(toRead < aCount);
+    uint32_t read = 0;
+    nsresult rv = UncachedReadAt(aOffset, aBuffer, toRead, &read);
+    if (NS_FAILED(rv)) {
+      ILOG("ReadAt(%" PRIu32 "@%" PRId64
+           ") uncached read before last block failed -> %s, %" PRIu32,
+           aCount,
+           aOffset,
+           ResultName(rv).get(),
+           *aBytes);
+      return rv;
+    }
+    if (read == 0) {
+      ILOG("ReadAt(%" PRIu32 "@%" PRId64
+           ") uncached read 0 before last block -> OK, %" PRIu32,
+           aCount,
+           aOffset,
+           *aBytes);
+      return NS_OK;
+    }
+    *aBytes += read;
+    if (read < toRead) {
+      // Could not read everything we wanted, we're done.
+      ILOG("ReadAt(%" PRIu32 "@%" PRId64
+           ") uncached read before last block, incomplete -> OK, %" PRIu32,
+           aCount,
+           aOffset,
+           *aBytes);
+      return NS_OK;
+    }
+    ILOG("ReadAt(%" PRIu32 "@%" PRId64 ") read %" PRIu32
+         " before last block, remaining: %" PRIu32 "@%" PRId64 "...",
+         aCount,
+         aOffset,
+         read,
+         aCount - read,
+         aOffset + read);
+    aOffset += read;
+    aBuffer += read;
+    aCount -= read;
+  }
+
+  // We should just have reached the start of the last block.
+  MOZ_ASSERT(aOffset == lastBlockOffset);
+  MOZ_ASSERT(aCount <= mCacheBlockSize);
+  // Make sure to invalidate the cache first.
+  mCachedBytes = 0;
+  return CacheOrReadAt(aOffset, aBuffer, aCount, aBytes);
+}
+
+nsresult
+MediaResourceIndex::CacheOrReadAt(int64_t aOffset,
+                                  char* aBuffer,
+                                  uint32_t aCount,
+                                  uint32_t* aBytes)
+{
+  // We should be here because there is more data to read.
+  MOZ_ASSERT(aCount > 0);
+  // We should be in the last block, so we shouldn't try to read past it.
+  MOZ_ASSERT(IndexInCache(aOffset) + aCount <= mCacheBlockSize);
+
+  const int64_t length = GetLength();
+  // If length is unknown (-1), look at resource-cached data.
+  // If length is known and equal or greater than requested, also look at
+  // resource-cached data.
+  // Otherwise, if length is known but same, or less than(!?), requested, don't
+  // attempt to access resource-cached data, as we're not expecting it to ever
+  // be greater than the length.
+  if (length < 0 || length >= aOffset + aCount) {
+    // Is there cached data covering at least the requested range?
+    const int64_t cachedDataEnd = mResource->GetCachedDataEnd(aOffset);
+    if (cachedDataEnd >= aOffset + aCount) {
+      // Try to read as much resource-cached data as can fill our local cache.
+      const uint32_t cacheIndex = IndexInCache(aOffset);
+      const uint32_t toRead =
+        uint32_t(std::min(cachedDataEnd - aOffset,
+                          int64_t(mCacheBlockSize - cacheIndex)));
+      MOZ_ASSERT(toRead >= aCount);
+      nsresult rv =
+        mResource->ReadFromCache(&mCachedBlock[cacheIndex], aOffset, toRead);
+      if (NS_SUCCEEDED(rv)) {
+        // Success means we have read the full `toRead` amount.
+        if (mCachedOffset + mCachedBytes == aOffset) {
+          // We were topping-up the cache, just update its size.
+          ILOG("ReadAt(%" PRIu32 "@%" PRId64 ") - ReadFromCache(%" PRIu32
+               "@%" PRId64 ") to top-up succeeded...",
+               aCount,
+               aOffset,
+               toRead,
+               aOffset);
+          mCachedBytes += toRead;
+        } else {
+          // We were filling the cache from scratch, save new cache information.
+          ILOG("ReadAt(%" PRIu32 "@%" PRId64 ") - ReadFromCache(%" PRIu32
+               "@%" PRId64 ") to fill cache succeeded...",
+               aCount,
+               aOffset,
+               toRead,
+               aOffset);
+          mCachedOffset = aOffset;
+          mCachedBytes = toRead;
+        }
+        // Copy relevant part into output.
+        memcpy(aBuffer, &mCachedBlock[cacheIndex], aCount);
+        *aBytes += aCount;
+        ILOG("ReadAt(%" PRIu32 "@%" PRId64 ") - copied %" PRIu32 "@%" PRId64
+             " -> OK, %" PRIu32,
+             aCount,
+             aOffset,
+             aCount,
+             aOffset,
+             *aBytes);
+        // We may not have read all that was requested, but we got everything
+        // we could get, so we're done.
+        return NS_OK;
+      }
+      ILOG("ReadAt(%" PRIu32 "@%" PRId64 ") - ReadFromCache(%" PRIu32
+           "@%" PRId64 ") failed: %s, will fallback to blocking read...",
+           aCount,
+           aOffset,
+           toRead,
+           aOffset,
+           ResultName(rv).get());
+      // Failure during reading. Note that this may be due to the cache
+      // changing between `GetCachedDataEnd` and `ReadFromCache`, so it's not
+      // totally unexpected, just hopefully rare; but we do need to handle it.
+
+      // Invalidate part of cache that may have been partially overridden.
+      if (mCachedOffset + mCachedBytes == aOffset) {
+        // We were topping-up the cache, just keep the old untouched data.
+        // (i.e., nothing to do here.)
+      } else {
+        // We were filling the cache from scratch, invalidate cache.
+        mCachedBytes = 0;
+      }
+    } else {
+      ILOG("ReadAt(%" PRIu32 "@%" PRId64
+           ") - no cached data, will fallback to blocking read...",
+           aCount,
+           aOffset);
+    }
+  } else {
+    ILOG("ReadAt(%" PRIu32 "@%" PRId64 ") - length is %" PRId64
+         " (%s), will fallback to blocking read as the caller requested...",
+         aCount,
+         aOffset,
+         length,
+         length < 0 ? "unknown" : "too short!");
+  }
+  uint32_t read = 0;
+  nsresult rv = UncachedReadAt(aOffset, aBuffer, aCount, &read);
+  if (NS_SUCCEEDED(rv)) {
+    *aBytes += read;
+    ILOG("ReadAt(%" PRIu32 "@%" PRId64 ") - fallback uncached read got %" PRIu32
+         " bytes -> %s, %" PRIu32,
+         aCount,
+         aOffset,
+         read,
+         ResultName(rv).get(),
+         *aBytes);
+  } else {
+    ILOG("ReadAt(%" PRIu32 "@%" PRId64
+         ") - fallback uncached read failed -> %s, %" PRIu32,
+         aCount,
+         aOffset,
+         ResultName(rv).get(),
+         *aBytes);
+  }
+  return rv;
+}
+
+nsresult
+MediaResourceIndex::UncachedReadAt(int64_t aOffset,
+                                   char* aBuffer,
+                                   uint32_t aCount,
+                                   uint32_t* aBytes) const
 {
   *aBytes = 0;
-  while (aCount > 0) {
-    uint32_t bytesRead = 0;
-    nsresult rv = mResource->ReadAt(aOffset, aBuffer, aCount, &bytesRead);
-    NS_ENSURE_SUCCESS(rv, rv);
-    if (!bytesRead) {
-      break;
+  if (aCount != 0) {
+    for (;;) {
+      uint32_t bytesRead = 0;
+      nsresult rv = mResource->ReadAt(aOffset, aBuffer, aCount, &bytesRead);
+      if (NS_FAILED(rv)) {
+        return rv;
+      }
+      if (bytesRead == 0) {
+        break;
+      }
+      *aBytes += bytesRead;
+      aCount -= bytesRead;
+      if (aCount == 0) {
+        break;
+      }
+      aOffset += bytesRead;
+      aBuffer += bytesRead;
     }
-    *aBytes += bytesRead;
-    aOffset += bytesRead;
-    aBuffer += bytesRead;
-    aCount -= bytesRead;
   }
   return NS_OK;
 }
 
 nsresult
 MediaResourceIndex::Seek(int32_t aWhence, int64_t aOffset)
 {
   switch (aWhence) {
@@ -1689,8 +2012,9 @@ MediaResourceIndex::Seek(int32_t aWhence
 
   return NS_OK;
 }
 
 } // namespace mozilla
 
 // avoid redefined macro in unified build
 #undef LOG
+#undef ILOG
--- a/dom/media/MediaResource.h
+++ b/dom/media/MediaResource.h
@@ -13,20 +13,22 @@
 #include "nsIStreamingProtocolController.h"
 #include "nsIStreamListener.h"
 #include "nsIChannelEventSink.h"
 #include "nsIInterfaceRequestor.h"
 #include "Intervals.h"
 #include "MediaCache.h"
 #include "MediaContainerType.h"
 #include "MediaData.h"
+#include "MediaPrefs.h"
 #include "MediaResourceCallback.h"
 #include "mozilla/Atomics.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/TimeStamp.h"
+#include "mozilla/UniquePtr.h"
 #include "nsThreadUtils.h"
 #include <algorithm>
 
 // For HTTP seeking, if number of bytes needing to be
 // seeked forward is less than this value then a read is
 // done rather than a byte range request.
 //
 // If we assume a 100Mbit connection, and assume reissuing an HTTP seek causes
@@ -285,18 +287,18 @@ public:
   // server may give us a resource of a different length to what it had
   // reported previously --- or it may just lie in its Content-Length
   // header and give us more or less data than it reported. We will adjust
   // the result of GetLength to reflect the data that's actually arriving.
   virtual int64_t GetLength() = 0;
   // Returns the offset of the first byte of cached data at or after aOffset,
   // or -1 if there is no such cached data.
   virtual int64_t GetNextCachedData(int64_t aOffset) = 0;
-  // Returns the end of the bytes starting at the given offset
-  // which are in cache.
+  // Returns the end of the bytes starting at the given offset which are in
+  // cache. Returns aOffset itself if there are zero bytes available there.
   virtual int64_t GetCachedDataEnd(int64_t aOffset) = 0;
   // Returns true if all the data from aOffset to the end of the stream
   // is in cache. If the end of the stream is not known, we return false.
   virtual bool IsDataCachedToEndOfResource(int64_t aOffset) = 0;
   // Returns true if we are expecting any more data to arrive
   // sometime in the not-too-distant future, either from the network or from
   // an appendBuffer call on a MediaSource element.
   virtual bool IsExpectingMoreData()
@@ -755,16 +757,20 @@ private:
  */
 
 class MediaResourceIndex
 {
 public:
   explicit MediaResourceIndex(MediaResource* aResource)
     : mResource(aResource)
     , mOffset(0)
+    , mCacheBlockSize(SelectCacheSize(MediaPrefs::MediaResourceIndexCache()))
+    , mCachedOffset(0)
+    , mCachedBytes(0)
+    , mCachedBlock(MakeUnique<char[]>(mCacheBlockSize))
   {}
 
   // Read up to aCount bytes from the stream. The buffer must have
   // enough room for at least aCount bytes. Stores the number of
   // actual bytes read in aBytes (0 on end of file).
   // May read less than aCount bytes if the number of
   // available bytes is less than aCount. Always check *aBytes after
   // read, and call again if necessary.
@@ -803,20 +809,32 @@ public:
   MediaResource* GetResource() const { return mResource; }
 
   // Read up to aCount bytes from the stream. The read starts at
   // aOffset in the stream, seeking to that location initially if
   // it is not the current stream offset.
   // Unlike MediaResource::ReadAt, ReadAt only returns fewer bytes than
   // requested if end of stream or an error is encountered. There is no need to
   // call it again to get more data.
+  // If the resource has cached data past the end of the request, it will be
+  // used to fill a local cache, which should speed up consecutive ReadAt's
+  // (mostly by avoiding using the resource's IOs and locks.)
   // *aBytes will contain the number of bytes copied, even if an error occurred.
   // ReadAt doesn't have an impact on the offset returned by Tell().
-  nsresult ReadAt(int64_t aOffset, char* aBuffer,
-                  uint32_t aCount, uint32_t* aBytes) const;
+  nsresult ReadAt(int64_t aOffset,
+                  char* aBuffer,
+                  uint32_t aCount,
+                  uint32_t* aBytes);
+
+  // Same as ReadAt, but doesn't try to cache around the read.
+  // Useful if you know that you will not read again from the same area.
+  nsresult UncachedReadAt(int64_t aOffset,
+                          char* aBuffer,
+                          uint32_t aCount,
+                          uint32_t* aBytes) const;
 
   // Convenience methods, directly calling the MediaResource method of the same
   // name.
   // Those functions do not update the MediaResource offset as returned
   // by Tell().
 
   // This method returns nullptr if anything fails.
   // Otherwise, it returns an owned buffer.
@@ -830,15 +848,82 @@ public:
   // This can change over time; after a seek operation, a misbehaving
   // server may give us a resource of a different length to what it had
   // reported previously --- or it may just lie in its Content-Length
   // header and give us more or less data than it reported. We will adjust
   // the result of GetLength to reflect the data that's actually arriving.
   int64_t GetLength() const { return mResource->GetLength(); }
 
 private:
+  // If the resource has cached data past the requested range, try to grab it
+  // into our local cache.
+  // If there is no cached data, or attempting to read it fails, fallback on
+  // a (potentially-blocking) read of just what was requested, so that we don't
+  // get unexpected side-effects by trying to read more than intended.
+  nsresult CacheOrReadAt(int64_t aOffset,
+                         char* aBuffer,
+                         uint32_t aCount,
+                         uint32_t* aBytes);
+
+  // Select the next power of 2 (in range 32B-128KB, or 0 -> no cache)
+  static uint32_t SelectCacheSize(uint32_t aHint)
+  {
+    if (aHint == 0) {
+      return 0;
+    }
+    if (aHint <= 32) {
+      return 32;
+    }
+    if (aHint > 64*1024) {
+      return 128*1024;
+    }
+    // 32-bit next power of 2, from:
+    // http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
+    aHint--;
+    aHint |= aHint >> 1;
+    aHint |= aHint >> 2;
+    aHint |= aHint >> 4;
+    aHint |= aHint >> 8;
+    aHint |= aHint >> 16;
+    aHint++;
+    return aHint;
+  }
+
+  // Maps a file offset to a mCachedBlock index.
+  uint32_t IndexInCache(int64_t aOffsetInFile) const
+  {
+    const uint32_t index = uint32_t(aOffsetInFile) & (mCacheBlockSize - 1);
+    MOZ_ASSERT(index == aOffsetInFile % mCacheBlockSize);
+    return index;
+  }
+
+  // Starting file offset of the cache block that contains a given file offset.
+  int64_t CacheOffsetContaining(int64_t aOffsetInFile) const
+  {
+    const int64_t offset = aOffsetInFile & ~(int64_t(mCacheBlockSize) - 1);
+    MOZ_ASSERT(offset == aOffsetInFile - IndexInCache(aOffsetInFile));
+    return offset;
+  }
+
   RefPtr<MediaResource> mResource;
   int64_t mOffset;
+
+  // Local cache used by ReadAt().
+  // mCachedBlock is valid when mCachedBytes != 0, in which case it contains
+  // data of length mCachedBytes, starting at offset `mCachedOffset` in the
+  // resource, located at index `IndexInCache(mCachedOffset)` in mCachedBlock.
+  //
+  // resource: |------------------------------------------------------|
+  //                                          <----------> mCacheBlockSize
+  //           <---------------------------------> mCachedOffset
+  //                                             <--> mCachedBytes
+  // mCachedBlock:                            |..----....|
+  //  CacheOffsetContaining(mCachedOffset)    <--> IndexInCache(mCachedOffset)
+  //           <------------------------------>
+  const uint32_t mCacheBlockSize;
+  int64_t mCachedOffset;
+  uint32_t mCachedBytes;
+  UniquePtr<char[]> mCachedBlock;
 };
 
 } // namespace mozilla
 
 #endif
--- a/dom/media/gtest/MockMediaResource.cpp
+++ b/dom/media/gtest/MockMediaResource.cpp
@@ -46,18 +46,17 @@ MockMediaResource::ReadAt(int64_t aOffse
 
   // Make it fail if we're re-entrant
   if (mEntry++) {
     MOZ_ASSERT(false);
     return NS_ERROR_FAILURE;
   }
 
   fseek(mFileHandle, aOffset, SEEK_SET);
-  size_t objectsRead = fread(aBuffer, aCount, 1, mFileHandle);
-  *aBytes = objectsRead == 1 ? aCount : 0;
+  *aBytes = fread(aBuffer, 1, aCount, mFileHandle);
 
   mEntry--;
 
   return ferror(mFileHandle) ? NS_ERROR_FAILURE : NS_OK;
 }
 
 int64_t
 MockMediaResource::GetLength()
@@ -99,17 +98,17 @@ MockMediaResource::GetNextCachedData(int
 int64_t
 MockMediaResource::GetCachedDataEnd(int64_t aOffset)
 {
   for (size_t i = 0; i < mRanges.Length(); i++) {
     if (aOffset == mRanges[i].mStart) {
       return mRanges[i].mEnd;
     }
   }
-  return -1;
+  return aOffset;
 }
 
 nsresult
 MockMediaResource::GetCachedRanges(MediaByteRangeSet& aRanges)
 {
   aRanges = mRanges;
   return NS_OK;
 }
--- a/dom/media/mediasource/SourceBufferResource.h
+++ b/dom/media/mediasource/SourceBufferResource.h
@@ -79,18 +79,24 @@ public:
       return mInputBuffer.GetOffset();
     } else if (aOffset == GetLength()) {
       return -1;
     }
     return aOffset;
   }
   int64_t GetCachedDataEnd(int64_t aOffset) override
   {
-    UNIMPLEMENTED();
-    return -1;
+    MOZ_ASSERT(OnTaskQueue());
+    MOZ_ASSERT(aOffset >= 0);
+    if (uint64_t(aOffset) < mInputBuffer.GetOffset() ||
+        aOffset >= GetLength()) {
+      // aOffset is outside of the buffered range.
+      return aOffset;
+    }
+    return GetLength();
   }
   bool IsDataCachedToEndOfResource(int64_t aOffset) override { return false; }
   bool IsSuspendedByCache() override
   {
     UNIMPLEMENTED();
     return false;
   }
   bool IsSuspended() override
--- a/dom/media/wave/WaveDemuxer.cpp
+++ b/dom/media/wave/WaveDemuxer.cpp
@@ -28,17 +28,17 @@ WAVDemuxer::WAVDemuxer(MediaResource* aS
   : mSource(aSource)
 {
 }
 
 bool
 WAVDemuxer::InitInternal()
 {
   if (!mTrackDemuxer) {
-    mTrackDemuxer = new WAVTrackDemuxer(mSource);
+    mTrackDemuxer = new WAVTrackDemuxer(mSource.GetResource());
   }
   return mTrackDemuxer->Init();
 }
 
 RefPtr<WAVDemuxer::InitPromise>
 WAVDemuxer::Init()
 {
   if (!InitInternal()) {
@@ -72,17 +72,17 @@ WAVDemuxer::GetTrackDemuxer(TrackInfo::T
 bool
 WAVDemuxer::IsSeekable() const
 {
   return true;
 }
 
 // WAVTrackDemuxer
 
-WAVTrackDemuxer::WAVTrackDemuxer(MediaResourceIndex aSource)
+WAVTrackDemuxer::WAVTrackDemuxer(MediaResource* aSource)
   : mSource(aSource)
   , mOffset(0)
   , mFirstChunkOffset(0)
   , mNumParsedChunks(0)
   , mChunkIndex(0)
   , mTotalChunkLen(0)
   , mSamplesPerChunk(0)
   , mSamplesPerSecond(0)
--- a/dom/media/wave/WaveDemuxer.h
+++ b/dom/media/wave/WaveDemuxer.h
@@ -179,17 +179,17 @@ private:
   };
 
   DataChunk mChunk;
 };
 
 class WAVTrackDemuxer : public MediaTrackDemuxer
 {
 public:
-  explicit WAVTrackDemuxer(MediaResourceIndex aSource);
+  explicit WAVTrackDemuxer(MediaResource* aSource);
 
   bool Init();
 
   int64_t StreamLength() const;
 
   media::TimeUnit Duration() const;
   media::TimeUnit Duration(int64_t aNumDataChunks) const;
   media::TimeUnit DurationFromBytes(uint32_t aNumBytes) const;
--- a/ipc/glue/GeckoChildProcessHost.cpp
+++ b/ipc/glue/GeckoChildProcessHost.cpp
@@ -18,19 +18,22 @@
 #include "SharedMemoryBasic.h"
 #endif
 
 #include "MainThreadUtils.h"
 #include "mozilla/Sprintf.h"
 #include "prenv.h"
 #include "nsXPCOMPrivate.h"
 
-#if defined(MOZ_CONTENT_SANDBOX) && defined(XP_MACOSX)
+#if defined(MOZ_CONTENT_SANDBOX)
+#include "mozilla/SandboxSettings.h"
+#if defined(XP_MACOSX)
 #include "nsAppDirectoryServiceDefs.h"
 #endif
+#endif
 
 #include "nsExceptionHandler.h"
 
 #include "nsDirectoryServiceDefs.h"
 #include "nsIFile.h"
 #include "nsPrintfCString.h"
 
 #include "mozilla/ClearOnShutdown.h"
@@ -306,17 +309,17 @@ GeckoChildProcessHost::PrepareLaunch()
 #ifdef XP_WIN
   if (mProcessType == GeckoProcessType_Plugin) {
     InitWindowsGroupID();
   }
 
 #if defined(MOZ_CONTENT_SANDBOX)
   // We need to get the pref here as the process is launched off main thread.
   if (mProcessType == GeckoProcessType_Content) {
-    mSandboxLevel = Preferences::GetInt("security.sandbox.content.level");
+    mSandboxLevel = GetEffectiveContentSandboxLevel();
     mEnableSandboxLogging =
       Preferences::GetBool("security.sandbox.logging.enabled");
   }
 #endif
 
 #if defined(MOZ_SANDBOX)
   // For other process types we can't rely on them being launched on main
   // thread and they may not have access to prefs in the child process, so allow
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -4417,16 +4417,20 @@ nsDisplayLayerEventRegions::AddFrame(nsD
     if (clip->GetRoundedRectCount() > 0) {
       borderBoxHasRoundedCorners = true;
     }
   }
 
   if (borderBoxHasRoundedCorners ||
       (aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT)) {
     mMaybeHitRegion.Or(mMaybeHitRegion, borderBox);
+
+    // Avoid quadratic performance as a result of the region growing to include
+    // an arbitrarily large number of rects, which can happen on some pages.
+    mMaybeHitRegion.SimplifyOutward(8);
   } else {
     mHitRegion.Or(mHitRegion, borderBox);
   }
 
   if (aBuilder->IsBuildingNonLayerizedScrollbar() ||
       aBuilder->GetAncestorHasApzAwareEventHandler())
   {
     // Scrollbars may be painted into a layer below the actual layer they will
--- a/memory/build/malloc_decls.h
+++ b/memory/build/malloc_decls.h
@@ -38,34 +38,34 @@ typedef MALLOC_USABLE_SIZE_CONST_PTR voi
 #  ifndef MALLOC_DECL_VOID
 #    define MALLOC_DECL_VOID(func, ...) MALLOC_DECL(func, void, __VA_ARGS__)
 #  endif
 
 #  if MALLOC_FUNCS & MALLOC_FUNCS_INIT
 MALLOC_DECL(init, void, const malloc_table_t *)
 #  endif
 #  if MALLOC_FUNCS & MALLOC_FUNCS_BRIDGE
-MALLOC_DECL(get_bridge, struct ReplaceMallocBridge*, void)
+MALLOC_DECL(get_bridge, struct ReplaceMallocBridge*)
 #  endif
 #  if MALLOC_FUNCS & MALLOC_FUNCS_MALLOC
 MALLOC_DECL(malloc, void *, size_t)
 MALLOC_DECL(posix_memalign, int, void **, size_t, size_t)
 MALLOC_DECL(aligned_alloc, void *, size_t, size_t)
 MALLOC_DECL(calloc, void *, size_t, size_t)
 MALLOC_DECL(realloc, void *, void *, size_t)
 MALLOC_DECL_VOID(free, void *)
 MALLOC_DECL(memalign, void *, size_t, size_t)
 MALLOC_DECL(valloc, void *, size_t)
 MALLOC_DECL(malloc_usable_size, size_t, usable_ptr_t)
 MALLOC_DECL(malloc_good_size, size_t, size_t)
 #  endif
 #  if MALLOC_FUNCS & MALLOC_FUNCS_JEMALLOC
 MALLOC_DECL_VOID(jemalloc_stats, jemalloc_stats_t *)
-MALLOC_DECL_VOID(jemalloc_purge_freed_pages, void)
-MALLOC_DECL_VOID(jemalloc_free_dirty_pages, void)
+MALLOC_DECL_VOID(jemalloc_purge_freed_pages)
+MALLOC_DECL_VOID(jemalloc_free_dirty_pages)
 MALLOC_DECL_VOID(jemalloc_thread_local_arena, jemalloc_bool)
 #  endif
 
 #  undef MALLOC_DECL_VOID
 #endif /* MALLOC_DECL */
 
 #undef MALLOC_DECL
 #undef MALLOC_FUNCS
--- a/memory/build/replace_malloc.c
+++ b/memory/build/replace_malloc.c
@@ -13,16 +13,21 @@
 #include "mozmemory_wrap.h"
 
 /* Declare all je_* functions */
 #define MALLOC_DECL(name, return_type, ...) \
   return_type je_ ## name(__VA_ARGS__);
 #include "malloc_decls.h"
 
 #include "mozilla/Likely.h"
+#include "mozilla/MacroArgs.h"
+#include <errno.h>
+#ifndef XP_WIN
+#include <unistd.h>
+#endif
 
 /*
  * Windows doesn't come with weak imports as they are possible with
  * LD_PRELOAD or DYLD_INSERT_LIBRARIES on Linux/OSX. On this platform,
  * the replacement functions are defined as variable pointers to the
  * function resolved with GetProcAddress() instead of weak definitions
  * of functions. On Android, the same needs to happen as well, because
  * the Android linker doesn't handle weak linking with non LD_PRELOADed
@@ -41,253 +46,154 @@
 
 #define MALLOC_DECL(name, return_type, ...) \
     je_ ## name,
 
 static const malloc_table_t malloc_table = {
 #include "malloc_decls.h"
 };
 
+static malloc_table_t replace_malloc_table;
+
 #ifdef MOZ_NO_REPLACE_FUNC_DECL
 #  define MALLOC_DECL(name, return_type, ...) \
-    typedef return_type (replace_ ## name ## _impl_t)(__VA_ARGS__); \
-    replace_ ## name ## _impl_t *replace_ ## name = NULL;
-#  define MALLOC_FUNCS MALLOC_FUNCS_ALL
+    typedef return_type (name ## _impl_t)(__VA_ARGS__); \
+    name ## _impl_t* replace_ ## name = NULL;
+#  define MALLOC_FUNCS (MALLOC_FUNCS_INIT | MALLOC_FUNCS_BRIDGE)
 #  include "malloc_decls.h"
+#endif
 
-#  ifdef XP_WIN
-#    include <windows.h>
-static void
-replace_malloc_init_funcs()
+#ifdef XP_WIN
+#  include <windows.h>
+
+typedef HMODULE replace_malloc_handle_t;
+
+static replace_malloc_handle_t
+replace_malloc_handle()
 {
   char replace_malloc_lib[1024];
   if (GetEnvironmentVariableA("MOZ_REPLACE_MALLOC_LIB", (LPSTR)&replace_malloc_lib,
                               sizeof(replace_malloc_lib)) > 0) {
-    HMODULE handle = LoadLibraryA(replace_malloc_lib);
-    if (handle) {
-#define MALLOC_DECL(name, ...) \
-  replace_ ## name = (replace_ ## name ## _impl_t *) GetProcAddress(handle, "replace_" # name);
+    return LoadLibraryA(replace_malloc_lib);
+  }
+  return NULL;
+}
+
+#    define REPLACE_MALLOC_GET_FUNC(handle, name) \
+      (name ## _impl_t*) GetProcAddress(handle, "replace_" # name)
 
-#  define MALLOC_FUNCS MALLOC_FUNCS_ALL
-#include "malloc_decls.h"
-    }
-  }
-}
-#  elif defined(MOZ_WIDGET_ANDROID)
-#    include <dlfcn.h>
-#    include <stdlib.h>
-static void
-replace_malloc_init_funcs()
+#elif defined(MOZ_WIDGET_ANDROID)
+#  include <dlfcn.h>
+#  include <stdlib.h>
+
+typedef void* replace_malloc_handle_t;
+
+static replace_malloc_handle_t
+replace_malloc_handle()
 {
   const char *replace_malloc_lib = getenv("MOZ_REPLACE_MALLOC_LIB");
   if (replace_malloc_lib && *replace_malloc_lib) {
-    void *handle = dlopen(replace_malloc_lib, RTLD_LAZY);
-    if (handle) {
-#define MALLOC_DECL(name, ...) \
-  replace_ ## name = (replace_ ## name ## _impl_t *) dlsym(handle, "replace_" # name);
+    return dlopen(replace_malloc_lib, RTLD_LAZY);
+  }
+  return NULL;
+}
+
+#  define REPLACE_MALLOC_GET_FUNC(handle, name) \
+    (name ## _impl_t*) dlsym(handle, "replace_" # name)
+
+#else
+
+#  include <stdbool.h>
 
-#  define MALLOC_FUNCS MALLOC_FUNCS_ALL
-#include "malloc_decls.h"
-    }
-  }
+typedef bool replace_malloc_handle_t;
+
+static replace_malloc_handle_t
+replace_malloc_handle()
+{
+  return true;
 }
-#  else
-#    error No implementation for replace_malloc_init_funcs()
-#  endif
+
+#  define REPLACE_MALLOC_GET_FUNC(handle, name) \
+    replace_ ## name
 
-#endif /* MOZ_NO_REPLACE_FUNC_DECL */
+#endif
+
+static void replace_malloc_init_funcs();
 
 /*
  * Below is the malloc implementation overriding jemalloc and calling the
  * replacement functions if they exist.
  */
 
-/*
- * Malloc implementation functions are MOZ_MEMORY_API, and jemalloc
- * specific functions MOZ_JEMALLOC_API; see mozmemory_wrap.h
- */
-#define MALLOC_DECL(name, return_type, ...) \
-  MOZ_MEMORY_API return_type name ## _impl(__VA_ARGS__);
-#define MALLOC_FUNCS MALLOC_FUNCS_MALLOC
-#include "malloc_decls.h"
-
-#define MALLOC_DECL(name, return_type, ...) \
-  MOZ_JEMALLOC_API return_type name ## _impl(__VA_ARGS__);
-#define MALLOC_FUNCS MALLOC_FUNCS_JEMALLOC
-#include "malloc_decls.h"
-
 static int replace_malloc_initialized = 0;
 static void
 init()
 {
-#ifdef MOZ_NO_REPLACE_FUNC_DECL
   replace_malloc_init_funcs();
-#endif
   // Set this *before* calling replace_init, otherwise if replace_init calls
   // malloc() we'll get an infinite loop.
   replace_malloc_initialized = 1;
   if (replace_init)
     replace_init(&malloc_table);
 }
 
+/*
+ * Malloc implementation functions are MOZ_MEMORY_API, and jemalloc
+ * specific functions MOZ_JEMALLOC_API; see mozmemory_wrap.h
+ */
+#define MACRO_CALL(a, b) a b
+/* Can't use macros recursively, so we need another one doing the same as above. */
+#define MACRO_CALL2(a, b) a b
+
+#define ARGS_HELPER(name, ...) MACRO_CALL2( \
+  MOZ_PASTE_PREFIX_AND_ARG_COUNT(name, ##__VA_ARGS__), \
+  (__VA_ARGS__))
+#define TYPED_ARGS0()
+#define TYPED_ARGS1(t1) t1 arg1
+#define TYPED_ARGS2(t1, t2) TYPED_ARGS1(t1), t2 arg2
+#define TYPED_ARGS3(t1, t2, t3) TYPED_ARGS2(t1, t2), t3 arg3
+
+#define ARGS0()
+#define ARGS1(t1) arg1
+#define ARGS2(t1, t2) ARGS1(t1), arg2
+#define ARGS3(t1, t2, t3) ARGS2(t1, t2), arg3
+
+#define GENERIC_MALLOC_DECL_HELPER(name, return, return_type, ...) \
+  return_type name ## _impl(ARGS_HELPER(TYPED_ARGS, ##__VA_ARGS__)) \
+  { \
+    if (MOZ_UNLIKELY(!replace_malloc_initialized)) \
+      init(); \
+    return replace_malloc_table.name(ARGS_HELPER(ARGS, ##__VA_ARGS__)); \
+  }
+
+#define GENERIC_MALLOC_DECL(name, return_type, ...) \
+  GENERIC_MALLOC_DECL_HELPER(name, return, return_type, ##__VA_ARGS__)
+#define GENERIC_MALLOC_DECL_VOID(name, ...) \
+  GENERIC_MALLOC_DECL_HELPER(name, , void, ##__VA_ARGS__)
+
+#define MALLOC_DECL(...) MOZ_MEMORY_API MACRO_CALL(GENERIC_MALLOC_DECL, (__VA_ARGS__))
+#define MALLOC_DECL_VOID(...) MOZ_MEMORY_API MACRO_CALL(GENERIC_MALLOC_DECL_VOID, (__VA_ARGS__))
+#define MALLOC_FUNCS MALLOC_FUNCS_MALLOC
+#include "malloc_decls.h"
+
+#define MALLOC_DECL(...) MOZ_JEMALLOC_API MACRO_CALL(GENERIC_MALLOC_DECL, (__VA_ARGS__))
+#define MALLOC_DECL_VOID(...) MOZ_JEMALLOC_API MACRO_CALL(GENERIC_MALLOC_DECL_VOID, (__VA_ARGS__))
+#define MALLOC_FUNCS MALLOC_FUNCS_JEMALLOC
+#include "malloc_decls.h"
+
 MFBT_API struct ReplaceMallocBridge*
 get_bridge(void)
 {
   if (MOZ_UNLIKELY(!replace_malloc_initialized))
     init();
   if (MOZ_LIKELY(!replace_get_bridge))
     return NULL;
   return replace_get_bridge();
 }
 
-void*
-malloc_impl(size_t size)
-{
-  if (MOZ_UNLIKELY(!replace_malloc_initialized))
-    init();
-  if (MOZ_LIKELY(!replace_malloc))
-    return je_malloc(size);
-  return replace_malloc(size);
-}
-
-int
-posix_memalign_impl(void **memptr, size_t alignment, size_t size)
-{
-  if (MOZ_UNLIKELY(!replace_malloc_initialized))
-    init();
-  if (MOZ_LIKELY(!replace_posix_memalign))
-    return je_posix_memalign(memptr, alignment, size);
-  return replace_posix_memalign(memptr, alignment, size);
-}
-
-void*
-aligned_alloc_impl(size_t alignment, size_t size)
-{
-  if (MOZ_UNLIKELY(!replace_malloc_initialized))
-    init();
-  if (MOZ_LIKELY(!replace_aligned_alloc))
-    return je_aligned_alloc(alignment, size);
-  return replace_aligned_alloc(alignment, size);
-}
-
-void*
-calloc_impl(size_t num, size_t size)
-{
-  if (MOZ_UNLIKELY(!replace_malloc_initialized))
-    init();
-  if (MOZ_LIKELY(!replace_calloc))
-    return je_calloc(num, size);
-  return replace_calloc(num, size);
-}
-
-void*
-realloc_impl(void *ptr, size_t size)
-{
-  if (MOZ_UNLIKELY(!replace_malloc_initialized))
-    init();
-  if (MOZ_LIKELY(!replace_realloc))
-    return je_realloc(ptr, size);
-  return replace_realloc(ptr, size);
-}
-
-void
-free_impl(void *ptr)
-{
-  if (MOZ_UNLIKELY(!replace_malloc_initialized))
-    init();
-  if (MOZ_LIKELY(!replace_free))
-    je_free(ptr);
-  else
-    replace_free(ptr);
-}
-
-void*
-memalign_impl(size_t alignment, size_t size)
-{
-  if (MOZ_UNLIKELY(!replace_malloc_initialized))
-    init();
-  if (MOZ_LIKELY(!replace_memalign))
-    return je_memalign(alignment, size);
-  return replace_memalign(alignment, size);
-}
-
-void*
-valloc_impl(size_t size)
-{
-  if (MOZ_UNLIKELY(!replace_malloc_initialized))
-    init();
-  if (MOZ_LIKELY(!replace_valloc))
-    return je_valloc(size);
-  return replace_valloc(size);
-}
-
-size_t
-malloc_usable_size_impl(usable_ptr_t ptr)
-{
-  if (MOZ_UNLIKELY(!replace_malloc_initialized))
-    init();
-  if (MOZ_LIKELY(!replace_malloc_usable_size))
-    return je_malloc_usable_size(ptr);
-  return replace_malloc_usable_size(ptr);
-}
-
-size_t
-malloc_good_size_impl(size_t size)
-{
-  if (MOZ_UNLIKELY(!replace_malloc_initialized))
-    init();
-  if (MOZ_LIKELY(!replace_malloc_good_size))
-    return je_malloc_good_size(size);
-  return replace_malloc_good_size(size);
-}
-
-void
-jemalloc_stats_impl(jemalloc_stats_t *stats)
-{
-  if (MOZ_UNLIKELY(!replace_malloc_initialized))
-    init();
-  if (MOZ_LIKELY(!replace_jemalloc_stats))
-    je_jemalloc_stats(stats);
-  else
-    replace_jemalloc_stats(stats);
-}
-
-void
-jemalloc_purge_freed_pages_impl()
-{
-  if (MOZ_UNLIKELY(!replace_malloc_initialized))
-    init();
-  if (MOZ_LIKELY(!replace_jemalloc_purge_freed_pages))
-    je_jemalloc_purge_freed_pages();
-  else
-    replace_jemalloc_purge_freed_pages();
-}
-
-void
-jemalloc_free_dirty_pages_impl()
-{
-  if (MOZ_UNLIKELY(!replace_malloc_initialized))
-    init();
-  if (MOZ_LIKELY(!replace_jemalloc_free_dirty_pages))
-    je_jemalloc_free_dirty_pages();
-  else
-    replace_jemalloc_free_dirty_pages();
-}
-
-void
-jemalloc_thread_local_arena_impl(jemalloc_bool enabled)
-{
-  if (MOZ_UNLIKELY(!replace_malloc_initialized))
-    init();
-  if (MOZ_LIKELY(!replace_jemalloc_thread_local_arena))
-    je_jemalloc_thread_local_arena(enabled);
-  else
-    replace_jemalloc_thread_local_arena(enabled);
-}
-
 /* The following comment and definitions are from jemalloc.c: */
 #if defined(__GLIBC__) && !defined(__UCLIBC__)
 
 /*
  * glibc provides the RTLD_DEEPBIND flag for dlopen which can make it possible
  * to inconsistently reference libc's malloc(3)-compatible functions
  * (https://bugzilla.mozilla.org/show_bug.cgi?id=493541).
  *
@@ -302,8 +208,86 @@ typedef void *(* __realloc_hook_type)(vo
 typedef void *(* __memalign_hook_type)(size_t alignment, size_t size);
 
 MOZ_MEMORY_API __free_hook_type __free_hook = free_impl;
 MOZ_MEMORY_API __malloc_hook_type __malloc_hook = malloc_impl;
 MOZ_MEMORY_API __realloc_hook_type __realloc_hook = realloc_impl;
 MOZ_MEMORY_API __memalign_hook_type __memalign_hook = memalign_impl;
 
 #endif
+
+/*
+ * posix_memalign, aligned_alloc, memalign and valloc all implement some kind
+ * of aligned memory allocation. For convenience, a replace-malloc library can
+ * skip defining replace_posix_memalign, replace_aligned_alloc and
+ * replace_valloc, and default implementations will be automatically derived
+ * from replace_memalign.
+ */
+static int
+default_posix_memalign(void** ptr, size_t alignment, size_t size)
+{
+  if (size == 0) {
+    *ptr = NULL;
+    return 0;
+  }
+  /* alignment must be a power of two and a multiple of sizeof(void *) */
+  if (((alignment - 1) & alignment) != 0 || (alignment % sizeof(void *)))
+    return EINVAL;
+  *ptr = replace_malloc_table.memalign(alignment, size);
+  return *ptr ? 0 : ENOMEM;
+}
+
+static void*
+default_aligned_alloc(size_t alignment, size_t size)
+{
+  /* size should be a multiple of alignment */
+  if (size % alignment)
+    return NULL;
+  return replace_malloc_table.memalign(alignment, size);
+}
+
+// Nb: sysconf() is expensive, but valloc is obsolete and rarely used.
+static void*
+default_valloc(size_t size)
+{
+#ifdef XP_WIN
+  SYSTEM_INFO si;
+  GetSystemInfo(&si);
+  size_t page_size = si.dwPageSize;
+#else
+  size_t page_size = sysconf(_SC_PAGE_SIZE);
+#endif
+  return replace_malloc_table.memalign(page_size, size);
+}
+
+static void
+replace_malloc_init_funcs()
+{
+  replace_malloc_handle_t handle = replace_malloc_handle();
+  if (handle) {
+#ifdef MOZ_NO_REPLACE_FUNC_DECL
+#  define MALLOC_DECL(name, ...) \
+    replace_ ## name = REPLACE_MALLOC_GET_FUNC(handle, name);
+
+#  define MALLOC_FUNCS (MALLOC_FUNCS_INIT | MALLOC_FUNCS_BRIDGE)
+#  include "malloc_decls.h"
+#endif
+
+#define MALLOC_DECL(name, ...) \
+  replace_malloc_table.name = REPLACE_MALLOC_GET_FUNC(handle, name);
+#include "malloc_decls.h"
+  }
+
+  if (!replace_malloc_table.posix_memalign && replace_malloc_table.memalign)
+    replace_malloc_table.posix_memalign = default_posix_memalign;
+
+  if (!replace_malloc_table.aligned_alloc && replace_malloc_table.memalign)
+    replace_malloc_table.aligned_alloc = default_aligned_alloc;
+
+  if (!replace_malloc_table.valloc && replace_malloc_table.memalign)
+    replace_malloc_table.valloc = default_valloc;
+
+#define MALLOC_DECL(name, ...) \
+  if (!replace_malloc_table.name) { \
+    replace_malloc_table.name = je_ ## name; \
+  }
+#include "malloc_decls.h"
+}
--- a/memory/build/replace_malloc.h
+++ b/memory/build/replace_malloc.h
@@ -86,48 +86,11 @@ MOZ_BEGIN_EXTERN_C
 #  define MALLOC_DECL(name, return_type, ...) \
     MOZ_EXPORT return_type replace_ ## name(__VA_ARGS__) MOZ_REPLACE_WEAK;
 
 #  define MALLOC_FUNCS MALLOC_FUNCS_ALL
 #  include "malloc_decls.h"
 
 #endif /* MOZ_NO_REPLACE_FUNC_DECL */
 
-/*
- * posix_memalign, aligned_alloc, memalign and valloc all implement some
- * kind of aligned memory allocation. For convenience, replace_posix_memalign,
- * replace_aligned_alloc and replace_valloc can be automatically derived from
- * memalign when MOZ_REPLACE_ONLY_MEMALIGN is defined before including this
- * header. PAGE_SIZE also needs to be defined to the appropriate expression.
- */
-#ifdef MOZ_REPLACE_ONLY_MEMALIGN
-#include <errno.h>
-
-int replace_posix_memalign(void **ptr, size_t alignment, size_t size)
-{
-  if (size == 0) {
-    *ptr = NULL;
-    return 0;
-  }
-  /* alignment must be a power of two and a multiple of sizeof(void *) */
-  if (((alignment - 1) & alignment) != 0 || (alignment % sizeof(void *)))
-    return EINVAL;
-  *ptr = replace_memalign(alignment, size);
-  return *ptr ? 0 : ENOMEM;
-}
-
-void *replace_aligned_alloc(size_t alignment, size_t size)
-{
-  /* size should be a multiple of alignment */
-  if (size % alignment)
-    return NULL;
-  return replace_memalign(alignment, size);
-}
-
-void *replace_valloc(size_t size)
-{
-  return replace_memalign(PAGE_SIZE, size);
-}
-#endif
-
 MOZ_END_EXTERN_C
 
 #endif /* replace_malloc_h */
--- a/memory/replace/dmd/DMD.cpp
+++ b/memory/replace/dmd/DMD.cpp
@@ -44,43 +44,17 @@
 #include "mozilla/MemoryReporting.h"
 
 // CodeAddressService is defined entirely in the header, so this does not make
 // DMD depend on XPCOM's object file.
 #include "CodeAddressService.h"
 
 // replace_malloc.h needs to be included before replace_malloc_bridge.h,
 // which DMD.h includes, so DMD.h needs to be included after replace_malloc.h.
-// MOZ_REPLACE_ONLY_MEMALIGN saves us from having to define
-// replace_{posix_memalign,aligned_alloc,valloc}.  It requires defining
-// PAGE_SIZE.  Nb: sysconf() is expensive, but it's only used for (the obsolete
-// and rarely used) valloc.
-#define MOZ_REPLACE_ONLY_MEMALIGN 1
-
-#ifndef PAGE_SIZE
-#define DMD_DEFINED_PAGE_SIZE
-#ifdef XP_WIN
-#define PAGE_SIZE GetPageSize()
-static long GetPageSize()
-{
-  SYSTEM_INFO si;
-  GetSystemInfo(&si);
-  return si.dwPageSize;
-}
-#else // XP_WIN
-#define PAGE_SIZE sysconf(_SC_PAGESIZE)
-#endif // XP_WIN
-#endif // PAGE_SIZE
 #include "replace_malloc.h"
-#undef MOZ_REPLACE_ONLY_MEMALIGN
-#ifdef DMD_DEFINED_PAGE_SIZE
-#undef DMD_DEFINED_PAGE_SIZE
-#undef PAGE_SIZE
-#endif // DMD_DEFINED_PAGE_SIZE
-
 #include "DMD.h"
 
 namespace mozilla {
 namespace dmd {
 
 class DMDBridge : public ReplaceMallocBridge
 {
   virtual DMDFuncs* GetDMDFuncs() override;
--- a/memory/replace/logalloc/LogAlloc.cpp
+++ b/memory/replace/logalloc/LogAlloc.cpp
@@ -181,16 +181,17 @@ replace_malloc(size_t aSize)
   AutoLock lock(sLock);
   void* ptr = sFuncs->malloc(aSize);
   if (ptr) {
     FdPrintf(sFd, "%zu %zu malloc(%zu)=%p\n", GetPid(), GetTid(), aSize, ptr);
   }
   return ptr;
 }
 
+#ifndef LOGALLOC_MINIMAL
 int
 replace_posix_memalign(void** aPtr, size_t aAlignment, size_t aSize)
 {
   AutoLock lock(sLock);
   int ret = sFuncs->posix_memalign(aPtr, aAlignment, aSize);
   if (ret == 0) {
     FdPrintf(sFd, "%zu %zu posix_memalign(%zu,%zu)=%p\n", GetPid(), GetTid(),
              aAlignment, aSize, *aPtr);
@@ -204,16 +205,17 @@ replace_aligned_alloc(size_t aAlignment,
   AutoLock lock(sLock);
   void* ptr = sFuncs->aligned_alloc(aAlignment, aSize);
   if (ptr) {
     FdPrintf(sFd, "%zu %zu aligned_alloc(%zu,%zu)=%p\n", GetPid(), GetTid(),
              aAlignment, aSize, ptr);
   }
   return ptr;
 }
+#endif
 
 void*
 replace_calloc(size_t aNum, size_t aSize)
 {
   AutoLock lock(sLock);
   void* ptr = sFuncs->calloc(aNum, aSize);
   if (ptr) {
     FdPrintf(sFd, "%zu %zu calloc(%zu,%zu)=%p\n", GetPid(), GetTid(), aNum,
@@ -251,26 +253,28 @@ replace_memalign(size_t aAlignment, size
   void* ptr = sFuncs->memalign(aAlignment, aSize);
   if (ptr) {
     FdPrintf(sFd, "%zu %zu memalign(%zu,%zu)=%p\n", GetPid(), GetTid(),
              aAlignment, aSize, ptr);
   }
   return ptr;
 }
 
+#ifndef LOGALLOC_MINIMAL
 void*
 replace_valloc(size_t aSize)
 {
   AutoLock lock(sLock);
   void* ptr = sFuncs->valloc(aSize);
   if (ptr) {
     FdPrintf(sFd, "%zu %zu valloc(%zu)=%p\n", GetPid(), GetTid(), aSize, ptr);
   }
   return ptr;
 }
+#endif
 
 void
 replace_jemalloc_stats(jemalloc_stats_t* aStats)
 {
   AutoLock lock(sLock);
   sFuncs->jemalloc_stats(aStats);
   FdPrintf(sFd, "%zu %zu jemalloc_stats()\n", GetPid(), GetTid());
 }
copy from memory/replace/logalloc/moz.build
copy to memory/replace/logalloc/logalloc.mozbuild
--- a/memory/replace/logalloc/moz.build
+++ b/memory/replace/logalloc/logalloc.mozbuild
@@ -1,16 +1,14 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
-SharedLibrary('logalloc')
-
 SOURCES += [
     'FdPrintf.cpp',
     'LogAlloc.cpp',
 ]
 
 DISABLE_STL_WRAPPING = True
 USE_STATIC_LIBS = True
 DEFINES['MOZ_NO_MOZALLOC'] = True
@@ -30,12 +28,8 @@ else:
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 # Android doesn't have pthread_atfork, but we have our own in mozglue.
 if CONFIG['OS_TARGET'] == 'Android':
     USE_LIBS += [
         'mozglue',
     ]
-
-DIRS += [
-    'replay',
-]
new file mode 100644
--- /dev/null
+++ b/memory/replace/logalloc/minimal/moz.build
@@ -0,0 +1,11 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+SharedLibrary('logalloc_minimal')
+
+include('../logalloc.mozbuild')
+
+DEFINES['LOGALLOC_MINIMAL'] = True
--- a/memory/replace/logalloc/moz.build
+++ b/memory/replace/logalloc/moz.build
@@ -1,41 +1,14 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
 SharedLibrary('logalloc')
 
-SOURCES += [
-    'FdPrintf.cpp',
-    'LogAlloc.cpp',
-]
-
-DISABLE_STL_WRAPPING = True
-USE_STATIC_LIBS = True
-DEFINES['MOZ_NO_MOZALLOC'] = True
-# Avoid Lock_impl code depending on mozilla::Logger.
-DEFINES['NDEBUG'] = True
-DEFINES['DEBUG'] = False
-
-# Use locking code from the chromium stack.
-if CONFIG['OS_TARGET'] == 'WINNT':
-    SOURCES += [
-        '../../../ipc/chromium/src/base/lock_impl_win.cc',
-    ]
-else:
-    SOURCES += [
-        '../../../ipc/chromium/src/base/lock_impl_posix.cc',
-    ]
-
-include('/ipc/chromium/chromium-config.mozbuild')
-
-# Android doesn't have pthread_atfork, but we have our own in mozglue.
-if CONFIG['OS_TARGET'] == 'Android':
-    USE_LIBS += [
-        'mozglue',
-    ]
+include('logalloc.mozbuild')
 
 DIRS += [
+    'minimal',
     'replay',
 ]
--- a/memory/replace/logalloc/replay/Makefile.in
+++ b/memory/replace/logalloc/replay/Makefile.in
@@ -2,35 +2,40 @@
 # 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/.
 
 include $(topsrcdir)/mozglue/build/replace_malloc.mk
 
 ifndef CROSS_COMPILE
 
 ifeq ($(OS_TARGET),WINNT)
-LOGALLOC = MOZ_REPLACE_MALLOC_LIB=$(CURDIR)/../logalloc.dll
+LOGALLOC_VAR = MOZ_REPLACE_MALLOC_LIB
 else
 ifeq ($(OS_TARGET),Darwin)
-LOGALLOC = DYLD_INSERT_LIBRARIES=$(CURDIR)/../liblogalloc.dylib
+LOGALLOC_VAR = DYLD_INSERT_LIBRARIES
 else
-LOGALLOC = LD_PRELOAD=$(CURDIR)/../$(DLL_PREFIX)logalloc$(DLL_SUFFIX)
+LOGALLOC_VAR = LD_PRELOAD
 endif
 endif
 
+LOGALLOC = $(LOGALLOC_VAR)=$(CURDIR)/../$(DLL_PREFIX)logalloc$(DLL_SUFFIX)
+LOGALLOC_MINIMAL = $(LOGALLOC_VAR)=$(CURDIR)/../minimal/$(DLL_PREFIX)logalloc_minimal$(DLL_SUFFIX)
+
 expected_output.log: $(srcdir)/replay.log
 # The logalloc-replay program will only replay entries from the first pid,
 # so the expected output only contains entries beginning with "1 "
 	grep "^1 " $< > $@
 
-check:: $(srcdir)/replay.log expected_output.log
+check:: $(srcdir)/replay.log expected_output.log $(srcdir)/expected_output_minimal.log
 # Test with MALLOC_LOG as a file descriptor number
 # We filter out anything happening before the first jemalloc_stats (first
 # command in replay.log) because starting with libstdc++ 5, a static
 # initializer in the STL allocates memory, which we obviously don't have
 # in expected_output.log.
 	MALLOC_LOG=1 $(LOGALLOC) ./$(PROGRAM) < $< | sed -n '/jemalloc_stats/,$$p' | $(PYTHON) $(srcdir)/logalloc_munge.py | diff -w - expected_output.log
 # Test with MALLOC_LOG as a file name
 	$(RM) test_output.log
 	MALLOC_LOG=test_output.log $(LOGALLOC) ./$(PROGRAM) < $<
 	sed -n '/jemalloc_stats/,$$p' test_output.log | $(PYTHON) $(srcdir)/logalloc_munge.py | diff -w - expected_output.log
 
+	MALLOC_LOG=1 $(LOGALLOC_MINIMAL) ./$(PROGRAM) < $< | sed -n '/jemalloc_stats/,$$p' | $(PYTHON) $(srcdir)/logalloc_munge.py | diff -w - $(srcdir)/expected_output_minimal.log
+
 endif
copy from memory/replace/logalloc/replay/replay.log
copy to memory/replace/logalloc/replay/expected_output_minimal.log
--- a/memory/replace/logalloc/replay/replay.log
+++ b/memory/replace/logalloc/replay/expected_output_minimal.log
@@ -1,18 +1,17 @@
 1 1 jemalloc_stats()
 1 1 malloc(42)=#1
 1 1 malloc(24)=#2
-2 2 malloc(42)=#1
 1 1 free(#1)
-1 1 posix_memalign(4096,1024)=#1
+1 1 memalign(4096,1024)=#1
 1 1 calloc(4,42)=#3
 1 1 free(#2)
 1 1 realloc(#3,84)=#2
-1 1 aligned_alloc(512,1024)=#3
+1 1 memalign(256,1024)=#3
 1 1 memalign(512,1024)=#4
-1 1 valloc(1024)=#5
+1 1 memalign(4096,1024)=#5
 1 1 jemalloc_stats()
 1 1 free(#5)
 1 1 free(#4)
 1 1 free(#3)
 1 1 free(#2)
 1 1 free(#1)
--- a/memory/replace/logalloc/replay/replay.log
+++ b/memory/replace/logalloc/replay/replay.log
@@ -2,17 +2,17 @@ 1 1 jemalloc_stats()
 1 1 malloc(42)=#1
 1 1 malloc(24)=#2
 2 2 malloc(42)=#1
 1 1 free(#1)
 1 1 posix_memalign(4096,1024)=#1
 1 1 calloc(4,42)=#3
 1 1 free(#2)
 1 1 realloc(#3,84)=#2
-1 1 aligned_alloc(512,1024)=#3
+1 1 aligned_alloc(256,1024)=#3
 1 1 memalign(512,1024)=#4
 1 1 valloc(1024)=#5
 1 1 jemalloc_stats()
 1 1 free(#5)
 1 1 free(#4)
 1 1 free(#3)
 1 1 free(#2)
 1 1 free(#1)
--- a/mfbt/Assertions.h
+++ b/mfbt/Assertions.h
@@ -309,17 +309,16 @@ MOZ_CrashPrintf(const char* aFilename, i
  * information is desired than a string literal can supply. The caller provides
  * a printf-style format string, which must be a string literal and between
  * 1 and 4 additional arguments. A regular MOZ_CRASH() is preferred wherever
  * possible, as passing arbitrary strings to printf from a potentially
  * compromised process is not without risk.
  */
 #define MOZ_CRASH_UNSAFE_PRINTF(format, ...) \
    do { \
-     MOZ_STATIC_ASSERT_VALID_ARG_COUNT(__VA_ARGS__); \
      static_assert( \
        MOZ_PASTE_PREFIX_AND_ARG_COUNT(, __VA_ARGS__) <= sPrintfMaxArgs, \
        "Only up to 4 additional arguments are allowed!"); \
      static_assert(sizeof(format) <= sPrintfCrashReasonSize, \
        "The supplied format string is too long!"); \
      MOZ_CALL_CRASH_PRINTF("" format, __VA_ARGS__); \
    } while (0)
 
--- a/mfbt/MacroArgs.h
+++ b/mfbt/MacroArgs.h
@@ -16,87 +16,62 @@
 #define MOZ_CONCAT(x, y) MOZ_CONCAT2(x, y)
 
 /*
  * MOZ_PASTE_PREFIX_AND_ARG_COUNT(aPrefix, ...) counts the number of variadic
  * arguments and prefixes it with |aPrefix|. For example:
  *
  *   MOZ_PASTE_PREFIX_AND_ARG_COUNT(, foo, 42) expands to 2
  *   MOZ_PASTE_PREFIX_AND_ARG_COUNT(A, foo, 42, bar) expands to A3
+ *   MOZ_PASTE_PREFIX_AND_ARG_COUNT(A) expands to A0
+ *   MOZ_PASTE_PREFIX_AND_ARG_COUNT() expands to 0, but MSVC warns there
+ *   aren't enough arguments given.
  *
- * You must pass in between 1 and 50 (inclusive) variadic arguments, past
- * |aPrefix|. It is not legal to do
- *
- *   MOZ_PASTE_PREFIX_AND_ARG_COUNT(prefix)
+ * You must pass in between 0 and 50 (inclusive) variadic arguments, past
+ * |aPrefix|.
  *
- * (that is, pass in 0 variadic arguments). To ensure that a compile-time
- * error occurs when these constraints are violated, use the
- * MOZ_STATIC_ASSERT_VALID_ARG_COUNT macro with the same variaidc arguments
- * wherever this macro is used.
+ * The `##__VA_ARGS__` form is a GCC extension that removes the comma if
+ * __VA_ARGS__ is empty. It is supported by Clang too. MSVC ignores ##,
+ * and its default behavior is already to strip the comma when __VA_ARGS__
+ * is empty.
  *
- * Passing (__VA_ARGS__, <rest of arguments>) rather than simply calling
- * MOZ_MACROARGS_ARG_COUNT_HELPER2(__VA_ARGS__, <rest of arguments>) very
- * carefully tiptoes around a MSVC bug where it improperly expands __VA_ARGS__
- * as a single token in argument lists. For details, see:
- *
- *   http://connect.microsoft.com/VisualStudio/feedback/details/380090/variadic-macro-replacement
- *   http://cplusplus.co.il/2010/07/17/variadic-macro-to-count-number-of-arguments/#comment-644
+ * So MOZ_MACROARGS_ARG_COUNT_HELPER(prefix) expands to
+ *   (_, prefix50, prefix49, ...)
+ * MOZ_MACROARGS_ARG_COUNT_HELPER(prefix, a) expands to
+ *   (_, a, prefix50, prefix49, ...)
+ * etc.
  */
 #define MOZ_PASTE_PREFIX_AND_ARG_COUNT(aPrefix, ...) \
-  MOZ_MACROARGS_ARG_COUNT_HELPER((__VA_ARGS__, \
+  MOZ_MACROARGS_ARG_COUNT_HELPER2( \
+    MOZ_MACROARGS_ARG_COUNT_HELPER(aPrefix, ##__VA_ARGS__))
+
+#define MOZ_MACROARGS_ARG_COUNT_HELPER(aPrefix, ...) (_, ##__VA_ARGS__, \
     aPrefix##50, aPrefix##49, aPrefix##48, aPrefix##47, aPrefix##46, \
     aPrefix##45, aPrefix##44, aPrefix##43, aPrefix##42, aPrefix##41, \
     aPrefix##40, aPrefix##39, aPrefix##38, aPrefix##37, aPrefix##36, \
     aPrefix##35, aPrefix##34, aPrefix##33, aPrefix##32, aPrefix##31, \
     aPrefix##30, aPrefix##29, aPrefix##28, aPrefix##27, aPrefix##26, \
     aPrefix##25, aPrefix##24, aPrefix##23, aPrefix##22, aPrefix##21, \
     aPrefix##20, aPrefix##19, aPrefix##18, aPrefix##17, aPrefix##16, \
     aPrefix##15, aPrefix##14, aPrefix##13, aPrefix##12, aPrefix##11, \
     aPrefix##10, aPrefix##9,  aPrefix##8,  aPrefix##7,  aPrefix##6,  \
-    aPrefix##5,  aPrefix##4,  aPrefix##3,  aPrefix##2,  aPrefix##1, aPrefix##0))
+    aPrefix##5,  aPrefix##4,  aPrefix##3,  aPrefix##2,  aPrefix##1, aPrefix##0)
 
-#define MOZ_MACROARGS_ARG_COUNT_HELPER(aArgs) \
-  MOZ_MACROARGS_ARG_COUNT_HELPER2 aArgs
+#define MOZ_MACROARGS_ARG_COUNT_HELPER2(aArgs) \
+  MOZ_MACROARGS_ARG_COUNT_HELPER3 aArgs
 
-#define MOZ_MACROARGS_ARG_COUNT_HELPER2( \
+#define MOZ_MACROARGS_ARG_COUNT_HELPER3(a0, \
    a1,  a2,  a3,  a4,  a5,  a6,  a7,  a8,  a9, a10, \
   a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, \
   a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, \
   a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, \
   a41, a42, a43, a44, a45, a46, a47, a48, a49, a50, \
   a51, ...) a51
 
 /*
- * MOZ_STATIC_ASSERT_VALID_ARG_COUNT ensures that a compile-time error occurs
- * when the argument count constraints of MOZ_PASTE_PREFIX_AND_ARG_COUNT are
- * violated. Use this macro wherever MOZ_PASTE_PREFIX_AND_ARG_COUNT is used
- * and pass it the same variadic arguments.
- *
- * This macro employs a few dirty tricks to function. To detect the zero
- * argument case, |(__VA_ARGS__)| is stringified, sizeof-ed, and compared to
- * what it should be in the absence of arguments.
- *
- * Detecting too many arguments is a little trickier. With a valid argument
- * count and a prefix of 1, MOZ_PASTE_PREFIX_AND_ARG_COUNT expands to e.g. 14.
- * With a prefix of 0.0, it expands to e.g. 0.04. If there are too many
- * arguments, it expands to the first argument over the limit. If this
- * exceeding argument is a number, the assertion will fail as there is no
- * number than can simultaneously be both > 10 and == 0. If the exceeding
- * argument is not a number, a compile-time error should still occur due to
- * the operations performed on it.
- */
-#define MOZ_MACROARGS_STRINGIFY_HELPER(x) #x
-#define MOZ_STATIC_ASSERT_VALID_ARG_COUNT(...) \
-  static_assert( \
-    sizeof(MOZ_MACROARGS_STRINGIFY_HELPER((__VA_ARGS__))) != sizeof("()") && \
-      (MOZ_PASTE_PREFIX_AND_ARG_COUNT(1, __VA_ARGS__)) > 10 && \
-      (int)(MOZ_PASTE_PREFIX_AND_ARG_COUNT(0.0, __VA_ARGS__)) == 0, \
-    "MOZ_STATIC_ASSERT_VALID_ARG_COUNT requires 1 to 50 arguments") /* ; */
-
-/*
  * MOZ_ARGS_AFTER_N expands to its arguments excluding the first |N|
  * arguments. For example:
  *
  *   MOZ_ARGS_AFTER_2(a, b, c, d) expands to: c, d
  */
 #define MOZ_ARGS_AFTER_1(a1, ...) __VA_ARGS__
 #define MOZ_ARGS_AFTER_2(a1, a2, ...) __VA_ARGS__
 
--- a/mfbt/MacroForEach.h
+++ b/mfbt/MacroForEach.h
@@ -45,19 +45,17 @@
  *
  *   #define MACRO_B(t, n) t n
  *   void test(MOZ_FOR_EACH_SEPARATED(MACRO_B, (,), (int,), (a, b)));
  *   // Expands to: void test(MACRO_B(int, a) , MACRO_B(int, b));
  *   // And further to: void test(int a , int b);
  *
  * If the |aFixedArgs| list is not empty, a trailing comma must be included.
  *
- * The |aArgs| list must be not be empty and may be up to 50 items long. Use
- * MOZ_STATIC_ASSERT_VALID_ARG_COUNT to ensure that violating this constraint
- * results in a compile-time error.
+ * The |aArgs| list may be up to 50 items long.
  */
 #define MOZ_FOR_EACH_EXPAND_HELPER(...) __VA_ARGS__
 #define MOZ_FOR_EACH_GLUE(a, b) a b
 #define MOZ_FOR_EACH_SEPARATED(aMacro, aSeparator, aFixedArgs, aArgs) \
   MOZ_FOR_EACH_GLUE( \
     MOZ_PASTE_PREFIX_AND_ARG_COUNT(MOZ_FOR_EACH_, \
                                    MOZ_FOR_EACH_EXPAND_HELPER aArgs), \
     (aMacro, aSeparator, aFixedArgs, aArgs))
@@ -65,16 +63,17 @@
   MOZ_FOR_EACH_SEPARATED(aMacro, (), aFixedArgs, aArgs)
 
 #define MOZ_FOR_EACH_HELPER_GLUE(a, b) a b
 #define MOZ_FOR_EACH_HELPER(aMacro, aFixedArgs, aArgs) \
   MOZ_FOR_EACH_HELPER_GLUE( \
     aMacro, \
     (MOZ_FOR_EACH_EXPAND_HELPER aFixedArgs MOZ_ARG_1 aArgs))
 
+#define MOZ_FOR_EACH_0(m, s, fa, a)
 #define MOZ_FOR_EACH_1(m, s, fa, a) \
   MOZ_FOR_EACH_HELPER(m, fa, a)
 #define MOZ_FOR_EACH_2(m, s, fa, a) \
   MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_EXPAND_HELPER s \
   MOZ_FOR_EACH_1(m, s, fa, (MOZ_ARGS_AFTER_1 a))
 #define MOZ_FOR_EACH_3(m, s, fa, a) \
   MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_EXPAND_HELPER s \
   MOZ_FOR_EACH_2(m, s, fa, (MOZ_ARGS_AFTER_1 a))
--- a/mfbt/tests/TestMacroArgs.cpp
+++ b/mfbt/tests/TestMacroArgs.cpp
@@ -1,19 +1,19 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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/. */
 
 #include "mozilla/MacroArgs.h"
 
-MOZ_STATIC_ASSERT_VALID_ARG_COUNT(1);
-MOZ_STATIC_ASSERT_VALID_ARG_COUNT(1, 2);
-
+static_assert(MOZ_PASTE_PREFIX_AND_ARG_COUNT(100) == 1000, "");
+static_assert(MOZ_PASTE_PREFIX_AND_ARG_COUNT(100, a) == 1001, "");
+static_assert(MOZ_PASTE_PREFIX_AND_ARG_COUNT(100, a, b) == 1002, "");
 static_assert(MOZ_PASTE_PREFIX_AND_ARG_COUNT(100, a, b, c) == 1003, "");
 
 static_assert(MOZ_PASTE_PREFIX_AND_ARG_COUNT(, a, b, c) == 3, "");
 static_assert(MOZ_PASTE_PREFIX_AND_ARG_COUNT(, a) == 1, "");
 static_assert(MOZ_PASTE_PREFIX_AND_ARG_COUNT(, !a) == 1, "");
 static_assert(MOZ_PASTE_PREFIX_AND_ARG_COUNT(, (a, b)) == 1, "");
 
 static_assert(MOZ_PASTE_PREFIX_AND_ARG_COUNT(, MOZ_ARGS_AFTER_1(a, b, c)) == 2,
--- a/mobile/locales/search/list.json
+++ b/mobile/locales/search/list.json
@@ -70,17 +70,17 @@
         "visibleDefaultEngines": [
           "google", "bing", "amazondotcom", "azerdict", "duckduckgo", "wikipedia-az"
         ]
       }
     },
     "be": {
       "default": {
         "visibleDefaultEngines": [
-          "google", "wikipedia-be", "bing", "yahoo", "yandex.by"
+          "google", "bing", "yahoo", "duckduckgo", "wikipedia-be", "yandex.by"
         ]
       }
     },
     "bg": {
       "default": {
         "visibleDefaultEngines": [
           "google", "yahoo", "bing", "wikipedia-bg"
         ]
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -307,16 +307,20 @@ pref("media.cache_size", 512000);
 // When a network connection is suspended, don't resume it until the
 // amount of buffered data falls below this threshold (in seconds).
 pref("media.cache_resume_threshold", 30);
 // Stop reading ahead when our buffered data is this many seconds ahead
 // of the current playback position. This limit can stop us from using arbitrary
 // amounts of network bandwidth prefetching huge videos.
 pref("media.cache_readahead_limit", 60);
 
+// Cache size hint (in bytes) for each MediaResourceIndex.
+// 0 -> no cache. Will use next power of 2, clamped to 32B-128KB.
+pref("media.cache.resource-index", 8192);
+
 // We'll throttle the download if the download rate is throttle-factor times
 // the estimated playback rate, AND we satisfy the cache readahead_limit
 // above. The estimated playback rate is time_duration/length_in_bytes.
 // This means we'll only throttle the download if there's no concern that
 // throttling would cause us to stop and buffer.
 pref("media.throttle-factor", 2);
 // By default, we'll throttle media download once we've reached the the
 // readahead_limit if the download is fast. This pref toggles the "and the
new file mode 100644
--- /dev/null
+++ b/security/sandbox/common/SandboxSettings.cpp
@@ -0,0 +1,68 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#include "mozISandboxSettings.h"
+
+#include "mozilla/ModuleUtils.h"
+#include "mozilla/Preferences.h"
+
+namespace mozilla {
+
+int GetEffectiveContentSandboxLevel() {
+  int level = Preferences::GetInt("security.sandbox.content.level");
+// On Windows and macOS, enforce a minimum content sandbox level of 1 (except on
+// Nightly, where it can be set to 0).
+#if !defined(NIGHTLY_BUILD) && (defined(XP_WIN) || defined(XP_MACOSX))
+  if (level < 1) {
+    level = 1;
+  }
+#endif
+  return level;
+}
+
+class SandboxSettings final : public mozISandboxSettings
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_MOZISANDBOXSETTINGS
+
+  SandboxSettings() { }
+
+private:
+  ~SandboxSettings() { }
+};
+
+NS_IMPL_ISUPPORTS(SandboxSettings, mozISandboxSettings)
+
+NS_IMETHODIMP SandboxSettings::GetEffectiveContentSandboxLevel(int32_t *aRetVal)
+{
+  *aRetVal = mozilla::GetEffectiveContentSandboxLevel();
+  return NS_OK;
+}
+
+NS_GENERIC_FACTORY_CONSTRUCTOR(SandboxSettings)
+
+NS_DEFINE_NAMED_CID(MOZ_SANDBOX_SETTINGS_CID);
+
+static const mozilla::Module::CIDEntry kSandboxSettingsCIDs[] = {
+  { &kMOZ_SANDBOX_SETTINGS_CID, false, nullptr, SandboxSettingsConstructor },
+  { nullptr }
+};
+
+static const mozilla::Module::ContractIDEntry kSandboxSettingsContracts[] = {
+  { MOZ_SANDBOX_SETTINGS_CONTRACTID, &kMOZ_SANDBOX_SETTINGS_CID },
+  { nullptr }
+};
+
+static const mozilla::Module kSandboxSettingsModule = {
+  mozilla::Module::kVersion,
+  kSandboxSettingsCIDs,
+  kSandboxSettingsContracts
+};
+
+NSMODULE_DEFN(SandboxSettingsModule) = &kSandboxSettingsModule;
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/security/sandbox/common/SandboxSettings.h
@@ -0,0 +1,17 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+#ifndef mozilla_SandboxSettings_h
+#define mozilla_SandboxSettings_h
+
+namespace mozilla {
+
+// Return the current sandbox level. This is the
+// "security.sandbox.content.level" preference, but rounded up to the current
+// minimum allowed level.
+int GetEffectiveContentSandboxLevel();
+
+}
+#endif // mozilla_SandboxPolicies_h
new file mode 100644
--- /dev/null
+++ b/security/sandbox/common/moz.build
@@ -0,0 +1,20 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+with Files('**'):
+    BUG_COMPONENT = ('Core', 'Security: Process Sandboxing')
+
+UNIFIED_SOURCES += ['SandboxSettings.cpp']
+
+XPIDL_SOURCES += [
+    'mozISandboxSettings.idl',
+]
+
+XPIDL_MODULE = 'sandbox'
+
+FINAL_LIBRARY = 'xul'
+
+EXPORTS.mozilla += ['SandboxSettings.h']
new file mode 100644
--- /dev/null
+++ b/security/sandbox/common/mozISandboxSettings.idl
@@ -0,0 +1,25 @@
+/* -*- Mode: IDL; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#include "nsISupports.idl"
+
+/* Used to expose information about the configuration of the sanbox.
+ */
+[scriptable, builtinclass, uuid(5516303d-9007-45a0-94b9-940ef134a6e2)]
+interface mozISandboxSettings : nsISupports
+{
+  readonly attribute long effectiveContentSandboxLevel;
+};
+
+%{ C++
+
+#define MOZ_SANDBOX_SETTINGS_CID \
+{0x5516303d, 0x9007, 0x45a0, { 0x94, 0xb9, 0x94, 0x0e, 0xf1, 0x34, 0xa6, 0xe2}}
+
+#define MOZ_SANDBOX_SETTINGS_CONTRACTID \
+    "@mozilla.org/sandbox/sandbox-settings;1"
+
+%}
--- a/security/sandbox/linux/broker/SandboxBrokerPolicyFactory.cpp
+++ b/security/sandbox/linux/broker/SandboxBrokerPolicyFactory.cpp
@@ -5,16 +5,17 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "SandboxBrokerPolicyFactory.h"
 #include "SandboxInfo.h"
 #include "SandboxLogging.h"
 
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/Preferences.h"
+#include "mozilla/SandboxSettings.h"
 #include "nsPrintfCString.h"
 #include "nsString.h"
 #include "nsThreadUtils.h"
 #include "nsXULAppAPI.h"
 #include "SpecialSystemDirectory.h"
 
 #ifdef ANDROID
 #include "cutils/properties.h"
@@ -157,17 +158,17 @@ SandboxBrokerPolicyFactory::SandboxBroke
 UniquePtr<SandboxBroker::Policy>
 SandboxBrokerPolicyFactory::GetContentPolicy(int aPid)
 {
   // Policy entries that vary per-process (currently the only reason
   // that can happen is because they contain the pid) are added here.
 
   MOZ_ASSERT(NS_IsMainThread());
   // File broker usage is controlled through a pref.
-  if (Preferences::GetInt("security.sandbox.content.level") <= 1) {
+  if (GetEffectiveContentSandboxLevel() <= 1) {
     return nullptr;
   }
 
   MOZ_ASSERT(mCommonContentPolicy);
 #if defined(MOZ_WIDGET_GONK)
   // Allow overriding "unsupported"ness with a pref, for testing.
   if (!IsSystemSupported()) {
     return nullptr;
--- a/security/sandbox/moz.build
+++ b/security/sandbox/moz.build
@@ -4,16 +4,18 @@
 # 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/.
 
 BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
 
 with Files('**'):
     BUG_COMPONENT = ('Core', 'Security: Process Sandboxing')
 
+DIRS += ['common']
+
 if CONFIG['OS_ARCH'] == 'Linux':
     DIRS += ['linux']
 elif CONFIG['OS_ARCH'] == 'Darwin':
     DIRS += ['mac']
 elif CONFIG['OS_ARCH'] == 'WINNT':
     Library('sandbox_s')
     FORCE_STATIC_LIB = True
 
--- a/security/sandbox/test/browser_content_sandbox_fs.js
+++ b/security/sandbox/test/browser_content_sandbox_fs.js
@@ -169,20 +169,16 @@ add_task(function* () {
 
   ok(prefExists, "pref security.sandbox.content.level exists");
   if (!prefExists) {
     return;
   }
 
   info(`security.sandbox.content.level=${level}`);
   ok(level > 0, "content sandbox is enabled.");
-  if (level == 0) {
-    info("content sandbox is not enabled, exiting");
-    return;
-  }
 
   let isFileIOSandboxed = isContentFileIOSandboxed(level);
 
   // Content sandbox enabled, but level doesn't include file I/O sandboxing.
   ok(isFileIOSandboxed, "content file I/O sandboxing is enabled.");
   if (!isFileIOSandboxed) {
     info("content sandbox level too low for file I/O tests, exiting\n");
     return;
--- a/security/sandbox/test/browser_content_sandbox_syscalls.js
+++ b/security/sandbox/test/browser_content_sandbox_syscalls.js
@@ -145,20 +145,16 @@ add_task(function* () {
 
   ok(prefExists, "pref security.sandbox.content.level exists");
   if (!prefExists) {
     return;
   }
 
   info(`security.sandbox.content.level=${level}`);
   ok(level > 0, "content sandbox is enabled.");
-  if (level == 0) {
-    info("content sandbox is not enabled, exiting");
-    return;
-  }
 
   let areSyscallsSandboxed = areContentSyscallsSandboxed(level);
 
   // Content sandbox enabled, but level doesn't include syscall sandboxing.
   ok(areSyscallsSandboxed, "content syscall sandboxing is enabled.");
   if (!areSyscallsSandboxed) {
     info("content sandbox level too low for syscall tests, exiting\n");
     return;
--- a/servo/Cargo.lock
+++ b/servo/Cargo.lock
@@ -107,17 +107,17 @@ dependencies = [
  "core-foundation 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-graphics 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-text 4.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "freetype 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo-egl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo-freetype-sys 4.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "servo-skia 0.30000004.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "servo-skia 0.30000004.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "x11 2.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "backtrace"
 version = "0.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
@@ -1319,17 +1319,17 @@ version = "0.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "jpeg-decoder"
 version = "0.1.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rayon 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "js"
 version = "0.1.4"
 source = "git+https://github.com/servo/rust-mozjs#08af3654a1e781af7d6690838545975234ddd2a0"
 dependencies = [
  "cmake 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1388,17 +1388,17 @@ dependencies = [
  "libc 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "net_traits 0.0.1",
  "ordered-float 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "profile_traits 0.0.1",
  "range 0.0.1",
- "rayon 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "script_layout_interface 0.0.1",
  "script_traits 0.0.1",
  "selectors 0.19.0",
  "serde 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo_config 0.0.1",
  "servo_geometry 0.0.1",
@@ -1435,17 +1435,17 @@ dependencies = [
  "layout 0.0.1",
  "layout_traits 0.0.1",
  "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "net_traits 0.0.1",
  "parking_lot 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "profile_traits 0.0.1",
- "rayon 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "script 0.0.1",
  "script_layout_interface 0.0.1",
  "script_traits 0.0.1",
  "selectors 0.19.0",
  "serde_derive 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo_config 0.0.1",
  "servo_geometry 0.0.1",
@@ -1696,17 +1696,16 @@ dependencies = [
  "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "msg"
 version = "0.0.1"
 dependencies = [
  "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "cssparser 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize_derive 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)",
  "webrender_traits 0.39.0 (git+https://github.com/servo/webrender)",
 ]
 
 [[package]]
@@ -2197,25 +2196,25 @@ dependencies = [
  "heapsize_derive 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "rayon"
-version = "0.7.0"
+version = "0.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "rayon-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rayon-core 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "rayon-core"
-version = "1.0.0"
+version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "futures 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
  "num_cpus 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2590,17 +2589,17 @@ dependencies = [
  "shell32-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "x11-dl 2.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "servo-skia"
-version = "0.30000004.1"
+version = "0.30000004.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "cgl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "cmake 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "expat-sys 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "gleam 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "glx 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2843,17 +2842,17 @@ dependencies = [
  "nsstring_vendor 0.1.0",
  "num-integer 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
  "num_cpus 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "ordered-float 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "pdqsort 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "precomputed-hash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rayon 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "selectors 0.19.0",
  "serde 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo_atoms 0.0.1",
  "servo_config 0.0.1",
  "servo_url 0.0.1",
  "smallvec 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2880,17 +2879,17 @@ name = "style_tests"
 version = "0.0.1"
 dependencies = [
  "app_units 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "cssparser 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "html5ever 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "rayon 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
  "selectors 0.19.0",
  "servo_atoms 0.0.1",
  "servo_config 0.0.1",
  "servo_url 0.0.1",
  "size_of_test 0.0.1",
  "style 0.0.1",
  "style_traits 0.0.1",
@@ -3295,17 +3294,17 @@ dependencies = [
  "freetype 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "gamma-lut 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "gleam 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
  "offscreen_gl_context 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)",
  "plane-split 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rayon 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "thread_profiler 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "time 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
  "webrender_traits 0.39.0 (git+https://github.com/servo/webrender)",
 ]
 
 [[package]]
 name = "webrender_traits"
 version = "0.39.0"
@@ -3602,18 +3601,18 @@ dependencies = [
 "checksum png 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3cb773e9a557edb568ce9935cf783e3cdcabe06a9449d41b3e5506d88e582c82"
 "checksum precomputed-hash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf1fc3616b3ef726a847f2cd2388c646ef6a1f1ba4835c2629004da48184150"
 "checksum procedural-masquerade 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9f566249236c6ca4340f7ca78968271f0ed2b0f234007a61b66f9ecd0af09260"
 "checksum pulldown-cmark 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1058d7bb927ca067656537eec4e02c2b4b70eaaa129664c5b90c111e20326f41"
 "checksum quasi 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18c45c4854d6d1cf5d531db97c75880feb91c958b0720f4ec1057135fec358b3"
 "checksum quasi_codegen 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "51b9e25fa23c044c1803f43ca59c98dac608976dd04ce799411edd58ece776d4"
 "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
 "checksum rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "022e0636ec2519ddae48154b028864bdce4eaf7d35226ab8e65c611be97b189d"
-"checksum rayon 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8c83adcb08e5b922e804fe1918142b422602ef11f2fd670b0b52218cb5984a20"
-"checksum rayon-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "767d91bacddf07d442fe39257bf04fd95897d1c47c545d009f6beb03efd038f8"
+"checksum rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a77c51c07654ddd93f6cb543c7a849863b03abc7e82591afda6dc8ad4ac3ac4a"
+"checksum rayon-core 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bd1e76f8ee0322fbbeb0c43a07e1757fcf8ff06bb0ff92da017625882ddc04dd"
 "checksum redox_syscall 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "29dbdfd4b9df8ab31dec47c6087b7b13cbf4a776f335e4de8efba8288dda075b"
 "checksum ref_filter_map 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2b5ceb840e4009da4841ed22a15eb49f64fdd00a2138945c5beacf506b2fb5ed"
 "checksum ref_slice 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "825740057197b7d43025e7faf6477eaabc03434e153233da02d1f44602f71527"
 "checksum regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1731164734096285ec2a5ec7fea5248ae2f5485b3feeb0115af4fda2183b2d1b"
 "checksum regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad890a5eef7953f55427c50575c680c42841653abd2b028b68cd223d157f62db"
 "checksum rust-webvr 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "263be07c1d462798df737e4dcc6920ac92727340b05985a0328e3a86c9592b19"
 "checksum rustc-demangle 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3058a43ada2c2d0b92b3ae38007a2d0fa5e9db971be260e0171408a4ff471c95"
 "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
@@ -3625,17 +3624,17 @@ dependencies = [
 "checksum serde_codegen_internals 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bc888bd283bd2420b16ad0d860e35ad8acb21941180a83a189bb2046f9d00400"
 "checksum serde_derive 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)" = "978fd866f4d4872084a81ccc35e275158351d3b9fe620074e7d7504b816b74ba"
 "checksum serde_json 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ad8bcf487be7d2e15d3d543f04312de991d631cfe1b43ea0ade69e6a8a5b16a1"
 "checksum servo-egl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "21069a884c33fe6ee596975e1f3849ed88c4ec857fbaf11d33672d8ebe051217"
 "checksum servo-fontconfig 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "93f799b649b4a2bf362398910eca35240704c7e765e780349b2bb1070d892262"
 "checksum servo-fontconfig-sys 4.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6be80777ee6edecbbbf8774c76e19dddfe336256c57a4ded06d6ad3df7be358e"
 "checksum servo-freetype-sys 4.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9232032c2e85118c0282c6562c84cab12316e655491ba0a5d1905b2320060d1b"
 "checksum servo-glutin 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8398095f9b3dc3c6d706d395e192624be1f1bcc6f366b009fe17a20cb5dd3d72"
-"checksum servo-skia 0.30000004.1 (registry+https://github.com/rust-lang/crates.io-index)" = "22ba980da523e91b9d2f7da9fb35f721138a1e604b8d8191e56f403e4760a9e4"
+"checksum servo-skia 0.30000004.3 (registry+https://github.com/rust-lang/crates.io-index)" = "109e567850bad212ee98ed9651e256de862bd9764476f2b16355af5f6ef59cfe"
 "checksum servo-websocket 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8a1ff13c5d852c2793805226e688044309f2c1d8f063784805a13e99cb75b611"
 "checksum sha1 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cc30b1e1e8c40c121ca33b86c23308a090d19974ef001b4bf6e61fd1a0fb095c"
 "checksum shared_library 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fb04126b6fcfd2710fb5b6d18f4207b6c535f2850a7e1a43bcd526d44f30a79a"
 "checksum shell32-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "72f20b8f3c060374edb8046591ba28f62448c369ccbdc7b02075103fb3a9e38d"
 "checksum sig 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c6649e43c1a1e68d29ed56d0dc3b5b6cf3b901da77cf107c4066b9e3da036df5"
 "checksum signpost 0.1.0 (git+https://github.com/pcwalton/signpost.git)" = "<none>"
 "checksum simd 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a94d14a2ae1f1f110937de5fb69e494372560181c7e1739a097fcc2cee37ba0"
 "checksum siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0df90a788073e8d0235a67e50441d47db7c8ad9debd91cbf43736a2a92d36537"
--- a/servo/components/layout/Cargo.toml
+++ b/servo/components/layout/Cargo.toml
@@ -25,17 +25,17 @@ ipc-channel = "0.7"
 libc = "0.2"
 log = "0.3.5"
 msg = {path = "../msg"}
 net_traits = {path = "../net_traits"}
 ordered-float = "0.4"
 parking_lot = "0.3.3"
 profile_traits = {path = "../profile_traits"}
 range = {path = "../range"}
-rayon = "0.7"
+rayon = "0.7.1"
 script_layout_interface = {path = "../script_layout_interface"}
 script_traits = {path = "../script_traits"}
 selectors = { path = "../selectors" }
 serde = "0.9"
 serde_derive = "0.9"
 servo_geometry = {path = "../geometry"}
 serde_json = "0.9"
 servo_config = {path = "../config"}
--- a/servo/components/layout_thread/Cargo.toml
+++ b/servo/components/layout_thread/Cargo.toml
@@ -20,17 +20,17 @@ ipc-channel = "0.7"
 layout = {path = "../layout"}
 layout_traits = {path = "../layout_traits"}
 lazy_static = "0.2"
 log = "0.3.5"
 msg = {path = "../msg"}
 net_traits = {path = "../net_traits"}
 parking_lot = {version = "0.3.3", features = ["nightly"]}
 profile_traits = {path = "../profile_traits"}
-rayon = "0.7"
+rayon = "0.7.1"
 script = {path = "../script"}
 script_layout_interface = {path = "../script_layout_interface"}
 script_traits = {path = "../script_traits"}
 selectors = { path = "../selectors" }
 serde_derive = "0.9"
 serde_json = "0.9"
 servo_config = {path = "../config"}
 servo_geometry = {path = "../geometry"}
--- a/servo/components/msg/Cargo.toml
+++ b/servo/components/msg/Cargo.toml
@@ -6,14 +6,13 @@ license = "MPL-2.0"
 publish = false
 
 [lib]
 name = "msg"
 path = "lib.rs"
 
 [dependencies]
 bitflags = "0.7"
-cssparser = "0.13.3"
 heapsize = "0.3.0"
 heapsize_derive = "0.1"
 serde = "0.9"
 serde_derive = "0.9"
 webrender_traits = {git = "https://github.com/servo/webrender", features = ["ipc"]}
--- a/servo/components/script/dom/htmlimageelement.rs
+++ b/servo/components/script/dom/htmlimageelement.rs
@@ -519,32 +519,30 @@ impl HTMLImageElement {
                             pending_request.image = None;
                             pending_request.parsed_url = None;
                             LoadBlocker::terminate(&mut pending_request.blocker);
                             // TODO: queue a task to restart animation, if restart-animation is set
                             return
                         }
                         self.image_request.set(ImageRequestPhase::Pending);
                         self.init_image_request(&mut pending_request, &url, &src);
-                        self.fetch_image(&url);
                     },
                     (_, State::Broken) | (_, State::Unavailable) => {
                         // Step 12.5
                         self.init_image_request(&mut current_request, &url, &src);
-                        self.fetch_image(&url);
                     },
                     (_, _) => {
                         // step 12.6
                         self.image_request.set(ImageRequestPhase::Pending);
                         self.init_image_request(&mut pending_request, &url, &src);
-                        self.fetch_image(&url);
                     },
                 }
             }
         }
+        self.fetch_image(&url);
     }
 
     /// Step 8-12 of html.spec.whatwg.org/multipage/#update-the-image-data
     fn update_the_image_data_sync_steps(&self) {
         let document = document_from_node(self);
         // Step 8
         // TODO: take pixel density into account
         match self.select_image_source() {
--- a/servo/components/style/Cargo.toml
+++ b/servo/components/style/Cargo.toml
@@ -51,28 +51,28 @@ matches = "0.1"
 nsstring_vendor = {path = "gecko_bindings/nsstring_vendor", optional = true}
 num_cpus = {version = "1.1.0", optional = true}
 num-integer = "0.1.32"
 num-traits = "0.1.32"
 ordered-float = "0.4"
 parking_lot = "0.3.3"
 pdqsort = "0.1.0"
 precomputed-hash = "0.1"
-rayon = "0.7"
+rayon = "0.7.1"
 selectors = { path = "../selectors" }
 serde = {version = "0.9", optional = true}
 serde_derive = {version = "0.9", optional = true}
 servo_atoms = {path = "../atoms", optional = true}
 servo_config = {path = "../config", optional = true}
 smallvec = "0.3.3"
 style_derive = {path = "../style_derive"}
 style_traits = {path = "../style_traits"}
 servo_url = {path = "../url", optional = true}
 time = "0.1"
-unicode-bidi = {version = "0.3", features = ["with_serde"]}
+unicode-bidi = "0.3"
 unicode-segmentation = "1.0"
 
 [target.'cfg(windows)'.dependencies]
 kernel32-sys = "0.2"
 
 [build-dependencies]
 lazy_static = "0.2"
 log = "0.3"
--- a/servo/etc/ci/buildbot_steps.yml
+++ b/servo/etc/ci/buildbot_steps.yml
@@ -52,17 +52,16 @@ mac-rel-css2:
   - ./mach test-css --release --processes 4 --total-chunks 2 --this-chunk 2 --log-raw test-css.log --log-errorsummary css-errorsummary.log --always-succeed
   - ./mach filter-intermittents css-errorsummary.log --log-intermittents intermittents.log --log-filteredsummary filtered-css-errorsummary.log --use-tracker
 
 mac-nightly:
   - ./mach clean-nightlies --keep 3 --force
   - ./mach build --release
   - ./mach package --release
   - ./mach upload-nightly mac
-  - ./mach upload-nightly macbrew
 
 linux-rel-intermittent:
   - ./mach clean-nightlies --keep 3 --force
   - ./mach build --release
   - ./etc/ci/check_intermittents.sh --log-raw intermittents.log
 
 mac-rel-intermittent:
   - ./mach clean-nightlies --keep 3 --force
--- a/servo/etc/ci/check_dynamic_symbols.py
+++ b/servo/etc/ci/check_dynamic_symbols.py
@@ -18,17 +18,17 @@ symbol_regex = re.compile(b"D  \*UND\*\t
 allowed_symbols = frozenset([b'unshare', b'malloc_usable_size', b'__cxa_type_match'])
 actual_symbols = set()
 
 objdump_output = subprocess.check_output([
     os.path.join(
         os.environ['ANDROID_NDK'], 'toolchains', 'arm-linux-androideabi-4.9',
         'prebuilt', 'linux-x86_64', 'bin', 'arm-linux-androideabi-objdump'),
     '-T',
-    'target/arm-linux-androideabi/debug/libservo.so']
+    'target/armv7-linux-androideabi/debug/libservo.so']
 ).split(b'\n')
 
 for line in objdump_output:
     m = symbol_regex.search(line)
     if m is not None:
         actual_symbols.add(m.group(2))
 
 difference = actual_symbols - allowed_symbols
--- a/servo/python/servo/command_base.py
+++ b/servo/python/servo/command_base.py
@@ -272,17 +272,18 @@ class CommandBase(object):
         self.config["build"].setdefault("ccache", "")
         self.config["build"].setdefault("rustflags", "")
         self.config["build"].setdefault("incremental", False)
 
         self.config.setdefault("android", {})
         self.config["android"].setdefault("sdk", "")
         self.config["android"].setdefault("ndk", "")
         self.config["android"].setdefault("toolchain", "")
-        self.handle_android_target("arm-linux-androideabi")
+        # Set default android target
+        self.handle_android_target("armv7-linux-androideabi")
 
         self.set_cargo_root()
         self.set_use_stable_rust(False)
 
     _use_stable_rust = False
     _rust_version = None
     _rust_version_is_stable = False
     _cargo_build_id = None
--- a/servo/python/servo/package_commands.py
+++ b/servo/python/servo/package_commands.py
@@ -170,20 +170,28 @@ class PackageCommands(CommandBase):
     @CommandArgument('--release', '-r', action='store_true',
                      help='Package the release build')
     @CommandArgument('--dev', '-d', action='store_true',
                      help='Package the dev build')
     @CommandArgument('--android',
                      default=None,
                      action='store_true',
                      help='Package Android')
-    def package(self, release=False, dev=False, android=None, debug=False, debugger=None):
+    @CommandArgument('--target', '-t',
+                     default=None,
+                     help='Package for given target platform')
+    def package(self, release=False, dev=False, android=None, debug=False, debugger=None, target=None):
         env = self.build_env()
         if android is None:
             android = self.config["build"]["android"]
+        if target and android:
+            print("Please specify either --target or --android.")
+            sys.exit(1)
+        if not android:
+            android = self.handle_android_target(target)
         binary_path = self.get_binary_path(release, dev, android=android)
         dir_to_root = self.get_top_dir()
         target_dir = path.dirname(binary_path)
         if android:
             android_target = self.config["android"]["target"]
             if "aarch64" in android_target:
                 build_type = "Arm64"
             elif "armv7" in android_target:
@@ -379,17 +387,25 @@ class PackageCommands(CommandBase):
              category='package')
     @CommandArgument('--release', '-r', action='store_true',
                      help='Install the release build')
     @CommandArgument('--dev', '-d', action='store_true',
                      help='Install the dev build')
     @CommandArgument('--android',
                      action='store_true',
                      help='Install on Android')
-    def install(self, release=False, dev=False, android=False):
+    @CommandArgument('--target', '-t',
+                     default=None,
+                     help='Install the given target platform')
+    def install(self, release=False, dev=False, android=False, target=None):
+        if target and android:
+            print("Please specify either --target or --android.")
+            sys.exit(1)
+        if not android:
+            android = self.handle_android_target(target)
         try:
             binary_path = self.get_binary_path(release, dev, android=android)
         except BuildNotFound:
             print("Servo build not found. Building servo...")
             result = Registrar.dispatch(
                 "build", context=self.context, release=release, dev=dev, android=android
             )
             if result:
--- a/testing/geckodriver/Cargo.lock
+++ b/testing/geckodriver/Cargo.lock
@@ -1,14 +1,14 @@
 [root]
 name = "geckodriver"
 version = "0.16.1"
 dependencies = [
  "chrono 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)",
- "clap 2.20.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "clap 2.24.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "hyper 0.10.10 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "mozprofile 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "mozrunner 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "mozversion 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -66,17 +66,17 @@ name = "base64"
 version = "0.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "bitflags"
-version = "0.7.0"
+version = "0.8.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "byteorder"
 version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
@@ -108,26 +108,25 @@ version = "0.2.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "num 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
  "time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "clap"
-version = "2.20.5"
+version = "2.24.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "term_size 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "unicode-segmentation 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "vec_map 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "cookie"
 version = "0.6.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -177,26 +176,26 @@ dependencies = [
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "mime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "num_cpus 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
  "traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "url 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "idna"
-version = "0.1.0"
+version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "unicode-bidi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-bidi 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "unicode-normalization 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "isatty"
 version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
@@ -512,17 +511,17 @@ name = "tempdir"
 version = "0.3.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "term_size"
-version = "0.2.3"
+version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
  "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -569,17 +568,17 @@ name = "unicase"
 version = "1.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "unicode-bidi"
-version = "0.2.5"
+version = "0.3.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "unicode-normalization"
 version = "0.1.4"
@@ -600,20 +599,20 @@ name = "unreachable"
 version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "url"
-version = "1.4.0"
+version = "1.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "idna 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "utf8-ranges"
 version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
@@ -623,17 +622,17 @@ version = "0.1.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "vec_map"
-version = "0.6.0"
+version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "void"
 version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
@@ -643,17 +642,17 @@ source = "registry+https://github.com/ru
 dependencies = [
  "backtrace 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "cookie 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "hyper 0.10.10 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
  "time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
- "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "url 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "winapi"
 version = "0.2.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
@@ -686,31 +685,31 @@ dependencies = [
 ]
 
 [metadata]
 "checksum advapi32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "307c92332867e586720c0222ee9d890bbe8431711efed8a1b06bc5b40fc66bd7"
 "checksum aho-corasick 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0638fd549427caa90c499814196d1b9e3725eb4d15d7339d6de073a680ed0ca2"
 "checksum backtrace 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "72f9b4182546f4b04ebc4ab7f84948953a118bd6021a1b6a6c909e3e94f6be76"
 "checksum backtrace-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d192fd129132fbc97497c1f2ec2c2c5174e376b95f535199ef4fe0a293d33842"
 "checksum base64 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "30e93c03064e7590d0466209155251b90c22e37fab1daf2771582598b5827557"
-"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
+"checksum bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1370e9fc2a6ae53aea8b7a5110edbd08836ed87c88736dfabccade1c2b44bff4"
 "checksum byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c40977b0ee6b9885c9013cd41d9feffdd22deb3bb4dc3a71d901cc7a77de18c8"
 "checksum bzip2 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3eafc42c44e0d827de6b1c131175098fe7fb53b8ce8a47e65cb3ea94688be24"
 "checksum bzip2-sys 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "98ce3fff84d4e90011f464bbdf48e3428f04270439f703868fd489d2aaedfc30"
 "checksum cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de1e760d7b6535af4241fca8bd8adf68e2e7edacc6b29f5d399050c5e48cf88c"
 "checksum chrono 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)" = "9213f7cd7c27e95c2b57c49f0e69b1ea65b27138da84a170133fd21b07659c00"
-"checksum clap 2.20.5 (registry+https://github.com/rust-lang/crates.io-index)" = "7db281b0520e97fbd15cd615dcd8f8bcad0c26f5f7d5effe705f090f39e9a758"
+"checksum clap 2.24.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6b8f69e518f967224e628896b54e41ff6acfb4dcfefc5076325c36525dac900f"
 "checksum cookie 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "30b3493e12a550c2f96be785088d1da8d93189e7237c8a8d0d871bc9070334c3"
 "checksum crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0c5ea215664ca264da8a9d9c3be80d2eaf30923c259d03e870388eb927508f97"
 "checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850"
 "checksum flate2 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)" = "36df0166e856739905cd3d7e0b210fe818592211a008862599845e012d8d304c"
 "checksum gcc 0.3.42 (registry+https://github.com/rust-lang/crates.io-index)" = "291055c78f59ca3d84c99026c9501c469413d386bb46be1e1cf1d285cd1db3b0"
 "checksum httparse 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77f756bed9ee3a83ce98774f4155b42a31b787029013f3a7d83eca714e500e21"
 "checksum hyper 0.10.10 (registry+https://github.com/rust-lang/crates.io-index)" = "36e108e0b1fa2d17491cbaac4bc460dc0956029d10ccf83c913dd0e5db3e7f07"
-"checksum idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1053236e00ce4f668aeca4a769a09b3bf5a682d802abd6f3cb39374f6b162c11"
+"checksum idna 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2233d4940b1f19f0418c158509cd7396b8d70a5db5705ce410914dc8fa603b37"
 "checksum isatty 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fa500db770a99afe2a0f2229be2a3d09c7ed9d7e4e8440bf71253141994e240f"
 "checksum kernel32-sys 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e014dab1082fd9d80ea1fa6fcb261b47ed3eb511612a14198bb507701add083e"
 "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
 "checksum ktmw32-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7f9313a869ff779ae08dd990b75a92dc06aa16d771f41305f7286649cd39a0ee"
 "checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a"
 "checksum lazy_static 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "cf186d1a8aa5f5bee5fd662bc9c1b949e0259e1bcc379d1f006847b0080c7417"
 "checksum lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6abe0ee2e758cd6bc8a2cd56726359007748fbf4128da998b65d0b70f881e19b"
 "checksum libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)" = "684f330624d8c3784fb9558ca46c4ce488073a8d22450415c5eb4f4cfb0d11b5"
@@ -743,30 +742,30 @@ dependencies = [
 "checksum slog 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bab9d589681f7d6b9ca4ed5cc861779a392bca7beaae2f69f2341617415a78dc"
 "checksum slog-atomic 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d6f5a4e4908d6818fe553b6126ba5377801556ab885c65ebf960b722a6778864"
 "checksum slog-extra 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "511581f4dd1dc90e4eca99b60be8a692d9c975e8757558aa774f16007d27492a"
 "checksum slog-stdlog 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "56cc08f40c45e0ab41dcfde0a19a22c5b7176d3827fc7d078450ebfdc080a37c"
 "checksum slog-stream 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3fac4af71007ddb7338f771e059a46051f18d1454d8ac556f234a0573e719daa"
 "checksum slog-term 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cb53c0bae0745898fd5a7b75b1c389507333470ac4c645ae431890c0f828b6ca"
 "checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694"
 "checksum tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6"
-"checksum term_size 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "07b6c1ac5b3fffd75073276bca1ceed01f67a28537097a2a9539e116e50fb21a"
+"checksum term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2b6b55df3198cc93372e85dd2ed817f0e38ce8cc0f22eb32391bfad9c4bf209"
 "checksum thread-id 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4437c97558c70d129e40629a5b385b3fb1ffac301e63941335e4d354081ec14a"
 "checksum thread_local 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c85048c6260d17cf486ceae3282d9fb6b90be220bf5b28c400f5485ffc29f0c7"
 "checksum time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "211b63c112206356ef1ff9b19355f43740fc3f85960c598a93d3a3d3ba7beade"
 "checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079"
 "checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887"
 "checksum unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "13a5906ca2b98c799f4b1ab4557b76367ebd6ae5ef14930ec841c74aed5f3764"
-"checksum unicode-bidi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d3a078ebdd62c0e71a709c3d53d2af693fe09fe93fbff8344aebe289b78f9032"
+"checksum unicode-bidi 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a6a2c4e3710edd365cd7e78383153ed739fa31af19f9172f72d3575060f5a43a"
 "checksum unicode-normalization 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e28fa37426fceeb5cf8f41ee273faa7c82c47dc8fba5853402841e665fcd86ff"
 "checksum unicode-segmentation 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18127285758f0e2c6cf325bb3f3d138a12fee27de4f23e146cd6a179f26c2cf3"
 "checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f"
 "checksum unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2ae5ddb18e1c92664717616dd9549dde73f539f01bd7b77c2edb2446bdff91"
-"checksum url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f5ba8a749fb4479b043733416c244fa9d1d3af3d7c23804944651c8a448cb87e"
+"checksum url 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3e2ba3456fbe5c0098cb877cf08b92b76c3e18e0be9e47c35b487220d377d24e"
 "checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122"
 "checksum uuid 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "78c590b5bd79ed10aad8fb75f078a59d8db445af6c743e55c4a53227fc01c13f"
-"checksum vec_map 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cac5efe5cb0fa14ec2f84f83c701c562ee63f6dcc680861b21d65c682adfb05f"
+"checksum vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887b5b631c2ad01628bbbaa7dd4c869f80d3186688f8d0b6f58774fbe324988c"
 "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
 "checksum webdriver 0.25.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0d161bc62ed766ddc0838af89f1b339ed3c8b5c3dbe8776b59731dfae7b1a6c7"
 "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
 "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
 "checksum winreg 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e63857fb213f619b4c4fff86b158285c76766aac7e7474967e92fb6dbbfeefe9"
 "checksum zip 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)" = "c0deac03fc7d43abcf19f2c2db6bd9289f9ea3d31f350e26eb0ed8b4117983c1"
new file mode 100644
--- /dev/null
+++ b/third_party/rust/atty/.cargo-checksum.json
@@ -0,0 +1,1 @@
+{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".gitignore":"7a3d49ec6b768c90a70ae9c97fdcda96f90849b3e38164db8d3239f79a53c3e4",".travis.yml":"4752c993a36dc8b271f25998b2c0b34af65f82fb61f7d71d0e34612a8a7cd5b0","CHANGELOG.md":"a182831141a059342664a8aaf40b9fd7828e8004094fb42e1b17129a090899ec","Cargo.toml":"5fa1586ac82ee945f057b87c81acae6e588de2303536445b4a766028633347e0","LICENSE":"235760c32039b0a6b23207918b71c1aa5d8318ee651c0f245d290ba1f47631cf","README.md":"b23f66e15c8311e11cbc3b10bfc87a7cb10bc4d758c6a352b155127b48b970d7","appveyor.yml":"dfe3d3eddd762a3cc76174e03ea91c93f544ce7fa05fbca4975f1624757d65e4","examples/atty.rs":"1551387a71474d9ac1b5153231f884e9e05213badcfaa3494ad2cb7ea958374a","src/lib.rs":"4530fe39e123b042eb023e4cf98a81d5184d06c938d3604b002f418101beb524"},"package":"d912da0db7fa85514874458ca3651fe2cddace8d0b0505571dbdcd41ab490159"}
\ No newline at end of file
new file mode 100644
new file mode 100644
--- /dev/null
+++ b/third_party/rust/atty/.gitignore
@@ -0,0 +1,3 @@
+target
+Cargo.lock
+*.bk
new file mode 100644
--- /dev/null
+++ b/third_party/rust/atty/.travis.yml
@@ -0,0 +1,44 @@
+sudo: false
+language: rust
+matrix:
+  fast_finish: true
+  include:
+    - rust: nightly
+    - rust: beta
+    - rust: stable
+    - rust: 1.8.0
+os:
+ - linux
+ - osx
+script:
+  - cargo build
+  - cargo test
+cache:
+  apt: true
+  directories:
+  - target/debug/deps
+  - target/debug/build
+addons:
+  apt:
+    packages:
+    - libcurl4-openssl-dev
+    - libelf-dev
+    - libdw-dev
+    - binutils-dev # required for `kcov --verify`
+    - libbfd-dev # required for `kcov --verify`
+after_success: |
+  [ $TRAVIS_RUST_VERSION = stable ] &&
+  wget https://github.com/SimonKagstrom/kcov/archive/master.tar.gz &&
+  tar xzf master.tar.gz && mkdir kcov-master/build && cd kcov-master/build && cmake .. && make && make install DESTDIR=../tmp && cd ../.. &&
+  ls target/debug &&
+  ./kcov-master/tmp/usr/local/bin/kcov --verify --coveralls-id=$TRAVIS_JOB_ID --exclude-pattern=/.cargo target/kcov target/debug/atty-* &&
+  [ $TRAVIS_BRANCH = master ] &&
+  [ $TRAVIS_PULL_REQUEST = false ] &&
+  cargo doc --no-deps &&
+  echo "<meta http-equiv=refresh content=0;url=`echo $TRAVIS_REPO_SLUG | cut -d '/' -f 2`/index.html>" > target/doc/index.html &&
+  pip install --user ghp-import &&
+  /home/travis/.local/bin/ghp-import -n target/doc &&
+  git push -fq https://${GH_TOKEN}@github.com/${TRAVIS_REPO_SLUG}.git gh-pages
+env:
+  global:
+    secure: acjXoBFG4yFklz/iW4q9PLaMmTgug0c8hOov4uiaXYjDkVGhnEePBozGc8ctKuFv2BVlwBSzvE1neE9dHcCS6il0x+G79sVTekfVN5dERja3UpwrC0/QodJuDmErIUpb6zylupPnUGq5pzZabRPNKyAnsFS5wYhLMSLxGPu4pfYdW0Eu8CEPIgPYsI6o2pfKgNpXbeizdHRLMeZCN4cbEPohO1odc+Z6WJvgKn2xEkpAcfhAuaroqGGxRtmDiJZ/JaBijAKY/O9Q3Xq1GSGOPT5lmwJSp3Fxw5dgmeX6LmN0ZODASdnEoYfoqUDUFzkCON3Sk4a7hugxlkZ7cx1tfqXxMg+0BgYIUdGQNloDJnuusWvXPBFdB2jxMsfcbrCjNsrJ8kjN6uBsW9yy0kqN7a8eOJckwh5fYRWfNta0R+BrveNXWmGp4u4aBq/85jEiHi30XKTzaEUbF0Y3cIONweWeWwBOcAvPBhO63Y07TRRe+SSk1NYm7QHGW9RsHhz89OSbaIXqn+r/o+6DZcw5XaO73DtZ62Kx48NErej9kVqcIJ6HnyvCJ/fJoT7h1ixSRI/WmS30l2S/q33Q2G4C/IZ4ZZRD/1thSltAxeA6OAUnr8ITZyW47CqOmyL1IUptrdAb9OLEedYV/QrOhcg2RJLXyP66xnItOwMp014bEp4=
new file mode 100644
--- /dev/null
+++ b/third_party/rust/atty/CHANGELOG.md
@@ -0,0 +1,25 @@
+# 0.2.2
+
+* use target specific dependencies [#11](https://github.com/softprops/atty/pull/11)
+* Add tty detection for MSYS terminals [#12](https://github.com/softprops/atty/pull/12)
+
+# 0.2.1
+
+* fix windows bug
+
+# 0.2.0
+
+* support for various stream types
+
+# 0.1.2
+
+* windows support (with automated testing)
+* automated code coverage
+
+# 0.1.1
+
+* bumped libc dep from `0.1` to `0.2`
+
+# 0.1.0
+
+* initial release
new file mode 100644
--- /dev/null
+++ b/third_party/rust/atty/Cargo.toml
@@ -0,0 +1,17 @@
+[package]
+name = "atty"
+version = "0.2.2"
+authors = ["softprops <d.tangren@gmail.com>"]
+description = "A simple interface for querying atty"
+documentation = "http://softprops.github.io/atty"
+homepage = "https://github.com/softprops/atty"
+repository = "https://github.com/softprops/atty"
+keywords = ["terminal", "tty"]
+license = "MIT"
+
+[target.'cfg(not(windows))'.dependencies]
+libc = "0.2"
+
+[target.'cfg(windows)'.dependencies]
+kernel32-sys = "0.2"
+winapi = "0.2"
new file mode 100644
--- /dev/null
+++ b/third_party/rust/atty/LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2015-2016 Doug Tangren
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
new file mode 100644
--- /dev/null
+++ b/third_party/rust/atty/README.md
@@ -0,0 +1,78 @@
+# atty
+
+[![Build Status](https://travis-ci.org/softprops/atty.svg?branch=master)](https://travis-ci.org/softprops/atty) [![Build status](https://ci.appveyor.com/api/projects/status/geggrsnsjsuse8cv?svg=true)](https://ci.appveyor.com/project/softprops/atty) [![Coverage Status](https://coveralls.io/repos/softprops/atty/badge.svg?branch=master&service=github)](https://coveralls.io/github/softprops/atty?branch=master) [![crates.io](http://meritbadge.herokuapp.com/atty)](https://crates.io/crates/atty)
+
+> are you or are you not a tty?
+
+
+[Api documentation](http://softprops.github.io/atty)
+
+## usage
+
+```rust
+extern crate atty;
+
+use atty::Stream;
+
+fn main() {
+  if atty::is(Stream::Stdout) {
+    println!("I'm a terminal");
+  } else {
+    println!("I'm not");
+  }
+}
+```
+
+## install
+
+Add the following to your `Cargo.toml`
+
+```toml
+[dependencies]
+atty = "0.2"
+```
+
+## testing
+
+This library has been unit tested on both unix and windows platforms (via appveyor).
+
+
+A simple example program is provided in this repo to test various tty's. By default.
+
+It prints
+
+```bash
+$ cargo run --example atty
+stdout? true
+stderr? true
+stdin? true
+```
+
+To test std in, pipe some text to the program
+
+```bash
+$ echo "test" | cargo run --example atty
+stdout? true
+stderr? true
+stdin? false
+```
+
+To test std out, pipe the program to something
+
+```bash
+$ cargo run --example atty | grep std
+stdout? false
+stderr? true
+stdin? true
+```
+
+To test std err, pipe the program to something redirecting std err
+
+```bash
+$ cargo run --example atty 2>&1 | grep std
+stdout? false
+stderr? false
+stdin? true
+```
+
+Doug Tangren (softprops) 2015
new file mode 100644
--- /dev/null
+++ b/third_party/rust/atty/appveyor.yml
@@ -0,0 +1,17 @@
+environment:
+  matrix:
+  - TARGET: nightly-x86_64-pc-windows-msvc
+  - TARGET: nightly-i686-pc-windows-msvc
+  - TARGET: nightly-x86_64-pc-windows-gnu
+  - TARGET: nightly-i686-pc-windows-gnu
+  - TARGET: 1.8.0-x86_64-pc-windows-gnu
+install:
+  - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-${env:TARGET}.exe" -FileName "rust-install.exe"
+  - ps: .\rust-install.exe /VERYSILENT /NORESTART /DIR="C:\rust" | Out-Null
+  - ps: $env:PATH="$env:PATH;C:\rust\bin"
+  - call "%VCVARS%" || ver>nul
+  - rustc -vV
+  - cargo -vV
+build: false
+test_script:
+  - cargo test --verbose
new file mode 100644
--- /dev/null
+++ b/third_party/rust/atty/examples/atty.rs
@@ -0,0 +1,9 @@
+extern crate atty;
+
+use atty::{is, Stream};
+
+fn main() {
+    println!("stdout? {}", is(Stream::Stdout));
+    println!("stderr? {}", is(Stream::Stderr));
+    println!("stdin? {}", is(Stream::Stdin));
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/atty/src/lib.rs
@@ -0,0 +1,183 @@
+//! atty is a simple utility that answers one question
+//! > is this a tty?
+//!
+//! usage is just as simple
+//!
+//! ```
+//! if atty::is(atty::Stream::Stdout) {
+//!   println!("i'm a tty")
+//! }
+//! ```
+//!
+//! ```
+//! if atty::isnt(atty::Stream::Stdout) {
+//!   println!("i'm not a tty")
+//! }
+//! ```
+
+#[cfg(windows)]
+extern crate kernel32;
+#[cfg(not(windows))]
+extern crate libc;
+#[cfg(windows)]
+extern crate winapi;
+
+#[cfg(windows)]
+use winapi::minwindef::DWORD;
+
+/// possible stream sources
+#[derive(Clone, Copy, Debug)]
+pub enum Stream {
+    Stdout,
+    Stderr,
+    Stdin,
+}
+
+/// returns true if this is a tty
+#[cfg(unix)]
+pub fn is(stream: Stream) -> bool {
+    extern crate libc;
+
+    let fd = match stream {
+        Stream::Stdout => libc::STDOUT_FILENO,
+        Stream::Stderr => libc::STDERR_FILENO,
+        Stream::Stdin => libc::STDIN_FILENO,
+    };
+    unsafe { libc::isatty(fd) != 0 }
+}
+
+/// returns true if this is a tty
+#[cfg(windows)]
+pub fn is(stream: Stream) -> bool {
+    use winapi::{
+        STD_INPUT_HANDLE as STD_INPUT,
+        STD_ERROR_HANDLE as STD_ERROR,
+        STD_OUTPUT_HANDLE as STD_OUTPUT
+    };
+
+    let (fd, others) = match stream {
+        Stream::Stdin => (STD_INPUT, [STD_ERROR, STD_OUTPUT]),
+        Stream::Stderr => (STD_ERROR, [STD_INPUT, STD_OUTPUT]),
+        Stream::Stdout => (STD_OUTPUT, [STD_INPUT, STD_ERROR]),
+    };
+    if unsafe { console_on_any(&[fd]) } {
+        // False positives aren't possible. If we got a console then
+        // we definitely have a tty on stdin.
+        return true;
+    }
+
+    // At this point, we *could* have a false negative. We can determine that
+    // this is true negative if we can detect the presence of a console on
+    // any of the other streams. If another stream has a console, then we know
+    // we're in a Windows console and can therefore trust the negative.
+    if unsafe { console_on_any(&others) } {
+        return false;
+    }
+
+    // Otherwise, we fall back to a very strange msys hack to see if we can
+    // sneakily detect the presence of a tty.
+    unsafe { msys_tty_on(fd) }
+}
+
+/// returns true if this is _not_ a tty
+pub fn isnt(stream: Stream) -> bool {
+    !is(stream)
+}
+
+/// Returns true if any of the given fds are on a console.
+#[cfg(windows)]
+unsafe fn console_on_any(fds: &[DWORD]) -> bool {
+    for &fd in fds {
+        let mut out = 0;
+        let handle = kernel32::GetStdHandle(fd);
+        if kernel32::GetConsoleMode(handle, &mut out) != 0 {
+            return true;
+        }
+    }
+    false
+}
+
+/// Returns true if there is an MSYS tty on the given handle.
+#[cfg(windows)]
+unsafe fn msys_tty_on(fd: DWORD) -> bool {
+    use std::ffi::OsString;
+    use std::mem;
+    use std::os::raw::c_void;
+    use std::os::windows::ffi::OsStringExt;
+    use std::slice;
+
+    use kernel32::GetFileInformationByHandleEx;
+    use winapi::fileapi::FILE_NAME_INFO;
+    use winapi::minwinbase::FileNameInfo;
+    use winapi::minwindef::MAX_PATH;
+
+    let size = mem::size_of::<FILE_NAME_INFO>();
+    let mut name_info_bytes = vec![0u8; size + MAX_PATH];
+    let res = GetFileInformationByHandleEx(
+        kernel32::GetStdHandle(fd),
+        FileNameInfo,
+        &mut *name_info_bytes as *mut _ as *mut c_void,
+        name_info_bytes.len() as u32);
+    if res == 0 {
+        return true;
+    }
+    let name_info: FILE_NAME_INFO =
+        *(name_info_bytes[0..size].as_ptr() as *const FILE_NAME_INFO);
+    let name_bytes =
+        &name_info_bytes[size..size + name_info.FileNameLength as usize];
+    let name_u16 = slice::from_raw_parts(
+        name_bytes.as_ptr() as *const u16, name_bytes.len() / 2);
+    let name = OsString::from_wide(name_u16)
+        .as_os_str().to_string_lossy().into_owned();
+    name.contains("msys-") || name.contains("-pty")
+}
+
+#[cfg(test)]
+mod tests {
+    use super::{is, Stream};
+
+    #[test]
+    #[cfg(windows)]
+    fn is_err() {
+        // appveyor pipes its output
+        assert!(!is(Stream::Stderr))
+    }
+
+    #[test]
+    #[cfg(windows)]
+    fn is_out() {
+        // appveyor pipes its output
+        assert!(!is(Stream::Stdout))
+    }
+
+    #[test]
+    #[cfg(windows)]
+    fn is_in() {
+        assert!(is(Stream::Stdin))
+    }
+
+    #[test]
+    #[cfg(unix)]
+    fn is_err() {
+        assert!(is(Stream::Stderr))
+    }
+
+    #[test]
+    #[cfg(unix)]
+    fn is_out() {
+        assert!(is(Stream::Stdout))
+    }
+
+    #[test]
+    #[cfg(target_os = "macos")]
+    fn is_in() {
+        // macos on travis seems to pipe its input
+        assert!(!is(Stream::Stdin))
+    }
+
+    #[test]
+    #[cfg(all(not(target_os = "macos"), unix))]
+    fn is_in() {
+        assert!(is(Stream::Stdin))
+    }
+}
--- a/third_party/rust/clap/.cargo-checksum.json
+++ b/third_party/rust/clap/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".clog.toml":"f691701bd51b5f311931d0d8f05fa3d78c00dda8d60f3313e21011309c736ff1",".github/CONTRIBUTING.md":"f7eff737f3aa25294802fefb233e3758a64b248781dbbf3262532d693f340a87",".github/ISSUE_TEMPLATE.md":"681afbd64b3603e3e82789ceb6841d851eaa7333caec5769173462bab1b5d82b",".gitignore":"57b1cc6deeaf68d35909201e4bb863c7dbec899ceaa17edde7b9fe64ece8c3e9",".travis.yml":"2975b3159624d4ecc4dd29577f378e9d4fa27f1991bfd5042ac3c267fb2cdd38","CHANGELOG.md":"a1e86059e19fe5dd7c674d1165d31b77d1ec71d0db2aaa43c2442c3d65301ddd","CONTRIBUTORS.md":"62c5e9edb670a0b9315970b1a635a368928cf74b1240bbf1a0dab68d8ca6d598","Cargo.toml":"166690f9a21d1ea2f0492f10b8974d5ad5238eddea9b35cd3507059abb42ba66","LICENSE-MIT":"6725d1437fc6c77301f2ff0e7d52914cf4f9509213e1078dc77d9356dbe6eac5","README.md":"229557cb90d19e7632ec23820271b4aedad872544190b2477b9b43001c937e13","appveyor.yml":"303c64c2cc84c24b3c9ac0b4cd66b98d6bb25dec7d030ed53e5cb6ab3f13ebd1","clap-test.rs":"1021e44ea7981166f988268e619410f8329db8874018f4bc880a4f74b0b8ae76","index.html":"36f9ce4465266f3af9a259444b01c4239200473cabfc848f789f75b322a3ea8f","justfile":"82c20f705bc096a391f4b7232dbf712a0d3f00f9a2229aaa674f035ad0d9650e","rustfmt.toml":"8fd2d63119df515fd5f44e530c709b19d66b09fbc2e22a640bf4b64c57e7d6b3","src/app/help.rs":"f48bfb67331df1ff72da5d404b68a6e2049203ba1a091f701dc212ab0450461b","src/app/macros.rs":"8a8e8fe466da78588affeeadacf5c2a28d00299d387fdb8081ab9314a1d0b4eb","src/app/meta.rs":"81414fb8bfb32fa809eb470f3f3deee6610bfe54205240095371708c3d037933","src/app/mod.rs":"b36db7c4a404d04e58be00d3a720b87ed071f9234937cac5e77b938ac29d4f3f","src/app/parser.rs":"7aa95d1ddaf2941329668d5bd92c4a0b96ab00b8525207a0fa630e5d633d05e5","src/app/settings.rs":"52d5482b96e9832af1f06d15f5055cfe4cfb1edca0e2bf8f7c3ac7f72e982ec9","src/args/any_arg.rs":"6b1b480083ae2d31805a7d89ffaac8f452378fa19f0ef13bfc5a198707540f82","src/args/arg.rs":"77f8fd843928b7b963d332657ccaee21258fa9831565d225973579718d010ccc","src/args/arg_builder/base.rs":"70a9882495e2bcec53f5c9a370e5e2ae5d3b06559ef7ebda24c8a842c089df67","src/args/arg_builder/flag.rs":"2c20a751707fa0c5cc24afca3d3f3528eb68d9805ff69830bde66699bbcdd889","src/args/arg_builder/mod.rs":"7a32c8fd85b48f7b60e5f2c13dc70fa9100aa65cd933ba419300d28d682bf722","src/args/arg_builder/option.rs":"1a9473b10e94d09a7345c8c1c845a0380cd5234433ef01e0e62dabc28fa57470","src/args/arg_builder/positional.rs":"a60431c4619333ba0ed6e01cabd2d91f412c51f829c05656cf0f1bbf9b03c7da","src/args/arg_builder/switched.rs":"43b4da391b51a475a8a9bd3a396f507c2ae21bbd5a5a923bb8b1fd6d7829f228","src/args/arg_builder/valued.rs":"bdaa6943254e79c332d45af2e623baf2a99f6418a0d47240d7f666940af33e97","src/args/arg_matcher.rs":"16c4c68c253fa5660586dfa09bfa0f5dbae9cb8cb6de5e5f791ba41839ccc2e5","src/args/arg_matches.rs":"5b948efdc025fc9c39c93a84fbda1c8916c400e3557ae09a422aa29091072414","src/args/group.rs":"93797d3b8ca690d9bd23730ede9c490d49678220c70f8a90bf68914ea9eb8e22","src/args/macros.rs":"0dd7ae4c6e26ed78044c3ef90e21259816e544f724dcb09e6a0d92d4fcbc4b1a","src/args/matched_arg.rs":"ce480cff445964707663886ebbdc7c7bc168ac079ea1dafe928305d387ca07f7","src/args/mod.rs":"e15fc06bd63c3ef09c13c38c801b70c3318350456a3171d0110816eb92e0a0e2","src/args/settings.rs":"f1cdaa80def5760c72efdfddb3c509fa6ebbd83defb746dfc8fbfd57bcd080e3","src/args/subcommand.rs":"e1ad9638c33785f1301675de1795b0a4f4b079452aa11f7526d263c2a1179432","src/completions/bash.rs":"d323396378a5770ea09062fe22a6cade8c5ace74f26678dc992d86268a91c270","src/completions/fish.rs":"737084dc358bc3477477ecb18c0ec00e3ddf1bb8c238374ef017aed9f95d0bed","src/completions/macros.rs":"ebad5037e6e63401b1a54498e09d3bd93d1a3a06f045c2990902d47eb9a73774","src/completions/mod.rs":"5d4a734df6a21e6c1e0831a2f7be50a45d2e7bdaf7475589ea78b978643229cd","src/completions/powershell.rs":"e442d7ee240fb8430ed3ffd8abf7abb69f1523452f8dbe960b4b05047b3523c9","src/completions/shell.rs":"c7995ca229fd0d8671761da0aca0513c4f740165f02d06cd97aa0ae881c22cd4","src/completions/zsh.rs":"8ac4576e1cb3b1403dbb35ce146159aa8b29864e1d8201776200d999052b422d","src/errors.rs":"4da870f2002486b107b6b4b3dc8a5c81525b8416cef9aa1efb6bef495e431c09","src/fmt.rs":"284d4fc8463779241341b779b0a69d24368a21d4798862268036855fd331e18a","src/lib.rs":"78ae21e3fcfa8ffd1b9b2e5a846bd083f03b30b23a9bebc7d24249e3b0599d79","src/macros.rs":"50bf5bb36a4ca5511d3e1959aedb8d234bd84ff3d4eef0918fe9a269ef050a35","src/osstringext.rs":"680869e35af8f4f4b7f57bb7121b6274a9781cc6f7de6ba4c95683d1a71bd848","src/strext.rs":"d4418d396069e9c05804f92c042ba7192a4244e46059e2edc98670b45cd2daee","src/suggestions.rs":"ca35c332646fe9d3f93c6263830eaef77c87522f71794bfc986f90fc34229dec","src/usage_parser.rs":"ac23fdbff8a92eb02d0716685513f765dafe04a3d4ec0f4daf7cf40ed37149f7"},"package":"7db281b0520e97fbd15cd615dcd8f8bcad0c26f5f7d5effe705f090f39e9a758"}
\ No newline at end of file
+{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".clog.toml":"f691701bd51b5f311931d0d8f05fa3d78c00dda8d60f3313e21011309c736ff1",".github/CONTRIBUTING.md":"f7eff737f3aa25294802fefb233e3758a64b248781dbbf3262532d693f340a87",".github/ISSUE_TEMPLATE.md":"681afbd64b3603e3e82789ceb6841d851eaa7333caec5769173462bab1b5d82b",".gitignore":"57b1cc6deeaf68d35909201e4bb863c7dbec899ceaa17edde7b9fe64ece8c3e9",".travis.yml":"2975b3159624d4ecc4dd29577f378e9d4fa27f1991bfd5042ac3c267fb2cdd38","CHANGELOG.md":"82b23419a6964c8f80993b399c9dded5b7fd809ba51f5f806c2a139d3c6270a4","CONTRIBUTORS.md":"5d7dbafaff6879bbfbb01b22cca299953ec163872d8d624bbf99e20851ca0165","Cargo.toml":"94e3789815bfd001abf96cb0d10fa95a4b4576bc679539e79a531d0010e2ccdd","LICENSE-MIT":"6725d1437fc6c77301f2ff0e7d52914cf4f9509213e1078dc77d9356dbe6eac5","README.md":"031031971829f165ed7ffd8375c2249ce96336a9ed7f207d4722df05563d2d7e","appveyor.yml":"303c64c2cc84c24b3c9ac0b4cd66b98d6bb25dec7d030ed53e5cb6ab3f13ebd1","clap-test.rs":"a0b0d9ca9106a52bf9dc41cf52b0b87c98209dca3490caa6ec1452bd1fec5c4c","index.html":"36f9ce4465266f3af9a259444b01c4239200473cabfc848f789f75b322a3ea8f","justfile":"811b2dec57aec46e570aeeb9945018cf87fe65f6d5b27cdb9ffca79d906910f6","rustfmt.toml":"8fd2d63119df515fd5f44e530c709b19d66b09fbc2e22a640bf4b64c57e7d6b3","src/app/help.rs":"da53217886fb1ea289b9057d4b5e94dce74ce81a7b7006d216370aad709bff77","src/app/macros.rs":"0205c461041d917aecb4a15212f89908e72902b961f47014a645f2b061de5998","src/app/meta.rs":"a56d28bb466a8ba68155b3f2883e85228b4b74cf25658f62fc050e07cff2dc85","src/app/mod.rs":"d0e1843ae1f77c1da4179cebdd8fb1ea55803002fb1ae96087de3a8cdcedf6fc","src/app/parser.rs":"66b08057b7bc19f6c2c94671de7fc20ec623368e04f92d2a6775991d37430fc2","src/app/settings.rs":"cf9f4a1a9d3799ac30d1d98cf23987cc884435ad912a0dfd853b101ce86c97cc","src/app/usage.rs":"ecaeab6c7980544e9a2d35cc41f2797df8bc9c09f5da67e96286631a116c0ccc","src/app/validator.rs":"f19d876ac673019ed5fdd4b9f76ba598fa790aa5e64d482696ca1e45dce5f28b","src/args/any_arg.rs":"b082385eeff2505ced7b747bd44d20a3fb6fd9d4bd14be9e99870699c43ea072","src/args/arg.rs":"673de3f1957eccb1b116255bac9638fe24c0da54ccb358d958446c8ed54c9621","src/args/arg_builder/base.rs":"8b99a9ab811df3e0bdcfba8c0994042b0bcd06d8ddf794ab559baaf9a490ba59","src/args/arg_builder/flag.rs":"4007a950869789b1f4d5f953107aee228477e2d5fe82515d3b895286c65522c6","src/args/arg_builder/mod.rs":"7a32c8fd85b48f7b60e5f2c13dc70fa9100aa65cd933ba419300d28d682bf722","src/args/arg_builder/option.rs":"d5e5243e3a72d2c820c8fad4e1efc4b985881c6f60f3a72757b33a9054a87e99","src/args/arg_builder/positional.rs":"39615d22b586e744a0bdeb8490dbe43df7df66ed793abf8f50ed2037ec0fb90c","src/args/arg_builder/switched.rs":"61f5121b0ec746461215a47e1b7a4d699a37a3f181172820e0615f68d5f6f0ef","src/args/arg_builder/valued.rs":"19368a03e046d6b63451c3d04dff6e51d49f140ed45330f82879539c6d1b28dd","src/args/arg_matcher.rs":"27829739ae12ac7800a26109e751ce9f8c3d26e262d41de161a38baf5c421167","src/args/arg_matches.rs":"9d72a388053ef0c31fe2516df9ea791a4d0f6c0b5e9758eb61886f1ac8df89ab","src/args/group.rs":"3f72a6ecc6ff71c96dd9cd8098e4fb6f7c4e6207e9bd0b67a50b104f5dfdb23d","src/args/macros.rs":"0dd7ae4c6e26ed78044c3ef90e21259816e544f724dcb09e6a0d92d4fcbc4b1a","src/args/matched_arg.rs":"1ed8d338869ecc3b5fa426ef4cf42f4c9c3b1dd538cdea1fe0489169345536f7","src/args/mod.rs":"c155cd989fa4ca1f8de6a79115afbf5086f092adcb854ff9698b9100f45fc323","src/args/settings.rs":"e6bbfb49c2e38fcedb67481bcbf0eb887ee510031639be8134411121a9363f7e","src/args/subcommand.rs":"e1ad9638c33785f1301675de1795b0a4f4b079452aa11f7526d263c2a1179432","src/completions/bash.rs":"116c6830ee2b6310f299a69924f5b1e39b05ebec2b5f7b0ffe3b6938b7fa5514","src/completions/fish.rs":"63975f8beea9af6bef66c7dd7938bfa61c6f871995a74dbc1545daa9fbc1f2d0","src/completions/macros.rs":"ebad5037e6e63401b1a54498e09d3bd93d1a3a06f045c2990902d47eb9a73774","src/completions/mod.rs":"5d4a734df6a21e6c1e0831a2f7be50a45d2e7bdaf7475589ea78b978643229cd","src/completions/powershell.rs":"4267818aaa60583c055d7a276a7535309e5162c94467f3003799b6a8a7f6d6b0","src/completions/shell.rs":"c7995ca229fd0d8671761da0aca0513c4f740165f02d06cd97aa0ae881c22cd4","src/completions/zsh.rs":"8ac4576e1cb3b1403dbb35ce146159aa8b29864e1d8201776200d999052b422d","src/errors.rs":"5d0ab536ea62614a6cf88d175a5b5e9c2777a35958e1d4598ac1ec4a6f451593","src/fmt.rs":"42459e7f42f5495c005d2de3eaf8d7b5619bf4b8d245ecb76e583f08ecaa3869","src/lib.rs":"3471c5b046df081afecb4e541d4e55dc7afa34bf7fe8f369f301f6471887e930","src/macros.rs":"c1d40220947c62b0364eedd2c40ca2c414daccc334a1e04e029a884e782bf2b0","src/osstringext.rs":"a87a5a0685dd8310f6329d5f8e8f54c0fac68eb75595a835aeb1c36208efd5f9","src/strext.rs":"d4418d396069e9c05804f92c042ba7192a4244e46059e2edc98670b45cd2daee","src/suggestions.rs":"ca352c62cdcc1b6071c50e39f39e8f5f6cd11c318229cc6cf16511dfde43c5c7","src/usage_parser.rs":"a04143bba42a6506746091a3f898c38e2c7409bacefed21fa8194c90961ca390"},"package":"6b8f69e518f967224e628896b54e41ff6acfb4dcfefc5076325c36525dac900f"}
\ No newline at end of file
--- a/third_party/rust/clap/CHANGELOG.md
+++ b/third_party/rust/clap/CHANGELOG.md
@@ -1,8 +1,214 @@
+<a name="v2.24.2"></a>
+### v2.24.2 (2017-05-15)
+
+
+#### Bug Fixes
+
+*   adds a debug assertion to ensure all args added to groups actually exist ([14f6b8f3](https://github.com/kbknapp/clap-rs/commit/14f6b8f3a2f6df73aeeec9c54a54909b1acfc158), closes [#917](https://github.com/kbknapp/clap-rs/issues/917))
+*   fixes a bug where args that allow values to start with a hyphen couldnt contain a double hyphen -- as a value ([ebf73a09](https://github.com/kbknapp/clap-rs/commit/ebf73a09db6f3c03c19cdd76b1ba6113930e1643), closes [#960](https://github.com/kbknapp/clap-rs/issues/960))
+*   fixes a bug where positional argument help text is misaligned ([54c16836](https://github.com/kbknapp/clap-rs/commit/54c16836dea4651806a2cfad53146a83fa3abf21))
+
+#### Documentation
+
+* **App::template:**  adds details about the necessity to use AppSettings::UnifiedHelpMessage when using {unified} tags in the help template ([cf569438](https://github.com/kbknapp/clap-rs/commit/cf569438f309c199800bb8e46c9f140187de69d7), closes [#949](https://github.com/kbknapp/clap-rs/issues/949))
+* **Arg::allow_hyphen_values:**  updates the docs to include warnings for allow_hyphen_values and multiple(true) used together ([ded5a2f1](https://github.com/kbknapp/clap-rs/commit/ded5a2f15474d4a5bd46a67b130ccb8b6781bd01))
+* **clap_app!:**  adds using the @group specifier to the macro docs ([fe85fcb1](https://github.com/kbknapp/clap-rs/commit/fe85fcb1772b61f13b20b7ea5290e2437a76190c), closes [#932](https://github.com/kbknapp/clap-rs/issues/932))
+
+
+
+<a name="v2.24.0"></a>
+### v2.24.0 (2017-05-07)
+
+
+#### Bug Fixes
+
+*   fixes a bug where args with last(true) and required(true) set were not being printed in the usage string ([3ac533fe](https://github.com/kbknapp/clap-rs/commit/3ac533fedabf713943eedf006f830a5a486bbe80), closes [#944](https://github.com/kbknapp/clap-rs/issues/944))
+*   fixes a bug that was printing the arg name, instead of value name when Arg::last(true) was used ([e1fe8ac3](https://github.com/kbknapp/clap-rs/commit/e1fe8ac3bc1f9cf4e36df0d881f8419755f1787b), closes [#940](https://github.com/kbknapp/clap-rs/issues/940))
+*   fixes a bug where flags were parsed as flags AND positional values when specific combinations of settings were used ([20f83292](https://github.com/kbknapp/clap-rs/commit/20f83292d070038b8cee2a6b47e91f6b0a2f7871), closes [#946](https://github.com/kbknapp/clap-rs/issues/946))
+
+
+
+<a name="v2.24.0"></a>
+## v2.24.0 (2017-05-05)
+
+
+#### Documentation
+
+* **README.md:**  fix some typos ([fa34deac](https://github.com/kbknapp/clap-rs/commit/fa34deac079f334c3af97bb7fb151880ba8887f8))
+
+#### API Additions
+
+* **Arg:**  add `default_value_os` ([d5ef8955](https://github.com/kbknapp/clap-rs/commit/d5ef8955414b1587060f7218385256105b639c88))
+* **arg_matches.rs:**  Added a Default implementation for Values and OsValues iterators. ([0a4384e3](https://github.com/kbknapp/clap-rs/commit/0a4384e350eed74c2a4dc8964c203f21ac64897f))
+
+
+<a name="v2.23.2"></a>
+### v2.23.2 (2017-04-19)
+
+
+#### Bug Fixes
+
+* **PowerShell Completions:**  fixes a bug where powershells completions cant be used if no subcommands are defined ([a8bce558](https://github.com/kbknapp/clap-rs/commit/a8bce55837dc4e0fb187dc93180884a40ae09c6f), closes [#931](https://github.com/kbknapp/clap-rs/issues/931))
+
+#### Improvements
+
+*   bumps term_size to take advantage of better terminal dimension handling ([e05100b7](https://github.com/kbknapp/clap-rs/commit/e05100b73d74066a90876bf38f952adf5e8ee422))
+* **PowerShell Completions:**  massively dedups subcommand names in the generate script to make smaller scripts that are still functionally equiv ([85b0e1cc](https://github.com/kbknapp/clap-rs/commit/85b0e1cc4b9755dda75a93d898d79bc38631552b))
+
+#### Documentation
+
+*   Fix a typo the minimum rust version required ([71dabba3](https://github.com/kbknapp/clap-rs/commit/71dabba3ea0a17c88b0e2199c9d99f0acbf3bc17))
+
+<a name="v2.23.1"></a>
+### v2.23.1 (2017-04-05)
+
+
+#### Bug Fixes
+
+*   fixes a missing newline character in the autogenerated help and version messages in some instances ([5ae9007d](https://github.com/kbknapp/clap-rs/commit/5ae9007d984ae94ae2752df51bcbaeb0ec89bc15))
+
+
+<a name="v2.23.0"></a>
+## v2.23.0 (2017-04-05)
+
+
+#### API Additions
+
+* `App::long_about`
+* `App::long_version`
+* `App::print_long_help`
+* `App::write_long_help`
+* `App::print_long_version`
+* `App::write_long_version`
+* `Arg::long_help`
+
+#### Features
+
+*   allows distinguishing between short and long version messages (-V/short or --version/long) ([59272b06](https://github.com/kbknapp/clap-rs/commit/59272b06cc213289dc604dbc694cb95d383a5d68))
+*   allows distinguishing between short and long help with subcommands in the same manner as args ([6b371891](https://github.com/kbknapp/clap-rs/commit/6b371891a1702173a849d1e95f9fecb168bf6fc4))
+*   allows specifying a short help vs a long help (i.e. varying levels of detail depending on if -h or --help was used) ([ef1b24c3](https://github.com/kbknapp/clap-rs/commit/ef1b24c3a0dff2f58c5e2e90880fbc2b69df20ee))
+* **clap_app!:**  adds support for arg names with hyphens similar to longs with hyphens ([f7a88779](https://github.com/kbknapp/clap-rs/commit/f7a8877978c8f90e6543d4f0d9600c086cf92cd7), closes [#869](https://github.com/kbknapp/clap-rs/issues/869))
+
+#### Bug Fixes
+
+*   fixes a bug that wasn't allowing help and version to be properly overridden ([8b2ceb83](https://github.com/kbknapp/clap-rs/commit/8b2ceb8368bcb70689fadf1c7f4b9549184926c1), closes [#922](https://github.com/kbknapp/clap-rs/issues/922))
+
+#### Documentation
+
+* **clap_app!:**  documents the `--("some-arg")` method for using args with hyphens inside them ([bc08ef3e](https://github.com/kbknapp/clap-rs/commit/bc08ef3e185393073d969d301989b6319c616c1f), closes [#919](https://github.com/kbknapp/clap-rs/issues/919))
+
+
+
+<a name="v2.22.2"></a>
+### v2.22.2 (2017-03-30)
+
+
+#### Bug Fixes
+
+* **Custom Usage Strings:**  fixes the usage string regression when using help templates ([0e4fd96d](https://github.com/kbknapp/clap-rs/commit/0e4fd96d74280d306d09e60ac44f938a82321769))
+
+
+
+<a name="v2.22.1"></a>
+### v2.22.1 (2017-03-24)
+
+
+#### Bug Fixes
+
+* **usage:**  fixes a big regression with custom usage strings ([2c41caba](https://github.com/kbknapp/clap-rs/commit/2c41caba3c7d723a2894e315d04da796b0e97759))
+
+<a name="v2.22.0"></a>
+## v2.22.0 (2017-03-23)
+
+#### API Additions
+
+* **App::name:**  adds the ability to change the name of the App instance after creation ([d49e8292](https://github.com/kbknapp/clap-rs/commit/d49e8292b026b06e2b70447cd9f08299f4fcba76), closes [#908](https://github.com/kbknapp/clap-rs/issues/908))
+* **Arg::hide_default_value:**  adds ability to hide the default value of an argument from the help string ([89e6ea86](https://github.com/kbknapp/clap-rs/commit/89e6ea861e16a1ad56757ca12f6b32d02253e44a), closes [#902](https://github.com/kbknapp/clap-rs/issues/902))
+
+
+<a name="v2.21.3"></a>
+### v2.21.3 (2017-03-23)
+
+#### Bug Fixes
+
+* **yaml:**  adds support for loading author info from yaml ([e04c390c](https://github.com/kbknapp/clap-rs/commit/e04c390c597a55fa27e724050342f16c42f1c5c9))
+
+
+<a name="v2.21.2"></a>
+### v2.21.2 (2017-03-17)
+
+
+#### Improvements
+
+*   add fish subcommand help support ([f8f68cf8](https://github.com/kbknapp/clap-rs/commit/f8f68cf8251669aef4539a25a7c1166f0ac81ea6))
+*   options that use `require_equals(true)` now display the equals sign in help messages, usage strings, and errors" ([c8eb0384](https://github.com/kbknapp/clap-rs/commit/c8eb0384d394d2900ccdc1593099c97808a3fa05), closes [#903](https://github.com/kbknapp/clap-rs/issues/903))
+
+
+#### Bug Fixes
+
+*  setting the max term width now correctly propagates down through child subcommands
+
+
+
+<a name="v2.21.1"></a>
+### v2.21.1 (2017-03-12)
+
+
+#### Bug Fixes
+
+* **ArgRequiredElseHelp:**  fixes the precedence of this error to prioritize over other error messages ([74b751ff](https://github.com/kbknapp/clap-rs/commit/74b751ff2e3631e337b7946347c1119829a41c53), closes [#895](https://github.com/kbknapp/clap-rs/issues/895))
+* **Positionals:**  fixes some regression bugs resulting from old asserts in debug mode. ([9a3bc98e](https://github.com/kbknapp/clap-rs/commit/9a3bc98e9b55e7514b74b73374c5ac8b6e5e0508), closes [#896](https://github.com/kbknapp/clap-rs/issues/896))
+
+
+
+<a name="v2.21.0"></a>
+## v2.21.0 (2017-03-09)
+
+#### Performance
+
+*   doesn't run `arg_post_processing` on multiple values anymore ([ec516182](https://github.com/kbknapp/clap-rs/commit/ec5161828729f6a53f0fccec8648f71697f01f78))
+*   changes internal use of `VecMap` to `Vec` for matched values of `Arg`s ([22bf137a](https://github.com/kbknapp/clap-rs/commit/22bf137ac581684c6ed460d2c3c640c503d62621))
+*   vastly reduces the amount of cloning when adding non-global args minus when they're added from `App::args` which is forced to clone ([8da0303b](https://github.com/kbknapp/clap-rs/commit/8da0303bc02db5fe047cfc0631a9da41d9dc60f7))
+*   refactor to remove unneeded vectors and allocations and checks for significant performance increases ([0efa4119](https://github.com/kbknapp/clap-rs/commit/0efa4119632f134fc5b8b9695b007dd94b76735d))
+
+#### Documentation
+
+*   Fix examples link in CONTRIBUTING.md ([60cf875d](https://github.com/kbknapp/clap-rs/commit/60cf875d67a252e19bb85054be57696fac2c57a1))
+
+#### Improvements
+
+*   when `AppSettings::SubcommandsNegateReqs` and `ArgsNegateSubcommands` are used, a new more accurate double line usage string is shown ([50f02300](https://github.com/kbknapp/clap-rs/commit/50f02300d81788817acefef0697e157e01b6ca32), closes [#871](https://github.com/kbknapp/clap-rs/issues/871))
+
+#### API Additions
+
+* **Arg::last:**  adds the ability to mark a positional argument as 'last' which means it should be used with `--` syntax and can be accessed early ([6a7aea90](https://github.com/kbknapp/clap-rs/commit/6a7aea9043b83badd9ab038b4ecc4c787716147e), closes [#888](https://github.com/kbknapp/clap-rs/issues/888))
+*   provides `default_value_os` and `default_value_if[s]_os` ([0f2a3782](https://github.com/kbknapp/clap-rs/commit/0f2a378219a6930748d178ba350fe5925be5dad5), closes [#849](https://github.com/kbknapp/clap-rs/issues/849))
+*   provides `App::help_message` and `App::version_message` which allows one to override the auto-generated help/version flag associated help ([389c413](https://github.com/kbknapp/clap-rs/commit/389c413b7023dccab8c76aa00577ea1d048e7a99), closes [#889](https://github.com/kbknapp/clap-rs/issues/889))
+
+#### New Settings
+
+* **InferSubcommands:**  adds a setting to allow one to infer shortened subcommands or aliases (i.e. for subcommmand "test", "t", "te", or "tes" would be allowed assuming no other ambiguities) ([11602032](https://github.com/kbknapp/clap-rs/commit/11602032f6ff05881e3adf130356e37d5e66e8f9), closes [#863](https://github.com/kbknapp/clap-rs/issues/863))
+
+#### Bug Fixes
+
+*   doesn't print the argument sections in the help message if all args in that section are hidden ([ce5ee5f5](https://github.com/kbknapp/clap-rs/commit/ce5ee5f5a76f838104aeddd01c8ec956dd347f50))
+*   doesn't include the various [ARGS] [FLAGS] or [OPTIONS] if the only ones available are hidden ([7b4000af](https://github.com/kbknapp/clap-rs/commit/7b4000af97637703645c5fb2ac8bb65bd546b95b), closes [#882](https://github.com/kbknapp/clap-rs/issues/882))
+*   now correctly shows subcommand as required in the usage string when AppSettings::SubcommandRequiredElseHelp is used ([8f0884c1](https://github.com/kbknapp/clap-rs/commit/8f0884c1764983a49b45de52a1eddf8d721564d8))
+*   fixes some memory leaks when an error is detected and clap exits ([8c2dd287](https://github.com/kbknapp/clap-rs/commit/8c2dd28718262ace4ae0db98563809548e02a86b))
+*   fixes a trait that's marked private accidentlly, but should be crate internal public ([1ae21108](https://github.com/kbknapp/clap-rs/commit/1ae21108015cea87e5360402e1747025116c7878))
+* **Completions:**   fixes a bug that tried to propogate global args multiple times when generating multiple completion scripts ([5e9b9cf4](https://github.com/kbknapp/clap-rs/commit/5e9b9cf4dd80fa66a624374fd04e6545635c1f94), closes [#846](https://github.com/kbknapp/clap-rs/issues/846))
+
+#### Features
+
+* **Options:**  adds the ability to require the equals syntax with options --opt=val ([f002693d](https://github.com/kbknapp/clap-rs/commit/f002693dec6a6959c4e9590cb7b7bfffd6d6e5bc), closes [#833](https://github.com/kbknapp/clap-rs/issues/833))
+
+
+
 <a name="v2.20.5"></a>
 ### v2.20.5 (2017-02-18)
 
 
 #### Bug Fixes
 
 * **clap_app!:**   fixes a critical bug of a missing fragment specifier when using `!property` style tags. ([5635c1f94](https://github.com/kbknapp/clap-rs/commit/5e9b9cf4dd80fa66a624374fd04e6545635c1f94))
 
--- a/third_party/rust/clap/CONTRIBUTORS.md
+++ b/third_party/rust/clap/CONTRIBUTORS.md
@@ -1,56 +1,67 @@
-The following is a list of contributors in alphabetical order:
+the following is a list of contributors:
 
 
-[<img alt="afiune" src="https://avatars.githubusercontent.com/u/5712253?v=3&s=117" width="117">](https://github.com/afiune) |[<img alt="alex-gulyas" src="https://avatars.githubusercontent.com/u/8698329?v=3&s=117" width="117">](https://github.com/alex-gulyas) |[<img alt="alexbool" src="https://avatars.githubusercontent.com/u/1283792?v=3&s=117" width="117">](https://github.com/alexbool) |[<img alt="AluisioASG" src="https://avatars.githubusercontent.com/u/1904165?v=3&s=117" width="117">](https://github.com/AluisioASG) |[<img alt="archer884" src="https://avatars.githubusercontent.com/u/679494?v=3&s=117" width="117">](https://github.com/archer884) |[<img alt="Arnavion" src="https://avatars.githubusercontent.com/u/1096010?v=3&s=117" width="117">](https://github.com/Arnavion) |
+[<img alt="kbknapp" src="https://avatars2.githubusercontent.com/u/6942134?v=3&s=117" width="117">](https://github.com/kbknapp) |[<img alt="homu" src="https://avatars2.githubusercontent.com/u/10212162?v=3&s=117" width="117">](https://github.com/homu) |[<img alt="Vinatorul" src="https://avatars2.githubusercontent.com/u/6770624?v=3&s=117" width="117">](https://github.com/Vinatorul) |[<img alt="tormol" src="https://avatars0.githubusercontent.com/u/10460821?v=3&s=117" width="117">](https://github.com/tormol) |[<img alt="sru" src="https://avatars0.githubusercontent.com/u/2485892?v=3&s=117" width="117">](https://github.com/sru) |[<img alt="nabijaczleweli" src="https://avatars0.githubusercontent.com/u/6709544?v=3&s=117" width="117">](https://github.com/nabijaczleweli) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[afiune](https://github.com/afiune) |[alex-gulyas](https://github.com/alex-gulyas) |[alexbool](https://github.com/alexbool) |[AluisioASG](https://github.com/AluisioASG) |[archer884](https://github.com/archer884) |[Arnavion](https://github.com/Arnavion) |
+[kbknapp](https://github.com/kbknapp) |[homu](https://github.com/homu) |[Vinatorul](https://github.com/Vinatorul) |[tormol](https://github.com/tormol) |[sru](https://github.com/sru) |[nabijaczleweli](https://github.com/nabijaczleweli) |
 
-[<img alt="Bilalh" src="https://avatars.githubusercontent.com/u/171602?v=3&s=117" width="117">](https://github.com/Bilalh) |[<img alt="birkenfeld" src="https://avatars.githubusercontent.com/u/144359?v=3&s=117" width="117">](https://github.com/birkenfeld) |[<img alt="bradurani" src="https://avatars.githubusercontent.com/u/4195952?v=3&s=117" width="117">](https://github.com/bradurani) |[<img alt="brennie" src="https://avatars.githubusercontent.com/u/156585?v=3&s=117" width="117">](https://github.com/brennie) |[<img alt="brianp" src="https://avatars.githubusercontent.com/u/179134?v=3&s=117" width="117">](https://github.com/brianp) |[<img alt="BurntSushi" src="https://avatars.githubusercontent.com/u/456674?v=3&s=117" width="117">](https://github.com/BurntSushi) |
+[<img alt="Byron" src="https://avatars1.githubusercontent.com/u/63622?v=3&s=117" width="117">](https://github.com/Byron) |[<img alt="hgrecco" src="https://avatars3.githubusercontent.com/u/278566?v=3&s=117" width="117">](https://github.com/hgrecco) |[<img alt="james-darkfox" src="https://avatars0.githubusercontent.com/u/637155?v=3&s=117" width="117">](https://github.com/james-darkfox) |[<img alt="rtaycher" src="https://avatars3.githubusercontent.com/u/324733?v=3&s=117" width="117">](https://github.com/rtaycher) |[<img alt="glowing-chemist" src="https://avatars3.githubusercontent.com/u/17074682?v=3&s=117" width="117">](https://github.com/glowing-chemist) |[<img alt="Arnavion" src="https://avatars1.githubusercontent.com/u/1096010?v=3&s=117" width="117">](https://github.com/Arnavion) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[Bilalh](https://github.com/Bilalh) |[birkenfeld](https://github.com/birkenfeld) |[bradurani](https://github.com/bradurani) |[brennie](https://github.com/brennie) |[brianp](https://github.com/brianp) |[BurntSushi](https://github.com/BurntSushi) |
+[Byron](https://github.com/Byron) |[hgrecco](https://github.com/hgrecco) |[james-darkfox](https://github.com/james-darkfox) |[rtaycher](https://github.com/rtaycher) |[glowing-chemist](https://github.com/glowing-chemist) |[Arnavion](https://github.com/Arnavion) |
 
-[<img alt="Byron" src="https://avatars.githubusercontent.com/u/63622?v=3&s=117" width="117">](https://github.com/Byron) |[<img alt="casey" src="https://avatars.githubusercontent.com/u/1945?v=3&s=117" width="117">](https://github.com/casey) |[<img alt="cite-reader" src="https://avatars.githubusercontent.com/u/4196987?v=3&s=117" width="117">](https://github.com/cite-reader) |[<img alt="cstorey" src="https://avatars.githubusercontent.com/u/743059?v=3&s=117" width="117">](https://github.com/cstorey) |[<img alt="daboross" src="https://avatars.githubusercontent.com/u/1152146?v=3&s=117" width="117">](https://github.com/daboross) |[<img alt="davidszotten" src="https://avatars.githubusercontent.com/u/412005?v=3&s=117" width="117">](https://github.com/davidszotten) |
+[<img alt="mgeisler" src="https://avatars3.githubusercontent.com/u/89623?v=3&s=117" width="117">](https://github.com/mgeisler) |[<img alt="afiune" src="https://avatars3.githubusercontent.com/u/5712253?v=3&s=117" width="117">](https://github.com/afiune) |[<img alt="crazymerlyn" src="https://avatars2.githubusercontent.com/u/6919679?v=3&s=117" width="117">](https://github.com/crazymerlyn) |[<img alt="SuperFluffy" src="https://avatars3.githubusercontent.com/u/701177?v=3&s=117" width="117">](https://github.com/SuperFluffy) |[<img alt="untitaker" src="https://avatars3.githubusercontent.com/u/837573?v=3&s=117" width="117">](https://github.com/untitaker) |[<img alt="japaric" src="https://avatars0.githubusercontent.com/u/5018213?v=3&s=117" width="117">](https://github.com/japaric) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[Byron](https://github.com/Byron) |[casey](https://github.com/casey) |[cite-reader](https://github.com/cite-reader) |[cstorey](https://github.com/cstorey) |[daboross](https://github.com/daboross) |[davidszotten](https://github.com/davidszotten) |
+[mgeisler](https://github.com/mgeisler) |[afiune](https://github.com/afiune) |[crazymerlyn](https://github.com/crazymerlyn) |[SuperFluffy](https://github.com/SuperFluffy) |[untitaker](https://github.com/untitaker) |[japaric](https://github.com/japaric) |
 
-[<img alt="Deedasmi" src="https://avatars.githubusercontent.com/u/5093293?v=3&s=117" width="117">](https://github.com/Deedasmi) |[<img alt="dguo" src="https://avatars.githubusercontent.com/u/2763135?v=3&s=117" width="117">](https://github.com/dguo) |[<img alt="dotdash" src="https://avatars.githubusercontent.com/u/230962?v=3&s=117" width="117">](https://github.com/dotdash) |[<img alt="flying-sheep" src="https://avatars.githubusercontent.com/u/291575?v=3&s=117" width="117">](https://github.com/flying-sheep) |[<img alt="Geogi" src="https://avatars.githubusercontent.com/u/1818316?v=3&s=117" width="117">](https://github.com/Geogi) |[<img alt="glowing-chemist" src="https://avatars.githubusercontent.com/u/17074682?v=3&s=117" width="117">](https://github.com/glowing-chemist) |
+[<img alt="matthiasbeyer" src="https://avatars3.githubusercontent.com/u/427866?v=3&s=117" width="117">](https://github.com/matthiasbeyer) |[<img alt="SShrike" src="https://avatars2.githubusercontent.com/u/4061736?v=3&s=117" width="117">](https://github.com/SShrike) |[<img alt="gohyda" src="https://avatars0.githubusercontent.com/u/10263838?v=3&s=117" width="117">](https://github.com/gohyda) |[<img alt="jimmycuadra" src="https://avatars1.githubusercontent.com/u/122457?v=3&s=117" width="117">](https://github.com/jimmycuadra) |[<img alt="Nemo157" src="https://avatars2.githubusercontent.com/u/81079?v=3&s=117" width="117">](https://github.com/Nemo157) |[<img alt="tshepang" src="https://avatars3.githubusercontent.com/u/588486?v=3&s=117" width="117">](https://github.com/tshepang) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[Deedasmi](https://github.com/Deedasmi) |[dguo](https://github.com/dguo) |[dotdash](https://github.com/dotdash) |[flying-sheep](https://github.com/flying-sheep) |[Geogi](https://github.com/Geogi) |[glowing-chemist](https://github.com/glowing-chemist) |
+[matthiasbeyer](https://github.com/matthiasbeyer) |[SShrike](https://github.com/SShrike) |[gohyda](https://github.com/gohyda) |[jimmycuadra](https://github.com/jimmycuadra) |[Nemo157](https://github.com/Nemo157) |[tshepang](https://github.com/tshepang) |
 
-[<img alt="gohyda" src="https://avatars.githubusercontent.com/u/10263838?v=3&s=117" width="117">](https://github.com/gohyda) |[<img alt="GrappigPanda" src="https://avatars.githubusercontent.com/u/2055372?v=3&s=117" width="117">](https://github.com/GrappigPanda) |[<img alt="grossws" src="https://avatars.githubusercontent.com/u/171284?v=3&s=117" width="117">](https://github.com/grossws) |[<img alt="hexjelly" src="https://avatars.githubusercontent.com/u/435283?v=3&s=117" width="117">](https://github.com/hexjelly) |[<img alt="hgrecco" src="https://avatars.githubusercontent.com/u/278566?v=3&s=117" width="117">](https://github.com/hgrecco) |[<img alt="homu" src="https://avatars.githubusercontent.com/u/10212162?v=3&s=117" width="117">](https://github.com/homu) |
+[<img alt="porglezomp" src="https://avatars2.githubusercontent.com/u/1690225?v=3&s=117" width="117">](https://github.com/porglezomp) |[<img alt="wdv4758h" src="https://avatars2.githubusercontent.com/u/2716047?v=3&s=117" width="117">](https://github.com/wdv4758h) |[<img alt="frewsxcv" src="https://avatars1.githubusercontent.com/u/416575?v=3&s=117" width="117">](https://github.com/frewsxcv) |[<img alt="hoodie" src="https://avatars2.githubusercontent.com/u/260370?v=3&s=117" width="117">](https://github.com/hoodie) |[<img alt="huonw" src="https://avatars2.githubusercontent.com/u/1203825?v=3&s=117" width="117">](https://github.com/huonw) |[<img alt="GrappigPanda" src="https://avatars3.githubusercontent.com/u/2055372?v=3&s=117" width="117">](https://github.com/GrappigPanda) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[gohyda](https://github.com/gohyda) |[GrappigPanda](https://github.com/GrappigPanda) |[grossws](https://github.com/grossws) |[hexjelly](https://github.com/hexjelly) |[hgrecco](https://github.com/hgrecco) |[homu](https://github.com/homu) |
+[porglezomp](https://github.com/porglezomp) |[wdv4758h](https://github.com/wdv4758h) |[frewsxcv](https://github.com/frewsxcv) |[hoodie](https://github.com/hoodie) |[huonw](https://github.com/huonw) |[GrappigPanda](https://github.com/GrappigPanda) |
 
-[<img alt="hoodie" src="https://avatars.githubusercontent.com/u/260370?v=3&s=117" width="117">](https://github.com/hoodie) |[<img alt="huonw" src="https://avatars.githubusercontent.com/u/1203825?v=3&s=117" width="117">](https://github.com/huonw) |[<img alt="idmit" src="https://avatars.githubusercontent.com/u/2546728?v=3&s=117" width="117">](https://github.com/idmit) |[<img alt="iliekturtles" src="https://avatars.githubusercontent.com/u/5081378?v=3&s=117" width="117">](https://github.com/iliekturtles) |[<img alt="james-darkfox" src="https://avatars.githubusercontent.com/u/637155?v=3&s=117" width="117">](https://github.com/james-darkfox) |[<img alt="japaric" src="https://avatars.githubusercontent.com/u/5018213?v=3&s=117" width="117">](https://github.com/japaric) |
+[<img alt="ignatenkobrain" src="https://avatars2.githubusercontent.com/u/2866862?v=3&s=117" width="117">](https://github.com/ignatenkobrain) |[<img alt="cstorey" src="https://avatars0.githubusercontent.com/u/743059?v=3&s=117" width="117">](https://github.com/cstorey) |[<img alt="musoke" src="https://avatars3.githubusercontent.com/u/16665084?v=3&s=117" width="117">](https://github.com/musoke) |[<img alt="nelsonjchen" src="https://avatars2.githubusercontent.com/u/5363?v=3&s=117" width="117">](https://github.com/nelsonjchen) |[<img alt="pkgw" src="https://avatars3.githubusercontent.com/u/59598?v=3&s=117" width="117">](https://github.com/pkgw) |[<img alt="Deedasmi" src="https://avatars3.githubusercontent.com/u/5093293?v=3&s=117" width="117">](https://github.com/Deedasmi) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[hoodie](https://github.com/hoodie) |[huonw](https://github.com/huonw) |[idmit](https://github.com/idmit) |[iliekturtles](https://github.com/iliekturtles) |[james-darkfox](https://github.com/james-darkfox) |[japaric](https://github.com/japaric) |
+[ignatenkobrain](https://github.com/ignatenkobrain) |[cstorey](https://github.com/cstorey) |[musoke](https://github.com/musoke) |[nelsonjchen](https://github.com/nelsonjchen) |[pkgw](https://github.com/pkgw) |[Deedasmi](https://github.com/Deedasmi) |
 
-[<img alt="jespino" src="https://avatars.githubusercontent.com/u/290303?v=3&s=117" width="117">](https://github.com/jespino) |[<img alt="jimmycuadra" src="https://avatars.githubusercontent.com/u/122457?v=3&s=117" width="117">](https://github.com/jimmycuadra) |[<img alt="joshtriplett" src="https://avatars.githubusercontent.com/u/162737?v=3&s=117" width="117">](https://github.com/joshtriplett) |[<img alt="jtdowney" src="https://avatars.githubusercontent.com/u/44654?v=3&s=117" width="117">](https://github.com/jtdowney) |[<img alt="kbknapp" src="https://avatars.githubusercontent.com/u/6942134?v=3&s=117" width="117">](https://github.com/kbknapp) |[<img alt="Keats" src="https://avatars.githubusercontent.com/u/680355?v=3&s=117" width="117">](https://github.com/Keats) |
+[<img alt="N-006" src="https://avatars3.githubusercontent.com/u/399312?v=3&s=117" width="117">](https://github.com/N-006) |[<img alt="Keats" src="https://avatars1.githubusercontent.com/u/680355?v=3&s=117" width="117">](https://github.com/Keats) |[<img alt="starkat99" src="https://avatars2.githubusercontent.com/u/8295111?v=3&s=117" width="117">](https://github.com/starkat99) |[<img alt="alex-gulyas" src="https://avatars3.githubusercontent.com/u/8698329?v=3&s=117" width="117">](https://github.com/alex-gulyas) |[<img alt="cite-reader" src="https://avatars2.githubusercontent.com/u/4196987?v=3&s=117" width="117">](https://github.com/cite-reader) |[<img alt="alexbool" src="https://avatars0.githubusercontent.com/u/1283792?v=3&s=117" width="117">](https://github.com/alexbool) |
+:---: |:---: |:---: |:---: |:---: |:---: |
+[N-006](https://github.com/N-006) |[Keats](https://github.com/Keats) |[starkat99](https://github.com/starkat99) |[alex-gulyas](https://github.com/alex-gulyas) |[cite-reader](https://github.com/cite-reader) |[alexbool](https://github.com/alexbool) |
+
+[<img alt="AluisioASG" src="https://avatars1.githubusercontent.com/u/1904165?v=3&s=117" width="117">](https://github.com/AluisioASG) |[<img alt="BurntSushi" src="https://avatars0.githubusercontent.com/u/456674?v=3&s=117" width="117">](https://github.com/BurntSushi) |[<img alt="nox" src="https://avatars3.githubusercontent.com/u/123095?v=3&s=117" width="117">](https://github.com/nox) |[<img alt="pixelistik" src="https://avatars2.githubusercontent.com/u/170929?v=3&s=117" width="117">](https://github.com/pixelistik) |[<img alt="brennie" src="https://avatars0.githubusercontent.com/u/156585?v=3&s=117" width="117">](https://github.com/brennie) |[<img alt="ogham" src="https://avatars0.githubusercontent.com/u/503760?v=3&s=117" width="117">](https://github.com/ogham) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[jespino](https://github.com/jespino) |[jimmycuadra](https://github.com/jimmycuadra) |[joshtriplett](https://github.com/joshtriplett) |[jtdowney](https://github.com/jtdowney) |[kbknapp](https://github.com/kbknapp) |[Keats](https://github.com/Keats) |
+[AluisioASG](https://github.com/AluisioASG) |[BurntSushi](https://github.com/BurntSushi) |[nox](https://github.com/nox) |[pixelistik](https://github.com/pixelistik) |[brennie](https://github.com/brennie) |[ogham](https://github.com/ogham) |
 
-[<img alt="matthiasbeyer" src="https://avatars.githubusercontent.com/u/427866?v=3&s=117" width="117">](https://github.com/matthiasbeyer) |[<img alt="mernen" src="https://avatars.githubusercontent.com/u/6412?v=3&s=117" width="117">](https://github.com/mernen) |[<img alt="messense" src="https://avatars.githubusercontent.com/u/1556054?v=3&s=117" width="117">](https://github.com/messense) |[<img alt="mgeisler" src="https://avatars.githubusercontent.com/u/89623?v=3&s=117" width="117">](https://github.com/mgeisler) |[<img alt="mineo" src="https://avatars.githubusercontent.com/u/78236?v=3&s=117" width="117">](https://github.com/mineo) |[<img alt="musoke" src="https://avatars.githubusercontent.com/u/16665084?v=3&s=117" width="117">](https://github.com/musoke) |
+[<img alt="Bilalh" src="https://avatars3.githubusercontent.com/u/171602?v=3&s=117" width="117">](https://github.com/Bilalh) |[<img alt="dotdash" src="https://avatars2.githubusercontent.com/u/230962?v=3&s=117" width="117">](https://github.com/dotdash) |[<img alt="bradurani" src="https://avatars3.githubusercontent.com/u/4195952?v=3&s=117" width="117">](https://github.com/bradurani) |[<img alt="Seeker14491" src="https://avatars1.githubusercontent.com/u/6490497?v=3&s=117" width="117">](https://github.com/Seeker14491) |[<img alt="brianp" src="https://avatars2.githubusercontent.com/u/179134?v=3&s=117" width="117">](https://github.com/brianp) |[<img alt="casey" src="https://avatars1.githubusercontent.com/u/1945?v=3&s=117" width="117">](https://github.com/casey) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[matthiasbeyer](https://github.com/matthiasbeyer) |[mernen](https://github.com/mernen) |[messense](https://github.com/messense) |[mgeisler](https://github.com/mgeisler) |[mineo](https://github.com/mineo) |[musoke](https://github.com/musoke) |
+[Bilalh](https://github.com/Bilalh) |[dotdash](https://github.com/dotdash) |[bradurani](https://github.com/bradurani) |[Seeker14491](https://github.com/Seeker14491) |[brianp](https://github.com/brianp) |[casey](https://github.com/casey) |
 
-[<img alt="mvaude" src="https://avatars.githubusercontent.com/u/9532611?v=3&s=117" width="117">](https://github.com/mvaude) |[<img alt="N-006" src="https://avatars.githubusercontent.com/u/399312?v=3&s=117" width="117">](https://github.com/N-006) |[<img alt="nabijaczleweli" src="https://avatars.githubusercontent.com/u/6709544?v=3&s=117" width="117">](https://github.com/nabijaczleweli) |[<img alt="nelsonjchen" src="https://avatars.githubusercontent.com/u/5363?v=3&s=117" width="117">](https://github.com/nelsonjchen) |[<img alt="Nemo157" src="https://avatars.githubusercontent.com/u/81079?v=3&s=117" width="117">](https://github.com/Nemo157) |[<img alt="nicompte" src="https://avatars.githubusercontent.com/u/439369?v=3&s=117" width="117">](https://github.com/nicompte) |
+[<img alt="volks73" src="https://avatars2.githubusercontent.com/u/1915469?v=3&s=117" width="117">](https://github.com/volks73) |[<img alt="daboross" src="https://avatars2.githubusercontent.com/u/1152146?v=3&s=117" width="117">](https://github.com/daboross) |[<img alt="mernen" src="https://avatars3.githubusercontent.com/u/6412?v=3&s=117" width="117">](https://github.com/mernen) |[<img alt="dguo" src="https://avatars3.githubusercontent.com/u/2763135?v=3&s=117" width="117">](https://github.com/dguo) |[<img alt="davidszotten" src="https://avatars0.githubusercontent.com/u/412005?v=3&s=117" width="117">](https://github.com/davidszotten) |[<img alt="eddyb" src="https://avatars1.githubusercontent.com/u/77424?v=3&s=117" width="117">](https://github.com/eddyb) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[mvaude](https://github.com/mvaude) |[N-006](https://github.com/N-006) |[nabijaczleweli](https://github.com/nabijaczleweli) |[nelsonjchen](https://github.com/nelsonjchen) |[Nemo157](https://github.com/Nemo157) |[nicompte](https://github.com/nicompte) |
+[volks73](https://github.com/volks73) |[daboross](https://github.com/daboross) |[mernen](https://github.com/mernen) |[dguo](https://github.com/dguo) |[davidszotten](https://github.com/davidszotten) |[eddyb](https://github.com/eddyb) |
 
-[<img alt="nvzqz" src="https://avatars.githubusercontent.com/u/10367662?v=3&s=117" width="117">](https://github.com/nvzqz) |[<img alt="ogham" src="https://avatars.githubusercontent.com/u/503760?v=3&s=117" width="117">](https://github.com/ogham) |[<img alt="panicbit" src="https://avatars.githubusercontent.com/u/628445?v=3&s=117" width="117">](https://github.com/panicbit) |[<img alt="pixelistik" src="https://avatars.githubusercontent.com/u/170929?v=3&s=117" width="117">](https://github.com/pixelistik) |[<img alt="rnelson" src="https://avatars.githubusercontent.com/u/118361?v=3&s=117" width="117">](https://github.com/rnelson) |[<img alt="rtaycher" src="https://avatars.githubusercontent.com/u/324733?v=3&s=117" width="117">](https://github.com/rtaycher) |
+[<img alt="birkenfeld" src="https://avatars3.githubusercontent.com/u/144359?v=3&s=117" width="117">](https://github.com/birkenfeld) |[<img alt="tanakh" src="https://avatars1.githubusercontent.com/u/109069?v=3&s=117" width="117">](https://github.com/tanakh) |[<img alt="SirVer" src="https://avatars3.githubusercontent.com/u/140115?v=3&s=117" width="117">](https://github.com/SirVer) |[<img alt="idmit" src="https://avatars2.githubusercontent.com/u/2546728?v=3&s=117" width="117">](https://github.com/idmit) |[<img alt="archer884" src="https://avatars2.githubusercontent.com/u/679494?v=3&s=117" width="117">](https://github.com/archer884) |[<img alt="shepmaster" src="https://avatars3.githubusercontent.com/u/174509?v=3&s=117" width="117">](https://github.com/shepmaster) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[nvzqz](https://github.com/nvzqz) |[ogham](https://github.com/ogham) |[panicbit](https://github.com/panicbit) |[pixelistik](https://github.com/pixelistik) |[rnelson](https://github.com/rnelson) |[rtaycher](https://github.com/rtaycher) |
+[birkenfeld](https://github.com/birkenfeld) |[tanakh](https://github.com/tanakh) |[SirVer](https://github.com/SirVer) |[idmit](https://github.com/idmit) |[archer884](https://github.com/archer884) |[shepmaster](https://github.com/shepmaster) |
 
-[<img alt="Seeker14491" src="https://avatars.githubusercontent.com/u/6490497?v=3&s=117" width="117">](https://github.com/Seeker14491) |[<img alt="shepmaster" src="https://avatars.githubusercontent.com/u/174509?v=3&s=117" width="117">](https://github.com/shepmaster) |[<img alt="SirVer" src="https://avatars.githubusercontent.com/u/140115?v=3&s=117" width="117">](https://github.com/SirVer) |[<img alt="sru" src="https://avatars.githubusercontent.com/u/2485892?v=3&s=117" width="117">](https://github.com/sru) |[<img alt="SShrike" src="https://avatars.githubusercontent.com/u/4061736?v=3&s=117" width="117">](https://github.com/SShrike) |[<img alt="starkat99" src="https://avatars.githubusercontent.com/u/8295111?v=3&s=117" width="117">](https://github.com/starkat99) |
+[<img alt="jespino" src="https://avatars3.githubusercontent.com/u/290303?v=3&s=117" width="117">](https://github.com/jespino) |[<img alt="jtdowney" src="https://avatars2.githubusercontent.com/u/44654?v=3&s=117" width="117">](https://github.com/jtdowney) |[<img alt="andete" src="https://avatars1.githubusercontent.com/u/689017?v=3&s=117" width="117">](https://github.com/andete) |[<img alt="joshtriplett" src="https://avatars1.githubusercontent.com/u/162737?v=3&s=117" width="117">](https://github.com/joshtriplett) |[<img alt="malbarbo" src="https://avatars0.githubusercontent.com/u/1678126?v=3&s=117" width="117">](https://github.com/malbarbo) |[<img alt="iliekturtles" src="https://avatars0.githubusercontent.com/u/5081378?v=3&s=117" width="117">](https://github.com/iliekturtles) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[Seeker14491](https://github.com/Seeker14491) |[shepmaster](https://github.com/shepmaster) |[SirVer](https://github.com/SirVer) |[sru](https://github.com/sru) |[SShrike](https://github.com/SShrike) |[starkat99](https://github.com/starkat99) |
+[jespino](https://github.com/jespino) |[jtdowney](https://github.com/jtdowney) |[andete](https://github.com/andete) |[joshtriplett](https://github.com/joshtriplett) |[malbarbo](https://github.com/malbarbo) |[iliekturtles](https://github.com/iliekturtles) |
 
-[<img alt="SuperFluffy" src="https://avatars.githubusercontent.com/u/701177?v=3&s=117" width="117">](https://github.com/SuperFluffy) |[<img alt="swatteau" src="https://avatars.githubusercontent.com/u/5521255?v=3&s=117" width="117">](https://github.com/swatteau) |[<img alt="tanakh" src="https://avatars.githubusercontent.com/u/109069?v=3&s=117" width="117">](https://github.com/tanakh) |[<img alt="th4t" src="https://avatars.githubusercontent.com/u/2801030?v=3&s=117" width="117">](https://github.com/th4t) |[<img alt="tormol" src="https://avatars.githubusercontent.com/u/10460821?v=3&s=117" width="117">](https://github.com/tormol) |[<img alt="tshepang" src="https://avatars.githubusercontent.com/u/588486?v=3&s=117" width="117">](https://github.com/tshepang) |
+[<img alt="nicompte" src="https://avatars1.githubusercontent.com/u/439369?v=3&s=117" width="117">](https://github.com/nicompte) |[<img alt="NickeZ" src="https://avatars1.githubusercontent.com/u/492753?v=3&s=117" width="117">](https://github.com/NickeZ) |[<img alt="nvzqz" src="https://avatars3.githubusercontent.com/u/10367662?v=3&s=117" width="117">](https://github.com/nvzqz) |[<img alt="Geogi" src="https://avatars2.githubusercontent.com/u/1818316?v=3&s=117" width="117">](https://github.com/Geogi) |[<img alt="flying-sheep" src="https://avatars3.githubusercontent.com/u/291575?v=3&s=117" width="117">](https://github.com/flying-sheep) |[<img alt="peppsac" src="https://avatars0.githubusercontent.com/u/2198295?v=3&s=117" width="117">](https://github.com/peppsac) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[SuperFluffy](https://github.com/SuperFluffy) |[swatteau](https://github.com/swatteau) |[tanakh](https://github.com/tanakh) |[th4t](https://github.com/th4t) |[tormol](https://github.com/tormol) |[tshepang](https://github.com/tshepang) |
+[nicompte](https://github.com/nicompte) |[NickeZ](https://github.com/NickeZ) |[nvzqz](https://github.com/nvzqz) |[Geogi](https://github.com/Geogi) |[flying-sheep](https://github.com/flying-sheep) |[peppsac](https://github.com/peppsac) |
 
-[<img alt="tspiteri" src="https://avatars.githubusercontent.com/u/18604588?v=3&s=117" width="117">](https://github.com/tspiteri) |[<img alt="untitaker" src="https://avatars.githubusercontent.com/u/837573?v=3&s=117" width="117">](https://github.com/untitaker) |[<img alt="Vinatorul" src="https://avatars.githubusercontent.com/u/6770624?v=3&s=117" width="117">](https://github.com/Vinatorul) |[<img alt="vks" src="https://avatars.githubusercontent.com/u/33460?v=3&s=117" width="117">](https://github.com/vks) |[<img alt="volks73" src="https://avatars.githubusercontent.com/u/1915469?v=3&s=117" width="117">](https://github.com/volks73) |[<img alt="wdv4758h" src="https://avatars.githubusercontent.com/u/2716047?v=3&s=117" width="117">](https://github.com/wdv4758h) |
+[<img alt="hexjelly" src="https://avatars3.githubusercontent.com/u/435283?v=3&s=117" width="117">](https://github.com/hexjelly) |[<img alt="rnelson" src="https://avatars0.githubusercontent.com/u/118361?v=3&s=117" width="117">](https://github.com/rnelson) |[<img alt="swatteau" src="https://avatars0.githubusercontent.com/u/5521255?v=3&s=117" width="117">](https://github.com/swatteau) |[<img alt="tspiteri" src="https://avatars3.githubusercontent.com/u/18604588?v=3&s=117" width="117">](https://github.com/tspiteri) |[<img alt="vks" src="https://avatars1.githubusercontent.com/u/33460?v=3&s=117" width="117">](https://github.com/vks) |[<img alt="th4t" src="https://avatars1.githubusercontent.com/u/2801030?v=3&s=117" width="117">](https://github.com/th4t) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[tspiteri](https://github.com/tspiteri) |[untitaker](https://github.com/untitaker) |[Vinatorul](https://github.com/Vinatorul) |[vks](https://github.com/vks) |[volks73](https://github.com/volks73) |[wdv4758h](https://github.com/wdv4758h) |
+[hexjelly](https://github.com/hexjelly) |[rnelson](https://github.com/rnelson) |[swatteau](https://github.com/swatteau) |[tspiteri](https://github.com/tspiteri) |[vks](https://github.com/vks) |[th4t](https://github.com/th4t) |
+
+[<img alt="mineo" src="https://avatars2.githubusercontent.com/u/78236?v=3&s=117" width="117">](https://github.com/mineo) |[<img alt="grossws" src="https://avatars1.githubusercontent.com/u/171284?v=3&s=117" width="117">](https://github.com/grossws) |[<img alt="messense" src="https://avatars3.githubusercontent.com/u/1556054?v=3&s=117" width="117">](https://github.com/messense) |[<img alt="mvaude" src="https://avatars2.githubusercontent.com/u/9532611?v=3&s=117" width="117">](https://github.com/mvaude) |[<img alt="panicbit" src="https://avatars1.githubusercontent.com/u/628445?v=3&s=117" width="117">](https://github.com/panicbit) |[<img alt="mitsuhiko" src="https://avatars2.githubusercontent.com/u/7396?v=3&s=117" width="117">](https://github.com/mitsuhiko) |
+:---: |:---: |:---: |:---: |:---: |:---: |
+[mineo](https://github.com/mineo) |[grossws](https://github.com/grossws) |[messense](https://github.com/messense) |[mvaude](https://github.com/mvaude) |[panicbit](https://github.com/panicbit) |[mitsuhiko](https://github.com/mitsuhiko) |
 
 
+
+
+This list was generated by [mgechev/github-contributors-list](https://github.com/mgechev/github-contributors-list)
--- a/third_party/rust/clap/Cargo.toml
+++ b/third_party/rust/clap/Cargo.toml
@@ -1,45 +1,46 @@
 [package]
 
 name = "clap"
-version = "2.20.5"
+version = "2.24.2"
 authors = ["Kevin K. <kbknapp@gmail.com>"]
 exclude = ["examples/*", "clap-test/*", "tests/*", "benches/*", "*.png", "clap-perf/*", "*.dot"]
 repository = "https://github.com/kbknapp/clap-rs.git"
 documentation = "https://docs.rs/clap/"
 homepage = "https://clap.rs/"
 readme = "README.md"
 license = "MIT"
 keywords = ["argument", "command", "arg", "parser", "parse"]
 categories = ["command-line-interface"]
 description = """
 A simple to use, efficient, and full featured  Command Line Argument Parser
 """
 
 [dependencies]
-bitflags              = "0.7.0"
-vec_map               = "0.6.0"
+bitflags              = "0.8.0"
+vec_map               = "0.8"
 unicode-width         = "0.1.4"
 unicode-segmentation  = "1.0.1"
 strsim    = { version = "0.6.0",  optional = true }
 ansi_term = { version = "0.9.0",  optional = true }
-term_size = { version = "0.2.2",  optional = true }
-libc      = { version = "0.2.20",  optional = true }
+term_size = { version = "0.3.0",  optional = true }
 yaml-rust = { version = "0.3.5",  optional = true }
-clippy    = { version = "~0.0.112", optional = true }
+clippy    = { version = "~0.0.131", optional = true }
+atty      = { version = "0.2.2",  optional = true }
 
 [dev-dependencies]
-regex = "~0.1.80"
+regex = "0.2"
+lazy_static = "0.2"
 
 [features]
 default     = ["suggestions", "color", "wrap_help"]
 suggestions = ["strsim"]
-color       = ["ansi_term", "libc"]
-wrap_help   = ["libc", "term_size"]
+color       = ["ansi_term", "atty"]
+wrap_help   = ["term_size"]
 yaml        = ["yaml-rust"]
 unstable    = [] # for building with unstable clap features (doesn't require nightly Rust) (currently none)
 nightly     = [] # for building with unstable Rust features (currently none)
 lints       = ["clippy"] # Requires nightly Rust
 debug       = [] # Enables debug messages
 no_cargo    = [] # Enable if you're not using Cargo, disables Cargo-env-var-dependent macros
 
 [profile.release]
@@ -59,17 +60,17 @@ debug-assertions = true
 codegen-units = 4
 
 [profile.test]
 opt-level = 1
 debug = true
 rpath = false
 lto = false
 debug-assertions = true
-codegen-units = 2
+codegen-units = 4
 
 [profile.bench]
 opt-level = 3
 debug = false
 rpath = false
 lto = true
 debug-assertions = false
 
--- a/third_party/rust/clap/README.md
+++ b/third_party/rust/clap/README.md
@@ -40,141 +40,74 @@ Table of Contents
 * [License](#license)
 * [Recent Breaking Changes](#recent-breaking-changes)
   * [Deprecations](#deprecations)
 
 Created by [gh-md-toc](https://github.com/ekalinin/github-markdown-toc)
 
 ## What's New
 
-Here's the highlights for v2.20.5
+Here's the highlights for v2.24.2
 
-* Fixes a critical bug in the `clap_app!` macro of a missing fragment specifier when using `!property` style tags.
+* fixes a bug where args that allow values to start with a hyphen couldnt contain a double hyphen -- as a value 
+* fixes a bug where positional argument help text is misaligned 
+* **App::template docs:**  adds details about the necessity to use AppSettings::UnifiedHelpMessage when using {unified} tags in the help template 
+* **Arg::allow_hyphen_values docs:**  updates the docs to include warnings for allow_hyphen_values and multiple(true) used together 
+* **clap_app! docs:**  adds using the @group specifier to the macro docs 
+* adds a debug assertion to ensure all args added to groups actually exist 
+
+Here's the highlights for v2.21.0 to v2.24.1
 
-
-Here's the highlights from v2.0.0 to v2.20.4
-
-* Fixes a bug that tried to propogate global args multiple times when generating multiple completion scripts
+* fixes a bug where args with last(true) and required(true) set were not being printed in the usage string 
+* fixes a bug that was printing the arg name, instead of value name when Arg::last(true) was used 
+* fixes a bug where flags were parsed as flags AND positional values when specific combinations of settings were used 
+* **README.md:**  fix some typos 
+* **Arg:**  add `default_value_os` 
+* **arg_matches.rs:**  Added a Default implementation for Values and OsValues iterators. 
+* **PowerShell Completions:**
+  * fixes a bug where powershells completions cant be used if no subcommands are defined
+  * massively dedups subcommand names in the generate script to make smaller scripts that are still functionally equiv
+* allows specifying a short help vs a long help (i.e. varying levels of detail depending on if -h or --help was used)
+* **clap_app!:**  adds support for arg names with hyphens similar to longs with hyphens
+* fixes a bug that wasn't allowing help and version to be properly overridden
+  * This may break code that was relying on this bug! If you add a flag with a long of `help` manually *and* rely on the help message to be printed automatically your code could break. Please see the commit link in the full CHANGELOG.md
+* `App::long_about`
+* `App::long_version`
+* `App::print_long_help`
+* `App::write_long_help`
+* `App::print_long_version`
+* `App::write_long_version`
+* `Arg::long_help`
+* **clap_app!:**  documents the `--("some-arg")` method for using args with hyphens inside them
+* fixes the usage string regression when using help templates
+* fixes a big regression with custom usage strings
+* adds the ability to change the name of the App instance after creation
+* adds ability to hide the default value of an argument from the help string
+* fixes support for loading author info from yaml
+* adds fish subcommand help support
+* options that use `require_equals(true)` now display the equals sign in help messages, usage strings, and errors
+* setting the max term width now correctly propagates down through child subcommands
+* fixes the precedence of this error to prioritize over other error messages
+* fixes some regression bugs resulting from old asserts in debug mode.
+* adds the ability to mark a positional argument as 'last' which means it should be used with `--` syntax and can be accessed early to effectivly skip other positional args
+* Some performance improvements by reducing the ammount of duplicate work, cloning, and allocations in all cases.
+* Some massive performance gains when using many args (i.e. things like shell glob expansions)
+* adds a setting to allow one to infer shortened subcommands or aliases (i.e. for subcommmand "test", "t", "te", or "tes" would be allowed assuming no other ambiguities)
+* when `AppSettings::SubcommandsNegateReqs` and `ArgsNegateSubcommands` are used, a new more accurate double line usage string is shown
+* provides `default_value_os` and `default_value_if[s]_os`
+* provides `App::help_message` and `App::version_message` which allows one to override the auto-generated help/version flag associated help
+* adds the ability to require the equals syntax with options `--opt=val`
+* doesn't print the argument sections in the help message if all args in that section are hidden
+* doesn't include the various `[ARGS]` `[FLAGS]` or `[OPTIONS]` if the only ones available are hidden
+* now correctly shows subcommand as required in the usage string when AppSettings::SubcommandRequiredElseHelp is used
+* fixes some "memory leaks" when an error is detected and clap exits
+* fixes a trait that's marked private accidentlly, but should be crate internal public
+* fixes a bug that tried to propogate global args multiple times when generating multiple completion scripts
+* Fixes a critical bug in the `clap_app!` macro of a missing fragment specifier when using `!property` style tags.
 * Fix examples link in CONTRIBUTING.md
-* **Completions**: fixes bash completions for commands that have an underscore in the name
-* **Completions**: fixes a bug where ZSH completions would panic if the binary name had an underscore in it
-* allow final word to be wrapped in wrap_help
-* **Completions**: fixes a bug where global args weren't included in the generated completion scripts
-* **Macros Documentation:**  adds a warning about changing values in Cargo.toml not triggering a rebuild automatically
-* Fixes a critical bug where subcommand settings were being propogated too far
-* Adds ArgGroup::multiple to the supported YAML fields for building ArgGroups from YAML
-* Fixes a bug where the final word wasn't wrapped in help messages
-* Fixes finding required arguments in group arguments
-* **ArgsNegateSubcommands:**  disables args being allowed between subcommands
-* **DontCollapseArgsInUsage:** disables the collapsing of positional args into `[ARGS]` in the usage string
-* **DisableHelpSubcommand:**  disables building the `help` subcommand
-* **AllowMissingPositional:**  allows one to implement `$ prog [optional] <required>` style CLIs where the second postional argument is required, but the first is optional
-* **PropagateGlobalValuesDown:**  automatically propagats global arg's values down through *used* subcommands
-* **Arg::value_terminator:**  adds the ability to terminate multiple values with a given string or char
-* **Arg::default_value_if[s]:**  adds new methods for *conditional* default values (such as a particular value from another argument was used)
-* **Arg::requires_if[s]:**  adds the ability to *conditionally* require additional args (such as if a particular value was used)
-* **Arg::required_if[s]:**  adds the ability for an arg to be *conditionally* required (i.e. "arg X is only required if arg Y was used with value Z")
-* **Arg::validator_os:**  adds ability to validate values which may contain invalid UTF-8
-* **crate_description!:** Uses the `Cargo.toml` description field to fill in the `App::about` method at compile time
-* **crate_name!:** Uses the `Cargo.toml` name field to fill in the `App::new` method at compile time
-* **app_from_crate!:** Combines `crate_version!`, `crate_name!`, `crate_description!`, and `crate_authors!` into a single macro call to build a default `App` instance from the `Cargo.toml` fields
-* **no_cargo:**  adds a `no_cargo` feature to disable Cargo-env-var-dependent macros for those *not* using `cargo` to build their crates
-* **Options:**  fixes a critical bug where options weren't forced to have a value
-*   fixes a bug where calling the help of a subcommand wasn't ignoring required args of parent commands
-* **Help Subcommand:**  fixes a bug where the help subcommand couldn't be overriden
-* **Low Index Multiples:**  fixes a bug which caused combinations of LowIndexMultiples and `Arg::allow_hyphen_values` to fail parsing
-* **Default Values:**  improves the error message when default values are involved
-* **YAML:**  adds conditional requirements and conditional default values to YAML
-*  Support `--("some-arg-name")` syntax for defining long arg names when using `clap_app!` macro
-*  Support `("some app name")` syntax for defining app names when using `clap_app!` macro
-* **Help Wrapping:**  long app names (with spaces), authors, and descriptions are now wrapped appropriately
-* **Conditional Default Values:**  fixes the failing doc tests of Arg::default_value_ifs
-* **Conditional Requirements:**  adds docs for Arg::requires_ifs
-* Fixes a bug where calling the help of a subcommand wasn't ignoring required args of parent commands
-* Fixes a bug by escaping square brackets in ZSH completions which were causing conflicts and errors.
-* **Bash Completion:**  allows bash completion to fall back to traidtional bash completion upon no matching completing function
-* **Arg Setting**: Allows specifying an `AllowLeadingHyphen` style setting for values only for specific args, vice command wide
-* **Validators:**  improves the error messages for validators
-* **Required Unless:**  fixes a bug where having required_unless set doesn't work when conflicts are also set
-* **ZSH Completions:**  fixes an issue where zsh completions caused panics if there were no subcommands
-* **Completions:**  Adds completion support for Microsoft PowerShell! (Thanks to @Arnavion)
-* Allows specifying the second to last positional argument as `multiple(true)` (i.e. things such as `mv <files>... <target>`)
-* Adds an `App::get_name` and `App::get_bin_name`
-* Conflicting argument errors are now symetrical, meaning more consistent and better usage suggestions
-* **Completions:**  adds automatic ZSH completion script generation support! :tada: :tada:
-* **AppSettings:**  adds new setting `AppSettings::AllowNegativeNumbers` which functions like `AllowLeadingHyphen` except only allows undefined negative numbers to pass parsing.
-* Stabilize `clap_app!` macro (i.e. no longer need to use `unstable` feature)
-* Deprecate `App::with_defaults`
-* One can now alias arguments either visibly (which appears in the help text) or invisibly just like subcommands!
-* The `from_usage` parser now correctly handles non-ascii names / options and help!
-* **Value Delimiters:**  fixes the confusion around implicitly setting value delimiters. (The default is to *not* use a delimiter unless explicitly set)
-* Changes the default value delimiter rules (i.e. the default is `use_delimiter(false)` *unless* a setting/method that implies multiple values was used) **[Bugfix that *may* "break" code]**
- * If code breaks, simply add `Arg::use_delimiter(true)` to the affected args
-* Adds ability to hide the possible values from the help text on a per argument basis, instead of command wide
-* Allows for limiting detected terminal width (i.e. wrap at `x` length, unless the terminal width is *smaller*)
-* `clap` now ignores hard newlines in help messages and properly re-aligns text, but still wraps if the term width is too small
-* Adds support for the setting `Arg::require_delimiter` from YAML
-* `clap` no longer requires one to use `{n}` inside help text to insert a newline that is properly aligned. One can now use the normal `\n`.
-* `clap` now ignores hard newlines in help messages and properly re-aligns text, but still wraps if the term width is too small
-* Errors can now have custom description
-* Uses `term_size` instead of home-grown solution on Windows
-* Adds the ability to wrap help text intelligently on Windows!
-* Moves docs to [docs.rs!](https://docs.rs/clap/)!
-* Automatically moves help text to the next line and wraps when term width is determined to be too small, or help text is too long
-* Vastly improves *development* error messages when using YAML
-* Adds a shorthand way to ignore help text wrapping and use source formatting (i.e. `App::set_term_width(0)`)
-* **Help Subcommand:**  fixes misleading usage string when using multi-level subcommmands such as `myprog help subcmd1 subcmd2`
-* **YAML:**  allows using lists or single values with certain arg declarations for increased ergonomics
-* **Fish Shell Completions:**  one can generate a basic fish completions script at compile time!
-* Adds the ability to generate completions to an `io::Write` object
-* Adds an `App::unset_setting` and `App::unset_settings`
-* **Completions:**  one can now [generate a bash completions](https://docs.rs/clap/2.9.0/clap/struct.App.html#method.gen_completions) script at compile time! These completions work with options using [possible values](https://docs.rs/clap/2.9.0/clap/struct.Arg.html#method.possible_values), [subcommand aliases](https://docs.rs/clap/2.9.0/clap/struct.App.html#method.aliases), and even multiple levels of subcommands
-* **Arg:**  adds new optional setting [`Arg::require_delimiter`](https://docs.rs/clap/2.8.0/clap/struct.Arg.html#method.require_delimiter) which requires val delimiter to parse multiple values
-* The terminal sizing portion has been factored out into a separate crate, [term_size](https://crates.io/crates/term_size)
-* Options using multiple values and delimiters no longer parse additional values after a trailing space (i.e. `prog -o 1,2 file.txt` parses as `1,2` for `-o` and `file.txt` for a positional arg)
-* Using options using multiple values and with an `=` no longer parse args after the trailing space as values (i.e. `prog -o=1 file.txt` parses as `1` for `-o` and `file.txt` for a positional arg)
-* **Usage Strings:**  `[FLAGS]` and `[ARGS]` are no longer blindly added to usage strings, instead only when applicable
-* `arg_enum!`:  allows using more than one meta item, or things like `#[repr(C)]` with `arg_enum!`s
-* `App::print_help`: now prints the same as would have been printed by `--help` or the like
-* Prevents invoking `<cmd> help help` and displaying incorrect help message
-* Subcommand help messages requested via `<cmd> help <sub>` now correctly match `<cmd> <sub> --help`
-* One can now specify groups which require AT LEAST one of the args
-* Allows adding multiple ArgGroups per Arg
-* **Global Settings:** One can now set an `AppSetting` which is propogated down through child subcommands
-* **Terminal Wrapping:**  Allows wrapping at specified term width (Even on Windows!) (can now set an absolute width to "smart" wrap at)
-* **SubCommands/Aliases:**  adds support for visible aliases for subcommands (i.e. aliases that are dipslayed in the help message)
-* **Subcommands/Aliases:**  when viewing the help of an alias, it now display help of the aliased subcommand
-* Adds new setting to stop delimiting values with `--` or `AppSettings::TrailingVarArg`
-* Subcommands now support aliases - think of them as hidden subcommands that dispatch to said subcommand automatically
-* Fixed times when `ArgGroup`s are duplicated in usage strings
-* **Before Help:**  adds support for displaying info before help message
-* **Required Unless:**  adds support for allowing args that are required unless certain other args are present
-* **New Help Template Engine!**: Now you have full control over the layout of your help message. Major thanks to @hgrecco
-* **Pull crate Authors from Cargo.toml**: One can now use the `crate_authors!` macro to automatically pull the crate authors from their Cargo.toml file
-* **Colored Help Messages**: Help messages can now be optionally colored (See the `AppSettings::ColoredHelp` setting). Screenshot below.
-* **Help text auto wraps and aligns at for subcommands too!** - Long help strings of subcommands will now properly wrap and align to term width on Linux and OS X. This can be turned off as well.
-* **Help text auto wraps and aligns at term width!** - Long help strings will now properly wrap and align to term width on Linux and OS X (and presumably Unix too). This can be turned off as well.
-* **Can customize the order of opts, flags, and subcommands in help messages**  - Instead of using the default alphabetical order, you can now re-arrange the order of your args and subcommands in help message. This helps to emphasize more popular or important options.
-* **Can auto-derive the order from declaration order** - Have a bunch of args or subcommmands to re-order? You can now just derive the order from the declaration order!
-* **Help subcommand now accepts other subcommands as arguments!** - Similar to other CLI precedents, the `help` subcommand can now accept other subcommands as arguments to display their help message. i.e. `$ myprog help mysubcmd` (*Note* these can even be nested heavily such as `$ myprog help subcmd1 subcmd2 subcmd3` etc.)
-* **Default Values**: Args can now specify default values
-* **Next Line Help**: Args can have help strings on the line following the argument (useful for long arguments, or those with many values). This can be set command-wide or for individual args
-
-Here's a gif of them in action!
-
-![zsh-comppletions](http://i.imgur.com/rwlMbAv.gif)
-
-An example of the help text wrapping at term width:
-
-![screenshot](http://i.imgur.com/PAJzJJG.png)
-
-An example of the optional colored help:
-
-![screenshot](http://i.imgur.com/7fs2h5j.png)
-
 
 For full details, see [CHANGELOG.md](https://github.com/kbknapp/clap-rs/blob/master/CHANGELOG.md)
 
 ## About
 
 `clap` is used to parse *and validate* the string of command line arguments provided by the user at runtime. You provide the list of valid possibilities, and `clap` handles the rest. This means you focus on your *applications* functionality, and less on the parsing and validating of arguments.
 
 `clap` also provides the traditional version and help switches (or flags) 'for free' meaning automatically with no configuration. It does this by checking list of valid possibilities you supplied and adding only the ones you haven't already defined. If you are using subcommands, `clap` will also auto-generate a `help` subcommand for you in addition to the traditional flags.
@@ -534,18 +467,18 @@ Define a list of valid arguments for you
 
 Then run `cargo build` or `cargo update && cargo build` for your project.
 
 ### Optional Dependencies / Features
 
 #### Features enabled by default
 
 * **"suggestions"**: Turns on the `Did you mean '--myoption'?` feature for when users make typos. (builds dependency `strsim`)
-* **"color"**: Turns on colored error messages. This feature only works on non-Windows OSs. (builds dependency `ansi-term` and `libc`)
-* **"wrap_help"**: Wraps the help at the actual terminal width when available, instead of 120 chracters. (builds dependency `term_size`, and `libc`)
+* **"color"**: Turns on colored error messages. This feature only works on non-Windows OSs. (builds dependency `ansi-term`)
+* **"wrap_help"**: Wraps the help at the actual terminal width when available, instead of 120 characters. (builds dependency `term_size`)
 
 To disable these, add this to your `Cargo.toml`:
 
 ```toml
 [dependencies.clap]
 version = "2.19"
 default-features = false
 ```
@@ -594,24 +527,24 @@ Contributions are always welcome! And th
 
 Another really great way to help is if you find an interesting, or helpful way in which to use `clap`. You can either add it to the [examples/](examples) directory, or file an issue and tell me. I'm all about giving credit where credit is due :)
 
 Please read [CONTRIBUTING.md](.github/CONTRIBUTING.md) before you start contributing.
 
 
 ### Testing Code
 
-To test with all features both enabled and disabled, you can run theese commands:
+To test with all features both enabled and disabled, you can run these commands:
 
 ```sh
 $ cargo test --no-default-features
 $ cargo test --features "yaml unstable"
 ```
 
-Alternatively, if you have [`just`](https://github.com/casey/just) installed you can run the prebuilt recipies. *Not* using `just` is prfeclty fine as well, it simply bundles commands automatically.
+Alternatively, if you have [`just`](https://github.com/casey/just) installed you can run the prebuilt recipes. *Not* using `just` is perfectly fine as well, it simply bundles commands automatically.
 
 For example, to test the code, as above simply run:
 
 ```sh
 $ just run-tests
 ```
 
 From here on, I will list the appropriate `cargo` command as well as the `just` command.
@@ -671,17 +604,17 @@ There are a few goals of `clap` that I'd
 * `panic!` on *developer* error, exit gracefully on *end-user* error
 
 ### Compatibility Policy
 
 Because `clap` takes SemVer and compatibility seriously, this is the official policy regarding breaking changes and minimum required versions of Rust.
 
 `clap` will pin the minimum required version of Rust to the CI builds. Bumping the minimum version of Rust is considered a minor breaking change, meaning *at a minimum* the minor version of `clap` will be bumped.
 
-In order to keep from being suprised of breaking changes, it is **highly** recommended to use the `~major.minor.patch` style in your `Cargo.toml` only if you wish to target a version of Rust that is *older* than current stable minus two releases:
+In order to keep from being surprised of breaking changes, it is **highly** recommended to use the `~major.minor.patch` style in your `Cargo.toml` only if you wish to target a version of Rust that is *older* than current stable minus two releases:
 
 ```toml
 [dependencies]
 clap = "~2.19.0"
 ```
 
 This will cause *only* the patch version to be updated upon a `cargo update` call, and therefore cannot break due to new features, or bumped minimum versions of Rust.
 
@@ -689,17 +622,17 @@ This will cause *only* the patch version
 
 `clap` will officially support current stable Rust, minus two releases, but may work with prior releases as well. For example, current stable Rust at the time of this writing is 1.13.0, meaning `clap` is guaranteed to compile with 1.11.0 and beyond.
 At the 1.14.0 release, `clap` will be guaranteed to compile with 1.12.0 and beyond, etc.
 
 Upon bumping the minimum version of Rust (assuming it's within the stable-2 range), it *must* be clearly annotated in the `CHANGELOG.md`
 
 #### Breaking Changes
 
-`clap` takes a similar policy to Rust and will bump the major veresion number upon breaking changes with only the following exceptions:
+`clap` takes a similar policy to Rust and will bump the major version number upon breaking changes with only the following exceptions:
 
  * The breaking change is to fix a security concern
  * The breaking change is to be fixing a bug (i.e. relying on a bug as a feature)
  * The breaking change is a feature isn't used in the wild, or all users of said feature have given approval *prior* to the change
 
 ## License
 
 `clap` is licensed under the MIT license. Please read the [LICENSE-MIT](LICENSE-MIT) file in this repository for more information.
--- a/third_party/rust/clap/clap-test.rs
+++ b/third_party/rust/clap/clap-test.rs
@@ -4,21 +4,24 @@ mod test {
     use std::io::{Cursor, Write};
 
     use regex::Regex;
 
     use clap::{App, Arg, SubCommand, ArgGroup};
 
     fn compare<S, S2>(l: S, r: S2) -> bool
         where S: AsRef<str>,
-              S2: AsRef<str> {
+              S2: AsRef<str>
+    {
         let re = Regex::new("\x1b[^m]*m").unwrap();
         // Strip out any mismatching \r character on windows that might sneak in on either side
-        let left = re.replace_all(&l.as_ref().trim().replace("\r", "")[..], "");
-        let right = re.replace_all(&r.as_ref().trim().replace("\r", "")[..], "");
+        let ls = l.as_ref().trim().replace("\r", "");
+        let rs = r.as_ref().trim().replace("\r", "");
+        let left = re.replace_all(&*ls, "");
+        let right = re.replace_all(&*rs, "");
         let b = left == right;
         if !b {
             println!("");
             println!("--> left");
             println!("{}", left);
             println!("--> right");
             println!("{}", right);
             println!("--")
@@ -64,9 +67,9 @@ mod test {
             ])
             .subcommand(SubCommand::with_name("subcmd")
                                     .about("tests subcommands")
                                     .version("0.1")
                                     .author("Kevin K. <kbknapp@gmail.com>")
                                     .arg_from_usage("-o --option [scoption]... 'tests options'")
                                     .arg_from_usage("[scpositional] 'tests positionals'"))
     }
-}
\ No newline at end of file
+}
--- a/third_party/rust/clap/justfile
+++ b/third_party/rust/clap/justfile
@@ -1,16 +1,19 @@
 @update-contributors:
 	echo 'Removing old CONTRIBUTORS.md'
 	mv CONTRIBUTORS.md CONTRIBUTORS.md.bak
 	echo 'Downloading a list of new contributors'
-	echo "The following is a list of contributors in alphabetical order:" > CONTRIBUTORS.md
+	echo "the following is a list of contributors:" > CONTRIBUTORS.md
 	echo "" >> CONTRIBUTORS.md
 	echo "" >> CONTRIBUTORS.md
-	githubcontrib --owner kbknapp --repo clap-rs --sha master --cols 6 --format md --showlogin true --sortBy login >> CONTRIBUTORS.md
+	githubcontrib --owner kbknapp --repo clap-rs --sha master --cols 6 --format md --showlogin true --sortBy contributions --sortOrder desc >> CONTRIBUTORS.md
+	echo "" >> CONTRIBUTORS.md
+	echo "" >> CONTRIBUTORS.md
+	echo "This list was generated by [mgechev/github-contributors-list](https://github.com/mgechev/github-contributors-list)" >> CONTRIBUTORS.md
 	rm CONTRIBUTORS.md.bak
 
 run-test TEST:
 	cargo test --test {{TEST}}
 
 debug TEST:
 	cargo test --test {{TEST}} --features debug
 
--- a/third_party/rust/clap/src/app/help.rs
+++ b/third_party/rust/clap/src/app/help.rs
@@ -6,16 +6,17 @@ use std::io::{self, Cursor, Read, Write}
 use std::usize;
 
 // Internal
 use app::{App, AppSettings};
 use app::parser::Parser;
 use args::{AnyArg, ArgSettings, DispOrder};
 use errors::{Error, Result as ClapResult};
 use fmt::{Format, Colorizer};
+use app::usage;
 
 // Third Party
 use unicode_width::UnicodeWidthStr;
 #[cfg(feature = "wrap_help")]
 use term_size;
 use unicode_segmentation::UnicodeSegmentation;
 use vec_map::VecMap;
 
@@ -83,28 +84,30 @@ pub struct Help<'a> {
     writer: &'a mut Write,
     next_line_help: bool,
     hide_pv: bool,
     term_w: usize,
     color: bool,
     cizer: Colorizer,
     longest: usize,
     force_next_line: bool,
+    use_long: bool,
 }
 
 // Public Functions
 impl<'a> Help<'a> {
     /// Create a new `Help` instance.
     pub fn new(w: &'a mut Write,
                next_line_help: bool,
                hide_pv: bool,
                color: bool,
                cizer: Colorizer,
                term_w: Option<usize>,
-               max_w: Option<usize>)
+               max_w: Option<usize>,
+               use_long: bool)
                -> Self {
         debugln!("Help::new;");
         Help {
             writer: w,
             next_line_help: next_line_help,
             hide_pv: hide_pv,
             term_w: match term_w {
                 Some(width) => if width == 0 { usize::MAX } else { width },
@@ -115,59 +118,61 @@ impl<'a> Help<'a> {
                                  Some(mw) => mw,
                              })
                 }
             },
             color: color,
             cizer: cizer,
             longest: 0,
             force_next_line: false,
+            use_long: use_long,
         }
     }
 
     /// Reads help settings from an App
     /// and write its help to the wrapped stream.
-    pub fn write_app_help(w: &'a mut Write, app: &App) -> ClapResult<()> {
+    pub fn write_app_help(w: &'a mut Write, app: &App, use_long: bool) -> ClapResult<()> {
         debugln!("Help::write_app_help;");
-        Self::write_parser_help(w, &app.p)
+        Self::write_parser_help(w, &app.p, use_long)
     }
 
     /// Reads help settings from a Parser
     /// and write its help to the wrapped stream.
-    pub fn write_parser_help(w: &'a mut Write, parser: &Parser) -> ClapResult<()> {
+    pub fn write_parser_help(w: &'a mut Write, parser: &Parser, use_long: bool) -> ClapResult<()> {
         debugln!("Help::write_parser_help;");
-        Self::_write_parser_help(w, parser, false)
+        Self::_write_parser_help(w, parser, false, use_long)
     }
 
     /// Reads help settings from a Parser
     /// and write its help to the wrapped stream which will be stderr. This method prevents
     /// formatting when required.
     pub fn write_parser_help_to_stderr(w: &'a mut Write, parser: &Parser) -> ClapResult<()> {
         debugln!("Help::write_parser_help;");
-        Self::_write_parser_help(w, parser, true)
+        Self::_write_parser_help(w, parser, true, false)
     }
 
     #[doc(hidden)]
-    pub fn _write_parser_help(w: &'a mut Write, parser: &Parser, stderr: bool) -> ClapResult<()> {
+    pub fn _write_parser_help(w: &'a mut Write, parser: &Parser, stderr: bool, use_long: bool) -> ClapResult<()> {
         debugln!("Help::write_parser_help;");
         let nlh = parser.is_set(AppSettings::NextLineHelp);
         let hide_v = parser.is_set(AppSettings::HidePossibleValuesInHelp);
         let color = parser.is_set(AppSettings::ColoredHelp);
         let cizer = Colorizer {
             use_stderr: stderr,
             when: parser.color(),
         };
         Self::new(w,
                   nlh,
                   hide_v,
                   color,
                   cizer,
                   parser.meta.term_w,
-                  parser.meta.max_w)
-            .write_help(parser)
+                  parser.meta.max_w,
+                  use_long)
+                .write_help(parser)
     }
 
     /// Writes the parser help to the wrapped stream.
     pub fn write_help(&mut self, parser: &Parser) -> ClapResult<()> {
         debugln!("Help::write_help;");
         if let Some(h) = parser.meta.help_str {
             try!(write!(self.writer, "{}", h).map_err(Error::from));
         } else if let Some(tmpl) = parser.meta.template {
@@ -185,24 +190,23 @@ impl<'a> Help<'a> {
     fn write_args_unsorted<'b: 'd, 'c: 'd, 'd, I: 'd>(&mut self, args: I) -> io::Result<()>
         where I: Iterator<Item = &'d ArgWithOrder<'b, 'c>>
     {
         debugln!("Help::write_args_unsorted;");
         // The shortest an arg can legally be is 2 (i.e. '-x')
         self.longest = 2;
         let mut arg_v = Vec::with_capacity(10);
         for arg in args.filter(|arg| {
-            !(arg.is_set(ArgSettings::Hidden)) || arg.is_set(ArgSettings::NextLineHelp)
-        }) {
+                                   !(arg.is_set(ArgSettings::Hidden)) ||
+                                   arg.is_set(ArgSettings::NextLineHelp)
+                               }) {
             if arg.longest_filter() {
                 self.longest = cmp::max(self.longest, arg.to_string().len());
             }
-            if !arg.is_set(ArgSettings::Hidden) {
-                arg_v.push(arg)
-            }
+            arg_v.push(arg)
         }
         let mut first = true;
         for arg in arg_v {
             if first {
                 first = false;
             } else {
                 try!(self.writer.write_all(b"\n"));
             }
@@ -279,17 +283,23 @@ impl<'a> Help<'a> {
         }
         if arg.takes_value() {
             if let Some(l) = arg.long() {
                 if arg.short().is_some() {
                     try!(write!(self.writer, ", "));
                 }
                 try!(color!(self, "--{}", l, good))
             }
-            try!(write!(self.writer, " "));
+
+            let sep = if arg.is_set(ArgSettings::RequireEquals) {
+                "="
+            } else {
+                " "
+            };
+            try!(write!(self.writer, "{}", sep));
         } else if let Some(l) = arg.long() {
             if arg.short().is_some() {
                 try!(write!(self.writer, ", "));
             }
             try!(color!(self, "--{}", l, good));
         }
         Ok(())
     }
@@ -379,28 +389,31 @@ impl<'a> Help<'a> {
         }
         Ok(spec_vals)
     }
 
     fn write_before_after_help(&mut self, h: &str) -> io::Result<()> {
         debugln!("Help::write_before_after_help;");
         let mut help = String::new();
         // determine if our help fits or needs to wrap
-        debugln!("Help::write_before_after_help: Term width...{}", self.term_w);
+        debugln!("Help::write_before_after_help: Term width...{}",
+                 self.term_w);
         let too_long = str_width(h) >= self.term_w;
 
         debug!("Help::write_before_after_help: Too long...");
         if too_long || h.contains("{n}") {
             sdebugln!("Yes");
             help.push_str(h);
             debugln!("Help::write_before_after_help: help: {}", help);
-            debugln!("Help::write_before_after_help: help width: {}", str_width(&*help));
+            debugln!("Help::write_before_after_help: help width: {}",
+                     str_width(&*help));
             // Determine how many newlines we need to insert
-            debugln!("Help::write_before_after_help: Usable space: {}", self.term_w);
-            let longest_w = find_longest!(help);            
+            debugln!("Help::write_before_after_help: Usable space: {}",
+                     self.term_w);
+            let longest_w = find_longest!(help);
             help = help.replace("{n}", "\n");
             wrap_help(&mut help, longest_w, self.term_w);
         } else {
             sdebugln!("No");
         }
         let help = if !help.is_empty() {
             &*help
         } else {
@@ -419,18 +432,22 @@ impl<'a> Help<'a> {
         }
         Ok(())
     }
 
     /// Writes argument's help to the wrapped stream.
     fn help<'b, 'c>(&mut self, arg: &ArgWithDisplay<'b, 'c>, spec_vals: &str) -> io::Result<()> {
         debugln!("Help::help;");
         let mut help = String::new();
-        let h = arg.help().unwrap_or("");
-        let nlh = self.next_line_help || arg.is_set(ArgSettings::NextLineHelp);
+        let h = if self.use_long {
+            arg.long_help().unwrap_or(arg.help().unwrap_or(""))
+        } else {
+            arg.help().unwrap_or(arg.long_help().unwrap_or(""))
+        };
+        let nlh = self.next_line_help || arg.is_set(ArgSettings::NextLineHelp) || self.use_long;
         debugln!("Help::help: Next Line...{:?}", nlh);
 
         let spcs = if nlh || self.force_next_line {
             12 // "tab" * 3
         } else {
             self.longest + 12
         };
 
@@ -446,17 +463,17 @@ impl<'a> Help<'a> {
             sdebugln!("Yes");
             help.push_str(h);
             help.push_str(&*spec_vals);
             debugln!("Help::help: help...{}", help);
             debugln!("Help::help: help width...{}", str_width(&*help));
             // Determine how many newlines we need to insert
             let avail_chars = self.term_w - spcs;
             debugln!("Help::help: Usable space...{}", avail_chars);
-            let longest_w = find_longest!(help);            
+            let longest_w = find_longest!(help);
             help = help.replace("{n}", "\n");
             wrap_help(&mut help, longest_w, avail_chars);
         } else {
             sdebugln!("No");
         }
         let help = if !help.is_empty() {
             &*help
         } else if spec_vals.is_empty() {
@@ -476,93 +493,102 @@ impl<'a> Help<'a> {
                     try!(write!(self.writer, "{}{}{}", TAB, TAB, TAB));
                 } else if arg.has_switch() {
                     write_nspaces!(self.writer, self.longest + 12);
                 } else {
                     write_nspaces!(self.writer, self.longest + 8);
                 }
                 try!(write!(self.writer, "{}", part));
             }
+        } else if nlh || self.force_next_line {
+            try!(write!(self.writer, "{}", help));
+            try!(write!(self.writer, "\n"));
         } else {
             try!(write!(self.writer, "{}", help));
         }
         Ok(())
     }
 
     fn spec_vals(&self, a: &ArgWithDisplay) -> String {
         debugln!("Help::spec_vals: a={}", a);
         let mut spec_vals = vec![];
-        if let Some(pv) = a.default_val() {
-            debugln!("Help::spec_vals: Found default value...[{}]", pv);
-            spec_vals.push(format!(" [default: {}]",
-                                   if self.color {
-                                       self.cizer.good(pv)
-                                   } else {
-                                       Format::None(pv)
-                                   }));
+        if !a.is_set(ArgSettings::HideDefaultValue) {
+            if let Some(pv) = a.default_val() {
+                debugln!("Help::spec_vals: Found default value...[{:?}]", pv);
+                spec_vals.push(format!(" [default: {}]",
+                                       if self.color {
+                                           self.cizer.good(pv.to_string_lossy())
+                                       } else {
+                                           Format::None(pv.to_string_lossy())
+                                       }));
+            }
         }
         if let Some(ref aliases) = a.aliases() {
             debugln!("Help::spec_vals: Found aliases...{:?}", aliases);
             spec_vals.push(format!(" [aliases: {}]",
                                    if self.color {
-                                       aliases.iter()
+                                       aliases
+                                           .iter()
                                            .map(|v| format!("{}", self.cizer.good(v)))
                                            .collect::<Vec<_>>()
                                            .join(", ")
                                    } else {
                                        aliases.join(", ")
                                    }));
         }
         if !self.hide_pv && !a.is_set(ArgSettings::HidePossibleValues) {
             if let Some(pv) = a.possible_vals() {
                 debugln!("Help::spec_vals: Found possible vals...{:?}", pv);
                 spec_vals.push(if self.color {
-                    format!(" [values: {}]",
-                            pv.iter()
-                                .map(|v| format!("{}", self.cizer.good(v)))
-                                .collect::<Vec<_>>()
-                                .join(", "))
-                } else {
-                    format!(" [values: {}]", pv.join(", "))
-                });
+                                   format!(" [values: {}]",
+                                           pv.iter()
+                                               .map(|v| format!("{}", self.cizer.good(v)))
+                                               .collect::<Vec<_>>()
+                                               .join(", "))
+                               } else {
+                                   format!(" [values: {}]", pv.join(", "))
+                               });
             }
         }
         spec_vals.join(" ")
     }
 }
 
 
 // Methods to write Parser help.
 impl<'a> Help<'a> {
     /// Writes help for all arguments (options, flags, args, subcommands)
     /// including titles of a Parser Object to the wrapped stream.
     #[cfg_attr(feature = "lints", allow(useless_let_if_seq))]
     pub fn write_all_args(&mut self, parser: &Parser) -> ClapResult<()> {
         debugln!("Help::write_all_args;");
         let flags = parser.has_flags();
-        let pos = parser.has_positionals();
+        let pos = parser
+            .positionals()
+            .filter(|arg| !arg.is_set(ArgSettings::Hidden))
+            .count() > 0;
         let opts = parser.has_opts();
         let subcmds = parser.has_subcommands();
 
         let unified_help = parser.is_set(AppSettings::UnifiedHelpMessage);
 
         let mut first = true;
 
         if unified_help && (flags || opts) {
-            let opts_flags = parser.flags()
+            let opts_flags = parser
+                .flags()
                 .map(as_arg_trait)
                 .chain(parser.opts().map(as_arg_trait));
             try!(color!(self, "OPTIONS:\n", warning));
             try!(self.write_args(opts_flags));
             first = false;
         } else {
             if flags {
                 try!(color!(self, "FLAGS:\n", warning));
-                try!(self.write_args(parser.flags()
-                    .map(as_arg_trait)));
+                try!(self.write_args(parser.flags().map(as_arg_trait)));
                 first = false;
             }
             if opts {
                 if !first {
                     try!(self.writer.write_all(b"\n\n"));
                 }
                 try!(color!(self, "OPTIONS:\n", warning));
                 try!(self.write_args(parser.opts().map(as_arg_trait)));
@@ -591,18 +617,23 @@ impl<'a> Help<'a> {
     }
 
     /// Writes help for subcommands of a Parser Object to the wrapped stream.
     fn write_subcommands(&mut self, parser: &Parser) -> io::Result<()> {
         debugln!("Help::write_subcommands;");
         // The shortest an arg can legally be is 2 (i.e. '-x')
         self.longest = 2;
         let mut ord_m = VecMap::new();
-        for sc in parser.subcommands.iter().filter(|s| !s.p.is_set(AppSettings::Hidden)) {
-            let btm = ord_m.entry(sc.p.meta.disp_ord).or_insert(BTreeMap::new());
+        for sc in parser
+                .subcommands
+                .iter()
+                .filter(|s| !s.p.is_set(AppSettings::Hidden)) {
+            let btm = ord_m
+                .entry(sc.p.meta.disp_ord)
+                .or_insert(BTreeMap::new());
             self.longest = cmp::max(self.longest, sc.p.meta.name.len());
             btm.insert(sc.p.meta.name.clone(), sc.clone());
         }
 
         let mut first = true;
         for btm in ord_m.values() {
             for sc in btm.values() {
                 if first {
@@ -676,17 +707,17 @@ impl<'a> Help<'a> {
         if let Some(about) = parser.meta.about {
             write_thing!(about)
         }
 
         try!(color!(self, "\nUSAGE:", warning));
         try!(write!(self.writer,
                     "\n{}{}\n\n",
                     TAB,
-                    parser.create_usage_no_title(&[])));
+                    usage::create_usage_no_title(parser, &[])));
 
         let flags = parser.has_flags();
         let pos = parser.has_positionals();
         let opts = parser.has_opts();
         let subcmds = parser.has_subcommands();
 
         if flags || opts || pos || subcmds {
             try!(self.write_all_args(&parser));
@@ -846,19 +877,19 @@ impl<'a> Help<'a> {
                 None => return Ok(()),
                 Some(Err(e)) => return Err(Error::from(e)),
                 Some(Ok(val)) if val > 0 => val,
                 _ => continue,
             };
 
             debugln!("Help::write_template_help:iter: tag_buf={};", unsafe {
                 String::from_utf8_unchecked(tag_buf.get_ref()[0..tag_length]
-                    .iter()
-                    .map(|&i| i)
-                    .collect::<Vec<_>>())
+                                                .iter()
+                                                .map(|&i| i)
+                                                .collect::<Vec<_>>())
             });
             match &tag_buf.get_ref()[0..tag_length] {
                 b"?" => {
                     try!(self.writer.write_all(b"Could not decode tag name"));
                 }
                 b"bin" => {
                     try!(self.write_bin_name(&parser));
                 }
@@ -873,38 +904,36 @@ impl<'a> Help<'a> {
                                 parser.meta.author.unwrap_or("unknown author")));
                 }
                 b"about" => {
                     try!(write!(self.writer,
                                 "{}",
                                 parser.meta.about.unwrap_or("unknown about")));
                 }
                 b"usage" => {
-                    try!(write!(self.writer, "{}", parser.create_usage_no_title(&[])));
+                    try!(write!(self.writer, "{}", usage::create_usage_no_title(parser, &[])));
                 }
                 b"all-args" => {
                     try!(self.write_all_args(&parser));
                 }
                 b"unified" => {
-                    let opts_flags = parser.flags()
+                    let opts_flags = parser
+                        .flags()
                         .map(as_arg_trait)
                         .chain(parser.opts().map(as_arg_trait));
                     try!(self.write_args(opts_flags));
                 }
                 b"flags" => {
-                    try!(self.write_args(parser.flags()
-                        .map(as_arg_trait)));
+                    try!(self.write_args(parser.flags().map(as_arg_trait)));
                 }
                 b"options" => {
-                    try!(self.write_args(parser.opts()
-                        .map(as_arg_trait)));
+                    try!(self.write_args(parser.opts().map(as_arg_trait)));
                 }
                 b"positionals" => {
-                    try!(self.write_args(parser.positionals()
-                        .map(as_arg_trait)));
+                    try!(self.write_args(parser.positionals().map(as_arg_trait)));
                 }
                 b"subcommands" => {
                     try!(self.write_subcommands(&parser));
                 }
                 b"after-help" => {
                     try!(write!(self.writer,
                                 "{}",
                                 parser.meta.more_help.unwrap_or("unknown after-help")));
@@ -933,17 +962,18 @@ fn wrap_help(help: &mut String, longest_
     if longest_w < avail_chars {
         sdebugln!("Yes");
         let mut prev_space = 0;
         let mut j = 0;
         for (idx, g) in (&*help.clone()).grapheme_indices(true) {
             debugln!("Help::wrap_help:iter: idx={}, g={}", idx, g);
             if g == "\n" {
                 debugln!("Help::wrap_help:iter: Newline found...");
-                debugln!("Help::wrap_help:iter: Still space...{:?}", str_width(&help[j..idx]) < avail_chars);
+                debugln!("Help::wrap_help:iter: Still space...{:?}",
+                         str_width(&help[j..idx]) < avail_chars);
                 if str_width(&help[j..idx]) < avail_chars {
                     j = idx;
                     continue;
                 }
             } else if g != " " {
                 if idx != help.len() - 1 || str_width(&help[j..idx]) < avail_chars {
                     continue;
                 }
@@ -952,17 +982,17 @@ fn wrap_help(help: &mut String, longest_
                 debugln!("Help::wrap_help:iter: Space found with room...");
                 prev_space = idx;
                 continue;
             }
             debugln!("Help::wrap_help:iter: Adding Newline...");
             j = prev_space;
             debugln!("Help::wrap_help:iter: prev_space={}, j={}", prev_space, j);
             debugln!("Help::wrap_help:iter: Removing...{}", j);
-            debugln!("Help::wrap_help:iter: Char at {}: {:?}", j, &help[j..j+1]);
+            debugln!("Help::wrap_help:iter: Char at {}: {:?}", j, &help[j..j + 1]);
             help.remove(j);
             help.insert(j, '\n');
             prev_space = idx;
         }
     } else {
         sdebugln!("No");
     }
 }
--- a/third_party/rust/clap/src/app/macros.rs
+++ b/third_party/rust/clap/src/app/macros.rs
@@ -14,21 +14,24 @@ macro_rules! remove_overriden {
     };
     (@arg $_self:ident, $arg:ident) => {
         remove_overriden!(@remove_requires $_self.required, $arg.requires);
         remove_overriden!(@remove $_self.blacklist, $arg.blacklist);
         remove_overriden!(@remove $_self.overrides, $arg.overrides);
     };
     ($_self:ident, $name:expr) => {
         debugln!("remove_overriden!;");
-        if let Some(ref o) = $_self.opts.iter().filter(|o| o.b.name == *$name).next() {
+        if let Some(o) = $_self.opts.iter() .find(|o| o.b.name == *$name) {
             remove_overriden!(@arg $_self, o);
-        } else if let Some(ref f) = $_self.flags.iter().filter(|f| f.b.name == *$name).next() {
+        } else if let Some(f) = $_self.flags.iter() .find(|f| f.b.name == *$name) {
             remove_overriden!(@arg $_self, f);
-        } else if let Some(p) = $_self.positionals.values().filter(|p| p.b.name == *$name).next() {
+        } else {
+            let p = $_self.positionals.values()
+                                      .find(|p| p.b.name == *$name)
+                                      .expect(INTERNAL_ERROR_MSG);
             remove_overriden!(@arg $_self, p);
         }
     };
 }
 
 macro_rules! arg_post_processing {
     ($me:ident, $arg:ident, $matcher:ident) => {
         debugln!("arg_post_processing!;");
@@ -51,59 +54,58 @@ macro_rules! arg_post_processing {
             $me.overrides.extend(or);
             vec_remove_all!($me.required, or.iter());
         } else { sdebugln!("No"); }
 
         // Handle conflicts
         debug!("arg_post_processing!: Does '{}' have conflicts...", $arg.to_string());
         if let Some(bl) = $arg.blacklist() {
             sdebugln!("Yes");
-            
+
             for c in bl {
                 // Inject two-way conflicts
                 debug!("arg_post_processing!: Has '{}' already been matched...", c);
                 if $matcher.contains(c) {
                     sdebugln!("Yes");
                     // find who blacklisted us...
                     $me.blacklist.push(&$arg.b.name);
                 } else {
                     sdebugln!("No");
                 }
             }
 
-            $me.blacklist.extend(bl);
+            $me.blacklist.extend_from_slice(bl);
             vec_remove_all!($me.overrides, bl.iter());
-            vec_remove_all!($me.required, bl.iter());
+            // vec_remove_all!($me.required, bl.iter());
         } else { sdebugln!("No"); }
 
         // Add all required args which aren't already found in matcher to the master
         // list
         debug!("arg_post_processing!: Does '{}' have requirements...", $arg.to_string());
         if let Some(reqs) = $arg.requires() {
-            for n in reqs.iter().filter(|&&(val, _)| val.is_none()).map(|&(_, name)| name) {
-                if $matcher.contains(&n) {
-                    sdebugln!("\tYes '{}' but it's already met", n);
-                    continue;
-                } else { sdebugln!("\tYes '{}'", n); }
-
+            for n in reqs.iter()
+                .filter(|&&(val, _)| val.is_none())
+                .filter(|&&(_, req)| !$matcher.contains(&req))
+                .map(|&(_, name)| name) {
+                    
                 $me.required.push(n);
             }
         } else { sdebugln!("No"); }
 
         _handle_group_reqs!($me, $arg);
     };
 }
 
 macro_rules! _handle_group_reqs{
     ($me:ident, $arg:ident) => ({
         use args::AnyArg;
         debugln!("_handle_group_reqs!;");
-        for grp in $me.groups.values() {
+        for grp in $me.groups.iter() {
             let found = if grp.args.contains(&$arg.name()) {
-                vec_remove!($me.required, &$arg.name());
+                // vec_remove!($me.required, &$arg.name());
                 if let Some(ref reqs) = grp.requires {
                     debugln!("_handle_group_reqs!: Adding {:?} to the required list", reqs);
                     $me.required.extend(reqs);
                 }
                 if let Some(ref bl) = grp.conflicts {
                     $me.blacklist.extend(bl);
                 }
                 true // What if arg is in more than one group with different reqs?
@@ -121,134 +123,40 @@ macro_rules! _handle_group_reqs{
                     $me.blacklist.extend(&grp.args);
                     vec_remove!($me.blacklist, &$arg.name());
                 }
             }
         }
     })
 }
 
-macro_rules! validate_multiples {
-    ($_self:ident, $a:ident, $m:ident) => {
-        debugln!("validate_multiples!;");
-        if $m.contains(&$a.b.name) && !$a.b.settings.is_set(ArgSettings::Multiple) {
-            // Not the first time, and we don't allow multiples
-            return Err(Error::unexpected_multiple_usage($a,
-                &*$_self.create_current_usage($m, None),
-                $_self.color()))
-        }
-    };
-}
-
 macro_rules! parse_positional {
     (
         $_self:ident,
         $p:ident,
         $arg_os:ident,
         $pos_counter:ident,
         $matcher:ident
     ) => {
         debugln!("parse_positional!;");
-        validate_multiples!($_self, $p, $matcher);
 
-        if !$_self.trailing_vals &&
-           ($_self.settings.is_set(AppSettings::TrailingVarArg) &&
+        if !$_self.is_set(AS::TrailingValues) &&
+           ($_self.is_set(AS::TrailingVarArg) &&
             $pos_counter == $_self.positionals.len()) {
-            $_self.trailing_vals = true;
+            $_self.settings.set(AS::TrailingValues);
         }
         let _ = try!($_self.add_val_to_arg($p, &$arg_os, $matcher));
 
         $matcher.inc_occurrence_of($p.b.name);
         let _ = $_self.groups_for_arg($p.b.name)
                       .and_then(|vec| Some($matcher.inc_occurrences_of(&*vec)));
-        arg_post_processing!($_self, $p, $matcher);
+        if $_self.cache.map_or(true, |name| name != $p.b.name) {
+            arg_post_processing!($_self, $p, $matcher);
+            $_self.cache = Some($p.b.name);
+        }
+
+        $_self.settings.set(AS::ValidArgFound);
         // Only increment the positional counter if it doesn't allow multiples
         if !$p.b.settings.is_set(ArgSettings::Multiple) {
             $pos_counter += 1;
         }
     };
 }
-
-macro_rules! find_from {
-    ($_self:ident, $arg_name:expr, $from:ident, $matcher:expr) => {{
-        let mut ret = None;
-        for k in $matcher.arg_names() {
-            if let Some(f) = find_by_name!($_self, &k, flags, iter) {
-                if let Some(ref v) = f.$from() {
-                    if v.contains($arg_name) {
-                        ret = Some(f.to_string());
-                    }
-                }
-            }
-            if let Some(o) = find_by_name!($_self, &k, opts, iter) {
-                if let Some(ref v) = o.$from() {
-                    if v.contains(&$arg_name) {
-                        ret = Some(o.to_string());
-                    }
-                }
-            }
-            if let Some(pos) = find_by_name!($_self, &k, positionals, values) {
-                if let Some(ref v) = pos.$from() {
-                    if v.contains($arg_name) {
-                        ret = Some(pos.b.name.to_owned());
-                    }
-                }
-            }
-        }
-        ret
-    }};
-}
-
-macro_rules! find_name_from {
-    ($_self:ident, $arg_name:expr, $from:ident, $matcher:expr) => {{
-        let mut ret = None;
-        for k in $matcher.arg_names() {
-            if let Some(f) = find_by_name!($_self, &k, flags, iter) {
-                if let Some(ref v) = f.$from() {
-                    if v.contains($arg_name) {
-                        ret = Some(f.b.name);
-                    }
-                }
-            }
-            if let Some(o) = find_by_name!($_self, &k, opts, iter) {
-                if let Some(ref v) = o.$from() {
-                    if v.contains(&$arg_name) {
-                        ret = Some(o.b.name);
-                    }
-                }
-            }
-            if let Some(pos) = find_by_name!($_self, &k, positionals, values) {
-                if let Some(ref v) = pos.$from() {
-                    if v.contains($arg_name) {
-                        ret = Some(pos.b.name);
-                    }
-                }
-            }
-        }
-        ret
-    }};
-}
-
-// Finds an arg by name
-macro_rules! find_by_name {
-    ($_self:ident, $name:expr, $what:ident, $how:ident) => {
-        $_self.$what.$how().find(|o| &o.b.name == $name)
-    }
-}
-
-// Finds an option including if it's aliasesed
-macro_rules! find_by_long {
-    ($_self:ident, $long:expr, $what:ident) => {
-        $_self.$what
-            .iter()
-            .filter(|o| o.s.long.is_some())
-            .find(|o| {
-                &&o.s.long.unwrap() == &$long ||
-                (o.s.aliases.is_some() &&
-                 o.s
-                    .aliases
-                    .as_ref()
-                    .unwrap()
-                    .iter()
-                    .any(|&(alias, _)| &&alias == &$long))
-            })
-    }
-}
--- a/third_party/rust/clap/src/app/meta.rs
+++ b/third_party/rust/clap/src/app/meta.rs
@@ -1,68 +1,27 @@
 #[doc(hidden)]
 #[allow(missing_debug_implementations)]
+#[derive(Default, Clone)]
 pub struct AppMeta<'b> {
     pub name: String,
     pub bin_name: Option<String>,
     pub author: Option<&'b str>,
     pub version: Option<&'b str>,
+    pub long_version: Option<&'b str>,
     pub about: Option<&'b str>,
+    pub long_about: Option<&'b str>,
     pub more_help: Option<&'b str>,
     pub pre_help: Option<&'b str>,
     pub aliases: Option<Vec<(&'b str, bool)>>, // (name, visible)
     pub usage_str: Option<&'b str>,
     pub usage: Option<String>,
     pub help_str: Option<&'b str>,
     pub disp_ord: usize,
     pub term_w: Option<usize>,
     pub max_w: Option<usize>,
     pub template: Option<&'b str>,
 }
 
-impl<'b> Default for AppMeta<'b> {
-    fn default() -> Self {
-        AppMeta {
-            name: String::new(),
-            author: None,
-            about: None,
-            more_help: None,
-            pre_help: None,
-            version: None,
-            usage_str: None,
-            usage: None,
-            bin_name: None,
-            help_str: None,
-            disp_ord: 999,
-            template: None,
-            aliases: None,
-            term_w: None,
-            max_w: None,
-        }
-    }
-}
-
 impl<'b> AppMeta<'b> {
     pub fn new() -> Self { Default::default() }
-    pub fn with_name(s: String) -> Self { AppMeta { name: s, ..Default::default() } }
-}
-
-impl<'b> Clone for AppMeta<'b> {
-    fn clone(&self) -> Self {
-        AppMeta {
-            name: self.name.clone(),
-            author: self.author,
-            about: self.about,
-            more_help: self.more_help,
-            pre_help: self.pre_help,
-            version: self.version,
-            usage_str: self.usage_str,
-            usage: self.usage.clone(),
-            bin_name: self.bin_name.clone(),
-            help_str: self.help_str,
-            disp_ord: self.disp_ord,
-            template: self.template,
-            aliases: self.aliases.clone(),
-            term_w: self.term_w,
-            max_w: self.max_w,
-        }
-    }
-}
+    pub fn with_name(s: String) -> Self { AppMeta { name: s, disp_ord: 999, ..Default::default() } }
+}
\ No newline at end of file
--- a/third_party/rust/clap/src/app/mod.rs
+++ b/third_party/rust/clap/src/app/mod.rs
@@ -1,17 +1,18 @@
 mod settings;
 #[macro_use]
 mod macros;
 pub mod parser;
 mod meta;
 mod help;
+mod validator;
+mod usage;
 
 // Std
-use std::borrow::Borrow;
 use std::env;
 use std::ffi::{OsStr, OsString};
 use std::fmt;
 use std::io::{self, BufRead, BufWriter, Write};
 use std::path::Path;
 use std::process;
 use std::rc::Rc;
 use std::result::Result as StdResult;
@@ -19,18 +20,17 @@ use std::result::Result as StdResult;
 // Third Party
 use vec_map::{self, VecMap};
 #[cfg(feature = "yaml")]
 use yaml_rust::Yaml;
 
 // Internal
 use app::help::Help;
 use app::parser::Parser;
-use args::{ArgKind, AnyArg, Arg, ArgGroup, ArgMatcher, ArgMatches, ArgSettings};
-use errors::Error;
+use args::{AnyArg, Arg, ArgGroup, ArgMatcher, ArgMatches, ArgSettings};
 use errors::Result as ClapResult;
 pub use self::settings::AppSettings;
 use completions::Shell;
 
 /// Used to create a representation of a command line program and all possible command line
 /// arguments. Application settings are set using the "builder pattern" with the
 /// [`App::get_matches`] family of methods being the terminal methods that starts the
 /// runtime-parsing process. These methods then return information about the user supplied
@@ -195,31 +195,91 @@ impl<'a, 'b> App<'a, 'b> {
     /// ```
     /// [`SubCommand`]: ./struct.SubCommand.html
     pub fn bin_name<S: Into<String>>(mut self, name: S) -> Self {
         self.p.meta.bin_name = Some(name.into());
         self
     }
 
     /// Sets a string describing what the program does. This will be displayed when displaying help
-    /// information.
+    /// information with `-h`.
+    ///
+    /// **NOTE:** If only `about` is provided, and not [`App::long_about`] but the user requests
+    /// `--help` clap will still display the contents of `about` appropriately
+    ///
+    /// **NOTE:** Only [`App::about`] is used in completion script generation in order to be
+    /// concise
     ///
     /// # Examples
     ///
     /// ```no_run
     /// # use clap::{App, Arg};
     /// App::new("myprog")
     ///     .about("Does really amazing things to great people")
     /// # ;
     /// ```
+    /// [`App::long_about`]: ./struct.App.html#method.long_about
     pub fn about<S: Into<&'b str>>(mut self, about: S) -> Self {
         self.p.meta.about = Some(about.into());
         self
     }
 
+    /// Sets a string describing what the program does. This will be displayed when displaying help
+    /// information.
+    ///
+    /// **NOTE:** If only `long_about` is provided, and not [`App::about`] but the user requests
+    /// `-h` clap will still display the contents of `long_about` appropriately
+    ///
+    /// **NOTE:** Only [`App::about`] is used in completion script generation in order to be
+    /// concise
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// # use clap::{App, Arg};
+    /// App::new("myprog")
+    ///     .long_about(
+    /// "Does really amazing things to great people. Now let's talk a little
+    ///  more in depth about how this subcommand really works. It may take about
+    ///  a few lines of text, but that's ok!")
+    /// # ;
+    /// ```
+    /// [`App::about`]: ./struct.App.html#method.about
+    pub fn long_about<S: Into<&'b str>>(mut self, about: S) -> Self {
+        self.p.meta.long_about = Some(about.into());
+        self
+    }
+
+    /// Sets the program's name. This will be displayed when displaying help information.
+    ///
+    /// **Pro-top:** This function is particularly useful when configuring a program via
+    /// [`App::from_yaml`] in conjunction with the [`crate_name!`] macro to derive the program's
+    /// name from its `Cargo.toml`.
+    ///
+    /// # Examples
+    /// ```ignore
+    /// # #[macro_use]
+    /// # extern crate clap;
+    /// # use clap::App;
+    /// # fn main() {
+    /// let yml = load_yaml!("app.yml");
+    /// let app = App::from_yaml(yml)
+    ///     .name(crate_name!());
+    ///
+    /// // continued logic goes here, such as `app.get_matches()` etc.
+    /// # }
+    /// ```
+    ///
+    /// [`App::from_yaml`]: ./struct.App.html#method.from_yaml
+    /// [`crate_name!`]: ./macro.crate_name.html
+    pub fn name<S: Into<String>>(mut self, name: S) -> Self {
+        self.p.meta.name = name.into();
+        self
+    }
+
     /// Adds additional help information to be displayed in addition to auto-generated help. This
     /// information is displayed **after** the auto-generated help information. This is often used
     /// to describe how to use the arguments, or caveats to be noted.
     ///
     /// # Examples
     ///
     /// ```no_run
     /// # use clap::App;
@@ -245,37 +305,72 @@ impl<'a, 'b> App<'a, 'b> {
     /// # ;
     /// ```
     pub fn before_help<S: Into<&'b str>>(mut self, help: S) -> Self {
         self.p.meta.pre_help = Some(help.into());
         self
     }
 
     /// Sets a string of the version number to be displayed when displaying version or help
-    /// information.
+    /// information with `-V`. 
+    ///
+    /// **NOTE:** If only `version` is provided, and not [`App::long_version`] but the user
+    /// requests `--version` clap will still display the contents of `version` appropriately
     ///
     /// **Pro-tip:** Use `clap`s convenience macro [`crate_version!`] to automatically set your
     /// application's version to the same thing as your crate at compile time. See the [`examples/`]
     /// directory for more information
     ///
     /// # Examples
     ///
     /// ```no_run
     /// # use clap::{App, Arg};
     /// App::new("myprog")
     ///     .version("v0.1.24")
     /// # ;
     /// ```
     /// [`crate_version!`]: ./macro.crate_version!.html
     /// [`examples/`]: https://github.com/kbknapp/clap-rs/tree/master/examples
+    /// [`App::long_version`]: ./struct.App.html#method.long_version
     pub fn version<S: Into<&'b str>>(mut self, ver: S) -> Self {
         self.p.meta.version = Some(ver.into());
         self
     }
 
+    /// Sets a string of the version number to be displayed when displaying version or help
+    /// information with `--version`.
+    ///
+    /// **NOTE:** If only `long_version` is provided, and not [`App::version`] but the user
+    /// requests `-V` clap will still display the contents of `long_version` appropriately
+    ///
+    /// **Pro-tip:** Use `clap`s convenience macro [`crate_version!`] to automatically set your
+    /// application's version to the same thing as your crate at compile time. See the [`examples/`]
+    /// directory for more information
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// # use clap::{App, Arg};
+    /// App::new("myprog")
+    ///     .long_version(
+    /// "v0.1.24
+    ///  commit: abcdef89726d
+    ///  revision: 123
+    ///  release: 2
+    ///  binary: myprog")
+    /// # ;
+    /// ```
+    /// [`crate_version!`]: ./macro.crate_version!.html
+    /// [`examples/`]: https://github.com/kbknapp/clap-rs/tree/master/examples
+    /// [`App::version`]: ./struct.App.html#method.version
+    pub fn long_version<S: Into<&'b str>>(mut self, ver: S) -> Self {
+        self.p.meta.long_version = Some(ver.into());
+        self
+    }
+
     /// Sets a custom usage string to override the auto-generated usage string.
     ///
     /// This will be displayed to the user when errors are found in argument parsing, or when you
     /// call [`ArgMatches::usage`]
     ///
     /// **CAUTION:** Using this setting disables `clap`s "context-aware" usage strings. After this
     /// setting is set, this will be the only usage string displayed to the user!
     ///
@@ -386,30 +481,70 @@ impl<'a, 'b> App<'a, 'b> {
     /// # ;
     /// ```
     /// [`short`]: ./struct.Arg.html#method.short
     pub fn version_short<S: AsRef<str>>(mut self, s: S) -> Self {
         self.p.version_short(s.as_ref());
         self
     }
 
+    /// Sets the help text for the auto-generated `help` argument.
+    ///
+    /// By default `clap` sets this to `"Prints help information"`, but if you're using a
+    /// different convention for your help messages and would prefer a different phrasing you can
+    /// override it.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// # use clap::{App, Arg};
+    /// App::new("myprog")
+    ///     .help_message("Print help information") // Perhaps you want imperative help messages
+    ///
+    /// # ;
+    /// ```
+    pub fn help_message<S: Into<&'a str>>(mut self, s: S) -> Self {
+        self.p.help_message = Some(s.into());
+        self
+    }
+
+    /// Sets the help text for the auto-generated `version` argument.
+    ///
+    /// By default `clap` sets this to `"Prints version information"`, but if you're using a
+    /// different convention for your help messages and would prefer a different phrasing then you
+    /// can change it.
+    ///
+    /// # Examples
+    /// ```no_run
+    /// # use clap::{App, Arg};
+    /// App::new("myprog")
+    ///     .version_message("Print version information") // Perhaps you want imperative help messages
+    /// # ;
+    /// ```
+    pub fn version_message<S: Into<&'a str>>(mut self, s: S) -> Self {
+        self.p.version_message = Some(s.into());
+        self
+    }
+
     /// Sets the help template to be used, overriding the default format.
     ///
     /// Tags arg given inside curly brackets.
     ///
     /// Valid tags are:
     ///
     ///   * `{bin}`         - Binary name.
     ///   * `{version}`     - Version number.
     ///   * `{author}`      - Author information.
     ///   * `{about}`       - General description (from [`App::about`])
     ///   * `{usage}`       - Automatically generated or given usage string.
     ///   * `{all-args}`    - Help for all arguments (options, flags, positionals arguments,
     ///                       and subcommands) including titles.
-    ///   * `{unified}`     - Unified help for options and flags.
+    ///   * `{unified}`     - Unified help for options and flags. Note, you must *also* set 
+    ///                       [`AppSettings::UnifiedHelpMessage`] to fully merge both options and 
+    ///                       flags, otherwise the ordering is "best effort"
     ///   * `{flags}`       - Help for flags.
     ///   * `{options}`     - Help for options.
     ///   * `{positionals}` - Help for positionals arguments.
     ///   * `{subcommands}` - Help for subcommands.
     ///   * `{after-help}`  - Help from [`App::after_help`]
     ///   * `{before-help}`  - Help from [`App::before_help`]
     ///
     /// # Examples
@@ -421,16 +556,17 @@ impl<'a, 'b> App<'a, 'b> {
     ///     .template("{bin} ({version}) - {usage}")
     /// # ;
     /// ```
     /// **NOTE:**The template system is, on purpose, very simple. Therefore the tags have to writen
     /// in the lowercase and without spacing.
     /// [`App::about`]: ./struct.App.html#method.about
     /// [`App::after_help`]: ./struct.App.html#method.after_help
     /// [`App::before_help`]: ./struct.App.html#method.before_help
+    /// [`AppSettings::UnifiedHelpMessage`]: ./enum.AppSettings.html#variant.UnifiedHelpMessage
     pub fn template<S: Into<&'b str>>(mut self, s: S) -> Self {
         self.p.meta.template = Some(s.into());
         self
     }
 
     /// Enables a single command, or [`SubCommand`], level settings.
     ///
     /// See [`AppSettings`] for a full list of possibilities and examples.
@@ -635,18 +771,18 @@ impl<'a, 'b> App<'a, 'b> {
     ///     // Adding a single "option" argument with a short, a long, and help text using the less
     ///     // verbose Arg::from_usage()
     ///     .arg(
     ///         Arg::from_usage("-c --config=[CONFIG] 'Optionally sets a config file to use'")
     ///     )
     /// # ;
     /// ```
     /// [argument]: ./struct.Arg.html
-    pub fn arg<A: Borrow<Arg<'a, 'b>> + 'a>(mut self, a: A) -> Self {
-        self.p.add_arg(a.borrow());
+    pub fn arg<A: Into<Arg<'a, 'b>>>(mut self, a: A) -> Self {
+        self.p.add_arg(a.into());
         self
     }
 
     /// Adds multiple [arguments] to the list of valid possibilties
     ///
     /// # Examples
     ///
     /// ```no_run
@@ -656,17 +792,17 @@ impl<'a, 'b> App<'a, 'b> {
     ///         &[Arg::from_usage("[debug] -d 'turns on debugging info'"),
     ///          Arg::with_name("input").index(1).help("the input file to use")]
     ///     )
     /// # ;
     /// ```
     /// [arguments]: ./struct.Arg.html
     pub fn args(mut self, args: &[Arg<'a, 'b>]) -> Self {
         for arg in args {
-            self.p.add_arg(arg);
+            self.p.add_arg_ref(arg);
         }
         self
     }
 
     /// A convenience method for adding a single [argument] from a usage type string. The string
     /// used follows the same rules and syntax as [`Arg::from_usage`]
     ///
     /// **NOTE:** The downside to using this method is that you can not set any additional
@@ -679,17 +815,17 @@ impl<'a, 'b> App<'a, 'b> {
     /// App::new("myprog")
     ///     .arg_from_usage("-c --config=<FILE> 'Sets a configuration file to use'")
     /// # ;
     /// ```
     /// [arguments]: ./struct.Arg.html
     /// [`Arg`]: ./struct.Arg.html
     /// [`Arg::from_usage`]: ./struct.Arg.html#method.from_usage
     pub fn arg_from_usage(mut self, usage: &'a str) -> Self {
-        self.p.add_arg(&Arg::from_usage(usage));
+        self.p.add_arg(Arg::from_usage(usage));
         self
     }
 
     /// Adds multiple [arguments] at once from a usage string, one per line. See
     /// [`Arg::from_usage`] for details on the syntax and rules supported.
     ///
     /// **NOTE:** Like [`App::arg_from_usage`] the downside is you only set properties for the
     /// [`Arg`]s which [`Arg::from_usage`] supports.
@@ -711,17 +847,17 @@ impl<'a, 'b> App<'a, 'b> {
     /// [`App::arg_from_usage`]: ./struct.App.html#method.arg_from_usage
     /// [`Arg`]: ./struct.Arg.html
     pub fn args_from_usage(mut self, usage: &'a str) -> Self {
         for line in usage.lines() {
             let l = line.trim();
             if l.is_empty() {
                 continue;
             }
-            self.p.add_arg(&Arg::from_usage(l));
+            self.p.add_arg(Arg::from_usage(l));
         }
         self
     }
 
     /// Allows adding a [`SubCommand`] alias, which function as "hidden" subcommands that
     /// automatically dispatch as if this subcommand was used. This is more efficient, and easier
     /// than creating multiple hidden subcommands as one only needs to check for the existence of
     /// this command, and not all variants.
@@ -992,81 +1128,179 @@ impl<'a, 'b> App<'a, 'b> {
     ///     alpha   Some help and text
     /// ```
     /// [`SubCommand`]: ./struct.SubCommand.html
     pub fn display_order(mut self, ord: usize) -> Self {
         self.p.meta.disp_ord = ord;
         self
     }
 
-    /// Prints the full help message to [`io::stdout()`] using a [`BufWriter`]
+    /// Prints the full help message to [`io::stdout()`] using a [`BufWriter`] using the same
+    /// method as if someone ran `-h` to request the help message
+    ///
+    /// **NOTE:** clap has the ability to distinguish between "short" and "long" help messages
+    /// depending on if the user ran [`-h` (short)] or [`--help` (long)]
     ///
     /// # Examples
     ///
     /// ```rust
     /// # use clap::App;
     /// let mut app = App::new("myprog");
     /// app.print_help();
     /// ```
     /// [`io::stdout()`]: https://doc.rust-lang.org/std/io/fn.stdout.html
     /// [`BufWriter`]: https://doc.rust-lang.org/std/io/struct.BufWriter.html
+    /// [`-h` (short)]: ./struct.Arg.html#method.help
+    /// [`--help` (long)]: ./struct.Arg.html#method.long_help
     pub fn print_help(&mut self) -> ClapResult<()> {
         // If there are global arguments, or settings we need to propgate them down to subcommands
         // before parsing incase we run into a subcommand
         self.p.propogate_globals();
         self.p.propogate_settings();
         self.p.derive_display_order();
 
         self.p.create_help_and_version();
         let out = io::stdout();
         let mut buf_w = BufWriter::new(out.lock());
         self.write_help(&mut buf_w)
     }
 
-    /// Writes the full help message to the user to a [`io::Write`] object
+    /// Prints the full help message to [`io::stdout()`] using a [`BufWriter`] using the same
+    /// method as if someone ran `-h` to request the help message
+    ///
+    /// **NOTE:** clap has the ability to distinguish between "short" and "long" help messages
+    /// depending on if the user ran [`-h` (short)] or [`--help` (long)]
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// # use clap::App;
+    /// let mut app = App::new("myprog");
+    /// app.print_long_help();
+    /// ```
+    /// [`io::stdout()`]: https://doc.rust-lang.org/std/io/fn.stdout.html
+    /// [`BufWriter`]: https://doc.rust-lang.org/std/io/struct.BufWriter.html
+    /// [`-h` (short)]: ./struct.Arg.html#method.help
+    /// [`--help` (long)]: ./struct.Arg.html#method.long_help
+    pub fn print_long_help(&mut self) -> ClapResult<()> {
+        // If there are global arguments, or settings we need to propgate them down to subcommands
+        // before parsing incase we run into a subcommand
+        self.p.propogate_globals();
+        self.p.propogate_settings();
+        self.p.derive_display_order();
+
+        self.p.create_help_and_version();
+        let out = io::stdout();
+        let mut buf_w = BufWriter::new(out.lock());
+        self.write_long_help(&mut buf_w)
+    }
+
+    /// Writes the full help message to the user to a [`io::Write`] object in the same method as if
+    /// the user ran `-h`
+    ///
+    /// **NOTE:** clap has the ability to distinguish between "short" and "long" help messages
+    /// depending on if the user ran [`-h` (short)] or [`--help` (long)]
+    ///
+    /// **NOTE:** There is a known bug where this method does not write propogated global arguments
+    /// or autogenerated arguments (i.e. the default help/version args). Prefer
+    /// [`App::write_long_help`] instead if possibe!
     ///
     /// # Examples
     ///
     /// ```rust
     /// # use clap::App;
     /// use std::io;
     /// let mut app = App::new("myprog");
     /// let mut out = io::stdout();
     /// app.write_help(&mut out).expect("failed to write to stdout");
     /// ```
     /// [`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
+    /// [`-h` (short)]: ./struct.Arg.html#method.help
+    /// [`--help` (long)]: ./struct.Arg.html#method.long_help
     pub fn write_help<W: Write>(&self, w: &mut W) -> ClapResult<()> {
         // PENDING ISSUE: 808
         //      https://github.com/kbknapp/clap-rs/issues/808
         // If there are global arguments, or settings we need to propgate them down to subcommands
         // before parsing incase we run into a subcommand
         // self.p.propogate_globals();
         // self.p.propogate_settings();
         // self.p.derive_display_order();
         // self.p.create_help_and_version();
 
-        Help::write_app_help(w, self)
+        Help::write_app_help(w, self, false)
     }
 
-    /// Writes the version message to the user to a [`io::Write`] object
+    /// Writes the full help message to the user to a [`io::Write`] object in the same method as if
+    /// the user ran `--help`
+    ///
+    /// **NOTE:** clap has the ability to distinguish between "short" and "long" help messages
+    /// depending on if the user ran [`-h` (short)] or [`--help` (long)]
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// # use clap::App;
+    /// use std::io;
+    /// let mut app = App::new("myprog");
+    /// let mut out = io::stdout();
+    /// app.write_long_help(&mut out).expect("failed to write to stdout");
+    /// ```
+    /// [`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
+    /// [`-h` (short)]: ./struct.Arg.html#method.help
+    /// [`--help` (long)]: ./struct.Arg.html#method.long_help
+    pub fn write_long_help<W: Write>(&mut self, w: &mut W) -> ClapResult<()> {
+        self.p.propogate_globals();
+        self.p.propogate_settings();
+        self.p.derive_display_order();
+        self.p.create_help_and_version();
+
+        Help::write_app_help(w, self, true)
+    }
+
+    /// Writes the version message to the user to a [`io::Write`] object as if the user ran `-V`.
+    ///
+    /// **NOTE:** clap has the ability to distinguish between "short" and "long" version messages
+    /// depending on if the user ran [`-V` (short)] or [`--version` (long)]
     ///
     /// # Examples
     ///
     /// ```rust
     /// # use clap::App;
     /// use std::io;
     /// let mut app = App::new("myprog");
     /// let mut out = io::stdout();
     /// app.write_version(&mut out).expect("failed to write to stdout");
     /// ```
     /// [`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
+    /// [`-V` (short)]: ./struct.App.html#method.version
+    /// [`--version` (long)]: ./struct.App.html#method.long_version
     pub fn write_version<W: Write>(&self, w: &mut W) -> ClapResult<()> {
-        self.p.write_version(w).map_err(From::from)
+        self.p.write_version(w, false).map_err(From::from)
     }
 
+    /// Writes the version message to the user to a [`io::Write`] object
+    ///
+    /// **NOTE:** clap has the ability to distinguish between "short" and "long" version messages
+    /// depending on if the user ran [`-V` (short)] or [`--version` (long)]
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// # use clap::App;
+    /// use std::io;
+    /// let mut app = App::new("myprog");
+    /// let mut out = io::stdout();
+    /// app.write_long_version(&mut out).expect("failed to write to stdout");
+    /// ```
+    /// [`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
+    /// [`-V` (short)]: ./struct.App.html#method.version
+    /// [`--version` (long)]: ./struct.App.html#method.long_version
+    pub fn write_long_version<W: Write>(&self, w: &mut W) -> ClapResult<()> {
+        self.p.write_version(w, true).map_err(From::from)
+    }
 
     /// Generate a completions file for a specified shell at compile time.
     ///
     /// **NOTE:** to generate the this file at compile time you must use a `build.rs` "Build Script"
     ///
     /// # Examples
     ///
     /// The following example generates a bash completion script via a `build.rs` script. In this
@@ -1113,17 +1347,17 @@ impl<'a, 'b> App<'a, 'b> {
     ///
     /// Next, we set up our `Cargo.toml` to use a `build.rs` build script.
     ///
     /// ```toml
     /// # Cargo.toml
     /// build = "build.rs"
     ///
     /// [build-dependencies]
-    /// clap = "2.9"
+    /// clap = "2.23"
     /// ```
     ///
     /// Next, we place a `build.rs` in our project root.
     ///
     /// ```ignore
     /// extern crate clap;
     ///
     /// use clap::Shell;
@@ -1263,17 +1497,31 @@ impl<'a, 'b> App<'a, 'b> {
     /// [`Vec`]: https://doc.rust-lang.org/std/vec/struct.Vec.html
     /// [`AppSettings::NoBinaryName`]: ./enum.AppSettings.html#variant.NoBinaryName
     pub fn get_matches_from<I, T>(mut self, itr: I) -> ArgMatches<'a>
         where I: IntoIterator<Item = T>,
               T: Into<OsString> + Clone
     {
         self.get_matches_from_safe_borrow(itr).unwrap_or_else(|e| {
             // Otherwise, write to stderr and exit
-            self.maybe_wait_for_exit(e);
+            if e.use_stderr() {
+                wlnerr!("{}", e.message);
+                if self.p.is_set(AppSettings::WaitOnError) {
+                    wlnerr!("\nPress [ENTER] / [RETURN] to continue...");
+                    let mut s = String::new();
+                    let i = io::stdin();
+                    i.lock().read_line(&mut s).unwrap();
+                }
+                drop(self);
+                drop(e);
+                process::exit(1);
+            }
+
+            drop(self);
+            e.exit()
         })
     }
 
     /// Starts the parsing process. A combination of [`App::get_matches_from`], and
     /// [`App::get_matches_safe`]
     ///
     /// **NOTE:** This method WILL NOT exit when `--help` or `--version` (or short versions) are
     /// used. It will return a [`clap::Error`], where the [`kind`] is a [`ErrorKind::HelpDisplayed`]
@@ -1368,39 +1616,22 @@ impl<'a, 'b> App<'a, 'b> {
 
         // do the real parsing
         if let Err(e) = self.p.get_matches_with(&mut matcher, &mut it.peekable()) {
             return Err(e);
         }
 
         if self.p.is_set(AppSettings::PropagateGlobalValuesDown) {
             for a in &self.p.global_args {
-                matcher.propagate(a.name);
+                matcher.propagate(a.b.name);
             }
         }
 
         Ok(matcher.into())
     }
-
-    // Re-implements ClapError::exit except it checks if we should wait for input before exiting
-    // since ClapError doesn't have that info and the error message must be printed before exiting
-    fn maybe_wait_for_exit(&self, e: Error) -> ! {
-        if e.use_stderr() {
-            wlnerr!("{}", e.message);
-            if self.p.is_set(AppSettings::WaitOnError) {
-                wlnerr!("\nPress [ENTER] / [RETURN] to continue...");
-                let mut s = String::new();
-                let i = io::stdin();
-                i.lock().read_line(&mut s).unwrap();
-            }
-            process::exit(1);
-        }
-
-        e.exit()
-    }
 }
 
 #[cfg(feature = "yaml")]
 impl<'a> From<&'a Yaml> for App<'a, 'a> {
     fn from(mut yaml: &'a Yaml) -> Self {
         use args::SubCommand;
         // We WANT this to panic on error...so expect() is good.
         let mut is_sc = None;
@@ -1420,25 +1651,28 @@ impl<'a> From<&'a Yaml> for App<'a, 'a> 
                     $a = $a.$i(v);
                 } else if $y[stringify!($i)] != Yaml::BadValue {
                     panic!("Failed to convert YAML value {:?} to a string", $y[stringify!($i)]);
                 }
             };
         }
 
         yaml_str!(a, yaml, version);
+        yaml_str!(a, yaml, author);
         yaml_str!(a, yaml, bin_name);
         yaml_str!(a, yaml, about);
         yaml_str!(a, yaml, before_help);
         yaml_str!(a, yaml, after_help);
         yaml_str!(a, yaml, template);
         yaml_str!(a, yaml, usage);
         yaml_str!(a, yaml, help);
         yaml_str!(a, yaml, help_short);
         yaml_str!(a, yaml, version_short);
+        yaml_str!(a, yaml, help_message);
+        yaml_str!(a, yaml, version_message);
         yaml_str!(a, yaml, alias);
         yaml_str!(a, yaml, visible_alias);
 
         if let Some(v) = yaml["display_order"].as_i64() {
             a = a.display_order(v as usize);
         } else if yaml["display_order"] != Yaml::BadValue {
             panic!("Failed to convert YAML value {:?} to a u64",
                    yaml["display_order"]);
@@ -1530,42 +1764,43 @@ impl<'a> From<&'a Yaml> for App<'a, 'a> 
 impl<'a, 'b> Clone for App<'a, 'b> {
     fn clone(&self) -> Self { App { p: self.p.clone() } }
 }
 
 impl<'n, 'e> AnyArg<'n, 'e> for App<'n, 'e> {
     fn name(&self) -> &'n str {
         unreachable!("App struct does not support AnyArg::name, this is a bug!")
     }
-    fn id(&self) -> usize { self.p.id }
-    fn kind(&self) -> ArgKind { ArgKind::Subcmd }
     fn overrides(&self) -> Option<&[&'e str]> { None }
     fn requires(&self) -> Option<&[(Option<&'e str>, &'n str)]> { None }
     fn blacklist(&self) -> Option<&[&'e str]> { None }
     fn required_unless(&self) -> Option<&[&'e str]> { None }
     fn val_names(&self) -> Option<&VecMap<&'e str>> { None }
     fn is_set(&self, _: ArgSettings) -> bool { false }
-    fn val_terminator(&self) -> Option<&'e str> {None}
+    fn val_terminator(&self) -> Option<&'e str> { None }
     fn set(&mut self, _: ArgSettings) {
         unreachable!("App struct does not support AnyArg::set, this is a bug!")
     }
     fn has_switch(&self) -> bool { false }
     fn max_vals(&self) -> Option<u64> { None }
     fn num_vals(&self) -> Option<u64> { None }
     fn possible_vals(&self) -> Option<&[&'e str]> { None }
     fn validator(&self) -> Option<&Rc<Fn(String) -> StdResult<(), String>>> { None }
     fn validator_os(&self) -> Option<&Rc<Fn(&OsStr) -> StdResult<(), OsString>>> { None }
     fn min_vals(&self) -> Option<u64> { None }
     fn short(&self) -> Option<char> { None }
     fn long(&self) -> Option<&'e str> { None }
     fn val_delim(&self) -> Option<char> { None }
     fn takes_value(&self) -> bool { true }
     fn help(&self) -> Option<&'e str> { self.p.meta.about }
-    fn default_val(&self) -> Option<&'n str> { None }
-    fn default_vals_ifs(&self) -> Option<vec_map::Values<(&'n str, Option<&'e str>, &'e str)>> {None}
+    fn long_help(&self) -> Option<&'e str> { self.p.meta.long_about }
+    fn default_val(&self) -> Option<&'e OsStr> { None }
+    fn default_vals_ifs(&self) -> Option<vec_map::Values<(&'n str, Option<&'e OsStr>, &'e OsStr)>> {
+        None
+    }
     fn longest_filter(&self) -> bool { true }
     fn aliases(&self) -> Option<Vec<&'e str>> {
         if let Some(ref aliases) = self.p.meta.aliases {
             let vis_aliases: Vec<_> =
                 aliases.iter().filter_map(|&(n, v)| if v { Some(n) } else { None }).collect();
             if vis_aliases.is_empty() {
                 None
             } else {
--- a/third_party/rust/clap/src/app/parser.rs
+++ b/third_party/rust/clap/src/app/parser.rs
@@ -1,10 +1,9 @@
 // Std
-use std::collections::{BTreeMap, HashMap, VecDeque};
 use std::ffi::{OsStr, OsString};
 use std::fmt::Display;
 use std::fs::File;
 use std::io::{self, BufWriter, Write};
 #[cfg(feature = "debug")]
 use std::os::unix::ffi::OsStrExt;
 use std::path::PathBuf;
 use std::slice::Iter;
@@ -15,118 +14,101 @@ use vec_map::{self, VecMap};
 
 // Internal
 use INTERNAL_ERROR_MSG;
 use INVALID_UTF8;
 use SubCommand;
 use app::App;
 use app::help::Help;
 use app::meta::AppMeta;
-use app::settings::{AppFlags, AppSettings};
+use app::settings::AppFlags;
 use args::{AnyArg, ArgMatcher, Base, Switched, Arg, ArgGroup, FlagBuilder, OptBuilder, PosBuilder};
-use args::MatchedArg;
 use args::settings::ArgSettings;
 use completions::ComplGen;
 use errors::{Error, ErrorKind};
 use errors::Result as ClapResult;
-use fmt::{Colorizer, ColorWhen};
+use fmt::ColorWhen;
 use osstringext::OsStrExt2;
 use completions::Shell;
 use suggestions;
+use app::settings::AppSettings as AS;
+use app::validator::Validator;
+use app::usage;
+
+#[derive(Debug, PartialEq, Copy, Clone)]
+#[doc(hidden)]
+pub enum ParseResult<'a> {
+    Flag,
+    Opt(&'a str),
+    Pos(&'a str),
+    MaybeHyphenValue,
+    MaybeNegNum,
+    NotFound,
+    ValuesDone,
+}
 
 #[allow(missing_debug_implementations)]
 #[doc(hidden)]
+#[derive(Clone, Default)]
 pub struct Parser<'a, 'b>
     where 'a: 'b
 {
-    propogated: bool,
-    required: Vec<&'a str>,
-    r_ifs: Vec<(&'a str, &'b str, &'a str)>,
-    pub short_list: Vec<char>,
-    pub long_list: Vec<&'b str>,
-    blacklist: Vec<&'b str>,
-    // A list of possible flags
-    pub flags: Vec<FlagBuilder<'a, 'b>>,
-    // A list of possible options
-    pub opts: Vec<OptBuilder<'a, 'b>>,
-    // A list of positional arguments
-    pub positionals: VecMap<PosBuilder<'a, 'b>>,
-    // A list of subcommands
-    #[doc(hidden)]
-    pub subcommands: Vec<App<'a, 'b>>,
-    groups: HashMap<&'a str, ArgGroup<'a>>,
-    pub global_args: Vec<Arg<'a, 'b>>,
-    overrides: Vec<&'b str>,
-    help_short: Option<char>,
-    version_short: Option<char>,
+    pub meta: AppMeta<'b>,
     settings: AppFlags,
     pub g_settings: AppFlags,
-    pub meta: AppMeta<'b>,
-    pub id: usize,
-    trailing_vals: bool,
-    valid_neg_num: bool,
-    // have we found a valid arg yet
-    valid_arg: bool,
-}
-
-impl<'a, 'b> Default for Parser<'a, 'b> {
-    fn default() -> Self {
-        Parser {
-            propogated: false,
-            flags: vec![],
-            opts: vec![],
-            positionals: VecMap::new(),
-            subcommands: vec![],
-            help_short: None,
-            version_short: None,
-            required: vec![],
-            r_ifs: vec![],
-            short_list: vec![],
-            long_list: vec![],
-            blacklist: vec![],
-            groups: HashMap::new(),
-            global_args: vec![],
-            overrides: vec![],
-            g_settings: AppFlags::new(),
-            settings: AppFlags::new(),
-            meta: AppMeta::new(),
-            trailing_vals: false,
-            id: 0,
-            valid_neg_num: false,
-            valid_arg: false,
-        }
-    }
+    pub flags: Vec<FlagBuilder<'a, 'b>>,
+    pub opts: Vec<OptBuilder<'a, 'b>>,
+    pub positionals: VecMap<PosBuilder<'a, 'b>>,
+    pub subcommands: Vec<App<'a, 'b>>,
+    pub groups: Vec<ArgGroup<'a>>,
+    pub global_args: Vec<Arg<'a, 'b>>,
+    pub required: Vec<&'a str>,
+    pub r_ifs: Vec<(&'a str, &'b str, &'a str)>,
+    pub blacklist: Vec<&'b str>,
+    pub overrides: Vec<&'b str>,
+    help_short: Option<char>,
+    version_short: Option<char>,
+    cache: Option<&'a str>,
+    pub help_message: Option<&'a str>,
+    pub version_message: Option<&'a str>,
 }
 
 impl<'a, 'b> Parser<'a, 'b>
     where 'a: 'b
 {
     pub fn with_name(n: String) -> Self {
-        Parser { meta: AppMeta::with_name(n), ..Default::default() }
+        Parser {
+            meta: AppMeta::with_name(n),
+            ..Default::default()
+        }
     }
 
     pub fn help_short(&mut self, s: &str) {
-        self.help_short = s.trim_left_matches(|c| c == '-')
+        let c = s.trim_left_matches(|c| c == '-')
             .chars()
-            .nth(0);
+            .nth(0)
+            .unwrap_or('h');
+        self.help_short = Some(c);
     }
 
     pub fn version_short(&mut self, s: &str) {
-        self.version_short = s.trim_left_matches(|c| c == '-')
+        let c = s.trim_left_matches(|c| c == '-')
             .chars()
-            .nth(0);
+            .nth(0)
+            .unwrap_or('V');
+        self.version_short = Some(c);
     }
 
     pub fn gen_completions_to<W: Write>(&mut self, for_shell: Shell, buf: &mut W) {
-        if !self.propogated {
+        if !self.is_set(AS::Propogated) {
             self.propogate_help_version();
             self.build_bin_names();
             self.propogate_globals();
             self.propogate_settings();
-            self.propogated = true;
+            self.set(AS::Propogated);
         }
 
         ComplGen::new(self).generate(for_shell, buf)
     }
 
     pub fn gen_completions(&mut self, for_shell: Shell, od: OsString) {
         use std::error::Error;
 
@@ -141,530 +123,561 @@ impl<'a, 'b> Parser<'a, 'b>
 
         let mut file = match File::create(out_dir.join(file_name)) {
             Err(why) => panic!("couldn't create completion file: {}", why.description()),
             Ok(file) => file,
         };
         self.gen_completions_to(for_shell, &mut file)
     }
 
-    // actually adds the arguments
-    pub fn add_arg(&mut self, a: &Arg<'a, 'b>) {
-        debug_assert!(!(self.flags.iter().any(|f| &f.b.name == &a.name) ||
-                        self.opts.iter().any(|o| o.b.name == a.name) ||
-                        self.positionals.values().any(|p| p.b.name == a.name)),
-                      format!("Non-unique argument name: {} is already in use", a.name));
+    #[inline]
+    fn app_debug_asserts(&mut self) -> bool {
+        assert!(self.verify_positionals());
+        let should_err = self.groups
+            .iter()
+            .all(|g| {
+                g.args
+                    .iter()
+                    .all(|arg| {
+                             (self.flags.iter().any(|f| &f.b.name == arg) ||
+                              self.opts.iter().any(|o| &o.b.name == arg) ||
+                              self.positionals.values().any(|p| &p.b.name == arg) ||
+                              self.groups.iter().any(|g| &g.name == arg))
+                         })
+            });
+        let g = self.groups
+            .iter()
+            .find(|g| {
+                g.args
+                    .iter()
+                    .any(|arg| {
+                             !(self.flags.iter().any(|f| &f.b.name == arg) ||
+                               self.opts.iter().any(|o| &o.b.name == arg) ||
+                               self.positionals.values().any(|p| &p.b.name == arg) ||
+                               self.groups.iter().any(|g| &g.name == arg))
+                         })
+            });
+        assert!(should_err,
+                "The group '{}' contains the arg '{}' that doesn't actually exist.",
+                g.unwrap().name,
+                g.unwrap()
+                    .args
+                    .iter()
+                    .find(|arg| {
+                              !(self.flags.iter().any(|f| &&f.b.name == arg) ||
+                                self.opts.iter().any(|o| &&o.b.name == arg) ||
+                                self.positionals.values().any(|p| &&p.b.name == arg) ||
+                                self.groups.iter().any(|g| &&g.name == arg))
+                          })
+                    .unwrap());
+        true
+    }
+
+    #[inline]
+    fn debug_asserts(&self, a: &Arg) -> bool {
+        assert!(!arg_names!(self).any(|name| name == a.b.name),
+                format!("Non-unique argument name: {} is already in use", a.b.name));
+        if let Some(l) = a.s.long {
+            assert!(!self.contains_long(l),
+                    "Argument long must be unique\n\n\t--{} is already in use",
+                    l);
+        }
+        if let Some(s) = a.s.short {
+            assert!(!self.contains_short(s),
+                    "Argument short must be unique\n\n\t-{} is already in use",
+                    s);
+        }
+        let i = if a.index.is_none() {
+            (self.positionals.len() + 1)
+        } else {
+            a.index.unwrap() as usize
+        };
+        assert!(!self.positionals.contains_key(i),
+                "Argument \"{}\" has the same index as another positional \
+                    argument\n\n\tPerhaps try .multiple(true) to allow one positional argument \
+                    to take multiple values",
+                a.b.name);
+        assert!(!(a.is_set(ArgSettings::Required) && a.is_set(ArgSettings::Global)),
+                "Global arguments cannot be required.\n\n\t'{}' is marked as \
+                          global and required",
+                a.b.name);
+        if a.b.is_set(ArgSettings::Last) {
+            assert!(!self.positionals
+                         .values()
+                         .any(|p| p.b.is_set(ArgSettings::Last)),
+                    "Only one positional argument may have last(true) set. Found two.");
+            assert!(a.s.long.is_none(),
+                    "Flags or Options may not have last(true) set. {} has both a long and last(true) set.",
+                    a.b.name);
+            assert!(a.s.short.is_none(),
+                    "Flags or Options may not have last(true) set. {} has both a short and last(true) set.",
+                    a.b.name);
+        }
+        true
+    }
+
+    #[inline]
+    fn add_conditional_reqs(&mut self, a: &Arg<'a, 'b>) {
         if let Some(ref r_ifs) = a.r_ifs {
             for &(arg, val) in r_ifs {
-                self.r_ifs.push((arg, val, a.name));
-            }
-        }
-        if let Some(ref grps) = a.groups {
-            for g in grps {
-                let ag = self.groups.entry(g).or_insert_with(|| ArgGroup::with_name(g));
-                ag.args.push(a.name);
+                self.r_ifs.push((arg, val, a.b.name));
             }
         }
-        if let Some(s) = a.short {
-            debug_assert!(!self.short_list.contains(&s),
-                          format!("Argument short must be unique\n\n\t-{} is already in use",
-                                  s));
-            self.short_list.push(s);
-        }
-        if let Some(l) = a.long {
-            debug_assert!(!self.long_list.contains(&l),
-                          format!("Argument long must be unique\n\n\t--{} is already in use",
-                                  l));
-            self.long_list.push(l);
-            if l == "help" {
-                self.unset(AppSettings::NeedsLongHelp);
-            } else if l == "version" {
-                self.unset(AppSettings::NeedsLongVersion);
+    }
+
+    #[inline]
+    fn add_arg_groups(&mut self, a: &Arg<'a, 'b>) {
+        if let Some(ref grps) = a.b.groups {
+            for g in grps {
+                let mut found = false;
+                if let Some(ref mut ag) = self.groups.iter_mut().find(|grp| &grp.name == g) {
+                    ag.args.push(a.b.name);
+                    found = true;
+                }
+                if !found {
+                    let mut ag = ArgGroup::with_name(g);
+                    ag.args.push(a.b.name);
+                    self.groups.push(ag);
+                }
             }
         }
+    }
+
+    #[inline]
+    fn add_reqs(&mut self, a: &Arg<'a, 'b>) {
         if a.is_set(ArgSettings::Required) {
-            self.required.push(a.name);
+            // If the arg is required, add all it's requirements to master required list
+            if let Some(ref areqs) = a.b.requires {
+                for name in areqs
+                        .iter()
+                        .filter(|&&(val, _)| val.is_none())
+                        .map(|&(_, name)| name) {
+                    self.required.push(name);
+                }
+            }
+            self.required.push(a.b.name);
+        }
+    }
+
+    #[inline]
+    fn implied_settings(&mut self, a: &Arg<'a, 'b>) {
+        if a.is_set(ArgSettings::Last) {
+            // if an arg has `Last` set, we need to imply DontCollapseArgsInUsage so that args
+            // in the usage string don't get confused or left out.
+            self.set(AS::DontCollapseArgsInUsage);
+            self.set(AS::ContainsLast);
         }
-        if a.index.is_some() || (a.short.is_none() && a.long.is_none()) {
+        if let Some(l) = a.s.long {
+            if l == "version" {
+                self.unset(AS::NeedsLongVersion);
+            } else if l == "help" {
+                self.unset(AS::NeedsLongHelp);
+            }
+        }
+    }
+
+    // actually adds the arguments
+    pub fn add_arg(&mut self, a: Arg<'a, 'b>) {
+        // if it's global we have to clone anyways
+        if a.is_set(ArgSettings::Global) {
+            return self.add_arg_ref(&a);
+        }
+        debug_assert!(self.debug_asserts(&a));
+        self.add_conditional_reqs(&a);
+        self.add_arg_groups(&a);
+        self.add_reqs(&a);
+        self.implied_settings(&a);
+        if a.index.is_some() || (a.s.short.is_none() && a.s.long.is_none()) {
             let i = if a.index.is_none() {
                 (self.positionals.len() + 1)
             } else {
                 a.index.unwrap() as usize
             };
-            debug_assert!(!self.positionals.contains_key(i),
-                          format!("Argument \"{}\" has the same index as another positional \
-                    argument\n\n\tPerhaps try .multiple(true) to allow one positional argument \
-                    to take multiple values",
-                                  a.name));
-            let pb = PosBuilder::from_arg(a, i as u64, &mut self.required);
+            self.positionals
+                .insert(i, PosBuilder::from_arg(a, i as u64));
+        } else if a.is_set(ArgSettings::TakesValue) {
+            let mut ob = OptBuilder::from(a);
+            ob.s.unified_ord = self.flags.len() + self.opts.len();
+            self.opts.push(ob);
+        } else {
+            let mut fb = FlagBuilder::from(a);
+            fb.s.unified_ord = self.flags.len() + self.opts.len();
+            self.flags.push(fb);
+        }
+    }
+    // actually adds the arguments but from a borrow (which means we have to do some clonine)
+    pub fn add_arg_ref(&mut self, a: &Arg<'a, 'b>) {
+        debug_assert!(self.debug_asserts(&a));
+        self.add_conditional_reqs(a);
+        self.add_arg_groups(a);
+        self.add_reqs(a);
+        self.implied_settings(&a);
+        if a.index.is_some() || (a.s.short.is_none() && a.s.long.is_none()) {
+            let i = if a.index.is_none() {
+                (self.positionals.len() + 1)
+            } else {
+                a.index.unwrap() as usize
+            };
+            let pb = PosBuilder::from_arg_ref(a, i as u64);
             self.positionals.insert(i, pb);
         } else if a.is_set(ArgSettings::TakesValue) {
-            let mut ob = OptBuilder::from_arg(a, &mut self.required);
-            let id = self.opts.len();
-            ob.b.id = id;
+            let mut ob = OptBuilder::from(a);
             ob.s.unified_ord = self.flags.len() + self.opts.len();
-            self.opts.insert(id, ob);
+            self.opts.push(ob);
         } else {
             let mut fb = FlagBuilder::from(a);
-            let id = self.flags.len();
-            fb.b.id = id;
             fb.s.unified_ord = self.flags.len() + self.opts.len();
-            self.flags.insert(id, fb);
+            self.flags.push(fb);
         }
         if a.is_set(ArgSettings::Global) {
-            debug_assert!(!a.is_set(ArgSettings::Required),
-                          format!("Global arguments cannot be required.\n\n\t'{}' is marked as \
-                          global and required",
-                                  a.name));
             self.global_args.push(a.into());
         }
     }
 
     pub fn add_group(&mut self, group: ArgGroup<'a>) {
         if group.required {
-            self.required.push(group.name.into());
+            self.required.push(group.name);
             if let Some(ref reqs) = group.requires {
                 self.required.extend_from_slice(reqs);
             }
             if let Some(ref bl) = group.conflicts {
                 self.blacklist.extend_from_slice(bl);
             }
         }
-        let mut found = false;
-        if let Some(ref mut grp) = self.groups.get_mut(&group.name) {
+        if self.groups.iter().any(|g| g.name == group.name) {
+            let grp = self.groups
+                .iter_mut()
+                .find(|g| g.name == group.name)
+                .expect(INTERNAL_ERROR_MSG);
             grp.args.extend_from_slice(&group.args);
             grp.requires = group.requires.clone();
             grp.conflicts = group.conflicts.clone();
             grp.required = group.required;
-            found = true;
-        }
-        if !found {
-            self.groups.insert(group.name.into(), group);
+        } else {
+            self.groups.push(group);
         }
     }
 
     pub fn add_subcommand(&mut self, mut subcmd: App<'a, 'b>) {
         debugln!("Parser::add_subcommand: term_w={:?}, name={}",
-                 self.meta.term_w, subcmd.p.meta.name);
+                 self.meta.term_w,
+                 subcmd.p.meta.name);
         subcmd.p.meta.term_w = self.meta.term_w;
         if subcmd.p.meta.name == "help" {
-            self.settings.unset(AppSettings::NeedsSubcommandHelp);
+            self.unset(AS::NeedsSubcommandHelp);
         }
 
         self.subcommands.push(subcmd);
     }
 
     pub fn propogate_settings(&mut self) {
-        debugln!("Parser::propogate_settings: self={}, g_settings={:#?}", 
-            self.meta.name, self.g_settings);
+        debugln!("Parser::propogate_settings: self={}, g_settings={:#?}",
+                 self.meta.name,
+                 self.g_settings);
         for sc in &mut self.subcommands {
-            debugln!("Parser::propogate_settings: sc={}, settings={:#?}, g_settings={:#?}", 
-                sc.p.meta.name, sc.p.settings, sc.p.g_settings);
+            debugln!("Parser::propogate_settings: sc={}, settings={:#?}, g_settings={:#?}",
+                     sc.p.meta.name,
+                     sc.p.settings,
+                     sc.p.g_settings);
             // We have to create a new scope in order to tell rustc the borrow of `sc` is
             // done and to recursively call this method
             {
-                let vsc = self.settings.is_set(AppSettings::VersionlessSubcommands);
-                let gv = self.settings.is_set(AppSettings::GlobalVersion);
+                let vsc = self.settings.is_set(AS::VersionlessSubcommands);
+                let gv = self.settings.is_set(AS::GlobalVersion);
 
                 if vsc {
-                    sc.p.settings.set(AppSettings::DisableVersion);
+                    sc.p.set(AS::DisableVersion);
                 }
                 if gv && sc.p.meta.version.is_none() && self.meta.version.is_some() {
-                    sc.p.set(AppSettings::GlobalVersion);
+                    sc.p.set(AS::GlobalVersion);
                     sc.p.meta.version = Some(self.meta.version.unwrap());
                 }
                 sc.p.settings = sc.p.settings | self.g_settings;
                 sc.p.g_settings = sc.p.g_settings | self.g_settings;
+                sc.p.meta.term_w = self.meta.term_w;
+                sc.p.meta.max_w = self.meta.max_w;
             }
             sc.p.propogate_settings();
         }
     }
 
     #[cfg_attr(feature = "lints", allow(needless_borrow))]
     pub fn derive_display_order(&mut self) {
-        if self.settings.is_set(AppSettings::DeriveDisplayOrder) {
-            let unified = self.settings.is_set(AppSettings::UnifiedHelpMessage);
+        if self.is_set(AS::DeriveDisplayOrder) {
+            let unified = self.is_set(AS::UnifiedHelpMessage);
             for (i, o) in self.opts
-                .iter_mut()
-                .enumerate()
-                .filter(|&(_, ref o)| o.s.disp_ord == 999) {
+                    .iter_mut()
+                    .enumerate()
+                    .filter(|&(_, ref o)| o.s.disp_ord == 999) {
                 o.s.disp_ord = if unified { o.s.unified_ord } else { i };
             }
             for (i, f) in self.flags
-                .iter_mut()
-                .enumerate()
-                .filter(|&(_, ref f)| f.s.disp_ord == 999) {
+                    .iter_mut()
+                    .enumerate()
+                    .filter(|&(_, ref f)| f.s.disp_ord == 999) {
                 f.s.disp_ord = if unified { f.s.unified_ord } else { i };
             }
             for (i, sc) in &mut self.subcommands
-                .iter_mut()
-                .enumerate()
-                .filter(|&(_, ref sc)| sc.p.meta.disp_ord == 999) {
+                                    .iter_mut()
+                                    .enumerate()
+                                    .filter(|&(_, ref sc)| sc.p.meta.disp_ord == 999) {
                 sc.p.meta.disp_ord = i;
             }
         }
         for sc in &mut self.subcommands {
             sc.p.derive_display_order();
         }
     }
 
     pub fn required(&self) -> Iter<&str> { self.required.iter() }
 
-    pub fn get_required_from(&self,
-                             reqs: &[&'a str],
-                             matcher: Option<&ArgMatcher<'a>>,
-                             extra: Option<&str>)
-                             -> VecDeque<String> {
-        debugln!("Parser::get_required_from: reqs={:?}, extra={:?}", reqs, extra);
-        let mut c_flags: Vec<&str> = vec![];
-        let mut c_pos: Vec<&str> = vec![];
-        let mut c_opt: Vec<&str> = vec![];
-        let mut grps: Vec<&str> = vec![];
-        macro_rules! categorize {
-            ($_self:ident, $name:ident, $c_flags:ident, $c_pos:ident, $c_opt:ident, $grps:ident) => {
-                if $_self.flags.iter().any(|f| &f.b.name == $name) {
-                    $c_flags.push($name);
-                } else if self.opts.iter().any(|o| &o.b.name == $name) {
-                    $c_opt.push($name);
-                } else if self.groups.contains_key($name) {
-                    $grps.push($name);
-                } else {
-                    $c_pos.push($name);
-                }
-            }
-        };
-        for name in reqs {
-            categorize!(self, name, c_flags, c_pos, c_opt, grps);
-        }
-        if let Some(ref name) = extra {
-            categorize!(self, name, c_flags, c_pos, c_opt, grps);
-        }
-        macro_rules! fill_vecs {
-            ($_self:ident {
-                $t1:ident => $v1:ident => $i1:ident,
-                $t2:ident => $v2:ident => $i2:ident,
-                $t3:ident => $v3:ident => $i3:ident,
-                $gv:ident, $tmp:ident
-            }) => {
-                for a in &$v1 {
-                    if let Some(a) = self.$t1.$i1().filter(|arg| &arg.b.name == a).next() {
-                        if let Some(ref rl) = a.b.requires {
-                            for &(_, r) in rl.iter() {
-                                if !reqs.contains(&r) {
-                                    if $_self.$t1.$i1().any(|t| &t.b.name == &r) {
-                                        $tmp.push(r);
-                                    } else if $_self.$t2.$i2().any(|t| &t.b.name == &r) {
-                                        $v2.push(r);
-                                    } else if $_self.$t3.$i3().any(|t| &t.b.name == &r) {
-                                        $v3.push(r);
-                                    } else if $_self.groups.contains_key(r) {
-                                        $gv.push(r);
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-                $v1.extend(&$tmp);
-            };
-        }
-
-        let mut tmp = vec![];
-        fill_vecs!(self {
-            flags       => c_flags => iter,
-            opts        => c_opt   => iter,
-            positionals => c_pos   => values,
-            grps, tmp
-        });
-        tmp.clear();
-        fill_vecs!(self {
-            opts        => c_opt   => iter,
-            flags       => c_flags => iter,
-            positionals => c_pos   => values,
-            grps, tmp
-        });
-        tmp.clear();
-        fill_vecs!(self {
-            positionals => c_pos   => values,
-            opts        => c_opt   => iter,
-            flags       => c_flags => iter,
-            grps, tmp
-        });
-        let mut ret_val = VecDeque::new();
-        c_pos.dedup();
-        c_flags.dedup();
-        c_opt.dedup();
-        grps.dedup();
-        let args_in_groups = grps.iter()
-            .flat_map(|g| self.arg_names_in_group(g))
-            .collect::<Vec<_>>();
-
-        let pmap = c_pos.into_iter()
-            .filter(|&p| matcher.is_none() || !matcher.as_ref().unwrap().contains(p))
-            .filter_map(|p| self.positionals.values().find(|x| x.b.name == p))
-            .filter(|p| !args_in_groups.contains(&p.b.name))
-            .map(|p| (p.index, p))
-            .collect::<BTreeMap<u64, &PosBuilder>>();// sort by index
-        debugln!("Parser::get_required_from: args_in_groups={:?}", args_in_groups);
-        for &p in pmap.values() {
-            let s = p.to_string();
-            if args_in_groups.is_empty() || !args_in_groups.contains(&&*s) {
-                ret_val.push_back(s);
-            }
-        }
-        macro_rules! write_arg {
-            ($i:expr, $m:ident, $v:ident, $r:ident, $aig:ident) => {
-                for f in $v {
-                    if $m.is_some() && $m.as_ref().unwrap().contains(f) || $aig.contains(&f) {
-                        continue;
-                    }
-                    $r.push_back($i.filter(|flg| &flg.b.name == &f).next().unwrap().to_string());
-                }
-            }
-        }
-        write_arg!(self.flags.iter(), matcher, c_flags, ret_val, args_in_groups);
-        write_arg!(self.opts.iter(), matcher, c_opt, ret_val, args_in_groups);
-        let mut g_vec = vec![];
-        for g in grps {
-            let g_string = self.args_in_group(g)
-                .join("|");
-            g_vec.push(format!("<{}>", &g_string[..g_string.len()]));
-        }
-        g_vec.dedup();
-        for g in g_vec {
-            ret_val.push_back(g);
-        }
-
-        ret_val
-    }
-
-    // Gets the `[ARGS]` tag for the usage string
-    pub fn get_args_tag(&self) -> Option<String> {
-        debugln!("Parser::get_args_tag;");
-        let mut count = 0;
-        'outer: for p in self.positionals.values().filter(|p| !p.is_set(ArgSettings::Required)) {
-            debugln!("Parser::get_args_tag:iter:iter: p={};", p.b.name);
-            if let Some(g_vec) = self.groups_for_arg(p.b.name) {
-                for grp_s in &g_vec {
-                    debugln!("Parser::get_args_tag:iter:iter: grp_s={};", grp_s);
-                    if let Some(grp) = self.groups.get(grp_s) {
-                        debug!("Parser::get_args_tag:iter:iter: Is group required...{:?}", grp.required);
-                        if grp.required {
-                            // if it's part of a required group we don't want to count it
-                            continue 'outer;
-                        }
-                    }
-                }
-            }
-            count += 1;
-            debugln!("Parser::get_args_tag:iter: {} Args not required", count);
-        }
-        if !self.is_set(AppSettings::DontCollapseArgsInUsage) &&
-           (count > 1 || self.positionals.len() > 1) {
-            return None; // [ARGS]
-        } else if count == 1 {
-            let p = self.positionals
-                .values()
-                .find(|p| !p.is_set(ArgSettings::Required))
-                .expect(INTERNAL_ERROR_MSG);
-            return Some(format!(" [{}]{}", p.name_no_brackets(), p.multiple_str()));
-        } else if self.is_set(AppSettings::DontCollapseArgsInUsage) &&
-                  !self.positionals.is_empty() {
-            return Some(self.positionals
-                .values()
-                .filter(|p| !p.is_set(ArgSettings::Required))
-                .map(|p| format!(" [{}]{}", p.name_no_brackets(), p.multiple_str()))
-                .collect::<Vec<_>>()
-                .join(""));
-        }
-        Some("".into())
-    }
-
-    // Determines if we need the `[FLAGS]` tag in the usage string
-    pub fn needs_flags_tag(&self) -> bool {
-        debugln!("Parser::needs_flags_tag;");
-        'outer: for f in &self.flags {
-            debugln!("Parser::needs_flags_tag:iter: f={};", f.b.name);
-            if let Some(l) = f.s.long {
-                if l == "help" || l == "version" {
-                    // Don't print `[FLAGS]` just for help or version
-                    continue;
-                }
-            }
-            if let Some(g_vec) = self.groups_for_arg(f.b.name) {
-                for grp_s in &g_vec {
-                    debugln!("Parser::needs_flags_tag:iter:iter: grp_s={};", grp_s);
-                    if let Some(grp) = self.groups.get(grp_s) {
-                        debug!("Parser::needs_flags_tag:iter:iter: Is group required...{:?}", grp.required);
-                        if grp.required {
-                            continue 'outer;
-                        }
-                    }
-                }
-            }
-            debugln!("Parser::needs_flags_tag:iter: [FLAGS] required");
-            return true;
-        }
-
-        debugln!("Parser::needs_flags_tag: [FLAGS] not required");
-        false
+    #[cfg_attr(feature = "lints", allow(needless_borrow))]
+    #[inline]
+    pub fn has_args(&self) -> bool {
+        !(self.flags.is_empty() && self.opts.is_empty() && self.positionals.is_empty())
     }
 
     #[inline]
     pub fn has_opts(&self) -> bool { !self.opts.is_empty() }
 
     #[inline]
     pub fn has_flags(&self) -> bool { !self.flags.is_empty() }
 
     #[inline]
     pub fn has_positionals(&self) -> bool { !self.positionals.is_empty() }
 
     #[inline]
     pub fn has_subcommands(&self) -> bool { !self.subcommands.is_empty() }
 
     #[inline]
-    pub fn is_set(&self, s: AppSettings) -> bool { self.settings.is_set(s) }
+    pub fn has_visible_opts(&self) -> bool {
+        if self.opts.is_empty() {
+            return false;
+        }
+        self.opts.iter().any(|o| !o.is_set(ArgSettings::Hidden))
+    }
+
+    #[inline]
+    pub fn has_visible_flags(&self) -> bool {
+        if self.flags.is_empty() {
+            return false;
+        }
+        self.flags.iter().any(|f| !f.is_set(ArgSettings::Hidden))
+    }
 
     #[inline]
-    pub fn set(&mut self, s: AppSettings) { self.settings.set(s) }
+    pub fn has_visible_positionals(&self) -> bool {
+        if self.positionals.is_empty() {
+            return false;
+        }
+        self.positionals
+            .values()
+            .any(|p| !p.is_set(ArgSettings::Hidden))
+    }
 
     #[inline]
-    pub fn unset(&mut self, s: AppSettings) { self.settings.unset(s) }
+    pub fn has_visible_subcommands(&self) -> bool {
+        if self.subcommands.is_empty() {
+            return false;
+        }
+        self.subcommands.iter().any(|s| !s.p.is_set(AS::Hidden))
+    }
+
+    #[inline]
+    pub fn is_set(&self, s: AS) -> bool { self.settings.is_set(s) }
+
+    #[inline]
+    pub fn set(&mut self, s: AS) { self.settings.set(s) }
+
+    #[inline]
+    pub fn unset(&mut self, s: AS) { self.settings.unset(s) }
 
     #[cfg_attr(feature = "lints", allow(block_in_if_condition_stmt))]
-    pub fn verify_positionals(&mut self) {
+    pub fn verify_positionals(&mut self) -> bool {
         // Because you must wait until all arguments have been supplied, this is the first chance
         // to make assertions on positional argument indexes
         //
         // Firt we verify that the index highest supplied index, is equal to the number of
         // positional arguments to verify there are no gaps (i.e. supplying an index of 1 and 3
         // but no 2)
         if let Some((idx, p)) = self.positionals.iter().rev().next() {
-            debug_assert!(!(idx != self.positionals.len()),
-                    format!("Found positional argument \"{}\" who's index is {} but there are \
-                    only {} positional arguments defined",
-                            p.b.name,
-                            idx,
-                            self.positionals.len()));
+            assert!(!(idx != self.positionals.len()),
+                    "Found positional argument \"{}\" who's index is {} but there \
+                          are only {} positional arguments defined",
+                    p.b.name,
+                    idx,
+                    self.positionals.len());
         }
 
         // Next we verify that only the highest index has a .multiple(true) (if any)
         if self.positionals
-            .values()
-            .any(|a| {
-                a.b.settings.is_set(ArgSettings::Multiple) &&
-                (a.index as usize != self.positionals.len())
-            }) {
+               .values()
+               .any(|a| {
+                        a.b.is_set(ArgSettings::Multiple) &&
+                        (a.index as usize != self.positionals.len())
+                    }) {
+            let mut it = self.positionals.values().rev();
+            let last = it.next().unwrap();
+            let second_to_last = it.next().unwrap();
+            // Either the final positional is required
+            // Or the second to last has a terminator or .last(true) set
+            let ok = last.is_set(ArgSettings::Required) ||
+                     (second_to_last.v.terminator.is_some() ||
+                      second_to_last.b.is_set(ArgSettings::Last)) ||
+                     last.is_set(ArgSettings::Last);
+            assert!(ok,
+                    "When using a positional argument with .multiple(true) that is *not the \
+                          last* positional argument, the last positional argument (i.e the one \
+                          with the highest index) *must* have .required(true) or .last(true) set.");
+            let ok = second_to_last.is_set(ArgSettings::Multiple) || last.is_set(ArgSettings::Last);
+            assert!(ok,
+                    "Only the last positional argument, or second to last positional \
+                          argument may be set to .multiple(true)");
 
-            debug_assert!({
-                    let mut it = self.positionals.values().rev();
-                    // Either the final positional is required
-                    it.next().unwrap().is_set(ArgSettings::Required)
-                    // Or the second to last has a terminator set
-                    || it.next().unwrap().v.terminator.is_some()
-                },
-                "When using a positional argument with .multiple(true) that is *not the last* \
-                positional argument, the last positional argument (i.e the one with the highest \
-                index) *must* have .required(true) set."
-            );
-
-            debug_assert!({
-                let num = self.positionals.len() - 1;
-                self.positionals.get(num).unwrap().is_set(ArgSettings::Multiple)
-            },
-            "Only the last positional argument, or second to last positional argument may be set to .multiple(true)");
-
-            self.set(AppSettings::LowIndexMultiplePositional);
+            let count = self.positionals
+                .values()
+                .filter(|p| p.b.settings.is_set(ArgSettings::Multiple) && p.v.num_vals.is_none())
+                .count();
+            let ok = count <= 1 ||
+                     (last.is_set(ArgSettings::Last) && last.is_set(ArgSettings::Multiple) &&
+                      second_to_last.is_set(ArgSettings::Multiple) &&
+                      count == 2);
+            assert!(ok,
+                    "Only one positional argument with .multiple(true) set is allowed per \
+                        command, unless the second one also has .last(true) set");
         }
 
-        debug_assert!(self.positionals.values()
-            .filter(|p| p.b.settings.is_set(ArgSettings::Multiple)
-                && p.v.num_vals.is_none())
-            .map(|_| 1)
-            .sum::<u64>() <= 1,
-            "Only one positional argument with .multiple(true) set is allowed per command");
 
-        // If it's required we also need to ensure all previous positionals are
-        // required too
-        if self.is_set(AppSettings::AllowMissingPositional) {
+        if self.is_set(AS::AllowMissingPositional) {
+            // Check that if a required positional argument is found, all positions with a lower
+            // index are also required.
             let mut found = false;
             let mut foundx2 = false;
             for p in self.positionals.values().rev() {
                 if foundx2 && !p.b.settings.is_set(ArgSettings::Required) {
-                    // [arg1] <arg2> is Ok
-                    // [arg1] <arg2> <arg3> Is not
-                    debug_assert!(p.b.settings.is_set(ArgSettings::Required),
-                                "Found positional argument which is not required with a lower index \
-                                than a required positional argument by two or more: {:?} index {}",
-                                p.b.name,
-                                p.index);
-                } else if p.b.settings.is_set(ArgSettings::Required) {
+                    assert!(p.b.is_set(ArgSettings::Required),
+                            "Found positional argument which is not required with a lower \
+                                  index than a required positional argument by two or more: {:?} \
+                                  index {}",
+                            p.b.name,
+                            p.index);
+                } else if p.b.is_set(ArgSettings::Required) && !p.b.is_set(ArgSettings::Last) {
+                    // Args that .last(true) don't count since they can be required and have
+                    // positionals with a lower index that aren't required
+                    // Imagine: prog <req1> [opt1] -- <req2>
+                    // Both of these are valid invocations:
+                    //      $ prog r1 -- r2
+                    //      $ prog r1 o1 -- r2
                     if found {
                         foundx2 = true;
                         continue;
                     }
                     found = true;
                     continue;
                 } else {
                     found = false;
                 }
             }
         } else {
+            // Check that if a required positional argument is found, all positions with a lower
+            // index are also required
             let mut found = false;
             for p in self.positionals.values().rev() {
                 if found {
-                    debug_assert!(p.b.settings.is_set(ArgSettings::Required),
-                                "Found positional argument which is not required with a lower index \
-                                than a required positional argument: {:?} index {}",
-                                p.b.name,
-                                p.index);
-                } else if p.b.settings.is_set(ArgSettings::Required) {
+                    assert!(p.b.is_set(ArgSettings::Required),
+                            "Found positional argument which is not required with a lower \
+                                  index than a required positional argument: {:?} index {}",
+                            p.b.name,
+                            p.index);
+                } else if p.b.is_set(ArgSettings::Required) && !p.b.is_set(ArgSettings::Last) {
+                    // Args that .last(true) don't count since they can be required and have
+                    // positionals with a lower index that aren't required
+                    // Imagine: prog <req1> [opt1] -- <req2>
+                    // Both of these are valid invocations:
+                    //      $ prog r1 -- r2
+                    //      $ prog r1 o1 -- r2
                     found = true;
                     continue;
                 }
             }
         }
+        if self.positionals
+               .values()
+               .any(|p| {
+                        p.b.is_set(ArgSettings::Last) && p.b.is_set(ArgSettings::Required)
+                    }) && self.has_subcommands() &&
+           !self.is_set(AS::SubcommandsNegateReqs) {
+            panic!("Having a required positional argument with .last(true) set *and* child \
+            subcommands without setting SubcommandsNegateReqs isn't compatible.");
+        }
+
+        true
     }
 
     pub fn propogate_globals(&mut self) {
         for sc in &mut self.subcommands {
             // We have to create a new scope in order to tell rustc the borrow of `sc` is
             // done and to recursively call this method
             {
                 for a in &self.global_args {
-                    sc.p.add_arg(a);
+                    sc.p.add_arg_ref(a);
                 }
             }
             sc.p.propogate_globals();
         }
     }
 
     // Checks if the arg matches a subcommand name, or any of it's aliases (if defined)
-    #[inline]
-    fn possible_subcommand(&self, arg_os: &OsStr) -> bool {
+    fn possible_subcommand(&self, arg_os: &OsStr) -> (bool, Option<&str>) {
         debugln!("Parser::possible_subcommand: arg={:?}", arg_os);
-        if self.is_set(AppSettings::ArgsNegateSubcommands) && self.valid_arg {
-            return false;
+        fn starts(h: &str, n: &OsStr) -> bool {
+            #[cfg(not(target_os = "windows"))]
+            use std::os::unix::ffi::OsStrExt;
+            #[cfg(target_os = "windows")]
+            use osstringext::OsStrExt3;
+
+            let n_bytes = n.as_bytes();
+            let h_bytes = OsStr::new(h).as_bytes();
+
+            h_bytes.starts_with(n_bytes)
+        }
+
+        if self.is_set(AS::ArgsNegateSubcommands) && self.is_set(AS::ValidArgFound) {
+            return (false, None);
         }
-        self.subcommands
-            .iter()
-            .any(|s| {
-                &s.p.meta.name[..] == &*arg_os ||
-                (s.p.meta.aliases.is_some() &&
-                 s.p
-                    .meta
-                    .aliases
-                    .as_ref()
-                    .unwrap()
-                    .iter()
-                    .any(|&(a, _)| a == &*arg_os))
-            })
+        if !self.is_set(AS::InferSubcommands) {
+            if let Some(sc) = find_subcmd!(self, arg_os) {
+                return (true, Some(&sc.p.meta.name));
+            }
+        } else {
+            let v = self.subcommands
+                .iter()
+                .filter(|s| {
+                    starts(&s.p.meta.name[..], &*arg_os) ||
+                    (s.p.meta.aliases.is_some() &&
+                     s.p
+                         .meta
+                         .aliases
+                         .as_ref()
+                         .unwrap()
+                         .iter()
+                         .filter(|&&(a, _)| starts(a, &*arg_os))
+                         .count() == 1)
+                })
+                .map(|sc| &sc.p.meta.name)
+                .collect::<Vec<_>>();
+
+            if v.len() == 1 {
+                return (true, Some(v[0]));
+            }
+        }
+        (false, None)
     }
 
-    fn parse_help_subcommand<I, T>(&self, it: &mut I) -> ClapResult<()>
+    fn parse_help_subcommand<I, T>(&self, it: &mut I) -> ClapResult<ParseResult<'a>>
         where I: Iterator<Item = T>,
               T: Into<OsString>
     {
         debugln!("Parser::parse_help_subcommand;");
         let cmds: Vec<OsString> = it.map(|c| c.into()).collect();
         let mut help_help = false;
         let mut bin_name = self.meta
             .bin_name
@@ -674,1461 +687,1092 @@ impl<'a, 'b> Parser<'a, 'b>
         let mut sc = {
             let mut sc: &Parser = self;
             for (i, cmd) in cmds.iter().enumerate() {
                 if &*cmd.to_string_lossy() == "help" {
                     // cmd help help
                     help_help = true;
                 }
                 if let Some(c) = sc.subcommands
-                    .iter()
-                    .find(|s| &*s.p.meta.name == cmd)
-                    .map(|sc| &sc.p) {
+                       .iter()
+                       .find(|s| &*s.p.meta.name == cmd)
+                       .map(|sc| &sc.p) {
                     sc = c;
                     if i == cmds.len() - 1 {
                         break;
                     }
                 } else if let Some(c) = sc.subcommands
-                    .iter()
-                    .find(|s| if let Some(ref als) = s.p
-                        .meta
-                        .aliases {
-                        als.iter()
-                            .any(|&(a, _)| &a == &&*cmd.to_string_lossy())
-                    } else {
-                        false
-                    })
-                    .map(|sc| &sc.p) {
+                              .iter()
+                              .find(|s| if let Some(ref als) = s.p.meta.aliases {
+                                        als.iter().any(|&(a, _)| &a == &&*cmd.to_string_lossy())
+                                    } else {
+                                        false
+                                    })
+                              .map(|sc| &sc.p) {
                     sc = c;
                     if i == cmds.len() - 1 {
                         break;
                     }
                 } else {
                     return Err(Error::unrecognized_subcommand(cmd.to_string_lossy().into_owned(),
                                                               self.meta
                                                                   .bin_name
                                                                   .as_ref()
                                                                   .unwrap_or(&self.meta.name),
                                                               self.color()));
                 }
-                bin_name = format!("{} {}",
-                    bin_name,
-                    &*sc.meta.name);
+                bin_name = format!("{} {}", bin_name, &*sc.meta.name);
             }
             sc.clone()
         };
         if help_help {
             let mut pb = PosBuilder::new("subcommand", 1);
             pb.b.help = Some("The subcommand whose help message to display");
             pb.set(ArgSettings::Multiple);
             sc.positionals.insert(1, pb);
             sc.settings = sc.settings | self.g_settings;
         } else {
             sc.create_help_and_version();
         }
         if sc.meta.bin_name != self.meta.bin_name {
             sc.meta.bin_name = Some(format!("{} {}", bin_name, sc.meta.name));
         }
-        sc._help()
+        Err(sc._help(false))
     }
 
     // allow wrong self convention due to self.valid_neg_num = true and it's a private method
     #[cfg_attr(feature = "lints", allow(wrong_self_convention))]
-    #[inline]
-    fn is_new_arg(&mut self, arg_os: &OsStr, needs_val_of: Option<&'a str>) -> bool {
-        debugln!("Parser::is_new_arg: arg={:?}, Needs Val of={:?}", arg_os, needs_val_of);
-        let app_wide_settings = if self.is_set(AppSettings::AllowLeadingHyphen) {
+    fn is_new_arg(&mut self, arg_os: &OsStr, needs_val_of: ParseResult<'a>) -> bool {
+        debugln!("Parser::is_new_arg: arg={:?}, Needs Val of={:?}",
+                 arg_os,
+                 needs_val_of);
+        let app_wide_settings = if self.is_set(AS::AllowLeadingHyphen) {
             true
-        } else if self.is_set(AppSettings::AllowNegativeNumbers) {
+        } else if self.is_set(AS::AllowNegativeNumbers) {
             let a = arg_os.to_string_lossy();
             if a.parse::<i64>().is_ok() || a.parse::<f64>().is_ok() {
-                self.valid_neg_num = true;
+                self.set(AS::ValidNegNumFound);
                 true
             } else {
                 false
             }
         } else {
             false
         };
-        let arg_allows_tac = if let Some(name) = needs_val_of {
-            if let Some(o) = find_by_name!(self, &name, opts, iter) {
+        let arg_allows_tac = match needs_val_of {
+            ParseResult::Opt(name) => {
+                let o = self.opts
+                    .iter()
+                    .find(|o| o.b.name == name)
+                    .expect(INTERNAL_ERROR_MSG);
                 (o.is_set(ArgSettings::AllowLeadingHyphen) || app_wide_settings)
-            } else if let Some(p) = find_by_name!(self, &name, positionals, values) {
+            }
+            ParseResult::Pos(name) => {
+                let p = self.positionals
+                    .values()
+                    .find(|p| p.b.name == name)
+                    .expect(INTERNAL_ERROR_MSG);
                 (p.is_set(ArgSettings::AllowLeadingHyphen) || app_wide_settings)
-            } else {
-                false
             }
-        } else {
-            false
+            _ => false,
         };
-        debugln!("Parser::is_new_arg: Does arg allow leading hyphen...{:?}", arg_allows_tac);
+        debugln!("Parser::is_new_arg: Arg::allow_leading_hyphen({:?})",
+                 arg_allows_tac);
 
         // Is this a new argument, or values from a previous option?
-        debug!("Parser::is_new_arg: Starts new arg...");
         let mut ret = if arg_os.starts_with(b"--") {
-            sdebugln!("--");
-            if arg_os.len_() == 2 {
+            debugln!("Parser::is_new_arg: -- found");
+            if arg_os.len_() == 2 && !arg_allows_tac {
                 return true; // We have to return true so override everything else
+            } else if arg_allows_tac {
+                return false;
             }
             true
         } else if arg_os.starts_with(b"-") {
-            sdebugln!("-");
+            debugln!("Parser::is_new_arg: - found");
             // a singe '-' by itself is a value and typically means "stdin" on unix systems
             !(arg_os.len_() == 1)
         } else {
-            sdebugln!("Probable value");
+            debugln!("Parser::is_new_arg: probably value");
             false
         };
 
         ret = ret && !arg_allows_tac;
 
-        debugln!("Parser::is_new_arg: Starts new arg...{:?}", ret);
+        debugln!("Parser::is_new_arg: starts_new_arg={:?}", ret);
         ret
     }
 
     // The actual parsing function
     #[cfg_attr(feature = "lints", allow(while_let_on_iterator, collapsible_if))]
     pub fn get_matches_with<I, T>(&mut self,
                                   matcher: &mut ArgMatcher<'a>,
                                   it: &mut Peekable<I>)
                                   -> ClapResult<()>
         where I: Iterator<Item = T>,
               T: Into<OsString> + Clone
     {
         debugln!("Parser::get_matches_with;");
         // Verify all positional assertions pass
-        self.verify_positionals();
+        debug_assert!(self.app_debug_asserts());
+        if self.positionals
+               .values()
+               .any(|a| {
+                        a.b.is_set(ArgSettings::Multiple) &&
+                        (a.index as usize != self.positionals.len())
+                    }) &&
+           self.positionals
+               .values()
+               .last()
+               .map_or(false, |p| !p.is_set(ArgSettings::Last)) {
+            self.settings.set(AS::LowIndexMultiplePositional);
+        }
+        let has_args = self.has_args();
 
         // Next we create the `--help` and `--version` arguments and add them if
         // necessary
         self.create_help_and_version();
 
         let mut subcmd_name: Option<String> = None;
-        let mut needs_val_of: Option<&'a str> = None;
+        let mut needs_val_of: ParseResult<'a> = ParseResult::NotFound;
         let mut pos_counter = 1;
         while let Some(arg) = it.next() {
             let arg_os = arg.into();
-            debugln!("Parser::get_matches_with: Begin parsing '{:?}' ({:?})", arg_os, &*arg_os.as_bytes());
+            debugln!("Parser::get_matches_with: Begin parsing '{:?}' ({:?})",
+                     arg_os,
+                     &*arg_os.as_bytes());
 
-            self.valid_neg_num = false;
+            self.unset(AS::ValidNegNumFound);
             // Is this a new argument, or values from a previous option?
             let starts_new_arg = self.is_new_arg(&arg_os, needs_val_of);
+            if arg_os.starts_with(b"--") && arg_os.len_() == 2 && starts_new_arg {
+                debugln!("Parser::get_matches_with: setting TrailingVals=true");
+                self.set(AS::TrailingValues);
+                continue;
+            }
 
             // Has the user already passed '--'? Meaning only positional args follow
-            if !self.trailing_vals {
+            if !self.is_set(AS::TrailingValues) {
                 // Does the arg match a subcommand name, or any of it's aliases (if defined)
-                if self.possible_subcommand(&arg_os) {
-                    if &*arg_os == "help" && self.is_set(AppSettings::NeedsSubcommandHelp) {
-                        try!(self.parse_help_subcommand(it));
+                {
+                    let (is_match, sc_name) = self.possible_subcommand(&arg_os);
+                    debugln!("Parser::get_matches_with: possible_sc={:?}, sc={:?}",
+                             is_match,
+                             sc_name);
+                    if is_match {
+                        let sc_name = sc_name.expect(INTERNAL_ERROR_MSG);
+                        if sc_name == "help" && self.is_set(AS::NeedsSubcommandHelp) {
+                            try!(self.parse_help_subcommand(it));
+                        }
+                        subcmd_name = Some(sc_name.to_owned());
+                        break;
                     }
-                    subcmd_name = Some(arg_os.to_str().expect(INVALID_UTF8).to_owned());
-                    break;
                 }
 
                 if !starts_new_arg {
-                    if let Some(name) = needs_val_of {
-                        // Check to see if parsing a value from a previous arg
-                        if let Some(arg) = find_by_name!(self, &name, opts, iter) {
-                        // get the OptBuilder so we can check the settings
-                            needs_val_of = try!(self.add_val_to_arg(&*arg, &arg_os, matcher));
+                    match needs_val_of {
+                        ParseResult::Opt(name) => {
+                            // Check to see if parsing a value from a previous arg
+                            let arg = self.opts
+                                .iter()
+                                .find(|o| o.b.name == name)
+                                .expect(INTERNAL_ERROR_MSG);
+                            // get the OptBuilder so we can check the settings
+                            needs_val_of = try!(self.add_val_to_arg(arg, &arg_os, matcher));
                             // get the next value from the iterator
                             continue;
                         }
+                        _ => (),
                     }
                 } else {
                     if arg_os.starts_with(b"--") {
-                        if arg_os.len_() == 2 {
-                            // The user has passed '--' which means only positional args follow no
-                            // matter what they start with
-                            self.trailing_vals = true;
-                            continue;
-                        }
-
                         needs_val_of = try!(self.parse_long_arg(matcher, &arg_os));
-                        if !(needs_val_of.is_none() && self.is_set(AppSettings::AllowLeadingHyphen)) {
-                            continue;
+                        debugln!("Parser:get_matches_with: After parse_long_arg {:?}",
+                                 needs_val_of);
+                        match needs_val_of {
+                            ParseResult::Flag |
+                            ParseResult::Opt(..) |
+                            ParseResult::ValuesDone => continue,
+                            _ => (),
                         }
                     } else if arg_os.starts_with(b"-") && arg_os.len_() != 1 {
                         // Try to parse short args like normal, if AllowLeadingHyphen or
                         // AllowNegativeNumbers is set, parse_short_arg will *not* throw
                         // an error, and instead return Ok(None)
                         needs_val_of = try!(self.parse_short_arg(matcher, &arg_os));
                         // If it's None, we then check if one of those two AppSettings was set
-                        if needs_val_of.is_none() {
-                            if self.is_set(AppSettings::AllowNegativeNumbers) {
+                        debugln!("Parser:get_matches_with: After parse_short_arg {:?}",
+                                 needs_val_of);
+                        match needs_val_of {
+                            ParseResult::MaybeNegNum => {
                                 if !(arg_os.to_string_lossy().parse::<i64>().is_ok() ||
-                                    arg_os.to_string_lossy().parse::<f64>().is_ok()) {
+                                     arg_os.to_string_lossy().parse::<f64>().is_ok()) {
                                     return Err(Error::unknown_argument(&*arg_os.to_string_lossy(),
-                                                                "",
-                                                                &*self.create_current_usage(matcher, None),
-                                                                self.color()));
+                                        "",
+                                        &*usage::create_error_usage(self, matcher, None),
+                                        self.color()));
                                 }
-                            } else if !self.is_set(AppSettings::AllowLeadingHyphen) {
-                                continue;
                             }
-                        } else {
-                            continue;
+                            ParseResult::Opt(..) |
+                            ParseResult::Flag |
+                            ParseResult::ValuesDone => continue,
+                            _ => (),
                         }
                     }
                 }
 
-                if !self.is_set(AppSettings::ArgsNegateSubcommands) {
-                    if let Some(cdate) =
-                    suggestions::did_you_mean(&*arg_os.to_string_lossy(),
-                                              self.subcommands
-                                                  .iter()
-                                                  .map(|s| &s.p.meta.name)) {
-                        return Err(Error::invalid_subcommand(arg_os.to_string_lossy().into_owned(),
-                                                            cdate,
-                                                            self.meta
-                                                                .bin_name
-                                                                .as_ref()
-                                                                .unwrap_or(&self.meta.name),
-                                                            &*self.create_current_usage(matcher, None),
-                                                            self.color()));
+                if !(self.is_set(AS::ArgsNegateSubcommands) && self.is_set(AS::ValidArgFound)) &&
+                   !self.is_set(AS::InferSubcommands) {
+                    if let Some(cdate) = suggestions::did_you_mean(&*arg_os.to_string_lossy(),
+                                                                   sc_names!(self)) {
+                        return Err(Error::invalid_subcommand(arg_os
+                                                                 .to_string_lossy()
+                                                                 .into_owned(),
+                                                             cdate,
+                                                             self.meta
+                                                                 .bin_name
+                                                                 .as_ref()
+                                                                 .unwrap_or(&self.meta.name),
+                                                             &*usage::create_error_usage(self,
+                                                                                         matcher,
+                                                                                         None),
+                                                             self.color()));
                     }
                 }
             }
 
-            let low_index_mults = self.is_set(AppSettings::LowIndexMultiplePositional) &&
-                                  !self.positionals.is_empty() &&
+            let low_index_mults = self.is_set(AS::LowIndexMultiplePositional) &&
                                   pos_counter == (self.positionals.len() - 1);
-            let missing_pos = self.is_set(AppSettings::AllowMissingPositional) &&
-                                  !self.positionals.is_empty() &&
-                                  pos_counter == (self.positionals.len() - 1);
-            debugln!("Parser::get_matches_with: Low index multiples...{:?}", low_index_mults);
-            debugln!("Parser::get_matches_with: Positional counter...{}", pos_counter);
+            let missing_pos = self.is_set(AS::AllowMissingPositional) &&
+                              pos_counter == (self.positionals.len() - 1);
+            debugln!("Parser::get_matches_with: Positional counter...{}",
+                     pos_counter);
+            debugln!("Parser::get_matches_with: Low index multiples...{:?}",
+                     low_index_mults);
             if low_index_mults || missing_pos {
                 if let Some(na) = it.peek() {
                     let n = (*na).clone().into();
-                    needs_val_of = if needs_val_of.is_none() {
+                    needs_val_of = if needs_val_of != ParseResult::ValuesDone {
                         if let Some(p) = self.positionals.get(pos_counter) {
-                            Some(p.b.name)
+                            ParseResult::Pos(p.b.name)
                         } else {
-                            None
+                            ParseResult::ValuesDone
                         }
                     } else {
-                        None
+                        ParseResult::ValuesDone
                     };
-                    if self.is_new_arg(&n, needs_val_of) || self.possible_subcommand(&n) ||
-                       suggestions::did_you_mean(&n.to_string_lossy(),
-                                                 self.subcommands
-                                                     .iter()
-                                                     .map(|s| &s.p.meta.name))
-                        .is_some() {
+                    let sc_match = {
+                        self.possible_subcommand(&n).0
+                    };
+                    if self.is_new_arg(&n, needs_val_of) || sc_match ||
+                       suggestions::did_you_mean(&n.to_string_lossy(), sc_names!(self)).is_some() {
                         debugln!("Parser::get_matches_with: Bumping the positional counter...");
                         pos_counter += 1;
                     }
                 } else {
                     debugln!("Parser::get_matches_with: Bumping the positional counter...");
                     pos_counter += 1;
                 }
+            } else if self.is_set(AS::ContainsLast) && self.is_set(AS::TrailingValues) {
+                // Came to -- and one postional has .last(true) set, so we go immediately
+                // to the last (highest index) positional
+                debugln!("Parser::get_matches_with: .last(true) and --, setting last pos");
+                pos_counter = self.positionals.len();
             }
             if let Some(p) = self.positionals.get(pos_counter) {
+                if p.is_set(ArgSettings::Last) && !self.is_set(AS::TrailingValues) {
+                    return Err(Error::unknown_argument(&*arg_os.to_string_lossy(),
+                                                       "",
+                                                       &*usage::create_error_usage(self,
+                                                                                   matcher,
+                                                                                   None),
+                                                       self.color()));
+                }
                 parse_positional!(self, p, arg_os, pos_counter, matcher);
-                self.valid_arg = true;
-            } else if self.settings.is_set(AppSettings::AllowExternalSubcommands) {
+                self.settings.set(AS::ValidArgFound);
+            } else if self.is_set(AS::AllowExternalSubcommands) {
                 // Get external subcommand name
                 let sc_name = match arg_os.to_str() {
                     Some(s) => s.to_string(),
                     None => {
-                        if !self.settings.is_set(AppSettings::StrictUtf8) {
-                            return Err(Error::invalid_utf8(&*self.create_current_usage(matcher, None),
+                        if !self.is_set(AS::StrictUtf8) {
+                            return Err(Error::invalid_utf8(&*usage::create_error_usage(self,
+                                                                                       matcher,
+                                                                                       None),
                                                            self.color()));
                         }
                         arg_os.to_string_lossy().into_owned()
                     }
                 };
 
                 // Collect the external subcommand args
                 let mut sc_m = ArgMatcher::new();
                 while let Some(v) = it.next() {
                     let a = v.into();
-                    if a.to_str().is_none() && !self.settings.is_set(AppSettings::StrictUtf8) {
-                        return Err(Error::invalid_utf8(&*self.create_current_usage(matcher, None),
+                    if a.to_str().is_none() && !self.is_set(AS::StrictUtf8) {
+                        return Err(Error::invalid_utf8(&*usage::create_error_usage(self,
+                                                                                   matcher,
+                                                                                   None),
                                                        self.color()));
                     }
                     sc_m.add_val_to("", &a);
                 }
 
                 matcher.subcommand(SubCommand {
-                    name: sc_name,
-                    matches: sc_m.into(),
-                });
-            } else if !(self.is_set(AppSettings::AllowLeadingHyphen) ||
-                        self.is_set(AppSettings::AllowNegativeNumbers)) {
+                                       name: sc_name,
+                                       matches: sc_m.into(),
+                                   });
+            } else if !(self.is_set(AS::AllowLeadingHyphen) ||
+                        self.is_set(AS::AllowNegativeNumbers)) &&
+                      !self.is_set(AS::InferSubcommands) {
                 return Err(Error::unknown_argument(&*arg_os.to_string_lossy(),
                                                    "",
-                                                   &*self.create_current_usage(matcher, None),
+                                                   &*usage::create_error_usage(self,
+                                                                               matcher,
+                                                                               None),
                                                    self.color()));
+            } else if !has_args || self.is_set(AS::InferSubcommands) && self.has_subcommands() {
+                if let Some(cdate) = suggestions::did_you_mean(&*arg_os.to_string_lossy(),
+                                                               sc_names!(self)) {
+                    return Err(Error::invalid_subcommand(arg_os.to_string_lossy().into_owned(),
+                                                         cdate,
+                                                         self.meta
+                                                             .bin_name
+                                                             .as_ref()
+                                                             .unwrap_or(&self.meta.name),
+                                                         &*usage::create_error_usage(self,
+                                                                                     matcher,
+                                                                                     None),
+                                                         self.color()));
+                } else {
+                    return Err(Error::unrecognized_subcommand(arg_os
+                                                                  .to_string_lossy()
+                                                                  .into_owned(),
+                                                              self.meta
+                                                                  .bin_name
+                                                                  .as_ref()
+                                                                  .unwrap_or(&self.meta.name),
+                                                              self.color()));
+                }
             }
         }
 
         if let Some(ref pos_sc_name) = subcmd_name {
-            // is this is a real subcommand, or an alias
-            if self.subcommands.iter().any(|sc| &sc.p.meta.name == pos_sc_name) {
-                try!(self.parse_subcommand(&*pos_sc_name, matcher, it));
-            } else {
-                let sc_name = &*self.subcommands
-                    .iter()
-                    .filter(|sc| sc.p.meta.aliases.is_some())
-                    .filter(|sc| {
-                        sc.p
-                            .meta
-                            .aliases
-                            .as_ref()
-                            .expect(INTERNAL_ERROR_MSG)
-                            .iter()
-                            .any(|&(a, _)| &a == &&*pos_sc_name)
-                    })
-                    .map(|sc| sc.p.meta.name.clone())
-                    .next()
-                    .expect(INTERNAL_ERROR_MSG);
-                try!(self.parse_subcommand(sc_name, matcher, it));
-            }
-        } else if self.is_set(AppSettings::SubcommandRequired) {
+            let sc_name = {
+                find_subcmd!(self, pos_sc_name)
+                    .expect(INTERNAL_ERROR_MSG)
+                    .p
+                    .meta
+                    .name
+                    .clone()
+            };
+            try!(self.parse_subcommand(&*sc_name, matcher, it));
+        } else if self.is_set(AS::SubcommandRequired) {
             let bn = self.meta.bin_name.as_ref().unwrap_or(&self.meta.name);
             return Err(Error::missing_subcommand(bn,
-                                                 &self.create_current_usage(matcher, None),
+                                                 &usage::create_error_usage(self, matcher, None),
                                                  self.color()));
-        } else if self.is_set(AppSettings::SubcommandRequiredElseHelp) {
-            debugln!("parser::get_matches_with: SubcommandRequiredElseHelp=true");
+        } else if self.is_set(AS::SubcommandRequiredElseHelp) {
+            debugln!("Parser::get_matches_with: SubcommandRequiredElseHelp=true");
             let mut out = vec![];
             try!(self.write_help_err(&mut out));
             return Err(Error {
-                message: String::from_utf8_lossy(&*out).into_owned(),
-                kind: ErrorKind::MissingArgumentOrSubcommand,
-                info: None,
-            });
+                           message: String::from_utf8_lossy(&*out).into_owned(),
+                           kind: ErrorKind::MissingArgumentOrSubcommand,
+                           info: None,
+                       });
         }
 
-        self.validate(needs_val_of, subcmd_name, matcher)
+        Validator::new(self).validate(needs_val_of, subcmd_name, matcher)
     }
 
-    fn validate(&mut self,
-                needs_val_of: Option<&'a str>,
-                subcmd_name: Option<String>,
-                matcher: &mut ArgMatcher<'a>)
-                -> ClapResult<()> {
-        debugln!("Parser::validate;");
-        let mut reqs_validated = false;
-        try!(self.add_defaults(matcher));
-        if let Some(a) = needs_val_of {
-            debugln!("Parser::validate: needs_val_of={:?}", a);
-            if let Some(o) = find_by_name!(self, &a, opts, iter) {
-                try!(self.validate_required(matcher));
-                reqs_validated = true;
-                let should_err = if let Some(v) = matcher.0.args.get(&*o.b.name) {
-                    v.vals.is_empty() && !(o.v.min_vals.is_some() && o.v.min_vals.unwrap() == 0)
-                } else {
-                    true
-                };
-                if should_err {
-                    return Err(Error::empty_value(o,
-                                                &*self.create_current_usage(matcher, None),
-                                                self.color()));
-                }
-            }
-        }
-
-        try!(self.validate_blacklist(matcher));
-        if !(self.settings.is_set(AppSettings::SubcommandsNegateReqs) && subcmd_name.is_some()) &&
-           !reqs_validated {
-            try!(self.validate_required(matcher));
-        }
-        try!(self.validate_matched_args(matcher));
-        matcher.usage(self.create_usage(&[]));
-
-        if matcher.is_empty() && matcher.subcommand_name().is_none() &&
-           self.is_set(AppSettings::ArgRequiredElseHelp) {
-            let mut out = vec![];
-            try!(self.write_help_err(&mut out));
-            return Err(Error {
-                message: String::from_utf8_lossy(&*out).into_owned(),
-                kind: ErrorKind::MissingArgumentOrSubcommand,
-                info: None,
-            });
-        }
-        Ok(())
-    }
 
     fn propogate_help_version(&mut self) {
         debugln!("Parser::propogate_help_version;");
         self.create_help_and_version();
         for sc in &mut self.subcommands {
             sc.p.propogate_help_version();
         }
     }
 
     fn build_bin_names(&mut self) {
         debugln!("Parser::build_bin_names;");
         for sc in &mut self.subcommands {
             debug!("Parser::build_bin_names:iter: bin_name set...");
             if sc.p.meta.bin_name.is_none() {
                 sdebugln!("No");
                 let bin_name = format!("{}{}{}",
-                                      self.meta
-                                          .bin_name
-                                          .as_ref()
-                                          .unwrap_or(&self.meta.name.clone()),
-                                      if self.meta.bin_name.is_some() {
-                                          " "
-                                      } else {
-                                          ""
-                                      },
-                                      &*sc.p.meta.name);
-                debugln!("Parser::build_bin_names:iter: Setting bin_name of {} to {}", self.meta.name, bin_name);
+                                       self.meta
+                                           .bin_name
+                                           .as_ref()
+                                           .unwrap_or(&self.meta.name.clone()),
+                                       if self.meta.bin_name.is_some() {
+                                           " "
+                                       } else {
+                                           ""
+                                       },
+                                       &*sc.p.meta.name);
+                debugln!("Parser::build_bin_names:iter: Setting bin_name of {} to {}",
+                         self.meta.name,
+                         bin_name);
                 sc.p.meta.bin_name = Some(bin_name);
             } else {
                 sdebugln!("yes ({:?})", sc.p.meta.bin_name);
             }
-            debugln!("Parser::build_bin_names:iter: Calling build_bin_names from...{}", sc.p.meta.name);
+            debugln!("Parser::build_bin_names:iter: Calling build_bin_names from...{}",
+                     sc.p.meta.name);
             sc.p.build_bin_names();
         }
     }
 
     fn parse_subcommand<I, T>(&mut self,
                               sc_name: &str,
                               matcher: &mut ArgMatcher<'a>,
                               it: &mut Peekable<I>)
                               -> ClapResult<()>
         where I: Iterator<Item = T>,
               T: Into<OsString> + Clone
     {
         use std::fmt::Write;
         debugln!("Parser::parse_subcommand;");
         let mut mid_string = String::new();
-        if !self.settings.is_set(AppSettings::SubcommandsNegateReqs) {
+        if !self.is_set(AS::SubcommandsNegateReqs) {
             let mut hs: Vec<&str> = self.required.iter().map(|n| &**n).collect();
             for k in matcher.arg_names() {
                 hs.push(k);
             }
-            let reqs = self.get_required_from(&hs, Some(matcher), None);
+            let reqs = usage::get_required_usage_from(self, &hs, Some(matcher), None, false);
 
             for s in &reqs {
                 write!(&mut mid_string, " {}", s).expect(INTERNAL_ERROR_MSG);
             }
         }
         mid_string.push_str(" ");
         if let Some(ref mut sc) = self.subcommands
-            .iter_mut()
-            .find(|s| &s.p.meta.name == &sc_name) {
+               .iter_mut()
+               .find(|s| &s.p.meta.name == &sc_name) {
             let mut sc_matcher = ArgMatcher::new();
             // bin_name should be parent's bin_name + [<reqs>] + the sc's name separated by
             // a space
             sc.p.meta.usage = Some(format!("{}{}{}",
                                            self.meta.bin_name.as_ref().unwrap_or(&String::new()),
                                            if self.meta.bin_name.is_some() {
                                                &*mid_string
                                            } else {
                                                ""
                                            },
                                            &*sc.p.meta.name));
-            sc.p.meta.bin_name = Some(format!("{}{}{}",
-                                              self.meta
-                                                  .bin_name
-                                                  .as_ref()
-                                                  .unwrap_or(&String::new()),
-                                              if self.meta.bin_name.is_some() {
-                                                  " "
-                                              } else {
-                                                  ""
-                                              },
-                                              &*sc.p.meta.name));
-            debugln!("Parser::parse_subcommand: About to parse sc={}", sc.p.meta.name);
+            sc.p.meta.bin_name =
+                Some(format!("{}{}{}",
+                             self.meta.bin_name.as_ref().unwrap_or(&String::new()),
+                             if self.meta.bin_name.is_some() {
+                                 " "
+                             } else {
+                                 ""
+                             },
+                             &*sc.p.meta.name));
+            debugln!("Parser::parse_subcommand: About to parse sc={}",
+                     sc.p.meta.name);
             debugln!("Parser::parse_subcommand: sc settings={:#?}", sc.p.settings);
             try!(sc.p.get_matches_with(&mut sc_matcher, it));
             matcher.subcommand(SubCommand {
-                name: sc.p.meta.name.clone(),
-                matches: sc_matcher.into(),
-            });
+                                   name: sc.p.meta.name.clone(),
+                                   matches: sc_matcher.into(),
+                               });
         }
         Ok(())
     }
 
-
-    fn groups_for_arg(&self, name: &str) -> Option<Vec<&'a str>> {
+    pub fn groups_for_arg(&self, name: &str) -> Option<Vec<&'a str>> {
         debugln!("Parser::groups_for_arg: name={}", name);
 
         if self.groups.is_empty() {
             debugln!("Parser::groups_for_arg: No groups defined");
             return None;
         }
         let mut res = vec![];
         debugln!("Parser::groups_for_arg: Searching through groups...");
-        for (gn, grp) in &self.groups {
+        for grp in &self.groups {
             for a in &grp.args {
                 if a == &name {
-                    sdebugln!("\tFound '{}'", gn);
-                    res.push(*gn);
+                    sdebugln!("\tFound '{}'", grp.name);
+                    res.push(&*grp.name);
                 }
             }
         }
         if res.is_empty() {
             return None;
         }
 
         Some(res)
     }
 
-    fn args_in_group(&self, group: &str) -> Vec<String> {
+    pub fn args_in_group(&self, group: &str) -> Vec<String> {
         let mut g_vec = vec![];
         let mut args = vec![];
 
-        for n in &self.groups[group].args {
+        for n in &self.groups
+                      .iter()
+                      .find(|g| g.name == group)
+                      .expect(INTERNAL_ERROR_MSG)
+                      .args {
             if let Some(f) = self.flags.iter().find(|f| &f.b.name == n) {
                 args.push(f.to_string());
             } else if let Some(f) = self.opts.iter().find(|o| &o.b.name == n) {
                 args.push(f.to_string());
-            } else if self.groups.contains_key(&**n) {
+            } else if let Some(p) = self.positionals.values().find(|p| &p.b.name == n) {
+                args.push(p.b.name.to_owned());
+            } else {
                 g_vec.push(*n);
-            } else if let Some(p) = self.positionals
-                .values()
-                .find(|p| &p.b.name == n) {
-                args.push(p.b.name.to_owned());
             }
         }
 
         for av in g_vec.iter().map(|g| self.args_in_group(g)) {
             args.extend(av);
         }
         args.dedup();
         args.iter().map(ToOwned::to_owned).collect()
     }
 
-    fn arg_names_in_group(&self, group: &str) -> Vec<&'a str> {
+    pub fn arg_names_in_group(&self, group: &str) -> Vec<&'a str> {
         let mut g_vec = vec![];
         let mut args = vec![];
 
-        for n in &self.groups[group].args {
-            if self.groups.contains_key(&*n) {
+        for n in &self.groups
+                      .iter()
+                      .find(|g| g.name == group)
+                      .expect(INTERNAL_ERROR_MSG)
+                      .args {
+            if self.groups.iter().any(|g| &g.name == &*n) {
+                args.extend(self.arg_names_in_group(n));
                 g_vec.push(*n);
             } else {
-                args.push(*n);
+                if !args.contains(n) {
+                    args.push(*n);
+                }
             }
         }
 
-        for av in g_vec.iter().map(|g| self.arg_names_in_group(g)) {
-            args.extend(av);
-        }
-        args.dedup();
         args.iter().map(|s| *s).collect()
     }
 
     pub fn create_help_and_version(&mut self) {
         debugln!("Parser::create_help_and_version;");
         // name is "hclap_help" because flags are sorted by name
-        if self.is_set(AppSettings::NeedsLongHelp) {
+        if !self.contains_long("help") {
             debugln!("Parser::create_help_and_version: Building --help");
-            if self.help_short.is_none() && !self.short_list.contains(&'h') {
+            if self.help_short.is_none() && !self.contains_short('h') {
                 self.help_short = Some('h');
             }
-            let id = self.flags.len();
             let arg = FlagBuilder {
                 b: Base {
                     name: "hclap_help",
-                    help: Some("Prints help information"),
-                    id: id,
+                    help: self.help_message.or(Some("Prints help information")),
                     ..Default::default()
                 },
                 s: Switched {
                     short: self.help_short,
                     long: Some("help"),
                     ..Default::default()
                 },
             };
-            if let Some(h) = self.help_short {
-                self.short_list.push(h);
-            }
-            self.long_list.push("help");
-            self.flags.insert(id, arg);
+            self.flags.push(arg);
         }
-        if !self.settings.is_set(AppSettings::DisableVersion) &&
-           self.is_set(AppSettings::NeedsLongVersion) {
+        if !self.is_set(AS::DisableVersion) && !self.contains_long("version") {
             debugln!("Parser::create_help_and_version: Building --version");
-            if self.version_short.is_none() && !self.short_list.contains(&'V') {
+            if self.version_short.is_none() && !self.contains_short('V') {
                 self.version_short = Some('V');
             }
-            let id = self.flags.len();
             // name is "vclap_version" because flags are sorted by name
             let arg = FlagBuilder {
                 b: Base {
                     name: "vclap_version",
-                    help: Some("Prints version information"),
-                    id: id,
+                    help: self.version_message.or(Some("Prints version information")),
                     ..Default::default()
                 },
                 s: Switched {
                     short: self.version_short,
                     long: Some("version"),
                     ..Default::default()
                 },
             };
-            if let Some(v) = self.version_short {
-                self.short_list.push(v);
-            }
-            self.long_list.push("version");
-            self.flags.insert(id, arg);
+            self.flags.push(arg);
         }
-        if !self.subcommands.is_empty() && !self.is_set(AppSettings::DisableHelpSubcommand) &&
-           self.is_set(AppSettings::NeedsSubcommandHelp) {
+        if !self.subcommands.is_empty() && !self.is_set(AS::DisableHelpSubcommand) &&
+           self.is_set(AS::NeedsSubcommandHelp) {
             debugln!("Parser::create_help_and_version: Building help");
             self.subcommands
                 .push(App::new("help")
-                    .about("Prints this message or the help of the given subcommand(s)"));
+                          .about("Prints this message or the help of the given subcommand(s)"));
         }
     }
 
     // Retrieves the names of all args the user has supplied thus far, except required ones
     // because those will be listed in self.required
-    pub fn create_current_usage(&self, matcher: &'b ArgMatcher<'a>, extra: Option<&str>) -> String {
-        let mut args: Vec<_> = matcher.arg_names()
-            .iter()
-            .filter(|n| {
-                if let Some(o) = find_by_name!(self, *n, opts, iter) {
-                    !o.b.settings.is_set(ArgSettings::Required)
-                } else if let Some(p) = find_by_name!(self, *n, positionals, values) {
-                    !p.b.settings.is_set(ArgSettings::Required)
-                } else {
-                    true // flags can't be required, so they're always true
-                }
-            })
-            .map(|&n| n)
-            .collect();
-        if let Some(r) = extra {
-            args.push(r);
-        }
-        self.create_usage(&*args)
-    }
-
     fn check_for_help_and_version_str(&self, arg: &OsStr) -> ClapResult<()> {
         debugln!("Parser::check_for_help_and_version_str;");
         debug!("Parser::check_for_help_and_version_str: Checking if --{} is help or version...",
                arg.to_str().unwrap());
-        if arg == "help" && self.settings.is_set(AppSettings::NeedsLongHelp) {
+        if arg == "help" && self.is_set(AS::NeedsLongHelp) {
             sdebugln!("Help");
-            try!(self._help());
+            return Err(self._help(true));
         }
-        if arg == "version" && self.settings.is_set(AppSettings::NeedsLongVersion) {
+        if arg == "version" && self.is_set(AS::NeedsLongVersion) {
             sdebugln!("Version");
-            try!(self._version());
+            return Err(self._version(true));
         }
         sdebugln!("Neither");
 
         Ok(())
     }
 
     fn check_for_help_and_version_char(&self, arg: char) -> ClapResult<()> {
         debugln!("Parser::check_for_help_and_version_char;");
-        debug!("Parser::check_for_help_and_version_char: Checking if -{} is help or version...", arg);
+        debug!("Parser::check_for_help_and_version_char: Checking if -{} is help or version...",
+               arg);
         if let Some(h) = self.help_short {
-            if arg == h && self.settings.is_set(AppSettings::NeedsLongHelp) {
+            if arg == h && self.is_set(AS::NeedsLongHelp) {
                 sdebugln!("Help");
-                try!(self._help());
+                return Err(self._help(false));
             }
         }
         if let Some(v) = self.version_short {
-            if arg == v && self.settings.is_set(AppSettings::NeedsLongVersion) {
+            if arg == v && self.is_set(AS::NeedsLongVersion) {
                 sdebugln!("Version");
-                try!(self._version());
+                return Err(self._version(false));
             }
         }
         sdebugln!("Neither");
         Ok(())
     }
 
-    fn _help(&self) -> ClapResult<()> {
+    fn use_long_help(&self) -> bool {
+        let ul = self.flags.iter().any(|f| f.b.long_help.is_some()) ||
+                 self.opts.iter().any(|o| o.b.long_help.is_some()) ||
+                 self.positionals.values().any(|p| p.b.long_help.is_some()) ||
+                 self.subcommands
+                     .iter()
+                     .any(|s| s.p.meta.long_about.is_some());
+        debugln!("Parser::use_long_help: ret={:?}", ul);
+        ul
+    }
+
+    fn _help(&self, mut use_long: bool) -> Error {
+        debugln!("Parser::_help: use_long={:?}", use_long);
+        use_long = use_long && self.use_long_help();
         let mut buf = vec![];
-        try!(Help::write_parser_help(&mut buf, self));
-        Err(Error {
+        match Help::write_parser_help(&mut buf, self, use_long) {
+            Err(e) => return e,
+            _ => (),
+        }
+        Error {
             message: unsafe { String::from_utf8_unchecked(buf) },
             kind: ErrorKind::HelpDisplayed,
             info: None,
-        })
+        }
     }
 
-    fn _version(&self) -> ClapResult<()> {
+    fn _version(&self, use_long: bool) -> Error {
+        debugln!("Parser::_version: ");
         let out = io::stdout();
         let mut buf_w = BufWriter::new(out.lock());
-        try!(self.print_version(&mut buf_w));
-        Err(Error {
+        match self.print_version(&mut buf_w, use_long) {
+            Err(e) => return e,
+            _ => (),
+        }
+        Error {
             message: String::new(),
             kind: ErrorKind::VersionDisplayed,
             info: None,
-        })
+        }
     }
 
     fn parse_long_arg(&mut self,
                       matcher: &mut ArgMatcher<'a>,
                       full_arg: &OsStr)
-                      -> ClapResult<Option<&'a str>> {
+                      -> ClapResult<ParseResult<'a>> {
         // maybe here lifetime should be 'a
         debugln!("Parser::parse_long_arg;");
         let mut val = None;
         debug!("Parser::parse_long_arg: Does it contain '='...");
         let arg = if full_arg.contains_byte(b'=') {
             let (p0, p1) = full_arg.trim_left_matches(b'-').split_at_byte(b'=');
             sdebugln!("Yes '{:?}'", p1);
             val = Some(p1);
             p0
         } else {
             sdebugln!("No");
             full_arg.trim_left_matches(b'-')
         };
 
-        if let Some(opt) = find_by_long!(self, &arg, opts) {
-            debugln!("Parser::parse_long_arg: Found valid opt '{}'", opt.to_string());
-            self.valid_arg = true;
-            let ret = try!(self.parse_opt(val, opt, matcher));
-            arg_post_processing!(self, opt, matcher);
+        if let Some(opt) = find_opt_by_long!(@os self, &arg) {
+            debugln!("Parser::parse_long_arg: Found valid opt '{}'",
+                     opt.to_string());
+            self.settings.set(AS::ValidArgFound);
+            let ret = try!(self.parse_opt(val, opt, val.is_some(), matcher));
+            if self.cache.map_or(true, |name| name != opt.b.name) {
+                arg_post_processing!(self, opt, matcher);
+                self.cache = Some(opt.b.name);
+            }
 
             return Ok(ret);
-        } else if let Some(flag) = find_by_long!(self, &arg, flags) {
-            debugln!("Parser::parse_long_arg: Found valid flag '{}'", flag.to_string());
-            self.valid_arg = true;
+        } else if let Some(flag) = find_flag_by_long!(@os self, &arg) {
+            debugln!("Parser::parse_long_arg: Found valid flag '{}'",
+                     flag.to_string());
+            self.settings.set(AS::ValidArgFound);
             // Only flags could be help or version, and we need to check the raw long
             // so this is the first point to check
             try!(self.check_for_help_and_version_str(arg));
 
             try!(self.parse_flag(flag, matcher));
 
             // Handle conflicts, requirements, etc.
+            // if self.cache.map_or(true, |name| name != flag.b.name) {
             arg_post_processing!(self, flag, matcher);
+            // self.cache = Some(flag.b.name);
+            // }
 
-            return Ok(None);
-        } else if self.is_set(AppSettings::AllowLeadingHyphen) {
-            return Ok(None);
-        } else if self.valid_neg_num {
-            return Ok(None);
+            return Ok(ParseResult::Flag);
+        } else if self.is_set(AS::AllowLeadingHyphen) {
+            return Ok(ParseResult::MaybeHyphenValue);
+        } else if self.is_set(AS::ValidNegNumFound) {
+            return Ok(ParseResult::MaybeNegNum);
         }
 
         debugln!("Parser::parse_long_arg: Didn't match anything");
-        self.did_you_mean_error(arg.to_str().expect(INVALID_UTF8), matcher).map(|_| None)
+        self.did_you_mean_error(arg.to_str().expect(INVALID_UTF8), matcher)
+            .map(|_| ParseResult::NotFound)
     }
 
+    #[cfg_attr(feature = "lints", allow(len_zero))]
     fn parse_short_arg(&mut self,
                        matcher: &mut ArgMatcher<'a>,
                        full_arg: &OsStr)
-                       -> ClapResult<Option<&'a str>> {
-        debugln!("Parser::parse_short_arg;");
-        // let mut utf8 = true;
+                       -> ClapResult<ParseResult<'a>> {
+        debugln!("Parser::parse_short_arg: full_arg={:?}", full_arg);
         let arg_os = full_arg.trim_left_matches(b'-');
         let arg = arg_os.to_string_lossy();
 
-        // If AllowLeadingHyphen is set, we want to ensure `-val` gets parsed as `-val` and not `-v` `-a` `-l` assuming
-        // `v` `a` and `l` are all, or mostly, valid shorts.
-        if self.is_set(AppSettings::AllowLeadingHyphen) {
-            let mut good = true;
-            for c in arg.chars() {
-                good = self.short_list.contains(&c);
+        // If AllowLeadingHyphen is set, we want to ensure `-val` gets parsed as `-val` and not
+        // `-v` `-a` `-l` assuming `v` `a` and `l` are all, or mostly, valid shorts.
+        if self.is_set(AS::AllowLeadingHyphen) {
+            if arg.chars().any(|c| !self.contains_short(c)) {
+                debugln!("Parser::parse_short_arg: LeadingHyphenAllowed yet -{} isn't valid",
+                         arg);
+                return Ok(ParseResult::MaybeHyphenValue);
             }
-            if !good {
-                return Ok(None);
-            }
-        } else if self.valid_neg_num {
+        } else if self.is_set(AS::ValidNegNumFound) {
             // TODO: Add docs about having AllowNegativeNumbers and `-2` as a valid short
             // May be better to move this to *after* not finding a vali