Merge m-c to inbound, a=merge
authorWes Kocher <wkocher@mozilla.com>
Mon, 28 Mar 2016 13:08:22 -0700
changeset 290758 b1d8eaeee18bfbe86d0ac4130dd92e42d47f5def
parent 290757 3eca091288e47d48edf843f9e73799d77e60362e (current diff)
parent 290704 a66bf0a800f3d859b4bd2ceebc57b2e3fa6544d8 (diff)
child 290759 67e4eb38e3b818ab71bcfa170cab353b05c39a98
push id19656
push usergwagner@mozilla.com
push dateMon, 04 Apr 2016 13:43:23 +0000
treeherderb2g-inbound@e99061fde28a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone48.0a1
Merge m-c to inbound, a=merge MozReview-Commit-ID: 42S5ImydrHw
devtools/client/performance/modules/logic/marker-utils.js
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_windowtitle.js
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_windowtitle.js
@@ -21,46 +21,46 @@ add_task(function test() {
   let pb_page_without_title;
   let pb_about_pb_title;
   if (isOSX) {
     page_with_title = test_title;
     page_without_title = app_name;
     about_pb_title = "Open a private window?";
     pb_page_with_title = test_title + " - (Private Browsing)";
     pb_page_without_title = app_name + " - (Private Browsing)";
-    pb_about_pb_title = "You're browsing privately - (Private Browsing)";
+    pb_about_pb_title = "You\u2019re browsing privately - (Private Browsing)";
   }
   else {
     page_with_title = test_title + " - " + app_name;
     page_without_title = app_name;
     about_pb_title = "Open a private window?" + " - " + app_name;
     pb_page_with_title = test_title + " - " + app_name + " (Private Browsing)";
     pb_page_without_title = app_name + " (Private Browsing)";
-    pb_about_pb_title = "You're browsing privately - " + app_name + " (Private Browsing)";
+    pb_about_pb_title = "You\u2019re browsing privately - " + app_name + " (Private Browsing)";
   }
 
   function* testTabTitle(aWindow, url, insidePB, expected_title) {
     let tab = (yield BrowserTestUtils.openNewForegroundTab(aWindow.gBrowser));
     yield BrowserTestUtils.loadURI(tab.linkedBrowser, url);
     yield BrowserTestUtils.browserLoaded(tab.linkedBrowser);
 
     yield BrowserTestUtils.waitForCondition(() => {
       return aWindow.document.title === expected_title;
-    });
+    }, `Window title should be ${expected_title}, got ${aWindow.document.title}`);
 
     is(aWindow.document.title, expected_title, "The window title for " + url +
        " is correct (" + (insidePB ? "inside" : "outside") +
        " private browsing mode)");
 
     let win = aWindow.gBrowser.replaceTabWithWindow(tab);
     yield BrowserTestUtils.waitForEvent(win, "load", false);
 
     yield BrowserTestUtils.waitForCondition(() => {
       return win.document.title === expected_title;
-    });
+    }, `Window title should be ${expected_title}, got ${aWindow.document.title}`);
 
     is(win.document.title, expected_title, "The window title for " + url +
        " detached tab is correct (" + (insidePB ? "inside" : "outside") +
        " private browsing mode)");
 
     yield Promise.all([ BrowserTestUtils.closeWindow(win),
                         BrowserTestUtils.closeWindow(aWindow) ]);
   }
--- a/browser/locales/en-US/chrome/browser/aboutCertError.dtd
+++ b/browser/locales/en-US/chrome/browser/aboutCertError.dtd
@@ -21,18 +21,18 @@ was trying to connect. -->
 <!ENTITY certerror.learnMore "Learn more…">
 <!ENTITY certerror.advanced.label "Advanced">
 
 <!ENTITY certerror.whatShouldIDo.badStsCertExplanation "This site uses HTTP
 Strict Transport Security (HSTS) to specify that &brandShortName; only connect
 to it securely. As a result, it is not possible to add an exception for this
 certificate.">
 
-<!ENTITY certerror.expert.content "If you understand what's going on, you
-can tell &brandShortName; to start trusting this site's identification.
+<!ENTITY certerror.expert.content "If you understand what’s going on, you
+can tell &brandShortName; to start trusting this site’s identification.
 <b>Even if you trust the site, this error could mean that someone is
 tampering with your connection.</b>">
-<!ENTITY certerror.expert.contentPara2 "Don't add an exception unless
-you know there's a good reason why this site doesn't use trusted identification.">
+<!ENTITY certerror.expert.contentPara2 "Don’t add an exception unless
+you know there’s a good reason why this site doesn’t use trusted identification.">
 <!ENTITY certerror.addException.label "Add Exception…">
 <!ENTITY certerror.copyToClipboard.label "Copy text to clipboard">
 
 <!ENTITY errorReporting.automatic "Report errors like this to help Mozilla identify misconfigured sites">
--- a/browser/locales/en-US/chrome/browser/aboutDialog.dtd
+++ b/browser/locales/en-US/chrome/browser/aboutDialog.dtd
@@ -41,17 +41,17 @@
 <!ENTITY helpus.start               "Want to help? ">
 <!-- LOCALIZATION NOTE (helpus.donateLink): This is a link title that links to https://sendto.mozilla.org/page/contribute/Give-Now?source=mozillaorg_default_footer&ref=firefox_about&utm_campaign=firefox_about&utm_source=firefox&utm_medium=referral&utm_content=20140929_FireFoxAbout. -->
 <!ENTITY helpus.donateLink          "Make a donation">
 <!ENTITY helpus.middle              " or ">
 <!-- LOCALIZATION NOTE (helpus.getInvolvedLink): This is a link title that links to http://www.mozilla.org/contribute/. -->
 <!ENTITY helpus.getInvolvedLink     "get involved!">
 <!ENTITY helpus.end                 "">
 
-<!ENTITY releaseNotes.link          "What's new">
+<!ENTITY releaseNotes.link          "What’s new">
 
 <!-- LOCALIZATION NOTE (bottomLinks.license): This is a link title that links to about:license. -->
 <!ENTITY bottomLinks.license        "Licensing Information">
 
 <!-- LOCALIZATION NOTE (bottomLinks.rights): This is a link title that links to about:rights. -->
 <!ENTITY bottomLinks.rights         "End-User Rights">
 
 <!-- LOCALIZATION NOTE (bottomLinks.privacy): This is a link title that links to https://www.mozilla.org/legal/privacy/. -->
--- a/browser/locales/en-US/chrome/browser/aboutHome.dtd
+++ b/browser/locales/en-US/chrome/browser/aboutHome.dtd
@@ -13,17 +13,17 @@
 
 <!-- LOCALIZATION NOTE (abouthome.defaultSnippet1.v1):
      text in <a/> will be linked to the Firefox features page on mozilla.com
 -->
 <!ENTITY abouthome.defaultSnippet1.v1 "Thanks for choosing Firefox! To get the most out of your browser, learn more about the <a>latest features</a>.">
 <!-- LOCALIZATION NOTE (abouthome.defaultSnippet2.v1):
      text in <a/> will be linked to the featured add-ons on addons.mozilla.org
 -->
-<!ENTITY abouthome.defaultSnippet2.v1 "It's easy to customize your Firefox exactly the way you want it. <a>Choose from thousands of add-ons</a>.">
+<!ENTITY abouthome.defaultSnippet2.v1 "It’s easy to customize your Firefox exactly the way you want it. <a>Choose from thousands of add-ons</a>.">
 <!-- LOCALIZATION NOTE (abouthome.rightsSnippet): text in <a/> will be linked to about:rights -->
 <!ENTITY abouthome.rightsSnippet "&brandFullName; is free and open source software from the non-profit Mozilla Foundation. <a>Know your rights…</a>">
 
 <!ENTITY abouthome.bookmarksButton.label "Bookmarks">
 <!ENTITY abouthome.historyButton.label   "History">
 <!-- LOCALIZATION NOTE (abouthome.preferencesButtonWin.label): The label for the
      preferences/options item on about:home on Windows -->
 <!ENTITY abouthome.preferencesButtonWin.label  "Options">
--- a/browser/locales/en-US/chrome/browser/aboutPrivateBrowsing.dtd
+++ b/browser/locales/en-US/chrome/browser/aboutPrivateBrowsing.dtd
@@ -10,17 +10,17 @@
 
 <!-- LOCALIZATION NOTE (aboutPrivateBrowsing.width1):
      Width of the Private Browsing section. This should depend primarily on the
      length of the headers and text, but should be roughly 1.5 times the width
      of the Tracking Protection section, and in general not much larger than
      30em to prevent the sections from wrapping on smaller window sizes.
      -->
 <!ENTITY aboutPrivateBrowsing.width1           "30em">
-<!ENTITY aboutPrivateBrowsing.title            "You're browsing privately">
+<!ENTITY aboutPrivateBrowsing.title            "You’re browsing privately">
 
 <!ENTITY aboutPrivateBrowsing.info.notsaved    "Not Saved">
 <!ENTITY aboutPrivateBrowsing.info.history     "History">
 <!ENTITY aboutPrivateBrowsing.info.searches    "Searches">
 <!ENTITY aboutPrivateBrowsing.info.cookies     "Cookies">
 <!ENTITY aboutPrivateBrowsing.info.temporaryFiles "Temporary Files">
 
 <!ENTITY aboutPrivateBrowsing.info.saved       "Saved">
--- a/browser/locales/en-US/chrome/browser/aboutPrivateBrowsing.properties
+++ b/browser/locales/en-US/chrome/browser/aboutPrivateBrowsing.properties
@@ -1,6 +1,6 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-title=You're browsing privately
+title=You’re browsing privately
 title.normal=Open a private window?
--- a/browser/locales/en-US/chrome/browser/aboutRobots.dtd
+++ b/browser/locales/en-US/chrome/browser/aboutRobots.dtd
@@ -10,20 +10,20 @@
 <!-- Nonsense line from the movie "The Day The Earth Stood Still". No translation needed. -->
 <!ENTITY robots.pagetitle  "Gort! Klaatu barada nikto!">
 <!-- Movie: Logan's Run... Box (cybog): "Welcome Humans! I am ready for you." -->
 <!ENTITY robots.errorTitleText "Welcome Humans!">
 <!-- Movie: The Day The Earth Stood Still. Spoken by Klaatu. -->
 <!ENTITY robots.errorShortDescText "We have come to visit you in peace and with goodwill!">
 <!-- Various books by Isaac Asimov. http://en.wikipedia.org/wiki/Three_Laws_of_Robotics -->
 <!ENTITY robots.errorLongDesc1 "Robots may not injure a human being or, through inaction, allow a human being to come to harm.">
-<!-- Movie: Blade Runner. Batty: "I've seen things you people wouldn't believe..." -->
-<!ENTITY robots.errorLongDesc2 "Robots have seen things you people wouldn't believe.">
-<!-- Book: Hitchhiker's Guide To The Galaxy. What the Sirius Cybernetics Corporation calls robots. -->
-<!ENTITY robots.errorLongDesc3 "Robots are Your Plastic Pal Who's Fun To Be With.">
+<!-- Movie: Blade Runner. Batty: "I've seen things you people wouldn’t believe..." -->
+<!ENTITY robots.errorLongDesc2 "Robots have seen things you people wouldn’t believe.">
+<!-- Book: Hitchhiker’s Guide To The Galaxy. What the Sirius Cybernetics Corporation calls robots. -->
+<!ENTITY robots.errorLongDesc3 "Robots are Your Plastic Pal Who’s Fun To Be With.">
 <!-- TV: Futurama. Bender's first line is "Bite my shiny metal ass." -->
 <!ENTITY robots.errorLongDesc4 "Robots have shiny metal posteriors which should not be bitten.">
 <!-- TV: Battlestar Galactica (2004 series). From the opening text. -->
 <!ENTITY robots.errorTrailerDescText "And they have a plan.">
 <!-- TV: Battlestar Galactica (2004 series). Common expletive referring to Cylons. -->
 <!ENTITY robots.imgtitle "Frakkin' Toasters">
 <!-- Book: Hitchhiker's Guide To The Galaxy. Arthur presses a button and it warns him. -->
 <!ENTITY robots.dontpress "Please do not press this button again.">
--- a/browser/locales/en-US/chrome/browser/aboutSessionRestore.dtd
+++ b/browser/locales/en-US/chrome/browser/aboutSessionRestore.dtd
@@ -21,17 +21,17 @@
 <!ENTITY restorepage.listHeader     "Windows and Tabs">
 <!-- LOCALIZATION NOTE: &#37;S will be replaced with a number. -->
 <!ENTITY restorepage.windowLabel    "Window &#37;S">
 
 
 <!-- LOCALIZATION NOTE: The following 'welcomeback2' strings are for about:welcomeback,
      not for about:sessionstore -->
 
-<!ENTITY welcomeback2.restoreButton  "Let's go!">
+<!ENTITY welcomeback2.restoreButton  "Let’s go!">
 <!ENTITY welcomeback2.restoreButton.access "L">
 
 <!ENTITY welcomeback2.tabtitle      "Success!">
 
 <!ENTITY welcomeback2.pageTitle     "Success!">
 <!ENTITY welcomeback2.pageInfo1     "&brandShortName; is ready to go.">
 
 <!ENTITY welcomeback2.label.restoreAll  "Restore all Windows and Tabs">
@@ -39,22 +39,22 @@
 
 
 <!-- LOCALIZATION NOTE (welcomeback2.beforelink.pageInfo2,
 welcomeback2.afterlink.pageInfo2): these two string are used respectively
 before and after the the "learn more" link (welcomeback2.link.pageInfo2).
 Localizers can use one of them, or both, to better adapt this sentence to
 their language.
 -->
-<!ENTITY welcomeback2.beforelink.pageInfo2  "Your add-ons and customizations have been removed and your browser settings have been restored to their defaults. If this didn't fix your issue, ">
+<!ENTITY welcomeback2.beforelink.pageInfo2  "Your add-ons and customizations have been removed and your browser settings have been restored to their defaults. If this didn’t fix your issue, ">
 <!ENTITY welcomeback2.afterlink.pageInfo2   "">
 
 <!ENTITY welcomeback2.link.pageInfo2        "learn more about what you can do.">
 
 <!-- LOCALIZATION NOTE: The following 'tabgroupsmigration' strings are for
      the tab groups (panorama) migration page, not about:sessionrestore -->
 <!ENTITY tabgroupsmigration.tabtitle            "Migrate your other Tab Groups">
-<!ENTITY tabgroupsmigration.pagetitle2          "We've removed Tab Groups, but saved your tabs">
+<!ENTITY tabgroupsmigration.pagetitle2          "We’ve removed Tab Groups, but saved your tabs">
 <!ENTITY tabgroupsmigration.learnaboutaddons    "Learn about Tab Groups replacement add-ons.">
-<!ENTITY tabgroupsmigration.description2        "&brandShortName; has bookmarked all your groups so you haven't lost anything.">
+<!ENTITY tabgroupsmigration.description2        "&brandShortName; has bookmarked all your groups so you haven’t lost anything.">
 <!ENTITY tabgroupsmigration.bookmarkbutton      "Show Bookmarked Tab Groups">
 <!ENTITY tabgroupsmigration.restoredescription  "You can also choose to restore some or all background groups into windows now:">
 
--- a/browser/locales/en-US/chrome/browser/accounts.properties
+++ b/browser/locales/en-US/chrome/browser/accounts.properties
@@ -1,15 +1,15 @@
 # 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/.
 
 # autoDisconnectDescription is shown in an info bar when we detect an old
 # Sync is being used.
-autoDisconnectDescription = We've rebuilt Sync to make it easier for everyone.
+autoDisconnectDescription = We’ve rebuilt Sync to make it easier for everyone.
 
 # autoDisconnectSignIn.label and .accessKey are for buttons when we auto-disconnect
 autoDisconnectSignIn.label = Sign in to Sync
 autoDisconnectSignIn.accessKey = S
 
 # LOCALIZATION NOTE (reconnectDescription) - %S = Email address of user's Firefox Account
 reconnectDescription = Reconnect %S
 
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -760,17 +760,17 @@ you can use these alternative items. Oth
 <!ENTITY identity.passiveLoaded "Parts of this page are not secure (such as images).">
 <!ENTITY identity.activeLoaded "You have disabled protection on this page.">
 <!ENTITY identity.weakEncryption "This page uses weak encryption.">
 
 <!-- Strings for connection state warnings in the subview. -->
 <!ENTITY identity.description.insecure "Your connection to this site is not private. Information you submit could be viewed by others (like passwords, messages, credit cards, etc.).">
 <!ENTITY identity.description.insecureLoginForms "The login information you enter on this page is not secure and could be compromised.">
 <!ENTITY identity.description.weakCipher "Your connection to this website uses weak encryption and is not private.">
-<!ENTITY identity.description.weakCipher2 "Other people can view your information or modify the website's behavior.">
+<!ENTITY identity.description.weakCipher2 "Other people can view your information or modify the website’s behavior.">
 <!ENTITY identity.description.activeBlocked "&brandShortName; has blocked parts of this page that are not secure.">
 <!ENTITY identity.description.passiveLoaded "Your connection is not private and information you share with the site could be viewed by others.">
 <!ENTITY identity.description.passiveLoaded2 "This website contains content that is not secure (such as images).">
 <!ENTITY identity.description.passiveLoaded3 "Although &brandShortName; has blocked some content, there is still content on the page that is not secure (such as images).">
 <!ENTITY identity.description.activeLoaded "This website contains content that is not secure (such as scripts) and your connection to it is not private.">
 <!ENTITY identity.description.activeLoaded2 "Information you share with this site could be viewed by others (like passwords, messages, credit cards, etc.).">
 
 <!ENTITY identity.enableMixedContentBlocking.label "Enable protection">
--- a/browser/locales/en-US/chrome/browser/browser.properties
+++ b/browser/locales/en-US/chrome/browser/browser.properties
@@ -128,18 +128,18 @@ lwthemeNeedsRestart.accesskey=R
 # #1 is brandShortName and #2 is the number of pop-ups blocked.
 popupWarning.message=#1 prevented this site from opening a pop-up window.;#1 prevented this site from opening #2 pop-up windows.
 popupWarningButton=Options
 popupWarningButton.accesskey=O
 popupWarningButtonUnix=Preferences
 popupWarningButtonUnix.accesskey=P
 popupAllow=Allow pop-ups for %S
 popupBlock=Block pop-ups for %S
-popupWarningDontShowFromMessage=Don't show this message when pop-ups are blocked
-popupWarningDontShowFromLocationbar=Don't show info bar when pop-ups are blocked
+popupWarningDontShowFromMessage=Don’t show this message when pop-ups are blocked
+popupWarningDontShowFromLocationbar=Don’t show info bar when pop-ups are blocked
 popupShowPopupPrefix=Show '%S'
 
 # Bad Content Blocker Doorhanger Notification
 # %S is brandShortName
 badContentBlocked.blocked.message=%S is blocking content on this page.
 badContentBlocked.notblocked.message=%S is not blocking any content on this page.
 
 crashedpluginsMessage.title=The %S plugin has crashed.
@@ -173,17 +173,17 @@ pluginActivate.learnMore=Learn More…
 pluginActivateOutdated.message=%3$S has prevented the outdated plugin "%1$S" from running on %2$S.
 pluginActivateOutdated.label=Outdated plugin
 pluginActivate.updateLabel=Update now…
 # LOCALIZATION NOTE (pluginActivateVulnerable.message, pluginActivateVulnerable.label):
 # These strings are used when an unsafe plugin has no update available.
 # %1$S is the plugin name, %2$S is the domain, and %3$S is brandShortName.
 pluginActivateVulnerable.message=%3$S has prevented the unsafe plugin "%1$S" from running on %2$S.
 pluginActivateVulnerable.label=Vulnerable plugin!
-pluginActivate.riskLabel=What's the risk?
+pluginActivate.riskLabel=What’s the risk?
 # LOCALIZATION NOTE (pluginActivateBlocked.message): %1$S is the plugin name, %2$S is brandShortName
 pluginActivateBlocked.message=%2$S has blocked "%1$S" for your protection.
 pluginActivateBlocked.label=Blocked for your protection
 pluginActivateDisabled.message="%S" is disabled.
 pluginActivateDisabled.label=Disabled
 pluginActivateDisabled.manage=Manage plugins…
 pluginEnabled.message="%S" is enabled on %S.
 pluginEnabledOutdated.message=Outdated plugin "%S" is enabled on %S.
@@ -361,17 +361,17 @@ pu.notifyButton.accesskey=D
 # LOCALIZATION NOTE %S will be replaced by the short name of the application.
 puNotifyText=%S has been updated
 puAlertTitle=%S Updated
 puAlertText=Click here for details
 
 # Geolocation UI
 
 # LOCALIZATION NOTE (geolocation.shareLocation geolocation.alwaysShareLocation geolocation.neverShareLocation):
-#If you're having trouble with the word Share, please use Allow and Block in your language.
+# If you're having trouble with the word Share, please use Allow and Block in your language.
 geolocation.shareLocation=Share Location
 geolocation.shareLocation.accesskey=a
 geolocation.alwaysShareLocation=Always Share Location
 geolocation.alwaysShareLocation.accesskey=A
 geolocation.neverShareLocation=Never Share Location
 geolocation.neverShareLocation.accesskey=N
 geolocation.shareWithSite2=Would you like to share your location with this site?
 geolocation.shareWithFile2=Would you like to share your location with this file?
@@ -401,20 +401,20 @@ pointerLock.autoLock.title3=This site wi
 
 # Phishing/Malware Notification Bar.
 # LOCALIZATION NOTE (notAForgery, notAnAttack)
 # The two button strings will never be shown at the same time, so
 # it's okay for them to have the same access key
 safebrowsing.getMeOutOfHereButton.label=Get me out of here!
 safebrowsing.getMeOutOfHereButton.accessKey=G
 safebrowsing.deceptiveSite=Deceptive Site!
-safebrowsing.notADeceptiveSiteButton.label=This isn't a deceptive site…
+safebrowsing.notADeceptiveSiteButton.label=This isn’t a deceptive site…
 safebrowsing.notADeceptiveSiteButton.accessKey=D
 safebrowsing.reportedAttackSite=Reported Attack Site!
-safebrowsing.notAnAttackButton.label=This isn't an attack site…
+safebrowsing.notAnAttackButton.label=This isn’t an attack site…
 safebrowsing.notAnAttackButton.accessKey=A
 safebrowsing.reportedUnwantedSite=Reported Unwanted Software Site!
 
 # Ctrl-Tab
 # LOCALIZATION NOTE (ctrlTab.listAllTabs.label): #1 represents the number
 # of tabs in the current browser window. It will always be 2 at least.
 # See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
 ctrlTab.listAllTabs.label=;List All #1 Tabs
@@ -505,20 +505,20 @@ social.aria.toolbarButtonBadgeText=%1$S 
 #                    getUserMedia.shareScreen.message, getUserMedia.shareCameraAndMicrophone.message,
 #                    getUserMedia.shareScreenAndMicrophone.message, getUserMedia.shareCameraAndAudioCapture.message,
 #                    getUserMedia.shareAudioCapture.message, getUserMedia.shareScreenAndAudioCapture.message):
 #  %S is the website origin (e.g. www.mozilla.org)
 getUserMedia.shareCamera.message = Would you like to share your camera with %S?
 getUserMedia.shareMicrophone.message = Would you like to share your microphone with %S?
 getUserMedia.shareScreen.message = Would you like to share your screen with %S?
 getUserMedia.shareCameraAndMicrophone.message = Would you like to share your camera and microphone with %S?
-getUserMedia.shareCameraAndAudioCapture.message = Would you like to share your camera and this tab's audio with %S?
+getUserMedia.shareCameraAndAudioCapture.message = Would you like to share your camera and this tab’s audio with %S?
 getUserMedia.shareScreenAndMicrophone.message = Would you like to share your microphone and screen with %S?
-getUserMedia.shareScreenAndAudioCapture.message = Would you like to share this tab's audio and your screen with %S?
-getUserMedia.shareAudioCapture.message = Would you like to share this tab's audio with %S?
+getUserMedia.shareScreenAndAudioCapture.message = Would you like to share this tab’s audio and your screen with %S?
+getUserMedia.shareAudioCapture.message = Would you like to share this tab’s audio with %S?
 getUserMedia.selectWindow.label=Window to share:
 getUserMedia.selectWindow.accesskey=W
 getUserMedia.selectScreen.label=Screen to share:
 getUserMedia.selectScreen.accesskey=S
 getUserMedia.selectApplication.label=Application to share:
 getUserMedia.selectApplication.accesskey=A
 getUserMedia.noVideo.label = No Video
 getUserMedia.noApplication.label = No Application
@@ -543,28 +543,28 @@ getUserMedia.shareApplicationWindowCount
 getUserMedia.shareSelectedDevices.label = Share Selected Device;Share Selected Devices
 getUserMedia.shareSelectedDevices.accesskey = S
 getUserMedia.shareScreen.label = Share Screen
 getUserMedia.shareApplication.label = Share Selected Application
 getUserMedia.shareWindow.label = Share Selected Window
 getUserMedia.shareSelectedItems.label = Share Selected Items
 getUserMedia.always.label = Always Share
 getUserMedia.always.accesskey = A
-getUserMedia.denyRequest.label = Don't Share
+getUserMedia.denyRequest.label = Don’t Share
 getUserMedia.denyRequest.accesskey = D
 getUserMedia.never.label = Never Share
 getUserMedia.never.accesskey = N
 getUserMedia.sharingCamera.message2 = You are currently sharing your camera with this page.
 getUserMedia.sharingMicrophone.message2 = You are currently sharing your microphone with this page.
 getUserMedia.sharingCameraAndMicrophone.message2 = You are currently sharing your camera and microphone with this page.
 getUserMedia.sharingApplication.message = You are currently sharing an application with this page.
 getUserMedia.sharingScreen.message = You are currently sharing your screen with this page.
 getUserMedia.sharingWindow.message = You are currently sharing a window with this page.
 getUserMedia.sharingBrowser.message = You are currently sharing a tab with this page.
-getUserMedia.sharingAudioCapture.message = You are currently sharing a tab's audio with this page.
+getUserMedia.sharingAudioCapture.message = You are currently sharing a tab’s audio with this page.
 getUserMedia.continueSharing.label = Continue Sharing
 getUserMedia.continueSharing.accesskey = C
 getUserMedia.stopSharing.label = Stop Sharing
 getUserMedia.stopSharing.accesskey = S
 
 getUserMedia.sharingMenu.label = Tabs sharing devices
 getUserMedia.sharingMenu.accesskey = d
 # LOCALIZATION NOTE (getUserMedia.sharingMenuCamera
@@ -657,17 +657,17 @@ emeNotifications.drmContentCDMInstalling
 emeNotifications.drmContentCDMNotSupported.unsupportedOS.message = The audio or video on this page requires DRM software that %1$S does not support on %2$S. %3$S
 
 emeNotifications.unknownDRMSoftware = Unknown
 
 # LOCALIZATION NOTE - %S is brandShortName
 slowStartup.message = %S seems slow… to… start.
 slowStartup.helpButton.label = Learn How to Speed It Up
 slowStartup.helpButton.accesskey = L
-slowStartup.disableNotificationButton.label = Don't Tell Me Again
+slowStartup.disableNotificationButton.label = Don’t Tell Me Again
 slowStartup.disableNotificationButton.accesskey = A
 
 # LOCALIZATION NOTE  - %S is brandShortName
 flashHang.message = %S changed some Adobe Flash settings to improve performance.
 flashHang.helpButton.label = Learn More…
 flashHang.helpButton.accesskey = L
 
 # LOCALIZATION NOTE(customizeTips.tip0): %1$S will be replaced with the text defined
@@ -751,18 +751,18 @@ usercontext.shopping.label = Shopping
 usercontext.banking.label = Banking
 
 muteTab.label = Mute Tab
 muteTab.accesskey = M
 unmuteTab.label = Unmute Tab
 unmuteTab.accesskey = M
 
 # LOCALIZATION NOTE (weakCryptoOverriding.message): %S is brandShortName
-weakCryptoOverriding.message = %S recommends that you don't enter your password, credit card and other personal information on this website.
-revokeOverride.label = Don't Trust This Website
+weakCryptoOverriding.message = %S recommends that you don’t enter your password, credit card and other personal information on this website.
+revokeOverride.label = Don’t Trust This Website
 revokeOverride.accesskey = D
 
 # LOCALIZATION NOTE (certErrorDetails*.label): These are text strings that
 # appear in the about:certerror page, so that the user can copy and send them to
 # the server administrators for troubleshooting.
 certErrorDetailsHSTS.label = HTTP Strict Transport Security: %S
 certErrorDetailsKeyPinning.label = HTTP Public Key Pinning: %S
 certErrorDetailsCertChain.label = Certificate chain:
--- a/browser/locales/en-US/chrome/browser/downloads/downloads.properties
+++ b/browser/locales/en-US/chrome/browser/downloads/downloads.properties
@@ -91,16 +91,16 @@ shortTimeLeftDays=%1$Sd
 # If you use a different separator, this might not be necessary.  However, there
 # is usually no need to change the separator or the order of the substitutions,
 # even for right-to-left languages, unless the defaults are not suitable.
 statusSeparator=%1$S \u2014 %2$S
 statusSeparatorBeforeNumber=%1$S \u2014  %2$S
 
 fileExecutableSecurityWarning="%S" is an executable file. Executable files may contain viruses or other malicious code that could harm your computer. Use caution when opening this file. Are you sure you want to launch "%S"?
 fileExecutableSecurityWarningTitle=Open Executable File?
-fileExecutableSecurityWarningDontAsk=Don't ask me this again
+fileExecutableSecurityWarningDontAsk=Don’t ask me this again
 
 # LOCALIZATION NOTE (otherDownloads2):
 # This is displayed in an item at the bottom of the Downloads Panel when
 # there are more downloads than can fit in the list in the panel. Use a
 # semi-colon list of plural forms.
 # See: http://developer.mozilla.org/en/Localization_and_Plurals
 otherDownloads2=+ %1$S other download; + %1$S other downloads
--- a/browser/locales/en-US/chrome/browser/feeds/subscribe.properties
+++ b/browser/locales/en-US/chrome/browser/feeds/subscribe.properties
@@ -20,17 +20,17 @@ mediaLabel=Media files
 #   %2$S = unit of measure (bytes, KB, MB, ...)
 enclosureSizeText=%1$S %2$S
 
 bytes=bytes
 kilobyte=KB
 megabyte=MB
 gigabyte=GB
 
-# LOCALIZATION NOTE: The next three strings explains to the user what they're 
+# LOCALIZATION NOTE: The next three strings explains to the user what they're
 # doing.
 #   e.g. alwaysUseForVideoPodcasts : "Always use Miro to subscribe to video podcasts."
 #   %S = application to use (Miro, iTunes, ...)
 alwaysUseForFeeds=Always use %S to subscribe to feeds.
 alwaysUseForAudioPodcasts=Always use %S to subscribe to podcasts.
 alwaysUseForVideoPodcasts=Always use %S to subscribe to video podcasts.
 
 subscribeFeedUsing=Subscribe to this feed using 
--- a/browser/locales/en-US/chrome/browser/migration/migration.dtd
+++ b/browser/locales/en-US/chrome/browser/migration/migration.dtd
@@ -8,17 +8,17 @@
 <!ENTITY importFrom.label               "Import Options, Bookmarks, History, Passwords and other data from:">
 <!ENTITY importFromUnix.label           "Import Preferences, Bookmarks, History, Passwords and other data from:">
 <!ENTITY importFromBookmarks.label      "Import Bookmarks from:">
 
 <!ENTITY importFromIE.label             "Microsoft Internet Explorer">
 <!ENTITY importFromIE.accesskey         "M">
 <!ENTITY importFromEdge.label           "Microsoft Edge">
 <!ENTITY importFromEdge.accesskey       "E">
-<!ENTITY importFromNothing.label        "Don't import anything">
+<!ENTITY importFromNothing.label        "Don’t import anything">
 <!ENTITY importFromNothing.accesskey    "D">
 <!ENTITY importFromSafari.label         "Safari">
 <!ENTITY importFromSafari.accesskey     "S">
 <!ENTITY importFromCanary.label         "Chrome Canary">
 <!ENTITY importFromCanary.accesskey     "n">
 <!ENTITY importFromChrome.label         "Chrome">
 <!ENTITY importFromChrome.accesskey     "C">
 <!ENTITY importFromChromium.label       "Chromium">
--- a/browser/locales/en-US/chrome/browser/newTab.properties
+++ b/browser/locales/en-US/chrome/browser/newTab.properties
@@ -29,17 +29,17 @@ newtab.sponsored.explain2=This site is s
 # LOCALIZATION NOTE(newtab.suggested.explain): %1$S will be replaced inline by
 # the (X) block icon. %2$S will be replaced by an active link using string
 # newtab.learn.link as text.
 newtab.suggested.explain=This site is suggested to you by Mozilla. You can remove it at any time by clicking the %1$S button. %2$S
 # LOCALIZATION NOTE(newtab.enhanced.explain): %1$S will be replaced inline by
 # the gear icon used to customize the new tab window. %2$S will be replaced by
 # an active link using string newtab.learn.link as text.
 newtab.enhanced.explain=A Mozilla partner has visually enhanced this tile, replacing the screenshot. You can turn off enhanced tiles by clicking the %1$S button for your preferences. %2$S
-newtab.intro1.paragraph1=Now when you open New Tab, you'll also see sites we think might be interesting to you. Some may be suggested by Mozilla or sponsored by one of our partners.
+newtab.intro1.paragraph1=Now when you open New Tab, you’ll also see sites we think might be interesting to you. Some may be suggested by Mozilla or sponsored by one of our partners.
 # LOCALIZATION NOTE(newtab.intro1.paragraph2): %1$S will be replaced inline by
 # an active link using string newtab.privacy.link as text. %2$S will be replaced
 # inline by the gear icon used to customize the new tab window.
 newtab.intro1.paragraph2=In order to provide this service, some data is automatically sent back to us in accordance with our %1$S. You can turn this off by unchecking the option under the gear icon (%2$S).
 newtab.learn.link=Learn more…
 newtab.privacy.link=Privacy Notice
 newtab.learn.link2=More about New Tab
 newtab.intro.header.update=New Tab got an update!
--- a/browser/locales/en-US/chrome/browser/places/places.properties
+++ b/browser/locales/en-US/chrome/browser/places/places.properties
@@ -83,11 +83,11 @@ bookmarkResultLabel=Bookmark
 switchtabResultLabel=Tab
 keywordResultLabel=Keyword
 searchengineResultLabel=Search
 
 
 # LOCALIZATION NOTE (lockPrompt.text)
 # %S will be replaced with the application name.
 lockPrompt.title=Browser Startup Error
-lockPrompt.text=The bookmarks and history system will not be functional because one of %S's files is in use by another application. Some security software can cause this problem.
+lockPrompt.text=The bookmarks and history system will not be functional because one of %S’s files is in use by another application. Some security software can cause this problem.
 lockPromptInfoButton.label=Learn More
 lockPromptInfoButton.accessKey=L
--- a/browser/locales/en-US/chrome/browser/quitDialog.properties
+++ b/browser/locales/en-US/chrome/browser/quitDialog.properties
@@ -5,9 +5,9 @@
 quitDialogTitle=Quit %S
 
 quitTitle=&Quit
 cancelTitle=&Cancel
 saveTitle=&Save and Quit
 neverAsk2=&Do not ask next time
 message=Do you want %S to save your tabs and windows for the next time it starts?
 messageNoWindows=Do you want %S to save your tabs for the next time it starts?
-messagePrivate=You're in private browsing mode. Quitting %S now will discard all your open tabs and windows.
+messagePrivate=You’re in private browsing mode. Quitting %S now will discard all your open tabs and windows.
--- a/browser/locales/en-US/chrome/browser/safebrowsing/phishing-afterload-warning-message.dtd
+++ b/browser/locales/en-US/chrome/browser/safebrowsing/phishing-afterload-warning-message.dtd
@@ -1,16 +1,16 @@
 <!-- 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/. -->
 
 <!ENTITY safeb.palm.accept.label "Get me out of here!">
 <!ENTITY safeb.palm.decline.label "Ignore this warning">
 <!-- Localization note (safeb.palm.notdeceptive.label) - Label of the Help menu item. -->
-<!ENTITY safeb.palm.notdeceptive.label "This isn't a deceptive site…">
+<!ENTITY safeb.palm.notdeceptive.label "This isn’t a deceptive site…">
 <!ENTITY safeb.palm.reportPage.label "Why was this page blocked?">
 <!ENTITY safeb.palm.whyForbidden.label "Why was this page blocked?">
 
 <!ENTITY safeb.blocked.malwarePage.title "Reported Attack Page!">
 <!-- Localization note (safeb.blocked.malwarePage.shortDesc) - Please don't translate the contents of the <span id="malware_sitename"/> tag.  It will be replaced at runtime with a domain name (e.g. www.badsite.com) -->
 <!ENTITY safeb.blocked.malwarePage.shortDesc "This web page at <span id='malware_sitename'/> has been reported as an attack page and has been blocked based on your security preferences.">
 <!ENTITY safeb.blocked.malwarePage.longDesc "<p>Attack pages try to install programs that steal private information, use your computer to attack others, or damage your system.</p><p>Some attack pages intentionally distribute harmful software, but many are compromised without the knowledge or permission of their owners.</p>">
 
--- a/browser/locales/en-US/chrome/browser/shellservice.properties
+++ b/browser/locales/en-US/chrome/browser/shellservice.properties
@@ -9,17 +9,17 @@ safeModeLabel=%S &Safe Mode
 # %S will be replaced by brandShortName
 setDefaultBrowserMessage2          = Get the most out of %S by setting it as your default browser
 setDefaultBrowserConfirm.label     = Use %S as my default browser
 setDefaultBrowserConfirm.accesskey = U
 setDefaultBrowserOptions.label     = Options
 setDefaultBrowserOptions.accesskey = O
 setDefaultBrowserNotNow.label      = Not now
 setDefaultBrowserNotNow.accesskey  = N
-setDefaultBrowserNever.label       = Don't ask me again
+setDefaultBrowserNever.label       = Don’t ask me again
 setDefaultBrowserNever.accesskey   = D
 
 # LOCALIZATION NOTE (setDefaultBrowserTitle, setDefaultBrowserMessage, setDefaultBrowserDontAsk, setDefaultBrowserAlertConfirm.label, setDefaultBrowserAlertNotNow.label):
 # These strings are used as an alternative to the ones above, in a modal dialog.
 # %S will be replaced by brandShortName
 setDefaultBrowserTitle=Default Browser
 setDefaultBrowserMessage=%S is not currently set as your default browser. Would you like to make it your default browser?
 setDefaultBrowserDontAsk=Always perform this check when starting %S.
--- a/browser/locales/en-US/chrome/browser/syncKey.dtd
+++ b/browser/locales/en-US/chrome/browser/syncKey.dtd
@@ -1,18 +1,18 @@
 <!-- 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/. -->
 
 <!ENTITY syncKey.page.title               "Your &syncBrand.fullName.label; Key">
 <!ENTITY syncKey.page.description2        "This key is used to decode the data in your &syncBrand.fullName.label; account. You will need to enter the key each time you configure &syncBrand.fullName.label; on a new device.">
 <!ENTITY syncKey.keepItSecret.heading     "Keep it secret">
-<!ENTITY syncKey.keepItSecret.description "Your &syncBrand.fullName.label; account is encrypted to protect your privacy. Without this key, it would take years for anyone to decode your personal information. You are the only person who holds this key. This means you're the only one who can access your &syncBrand.fullName.label; data.">
+<!ENTITY syncKey.keepItSecret.description "Your &syncBrand.fullName.label; account is encrypted to protect your privacy. Without this key, it would take years for anyone to decode your personal information. You are the only person who holds this key. This means you’re the only one who can access your &syncBrand.fullName.label; data.">
 <!ENTITY syncKey.keepItSafe.heading       "Keep it safe">
 <!ENTITY syncKey.keepItSafe1.description  "Do not lose this key.">
-<!ENTITY syncKey.keepItSafe2.description  " We don't keep a copy of your key (that wouldn't be keeping it secret!) so ">
-<!ENTITY syncKey.keepItSafe3.description  "we can't help you recover it">
-<!ENTITY syncKey.keepItSafe4a.description " if it's lost. You'll need to use this key any time you connect a new device to &syncBrand.fullName.label;.">
+<!ENTITY syncKey.keepItSafe2.description  " We don’t keep a copy of your key (that wouldn’t be keeping it secret!) so ">
+<!ENTITY syncKey.keepItSafe3.description  "we can’t help you recover it">
+<!ENTITY syncKey.keepItSafe4a.description " if it’s lost. You’ll need to use this key any time you connect a new device to &syncBrand.fullName.label;.">
 <!ENTITY syncKey.findOutMore1.label       "Find out more about &syncBrand.fullName.label; and your privacy at ">
 <!ENTITY syncKey.findOutMore2.label       ".">
 <!ENTITY syncKey.footer1.label            "&syncBrand.fullName.label; Terms of Service are available at ">
 <!ENTITY syncKey.footer2.label            ". The Privacy Policy is available at ">
 <!ENTITY syncKey.footer3.label            ".">
--- a/browser/locales/en-US/chrome/browser/syncSetup.dtd
+++ b/browser/locales/en-US/chrome/browser/syncSetup.dtd
@@ -1,23 +1,23 @@
 <!-- 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/. -->
 
 <!ENTITY accountSetupTitle.label    "&syncBrand.fullName.label; Setup">
 
 <!-- First page of the wizard -->
 
-<!ENTITY setup.pickSetupType.description2 "Welcome! If you've never used &syncBrand.fullName.label; before, you will need to create a new account.">
+<!ENTITY setup.pickSetupType.description2 "Welcome! If you’ve never used &syncBrand.fullName.label; before, you will need to create a new account.">
 <!ENTITY button.createNewAccount.label "Create a New Account">
 <!ENTITY button.haveAccount.label      "I Have an Account">
 
 <!ENTITY setup.choicePage.title.label     "Have you used &syncBrand.fullName.label; before?">
-<!ENTITY setup.choicePage.new.label       "I've never used &syncBrand.shortName.label; before">
-<!ENTITY setup.choicePage.existing2.label "I'm already using &syncBrand.shortName.label; on another device">
+<!ENTITY setup.choicePage.new.label       "I’ve never used &syncBrand.shortName.label; before">
+<!ENTITY setup.choicePage.existing2.label "I’m already using &syncBrand.shortName.label; on another device">
 
 <!-- New Account AND Existing Account -->
 <!ENTITY server.label               "Server">
 <!ENTITY serverType.default.label      "Default: Mozilla &syncBrand.fullName.label; server">
 <!ENTITY serverType.custom2.label   "Use a custom server…">
 <!ENTITY signIn.account2.label      "Account">
 <!ENTITY signIn.account2.accesskey  "A">
 <!ENTITY signIn.password.label      "Password">
@@ -55,17 +55,17 @@
 <!ENTITY button.syncKeyBackup.print.label     "Print…">
 <!ENTITY button.syncKeyBackup.print.accesskey "P">
 <!ENTITY button.syncKeyBackup.save.label      "Save…">
 <!ENTITY button.syncKeyBackup.save.accesskey  "S">
 
 <!-- Existing Account Page 1: Pair a Device (incl. Pair a Device dialog strings) -->
 <!ENTITY pairDevice.title.label             "Pair a Device">
 <!ENTITY addDevice.showMeHow.label          "Show me how.">
-<!ENTITY addDevice.dontHaveDevice.label     "I don't have the device with me">
+<!ENTITY addDevice.dontHaveDevice.label     "I don’t have the device with me">
 <!ENTITY pairDevice.setup.description.label  "To activate, select &#x0022;Pair a Device&#x0022; on your other device.">
 <!ENTITY addDevice.setup.enterCode.label    "Then, enter this code:">
 <!ENTITY pairDevice.dialog.description.label "To activate your new device, select &#x0022;Set Up Sync&#x0022; on the device.">
 <!ENTITY addDevice.dialog.enterCode.label   "Enter the code that the device provides:">
 <!ENTITY addDevice.dialog.tryAgain.label    "Please try again.">
 <!ENTITY addDevice.dialog.successful.label  "The device has been successfully added. The initial synchronization can take several minutes and will finish in the background.">
 <!ENTITY addDevice.dialog.recoveryKey.label     "To activate your device you will need to enter your Recovery Key. Please print or save this key and take it with you.">
 <!ENTITY addDevice.dialog.connected.label   "Device Connected">
@@ -91,24 +91,24 @@
 <!ENTITY engine.history.accesskey   "r">
 <!ENTITY engine.passwords.label     "Passwords">
 <!ENTITY engine.passwords.accesskey "P">
 <!ENTITY engine.prefs.label         "Preferences">
 <!ENTITY engine.prefs.accesskey     "S">
 <!ENTITY engine.addons.label        "Add-ons">
 <!ENTITY engine.addons.accesskey    "A">
 
-<!ENTITY choice2a.merge.main.label       "Merge this device's data with my &syncBrand.shortName.label; data">
+<!ENTITY choice2a.merge.main.label       "Merge this device’s data with my &syncBrand.shortName.label; data">
 <!ENTITY choice2.merge.recommended.label "Recommended:">
 <!ENTITY choice2a.client.main.label      "Replace all data on this device with my &syncBrand.shortName.label; data">
-<!ENTITY choice2a.server.main.label      "Replace all other devices with this device's data">
+<!ENTITY choice2a.server.main.label      "Replace all other devices with this device’s data">
 
 <!-- Confirm Merge Options -->
 <!ENTITY setup.optionsConfirmPage.title "Confirm">
-<!ENTITY confirm.merge2.label    "&syncBrand.fullName.label; will now merge all this device's browser data into your Sync account.">
+<!ENTITY confirm.merge2.label    "&syncBrand.fullName.label; will now merge all this device’s browser data into your Sync account.">
 <!ENTITY confirm.client3.label         "Warning: The following &brandShortName; data on this device  will be deleted:">
 <!ENTITY confirm.client2.moreinfo.label "&brandShortName; will then copy your &syncBrand.fullName.label; data to this device.">
 <!ENTITY confirm.server2.label         "Warning: The following devices will be overwritten with your local data:">
 
 <!-- New & Existing Account: Setup Complete -->
 <!ENTITY setup.successPage.title "Setup Complete">
 <!ENTITY changeOptions.label "You can change this preference by selecting Sync Options below.">
 <!ENTITY continueUsing.label "You may now continue using &brandShortName;.">
--- a/browser/locales/en-US/chrome/browser/syncSetup.properties
+++ b/browser/locales/en-US/chrome/browser/syncSetup.properties
@@ -37,17 +37,17 @@ passwordsCount.label        = #1 passwor
 # #1 is the number of add-ons, see the link above for forms
 addonsCount.label        = #1 add-on;#1 add-ons
 
 save.recoverykey.title = Save Recovery Key
 save.recoverykey.defaultfilename = Firefox Recovery Key.html
 
 newAccount.action.label = Firefox Sync is now set up to automatically sync all of your browser data.
 newAccount.change.label = You can choose exactly what to sync by selecting Sync Options below.
-resetClient.change2.label = Firefox Sync will now merge all this device's browser data into your Sync account.
+resetClient.change2.label = Firefox Sync will now merge all this device’s browser data into your Sync account.
 wipeClient.change2.label = Firefox Sync will now replace all of the browser data on this device with the data in your Sync account.
 wipeRemote.change2.label = Firefox Sync will now replace all of the browser data in your Sync account with the data on this device.
 existingAccount.change.label = You can change this preference by selecting Sync Options below.
 
 # Several other strings are used (via Weave.Status.login), but they come from
 #  /services/sync
 
 # Firefox Accounts based setup.
--- a/browser/locales/en-US/chrome/overrides/appstrings.properties
+++ b/browser/locales/en-US/chrome/overrides/appstrings.properties
@@ -1,30 +1,30 @@
 # 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/.
 
 malformedURI=The URL is not valid and cannot be loaded.
-fileNotFound=Firefox can't find the file at %S.
-dnsNotFound=Firefox can't find the server at %S.
-unknownProtocolFound=Firefox doesn't know how to open this address, because one of the following protocols (%S) isn't associated with any program or is not allowed in this context.
-connectionFailure=Firefox can't establish a connection to the server at %S.
+fileNotFound=Firefox can’t find the file at %S.
+dnsNotFound=Firefox can’t find the server at %S.
+unknownProtocolFound=Firefox doesn’t know how to open this address, because one of the following protocols (%S) isn’t associated with any program or is not allowed in this context.
+connectionFailure=Firefox can’t establish a connection to the server at %S.
 netInterrupt=The connection to %S was interrupted while the page was loading.
 netTimeout=The server at %S is taking too long to respond.
 redirectLoop=Firefox has detected that the server is redirecting the request for this address in a way that will never complete.
-## LOCALIZATION NOTE (confirmRepostPrompt): In this item, don't translate "%S"
+## LOCALIZATION NOTE (confirmRepostPrompt): In this item, don’t translate "%S"
 confirmRepostPrompt=To display this page, %S must send information that will repeat any action (such as a search or order confirmation) that was performed earlier.
 resendButton.label=Resend
-unknownSocketType=Firefox doesn't know how to communicate with the server.
+unknownSocketType=Firefox doesn’t know how to communicate with the server.
 netReset=The connection to the server was reset while the page was loading.
 notCached=This document is no longer available.
-netOffline=Firefox is currently in offline mode and can't browse the Web.
+netOffline=Firefox is currently in offline mode and can’t browse the Web.
 isprinting=The document cannot change while Printing or in Print Preview.
 deniedPortAccess=This address uses a network port which is normally used for purposes other than Web browsing. Firefox has canceled the request for your protection.
-proxyResolveFailure=Firefox is configured to use a proxy server that can't be found.
+proxyResolveFailure=Firefox is configured to use a proxy server that can’t be found.
 proxyConnectFailure=Firefox is configured to use a proxy server that is refusing connections.
 contentEncodingError=The page you are trying to view cannot be shown because it uses an invalid or unsupported form of compression.
 unsafeContentType=The page you are trying to view cannot be shown because it is contained in a file type that may not be safe to open. Please contact the website owners to inform them of this problem.
 externalProtocolTitle=External Protocol Request
 externalProtocolPrompt=An external application must be launched to handle %1$S: links.\n\n\nRequested link:\n\n%2$S\n\nApplication: %3$S\n\n\nIf you were not expecting this request it may be an attempt to exploit a weakness in that other program. Cancel this request unless you are sure it is not malicious.\n
 #LOCALIZATION NOTE (externalProtocolUnknown): The following string is shown if the application name can't be determined
 externalProtocolUnknown=<Unknown>
 externalProtocolChkMsg=Remember my choice for all links of this type.
--- a/browser/locales/en-US/crashreporter/crashreporter-override.ini
+++ b/browser/locales/en-US/crashreporter/crashreporter-override.ini
@@ -1,9 +1,9 @@
 ; 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/.
 
 # This file is in the UTF-8 encoding
 [Strings]
 # LOCALIZATION NOTE (CrashReporterProductErrorText2): The %s is replaced with a string containing detailed information.
-CrashReporterProductErrorText2=Firefox had a problem and crashed. We'll try to restore your tabs and windows when it restarts.\n\nUnfortunately the crash reporter is unable to submit a crash report.\n\nDetails: %s
-CrashReporterDescriptionText2=Firefox had a problem and crashed. We'll try to restore your tabs and windows when it restarts.\n\nTo help us diagnose and fix the problem, you can send us a crash report.
+CrashReporterProductErrorText2=Firefox had a problem and crashed. We’ll try to restore your tabs and windows when it restarts.\n\nUnfortunately the crash reporter is unable to submit a crash report.\n\nDetails: %s
+CrashReporterDescriptionText2=Firefox had a problem and crashed. We’ll try to restore your tabs and windows when it restarts.\n\nTo help us diagnose and fix the problem, you can send us a crash report.
--- a/devtools/client/inspector/inspector-search.js
+++ b/devtools/client/inspector/inspector-search.js
@@ -2,23 +2,24 @@
  * 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/. */
 
 "use strict";
 
 const {Cu, Ci} = require("chrome");
 
 const promise = require("promise");
+
+loader.lazyGetter(this, "system", () => require("devtools/shared/system"));
 loader.lazyGetter(this, "EventEmitter", () => require("devtools/shared/event-emitter"));
 loader.lazyGetter(this, "AutocompletePopup", () => require("devtools/client/shared/autocomplete-popup").AutocompletePopup);
 
 // Maximum number of selector suggestions shown in the panel.
 const MAX_SUGGESTIONS = 15;
 
-
 /**
  * Converts any input field into a document search box.
  *
  * @param {InspectorPanel} inspector The InspectorPanel whose `walker` attribute
  * should be used for document traversal.
  * @param {DOMNode} input The input element to which the panel will be attached
  * and from where search input will be taken.
  *
@@ -102,18 +103,22 @@ InspectorSearch.prototype = {
 
   _onKeyDown: function(event) {
     if (this.searchBox.value.length === 0) {
       this.searchBox.removeAttribute("filled");
     } else {
       this.searchBox.setAttribute("filled", true);
     }
     if (event.keyCode === event.DOM_VK_RETURN) {
-      this._onSearch();
-    } if (event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_G && event.metaKey) {
+      this._onSearch(event.shiftKey);
+    }
+
+    const modifierKey = system.constants.platform === "macosx" ? event.metaKey :
+event.ctrlKey;
+    if (event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_G && modifierKey) {
       this._onSearch(event.shiftKey);
       event.preventDefault();
     }
   }
 };
 
 /**
  * Converts any input box on a page to a CSS selector search and suggestion box.
--- a/devtools/client/inspector/test/browser.ini
+++ b/devtools/client/inspector/test/browser.ini
@@ -106,13 +106,14 @@ skip-if = (e10s && debug) # Bug 1250058 
 [browser_inspector_search-01.js]
 [browser_inspector_search-02.js]
 [browser_inspector_search-03.js]
 [browser_inspector_search-04.js]
 [browser_inspector_search-05.js]
 [browser_inspector_search-06.js]
 [browser_inspector_search-07.js]
 [browser_inspector_search-reserved.js]
+[browser_inspector_search-selection.js]
 [browser_inspector_select-docshell.js]
 [browser_inspector_select-last-selected.js]
 [browser_inspector_search-navigation.js]
 [browser_inspector_sidebarstate.js]
 [browser_inspector_switch-to-inspector-on-pick.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/test/browser_inspector_search-selection.js
@@ -0,0 +1,59 @@
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+// Testing navigation between nodes in search results
+var {AppConstants} = Cu.import("resource://gre/modules/AppConstants.jsm");
+
+const TEST_URL = URL_ROOT + "doc_inspector_search.html";
+
+add_task(function* () {
+  let {inspector} = yield openInspectorForURL(TEST_URL);
+
+  info("Focus the search box");
+  yield focusSearchBoxUsingShortcut(inspector.panelWin);
+
+  info("Enter body > p to search");
+  let processingDone = once(inspector.searchSuggestions, "processing-done");
+  EventUtils.sendString("body > p", inspector.panelWin);
+  yield processingDone;
+
+  info("Wait for search query to complete");
+  yield inspector.searchSuggestions._lastQuery;
+
+  let msg = "Press enter and expect a new selection";
+  yield sendKeyAndCheck(inspector, msg, "VK_RETURN", {}, "#p1");
+
+  msg = "Press enter to cycle through multiple nodes";
+  yield sendKeyAndCheck(inspector, msg, "VK_RETURN", {}, "#p2");
+
+  msg = "Press shift-enter to select the previous node";
+  yield sendKeyAndCheck(inspector, msg, "VK_RETURN", { shiftKey: true }, "#p1");
+
+  if (AppConstants.platform === "macosx") {
+    msg = "Press meta-g to cycle through multiple nodes";
+    yield sendKeyAndCheck(inspector, msg, "VK_G", { metaKey: true }, "#p2");
+
+    msg = "Press shift+meta-g to select the previous node";
+    yield sendKeyAndCheck(inspector, msg, "VK_G", { metaKey: true, shiftKey: true }, "#p1");
+  } else {
+    msg = "Press ctrl-g to cycle through multiple nodes";
+    yield sendKeyAndCheck(inspector, msg, "VK_G", { ctrlKey: true }, "#p2");
+
+    msg = "Press shift+ctrl-g to select the previous node";
+    yield sendKeyAndCheck(inspector, msg, "VK_G", { ctrlKey: true, shiftKey: true }, "#p1");
+  }
+});
+
+let sendKeyAndCheck = Task.async(function*(inspector, description, key, modifiers, expectedId) {
+  info(description);
+  let onSelect = inspector.once("inspector-updated");
+  EventUtils.synthesizeKey(key, modifiers, inspector.panelWin);
+  yield onSelect;
+
+  let selectedNode = inspector.selection.nodeFront;
+  info(selectedNode.id + " is selected with text " + inspector.searchBox.value);
+  let targetNode = yield getNodeFront(expectedId, inspector);
+  is(selectedNode, targetNode, "Correct node " + expectedId + " is selected");
+});
--- a/devtools/client/performance/modules/logic/moz.build
+++ b/devtools/client/performance/modules/logic/moz.build
@@ -1,13 +1,12 @@
 # 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/.
 
 DevToolsModules(
     'frame-utils.js',
     'jit.js',
-    'marker-utils.js',
     'telemetry.js',
     'tree-model.js',
     'waterfall-utils.js',
 )
--- a/devtools/client/performance/modules/logic/waterfall-utils.js
+++ b/devtools/client/performance/modules/logic/waterfall-utils.js
@@ -3,17 +3,17 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 /**
  * Utility functions for collapsing markers into a waterfall.
  */
 
 const { extend } = require("sdk/util/object");
-const MarkerUtils = require("devtools/client/performance/modules/logic/marker-utils");
+const { MarkerBlueprintUtils } = require("devtools/client/performance/modules/marker-blueprint-utils");
 
 /**
  * Creates a parent marker, which functions like a regular marker,
  * but is able to hold additional child markers.
  *
  * The marker is seeded with values from `marker`.
  * @param object marker
  * @return object
@@ -35,22 +35,22 @@ function collapseMarkersIntoNode({ rootN
     pushNode,
     popParentNode
   } = createParentNodeFactory(rootNode);
 
   for (let i = 0, len = markersList.length; i < len; i++) {
     let curr = markersList[i];
 
     // If this marker type should not be displayed, just skip
-    if (!MarkerUtils.isMarkerValid(curr, filter)) {
+    if (!MarkerBlueprintUtils.shouldDisplayMarker(curr, filter)) {
       continue;
     }
 
     let parentNode = getCurrentParentNode();
-    let blueprint = MarkerUtils.getBlueprintFor(curr);
+    let blueprint = MarkerBlueprintUtils.getBlueprintFor(curr);
 
     let nestable = "nestable" in blueprint ? blueprint.nestable : true;
     let collapsible = "collapsible" in blueprint ? blueprint.collapsible : true;
 
     let finalized = false;
 
     // If this marker is collapsible, turn it into a parent marker.
     // If there are no children within it later, it will be turned
new file mode 100644
--- /dev/null
+++ b/devtools/client/performance/modules/marker-blueprint-utils.js
@@ -0,0 +1,103 @@
+/* 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/. */
+"use strict";
+
+const { TIMELINE_BLUEPRINT } = require("devtools/client/performance/modules/markers");
+
+/**
+ * This file contains utilities for parsing out the markers blueprint
+ * to generate strings to be displayed in the UI.
+ */
+
+exports.MarkerBlueprintUtils = {
+  /**
+   * Takes a marker and a list of marker names that should be hidden, and
+   * determines if this marker should be filtered or not.
+   *
+   * @param object marker
+   * @return boolean
+   */
+  shouldDisplayMarker: function(marker, hiddenMarkerNames) {
+    if (!hiddenMarkerNames || hiddenMarkerNames.length == 0) {
+      return true;
+    }
+
+    // If this marker isn't yet defined in the blueprint, simply check if the
+    // entire category of "UNKNOWN" markers are supposed to be visible or not.
+    let isUnknown = !(marker.name in TIMELINE_BLUEPRINT);
+    if (isUnknown) {
+      return hiddenMarkerNames.indexOf("UNKNOWN") == -1;
+    }
+
+    return hiddenMarkerNames.indexOf(marker.name) == -1;
+  },
+
+  /**
+   * Takes a marker and returns the blueprint definition for that marker type,
+   * falling back to the UNKNOWN blueprint definition if undefined.
+   *
+   * @param object marker
+   * @return object
+   */
+  getBlueprintFor: function(marker) {
+    return TIMELINE_BLUEPRINT[marker.name] || TIMELINE_BLUEPRINT.UNKNOWN;
+  },
+
+  /**
+   * Returns the label to display for a marker, based off the blueprints.
+   *
+   * @param object marker
+   * @return string
+   */
+  getMarkerLabel: function(marker) {
+    let blueprint = this.getBlueprintFor(marker);
+    let dynamic = typeof blueprint.label === "function";
+    let label = dynamic ? blueprint.label(marker) : blueprint.label;
+    return label;
+  },
+
+  /**
+   * Returns the generic label to display for a marker name.
+   * (e.g. "Function Call" for JS markers, rather than "setTimeout", etc.)
+   *
+   * @param string type
+   * @return string
+   */
+  getMarkerGenericName: function(markerName) {
+    let blueprint = this.getBlueprintFor({ name: markerName });
+    let dynamic = typeof blueprint.label === "function";
+    let generic = dynamic ? blueprint.label() : blueprint.label;
+
+    // If no class name found, attempt to throw a descriptive error as to
+    // how the marker implementor can fix this.
+    if (!generic) {
+      let message = `Could not find marker generic name for "${markerName}".`;
+      if (typeof blueprint.label === "function") {
+        message += ` The following function must return a generic name string when no marker passed: ${blueprint.label}`;
+      } else {
+        message += ` ${markerName}.label must be defined in the marker blueprint.`;
+      }
+      throw new Error(message);
+    }
+
+    return generic;
+  },
+
+  /**
+   * Returns an array of objects with key/value pairs of what should be rendered
+   * in the marker details view.
+   *
+   * @param object marker
+   * @return array<object>
+   */
+  getMarkerFields: function(marker) {
+    let blueprint = this.getBlueprintFor(marker);
+    let dynamic = typeof blueprint.fields === "function";
+    let fields = dynamic ? blueprint.fields(marker) : blueprint.fields;
+
+    return Object.entries(fields || {})
+      .filter(([_, value]) => dynamic ? true : value in marker)
+      .map(([label, value]) => ({ label, value: dynamic ? value : marker[value] }));
+  },
+};
rename from devtools/client/performance/modules/logic/marker-utils.js
rename to devtools/client/performance/modules/marker-dom-utils.js
--- a/devtools/client/performance/modules/logic/marker-utils.js
+++ b/devtools/client/performance/modules/marker-dom-utils.js
@@ -1,221 +1,131 @@
 /* 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/. */
 "use strict";
 
 /**
- * This file contains utilities for creating elements for markers to be displayed,
- * and parsing out the blueprint to generate correct values for markers.
+ * This file contains utilities for creating DOM nodes for markers
+ * to be displayed in the UI.
  */
 
-const { Cu, Ci } = require("chrome");
-
-const Services = require("Services");
-const { L10N } = require("devtools/client/performance/modules/global");
-const { TIMELINE_BLUEPRINT } = require("devtools/client/performance/modules/markers");
+const { L10N, PREFS } = require("devtools/client/performance/modules/global");
+const { MarkerBlueprintUtils } = require("devtools/client/performance/modules/marker-blueprint-utils");
 const { getSourceNames } = require("devtools/client/shared/source-utils");
-const SHOW_TRIGGER_FOR_GC_TYPES_PREF = "devtools.performance.ui.show-triggers-for-gc-types";
-
-/**
- * Takes a marker, blueprint, and filter list and
- * determines if this marker should be filtered or not.
- */
-function isMarkerValid (marker, filter) {
-  if (!filter || filter.length === 0) {
-    return true;
-  }
-
-  let isUnknown = !(marker.name in TIMELINE_BLUEPRINT);
-  if (isUnknown) {
-    return filter.indexOf("UNKNOWN") === -1;
-  }
-  return filter.indexOf(marker.name) === -1;
-}
-
-/**
- * Returns the correct label to display for passed in marker, based
- * off of the blueprints.
- *
- * @param {ProfileTimelineMarker} marker
- * @return {string}
- */
-function getMarkerLabel (marker) {
-  let blueprint = getBlueprintFor(marker);
-  // Either use the label function in the blueprint, or use it directly
-  // as a string.
-  return typeof blueprint.label === "function" ? blueprint.label(marker) : blueprint.label;
-}
-
-/**
- * Returns the correct generic name for a marker class, like "Function Call"
- * being the general class for JS markers, rather than "setTimeout", etc.
- *
- * @param {string} type
- * @return {string}
- */
-function getMarkerClassName (type) {
-  let blueprint = getBlueprintFor({ name: type });
-  // Either use the label function in the blueprint, or use it directly
-  // as a string.
-  let className = typeof blueprint.label === "function" ? blueprint.label() : blueprint.label;
-
-  // If no class name found, attempt to throw a descriptive error how the marker
-  // implementor can fix this.
-  if (!className) {
-    let message = `Could not find marker class name for "${type}".`;
-    if (typeof blueprint.label === "function") {
-      message += ` The following function must return a class name string when no marker passed: ${blueprint.label}`;
-    } else {
-      message += ` ${type}.label must be defined in the marker blueprint.`;
-    }
-    throw new Error(message);
-  }
-
-  return className;
-}
-
-/**
- * Returns an array of objects with key/value pairs of what should be rendered
- * in the marker details view.
- *
- * @param {ProfileTimelineMarker} marker
- * @return {Array<object>}
- */
-function getMarkerFields (marker) {
-  let blueprint = getBlueprintFor(marker);
-
-  // If blueprint.fields is a function, use that
-  if (typeof blueprint.fields === "function") {
-    let fields = blueprint.fields(marker);
-    return Object.keys(fields || []).map(label => {
-      return { label, value: fields[label] };
-    });
-  }
-
-  // Otherwise, iterate over the array
-  return (blueprint.fields || []).reduce((fields, field) => {
-    // Ensure this marker has this field present
-    if (field.property in marker) {
-      let label = field.label;
-      let value = marker[field.property];
-      fields.push({ label, value });
-    }
-    return fields;
-  }, []);
-}
 
 /**
  * Utilites for creating elements for markers.
  */
-const DOM = {
+exports.MarkerDOMUtils = {
   /**
    * Builds all the fields possible for the given marker. Returns an
    * array of elements to be appended to a parent element.
    *
-   * @param {Document} doc
-   * @param {ProfileTimelineMarker} marker
-   * @return {Array<Element>}
+   * @param document doc
+   * @param object marker
+   * @return array<nsIDOMNode>
    */
   buildFields: function (doc, marker) {
-    let blueprint = getBlueprintFor(marker);
-    let fields = getMarkerFields(marker);
-
-    return fields.map(({ label, value }) => DOM.buildNameValueLabel(doc, label, value));
+    let fields = MarkerBlueprintUtils.getMarkerFields(marker);
+    return fields.map(({ label, value }) => this.buildNameValueLabel(doc, label, value));
   },
 
   /**
-   * Builds the label representing marker's type.
+   * Builds the label representing the marker's type.
    *
-   * @param {Document} doc
-   * @param {ProfileTimelineMarker}
-   * @return {Element}
+   * @param document doc
+   * @param object marker
+   * @return nsIDOMNode
    */
   buildTitle: function (doc, marker) {
-    let blueprint = getBlueprintFor(marker);
+    let blueprint = MarkerBlueprintUtils.getBlueprintFor(marker);
 
     let hbox = doc.createElement("hbox");
     hbox.setAttribute("align", "center");
 
     let bullet = doc.createElement("hbox");
     bullet.className = `marker-details-bullet marker-color-${blueprint.colorName}`;
 
-    let title = getMarkerLabel(marker);
+    let title = MarkerBlueprintUtils.getMarkerLabel(marker);
     let label = doc.createElement("label");
     label.className = "marker-details-type";
     label.setAttribute("value", title);
 
     hbox.appendChild(bullet);
     hbox.appendChild(label);
 
     return hbox;
   },
 
   /**
-   * Builds the duration element, like "Duration: 200ms".
+   * Builds the label representing the marker's duration.
    *
-   * @param {Document} doc
-   * @param {ProfileTimelineMarker} marker
-   * @return {Element}
+   * @param document doc
+   * @param object marker
+   * @return nsIDOMNode
    */
   buildDuration: function (doc, marker) {
     let label = L10N.getStr("marker.field.duration");
     let start = L10N.getFormatStrWithNumbers("timeline.tick", marker.start);
     let end = L10N.getFormatStrWithNumbers("timeline.tick", marker.end);
     let duration = L10N.getFormatStrWithNumbers("timeline.tick", marker.end - marker.start);
-    let el = DOM.buildNameValueLabel(doc, label, duration);
+
+    let el = this.buildNameValueLabel(doc, label, duration);
     el.classList.add("marker-details-duration");
     el.setAttribute("tooltiptext", `${start} → ${end}`);
+
     return el;
   },
 
   /**
-   * Builds labels for name:value pairs. Like "Start: 100ms",
-   * "Duration: 200ms", ...
+   * Builds labels for name:value pairs.
+   * E.g. "Start: 100ms", "Duration: 200ms", ...
    *
-   * @param {Document} doc
+   * @param document doc
    * @param string field
-   *        String identifier for label's name.
    * @param string value
-   *        Label's value.
-   * @return {Element}
+   * @return nsIDOMNode
    */
   buildNameValueLabel: function (doc, field, value) {
     let hbox = doc.createElement("hbox");
     hbox.className = "marker-details-labelcontainer";
-    let labelName = doc.createElement("label");
-    let labelValue = doc.createElement("label");
-    labelName.className = "plain marker-details-labelname";
-    labelValue.className = "plain marker-details-labelvalue";
-    labelName.setAttribute("value", field);
-    labelValue.setAttribute("value", value);
-    hbox.appendChild(labelName);
-    hbox.appendChild(labelValue);
+
+    let nameLabel = doc.createElement("label");
+    nameLabel.className = "plain marker-details-name-label";
+    nameLabel.setAttribute("value", field);
+    hbox.appendChild(nameLabel);
+
+    let valueLabel = doc.createElement("label");
+    valueLabel.className = "plain marker-details-value-label";
+    valueLabel.setAttribute("value", value);
+    hbox.appendChild(valueLabel);
+
     return hbox;
   },
 
   /**
    * Builds a stack trace in an element.
    *
-   * @param {Document} doc
+   * @param document doc
    * @param object params
    *        An options object with the following members:
-   *        string type - String identifier for type of stack ("stack", "startStack" or "endStack")
-   *        number frameIndex - The index of the topmost stack frame.
-   *        array frames - Array of stack frames.
+   *          - string type: string identifier for type of stack ("stack", "startStack" or "endStack"
+   *          - number frameIndex: the index of the topmost stack frame
+   *          - array frames: array of stack frames
    */
   buildStackTrace: function(doc, { type, frameIndex, frames }) {
     let container = doc.createElement("vbox");
-    let labelName = doc.createElement("label");
-    labelName.className = "plain marker-details-labelname";
-    labelName.setAttribute("value", L10N.getStr(`marker.field.${type}`));
+    container.className = "marker-details-stack";
     container.setAttribute("type", type);
-    container.className = "marker-details-stack";
-    container.appendChild(labelName);
+
+    let nameLabel = doc.createElement("label");
+    nameLabel.className = "plain marker-details-name-label";
+    nameLabel.setAttribute("value", L10N.getStr(`marker.field.${type}`));
+    container.appendChild(nameLabel);
 
     // Workaround for profiles that have looping stack traces.  See
     // bug 1246555.
     let wasAsyncParent = false;
     let seen = new Set();
 
     while (frameIndex > 0) {
       if (seen.has(frameIndex)) {
@@ -226,64 +136,67 @@ const DOM = {
       let frame = frames[frameIndex];
       let url = frame.source;
       let displayName = frame.functionDisplayName;
       let line = frame.line;
 
       // If the previous frame had an async parent, then the async
       // cause is in this frame and should be displayed.
       if (wasAsyncParent) {
+        let asyncStr = L10N.getFormatStr("marker.field.asyncStack", frame.asyncCause);
         let asyncBox = doc.createElement("hbox");
         let asyncLabel = doc.createElement("label");
         asyncLabel.className = "devtools-monospace";
-        asyncLabel.setAttribute("value", L10N.getFormatStr("marker.field.asyncStack",
-                                                           frame.asyncCause));
+        asyncLabel.setAttribute("value", asyncStr);
         asyncBox.appendChild(asyncLabel);
         container.appendChild(asyncBox);
         wasAsyncParent = false;
       }
 
       let hbox = doc.createElement("hbox");
 
       if (displayName) {
         let functionLabel = doc.createElement("label");
         functionLabel.className = "devtools-monospace";
         functionLabel.setAttribute("value", displayName);
         hbox.appendChild(functionLabel);
       }
 
       if (url) {
-        let aNode = doc.createElement("a");
-        aNode.className = "waterfall-marker-location devtools-source-link";
-        aNode.href = url;
-        aNode.draggable = false;
-        aNode.setAttribute("title", url);
+        let linkNode = doc.createElement("a");
+        linkNode.className = "waterfall-marker-location devtools-source-link";
+        linkNode.href = url;
+        linkNode.draggable = false;
+        linkNode.setAttribute("title", url);
 
-        let urlNode = doc.createElement("label");
-        urlNode.className = "filename";
-        urlNode.setAttribute("value", getSourceNames(url).short);
-        let lineNode = doc.createElement("label");
-        lineNode.className = "line-number";
-        lineNode.setAttribute("value", `:${line}`);
+        let urlLabel = doc.createElement("label");
+        urlLabel.className = "filename";
+        urlLabel.setAttribute("value", getSourceNames(url).short);
+        linkNode.appendChild(urlLabel);
 
-        aNode.appendChild(urlNode);
-        aNode.appendChild(lineNode);
-        hbox.appendChild(aNode);
+        let lineLabel = doc.createElement("label");
+        lineLabel.className = "line-number";
+        lineLabel.setAttribute("value", `:${line}`);
+        linkNode.appendChild(lineLabel);
+
+        hbox.appendChild(linkNode);
 
         // Clicking here will bubble up to the parent,
         // which handles the view source.
-        aNode.setAttribute("data-action", JSON.stringify({
-          url, line, action: "view-source"
+        linkNode.setAttribute("data-action", JSON.stringify({
+          url: url,
+          line: line,
+          action: "view-source"
         }));
       }
 
       if (!displayName && !url) {
-        let label = doc.createElement("label");
-        label.setAttribute("value", L10N.getStr("marker.value.unknownFrame"));
-        hbox.appendChild(label);
+        let unknownLabel = doc.createElement("label");
+        unknownLabel.setAttribute("value", L10N.getStr("marker.value.unknownFrame"));
+        hbox.appendChild(unknownLabel);
       }
 
       container.appendChild(hbox);
 
       if (frame.asyncParent) {
         frameIndex = frame.asyncParent;
         wasAsyncParent = true;
       } else {
@@ -292,66 +205,51 @@ const DOM = {
     }
 
     return container;
   },
 
   /**
    * Builds any custom fields specific to the marker.
    *
-   * @param {Document} doc
-   * @param {ProfileTimelineMarker} marker
-   * @param {object} options
-   * @return {Array<Element>}
+   * @param document doc
+   * @param object marker
+   * @param object options
+   * @return array<nsIDOMNode>
    */
   buildCustom: function (doc, marker, options) {
     let elements = [];
 
-    if (options.allocations && showAllocationsTrigger(marker)) {
+    if (options.allocations && shouldShowAllocationsTrigger(marker)) {
       let hbox = doc.createElement("hbox");
       hbox.className = "marker-details-customcontainer";
 
       let label = doc.createElement("label");
       label.className = "custom-button devtools-button";
       label.setAttribute("value", "Show allocation triggers");
       label.setAttribute("type", "show-allocations");
       label.setAttribute("data-action", JSON.stringify({
-        endTime: marker.start, action: "show-allocations"
+        endTime: marker.start,
+        action: "show-allocations"
       }));
 
       hbox.appendChild(label);
       elements.push(hbox);
     }
 
     return elements;
   },
 };
 
 /**
- * Takes a marker and returns the definition for that marker type,
- * falling back to the UNKNOWN definition if undefined.
- *
- * @param {Marker} marker
- * @return {object}
- */
-function getBlueprintFor (marker) {
-  return TIMELINE_BLUEPRINT[marker.name] || TIMELINE_BLUEPRINT.UNKNOWN;
-}
-
-/**
  * Takes a marker and determines if this marker should display
  * the allocations trigger button.
  *
- * @param {Marker} marker
- * @return {boolean}
+ * @param object marker
+ * @return boolean
  */
-function showAllocationsTrigger (marker) {
-  return marker.name === "GarbageCollection" &&
-         Services.prefs.getCharPref(SHOW_TRIGGER_FOR_GC_TYPES_PREF)
-         .split(" ").indexOf(marker.causeName) !== -1;
+function shouldShowAllocationsTrigger (marker) {
+  if (marker.name == "GarbageCollection") {
+    let showTriggers = PREFS["show-triggers-for-gc-types"];
+    return showTriggers.split(" ").indexOf(marker.causeName) !== -1;
+  }
+  return false;
 }
-
-exports.isMarkerValid = isMarkerValid;
-exports.getMarkerLabel = getMarkerLabel;
-exports.getMarkerClassName = getMarkerClassName;
-exports.getMarkerFields = getMarkerFields;
-exports.DOM = DOM;
-exports.getBlueprintFor = getBlueprintFor;
--- a/devtools/client/performance/modules/marker-formatters.js
+++ b/devtools/client/performance/modules/marker-formatters.js
@@ -167,25 +167,23 @@ exports.Formatters = {
       return {
         [L10N.getStr("marker.field.type")]: label
       };
     }
   },
 
   /* Group 2 - User Controlled */
 
-  ConsoleTimeFields: [{
-    label: L10N.getStr("marker.field.consoleTimerName"),
-    property: "causeName",
-  }],
+  ConsoleTimeFields: {
+    [L10N.getStr("marker.field.consoleTimerName")]: "causeName"
+  },
 
-  TimeStampFields: [{
-    label: L10N.getStr("marker.field.label"),
-    property: "causeName",
-  }]
+  TimeStampFields: {
+    [L10N.getStr("marker.field.label")]: "causeName"
+  }
 };
 
 /**
  * Takes a main label (e.g. "Timestamp") and a property name (e.g. "causeName"),
  * and returns a string that represents that property value for a marker if it
  * exists (e.g. "Timestamp (rendering)"), or just the main label if it does not.
  *
  * @param string mainLabel
--- a/devtools/client/performance/modules/markers.js
+++ b/devtools/client/performance/modules/markers.js
@@ -13,40 +13,32 @@ const { Formatters, labelForProperty } =
  * - group: The row index in the overview graph; multiple markers
  *          can be added on the same row. @see <overview.js/buildGraphImage>
  * - label: The label used in the waterfall to identify the marker. Can be a
  *          string or just a function that accepts the marker and returns a
  *          string (if you want to use a dynamic property for the main label).
  *          If you use a function for a label, it *must* handle the case where
  *          no marker is provided, to get a generic label used to describe
  *          all markers of this type.
+ * - fields: The fields used in the marker details view to display more
+ *           information about a currently selected marker. Can either be an
+ *           object of fields, or simply a function that accepts the marker and
+ *           returns such an object (if you want to use properties dynamically).
+ *           For example, a field in the object such as { "Cause": "causeName" }
+ *           would render something like `Cause: ${marker.causeName}` in the UI.
  * - colorName: The label of the DevTools color used for this marker. If
  *              adding a new color, be sure to check that there's an entry
  *              for `.marker-color-graphs-{COLORNAME}` for the equivilent
  *              entry in "./devtools/client/themes/performance.css"
  *              https://developer.mozilla.org/en-US/docs/Tools/DevToolsColors
  * - collapsible: Whether or not this marker can contain other markers it
  *                eclipses, and becomes collapsible to reveal its nestable
  *                children. Defaults to true.
  * - nestable: Whether or not this marker can be nested inside an eclipsing
  *             collapsible marker. Defaults to true.
- * - fields: An optional array of fields you wish to display in the marker
- *           details view. For example, a field in the array such as
- *           { label: "Cause", property: "causeName" } would render a string
- *           like `Cause: ${marker.causeName}` in the marker details view.
- *           Each field may take the following properties:
- *           - label: The name of the property that should be displayed.
- *           - property: The property that must exist on the marker to render,
- *                       and the value of the property will be displayed.
- *           Alternatively, this also be a function that returns an object.
- *           Each key in that object will be rendered as one field's label,
- *           with its value rendering as one field's value.
- *
- * Whenever this is changed, browser_timeline_waterfall-styles.js *must* be
- * updated as well.
  */
 const TIMELINE_BLUEPRINT = {
   /* Default definition used for markers that occur but are not defined here.
    * Should ultimately be defined, but this gives us room to work on the
    * front end separately from the platform. */
   "UNKNOWN": {
     group: 2,
     colorName: "graphs-grey",
--- a/devtools/client/performance/modules/moz.build
+++ b/devtools/client/performance/modules/moz.build
@@ -8,11 +8,13 @@ DIRS += [
     'widgets',
 ]
 
 DevToolsModules(
     'categories.js',
     'constants.js',
     'global.js',
     'io.js',
+    'marker-blueprint-utils.js',
+    'marker-dom-utils.js',
     'marker-formatters.js',
     'markers.js',
 )
--- a/devtools/client/performance/modules/widgets/marker-details.js
+++ b/devtools/client/performance/modules/widgets/marker-details.js
@@ -5,17 +5,17 @@
 
 /**
  * This file contains the rendering code for the marker sidebar.
  */
 
 const { Cc, Ci, Cu, Cr } = require("chrome");
 
 const EventEmitter = require("devtools/shared/event-emitter");
-const MarkerUtils = require("devtools/client/performance/modules/logic/marker-utils");
+const { MarkerDOMUtils } = require("devtools/client/performance/modules/marker-dom-utils");
 
 /**
  * A detailed view for one single marker.
  *
  * @param nsIDOMNode parent
  *        The parent node holding the view.
  * @param nsIDOMNode splitter
  *        The splitter node that the resize event is bound to.
@@ -88,32 +88,32 @@ MarkerDetails.prototype = {
    *          - frames: Array of stack frame information; see stack.js.
    *          - allocations: Whether or not allocations were enabled for this recording. [optional]
    */
   render: function (options) {
     let { marker, frames } = options;
     this.empty();
 
     let elements = [];
-    elements.push(MarkerUtils.DOM.buildTitle(this._document, marker));
-    elements.push(MarkerUtils.DOM.buildDuration(this._document, marker));
-    MarkerUtils.DOM.buildFields(this._document, marker).forEach(f => elements.push(f));
-    MarkerUtils.DOM.buildCustom(this._document, marker, options).forEach(f => elements.push(f));
+    elements.push(MarkerDOMUtils.buildTitle(this._document, marker));
+    elements.push(MarkerDOMUtils.buildDuration(this._document, marker));
+    MarkerDOMUtils.buildFields(this._document, marker).forEach(f => elements.push(f));
+    MarkerDOMUtils.buildCustom(this._document, marker, options).forEach(f => elements.push(f));
 
     // Build a stack element -- and use the "startStack" label if
     // we have both a startStack and endStack.
     if (marker.stack) {
       let type = marker.endStack ? "startStack" : "stack";
-      elements.push(MarkerUtils.DOM.buildStackTrace(this._document, {
+      elements.push(MarkerDOMUtils.buildStackTrace(this._document, {
         frameIndex: marker.stack, frames, type
       }));
     }
     if (marker.endStack) {
       let type = "endStack";
-      elements.push(MarkerUtils.DOM.buildStackTrace(this._document, {
+      elements.push(MarkerDOMUtils.buildStackTrace(this._document, {
         frameIndex: marker.endStack, frames, type
       }));
     }
 
     elements.forEach(el => this._parent.appendChild(el));
   },
 
   /**
--- a/devtools/client/performance/modules/widgets/marker-view.js
+++ b/devtools/client/performance/modules/widgets/marker-view.js
@@ -6,18 +6,17 @@
 /**
  * This file contains the "marker" view, essentially a detailed list
  * of all the markers in the timeline data.
  */
 
 const { Cc, Ci, Cu, Cr } = require("chrome");
 const { Heritage } = require("resource://devtools/client/shared/widgets/ViewHelpers.jsm");
 const { AbstractTreeItem } = require("resource://devtools/client/shared/widgets/AbstractTreeItem.jsm");
-
-const MarkerUtils = require("devtools/client/performance/modules/logic/marker-utils");
+const { MarkerBlueprintUtils } = require("devtools/client/performance/modules/marker-blueprint-utils");
 
 const HTML_NS = "http://www.w3.org/1999/xhtml";
 
 const LEVEL_INDENT = 10; // px
 const ARROW_NODE_OFFSET = -15; // px
 const WATERFALL_MARKER_SIDEBAR_SAFE_BOUNDS = 20; // px
 const WATERFALL_MARKER_SIDEBAR_WIDTH = 175; // px
 const WATERFALL_MARKER_TIMEBAR_WIDTH_MIN = 5; // px
@@ -143,17 +142,17 @@ MarkerView.prototype = Heritage.extend(A
     let startTime = this.root._interval.startTime;
     let endTime = this.root._interval.endTime;
     let newLevel = this.level + 1;
 
     for (let i = 0, len = submarkers.length; i < len; i++) {
       let marker = submarkers[i];
 
       // Skip filtered markers
-      if (!MarkerUtils.isMarkerValid(marker, this.filter)) {
+      if (!MarkerBlueprintUtils.shouldDisplayMarker(marker, this.filter)) {
         continue;
       }
 
       if (!isMarkerInRange(marker, startTime|0, endTime|0)) {
         continue;
       }
 
       children.push(new MarkerView({
@@ -168,17 +167,17 @@ MarkerView.prototype = Heritage.extend(A
   /**
    * Builds all the nodes representing a marker in the waterfall.
    * @param nsIDOMNode document
    * @param nsIDOMNode targetNode
    * @param nsIDOMNode arrowNode
    */
   _buildMarkerCells: function(doc, targetNode, arrowNode) {
     let marker = this.marker;
-    let blueprint = MarkerUtils.getBlueprintFor(marker);
+    let blueprint = MarkerBlueprintUtils.getBlueprintFor(marker);
     let startTime = this.root._interval.startTime;
     let endTime = this.root._interval.endTime;
 
     let sidebarCell = this._buildMarkerSidebar(doc, blueprint, marker);
     let timebarCell = this._buildMarkerTimebar(doc, blueprint, marker, startTime, endTime, arrowNode);
 
     targetNode.appendChild(sidebarCell);
     targetNode.appendChild(timebarCell);
@@ -207,17 +206,17 @@ MarkerView.prototype = Heritage.extend(A
 
     let bullet = doc.createElement("hbox");
     bullet.className = `waterfall-marker-bullet marker-color-${style.colorName}`;
     bullet.style.transform = `translateX(${this.level * LEVEL_INDENT}px)`;
     bullet.setAttribute("type", marker.name);
     cell.appendChild(bullet);
 
     let name = doc.createElement("description");
-    let label = MarkerUtils.getMarkerLabel(marker);
+    let label = MarkerBlueprintUtils.getMarkerLabel(marker);
     name.className = "plain waterfall-marker-name";
     name.style.transform = `translateX(${this.level * LEVEL_INDENT}px)`;
     name.setAttribute("crop", "end");
     name.setAttribute("flex", "1");
     name.setAttribute("value", label);
     name.setAttribute("tooltiptext", label);
     cell.appendChild(name);
 
--- a/devtools/client/performance/modules/widgets/markers-overview.js
+++ b/devtools/client/performance/modules/widgets/markers-overview.js
@@ -11,17 +11,17 @@
 
 const { Cc, Ci, Cu, Cr } = require("chrome");
 const { Heritage } = require("resource://devtools/client/shared/widgets/ViewHelpers.jsm");
 const { AbstractCanvasGraph } = require("devtools/client/shared/widgets/Graphs");
 
 const { colorUtils } = require("devtools/shared/css-color");
 const { getColor } = require("devtools/client/shared/theme");
 const ProfilerGlobal = require("devtools/client/performance/modules/global");
-const MarkerUtils = require("devtools/client/performance/modules/logic/marker-utils");
+const { MarkerBlueprintUtils } = require("devtools/client/performance/modules/marker-blueprint-utils");
 const { TickUtils } = require("devtools/client/performance/modules/widgets/waterfall-ticks");
 const { TIMELINE_BLUEPRINT } = require("devtools/client/performance/modules/markers");
 
 const OVERVIEW_HEADER_HEIGHT = 14; // px
 const OVERVIEW_ROW_HEIGHT = 11; // px
 
 const OVERVIEW_SELECTION_LINE_COLOR = "#666";
 const OVERVIEW_CLIPHEAD_LINE_COLOR = "#555";
@@ -112,17 +112,17 @@ MarkersOverview.prototype = Heritage.ext
     let canvasWidth = this._width;
     let canvasHeight = this._height;
 
     // Group markers into separate paint batches. This is necessary to
     // draw all markers sharing the same style at once.
     for (let marker of markers) {
       // Again skip over markers that we're filtering -- we don't want them
       // to be labeled as "Unknown"
-      if (!MarkerUtils.isMarkerValid(marker, this._filter)) {
+      if (!MarkerBlueprintUtils.shouldDisplayMarker(marker, this._filter)) {
         continue;
       }
 
       let markerType = this._paintBatches.get(marker.name) || this._paintBatches.get("UNKNOWN");
       markerType.batch.push(marker);
     }
 
     // Calculate each row's height, and the time-based scaling.
--- a/devtools/client/performance/performance-controller.js
+++ b/devtools/client/performance/performance-controller.js
@@ -36,17 +36,17 @@ var system = require("devtools/shared/sy
 var { L10N } = require("devtools/client/performance/modules/global");
 var { PerformanceTelemetry } = require("devtools/client/performance/modules/logic/telemetry");
 var { TIMELINE_BLUEPRINT } = require("devtools/client/performance/modules/markers");
 var RecordingUtils = require("devtools/shared/performance/recording-utils");
 var { OptimizationsGraph, GraphsController } = require("devtools/client/performance/modules/widgets/graphs");
 var { WaterfallHeader } = require("devtools/client/performance/modules/widgets/waterfall-ticks");
 var { MarkerView } = require("devtools/client/performance/modules/widgets/marker-view");
 var { MarkerDetails } = require("devtools/client/performance/modules/widgets/marker-details");
-var MarkerUtils = require("devtools/client/performance/modules/logic/marker-utils");
+var { MarkerBlueprintUtils } = require("devtools/client/performance/modules/marker-blueprint-utils");
 var WaterfallUtils = require("devtools/client/performance/modules/logic/waterfall-utils");
 var FrameUtils = require("devtools/client/performance/modules/logic/frame-utils");
 var { CallView } = require("devtools/client/performance/modules/widgets/tree-view");
 var { ThreadNode } = require("devtools/client/performance/modules/logic/tree-model");
 var { FrameNode } = require("devtools/client/performance/modules/logic/tree-model");
 
 // Widgets modules
 
--- a/devtools/client/performance/test/browser_timeline-waterfall-sidebar.js
+++ b/devtools/client/performance/test/browser_timeline-waterfall-sidebar.js
@@ -4,17 +4,17 @@
 /**
  * Tests if the sidebar is properly updated when a marker is selected.
  */
 
 function* spawnTest() {
   let { target, panel } = yield initPerformance(SIMPLE_URL);
   let { $, $$, PerformanceController, WaterfallView } = panel.panelWin;
   let { L10N } = require("devtools/client/performance/modules/global");
-  let { getMarkerLabel } = require("devtools/client/performance/modules/logic/marker-utils");
+  let { MarkerBlueprintUtils } = require("devtools/client/performance/modules/marker-blueprint-utils");
 
   // Hijack the markers massaging part of creating the waterfall view,
   // to prevent collapsing markers and allowing this test to verify
   // everything individually. A better solution would be to just expand
   // all markers first and then skip the meta nodes, but I'm lazy.
   WaterfallView._prepareWaterfallTree = markers => {
     return { submarkers: markers };
   };
@@ -55,17 +55,17 @@ function* spawnTest() {
 
     let type = $(".marker-details-type").getAttribute("value");
     let tooltip = $(".marker-details-duration").getAttribute("tooltiptext");
     let duration = $(".marker-details-duration .marker-details-labelvalue").getAttribute("value");
 
     info("Current marker data: " + mkr.toSource());
     info("Current marker output: " + $("#waterfall-details").innerHTML);
 
-    is(type, getMarkerLabel(mkr), "Sidebar title matches markers name.");
+    is(type, MarkerBlueprintUtils.getMarkerLabel(mkr), "Sidebar title matches markers name.");
 
     // Values are rounded. We don't use a strict equality.
     is(toMs(mkr.end - mkr.start), duration, "Sidebar duration is valid.");
 
     // For some reason, anything that creates "→" here turns it into a "â" for some reason.
     // So just check that start and end time are in there somewhere.
     ok(tooltip.indexOf(toMs(mkr.start)) !== -1, "Tooltip has start time.");
     ok(tooltip.indexOf(toMs(mkr.end)) !== -1, "Tooltip has end time.");
--- a/devtools/client/performance/test/unit/test_marker-utils.js
+++ b/devtools/client/performance/test/unit/test_marker-utils.js
@@ -7,95 +7,95 @@
 
 function run_test() {
   run_next_test();
 }
 
 add_task(function () {
   let { TIMELINE_BLUEPRINT } = require("devtools/client/performance/modules/markers");
   let { PREFS } = require("devtools/client/performance/modules/global");
-  let Utils = require("devtools/client/performance/modules/logic/marker-utils");
+  let { MarkerBlueprintUtils } = require("devtools/client/performance/modules/marker-blueprint-utils");
 
   PREFS.registerObserver();
 
   Services.prefs.setBoolPref(PLATFORM_DATA_PREF, false);
 
-  equal(Utils.getMarkerLabel({ name: "DOMEvent" }), "DOM Event",
+  equal(MarkerBlueprintUtils.getMarkerLabel({ name: "DOMEvent" }), "DOM Event",
     "getMarkerLabel() returns a simple label");
-  equal(Utils.getMarkerLabel({ name: "Javascript", causeName: "setTimeout handler" }), "setTimeout",
+  equal(MarkerBlueprintUtils.getMarkerLabel({ name: "Javascript", causeName: "setTimeout handler" }), "setTimeout",
     "getMarkerLabel() returns a label defined via function");
-  equal(Utils.getMarkerLabel({ name: "GarbageCollection", causeName: "ALLOC_TRIGGER" }), "Incremental GC",
+  equal(MarkerBlueprintUtils.getMarkerLabel({ name: "GarbageCollection", causeName: "ALLOC_TRIGGER" }), "Incremental GC",
     "getMarkerLabel() returns a label for a function that is generalizable");
 
-  ok(Utils.getMarkerFields({ name: "Paint" }).length === 0,
+  ok(MarkerBlueprintUtils.getMarkerFields({ name: "Paint" }).length === 0,
     "getMarkerFields() returns an empty array when no fields defined");
 
-  let fields = Utils.getMarkerFields({ name: "ConsoleTime", causeName: "snowstorm" });
+  let fields = MarkerBlueprintUtils.getMarkerFields({ name: "ConsoleTime", causeName: "snowstorm" });
   equal(fields[0].label, "Timer Name:", "getMarkerFields() returns an array with proper label");
   equal(fields[0].value, "snowstorm", "getMarkerFields() returns an array with proper value");
 
-  fields = Utils.getMarkerFields({ name: "DOMEvent", type: "mouseclick" });
+  fields = MarkerBlueprintUtils.getMarkerFields({ name: "DOMEvent", type: "mouseclick" });
   equal(fields.length, 1, "getMarkerFields() ignores fields that are not found on marker");
   equal(fields[0].label, "Event Type:", "getMarkerFields() returns an array with proper label");
   equal(fields[0].value, "mouseclick", "getMarkerFields() returns an array with proper value");
 
-  fields = Utils.getMarkerFields({ name: "DOMEvent", eventPhase: Ci.nsIDOMEvent.AT_TARGET, type: "mouseclick" });
+  fields = MarkerBlueprintUtils.getMarkerFields({ name: "DOMEvent", eventPhase: Ci.nsIDOMEvent.AT_TARGET, type: "mouseclick" });
   equal(fields.length, 2, "getMarkerFields() returns multiple fields when using a fields function");
   equal(fields[0].label, "Event Type:", "getMarkerFields() correctly returns fields via function (1)");
   equal(fields[0].value, "mouseclick", "getMarkerFields() correctly returns fields via function (2)");
   equal(fields[1].label, "Phase:", "getMarkerFields() correctly returns fields via function (3)");
   equal(fields[1].value, "Target", "getMarkerFields() correctly returns fields via function (4)");
 
-  fields = Utils.getMarkerFields({ name: "GarbageCollection", causeName: "ALLOC_TRIGGER" });
+  fields = MarkerBlueprintUtils.getMarkerFields({ name: "GarbageCollection", causeName: "ALLOC_TRIGGER" });
   equal(fields[0].value, "Too Many Allocations", "Uses L10N for GC reasons");
 
-  fields = Utils.getMarkerFields({ name: "GarbageCollection", causeName: "NOT_A_GC_REASON" });
+  fields = MarkerBlueprintUtils.getMarkerFields({ name: "GarbageCollection", causeName: "NOT_A_GC_REASON" });
   equal(fields[0].value, "NOT_A_GC_REASON", "Defaults to enum for GC reasons when not L10N'd");
 
-  equal(Utils.getMarkerFields({ name: "Javascript", causeName: "Some Platform Field" })[0].value, "(Gecko)",
+  equal(MarkerBlueprintUtils.getMarkerFields({ name: "Javascript", causeName: "Some Platform Field" })[0].value, "(Gecko)",
     "Correctly obfuscates JS markers when platform data is off.");
   Services.prefs.setBoolPref(PLATFORM_DATA_PREF, true);
-  equal(Utils.getMarkerFields({ name: "Javascript", causeName: "Some Platform Field" })[0].value, "Some Platform Field",
+  equal(MarkerBlueprintUtils.getMarkerFields({ name: "Javascript", causeName: "Some Platform Field" })[0].value, "Some Platform Field",
     "Correctly deobfuscates JS markers when platform data is on.");
 
-  equal(Utils.getMarkerClassName("Javascript"), "Function Call",
-    "getMarkerClassName() returns correct string when defined via function");
-  equal(Utils.getMarkerClassName("GarbageCollection"), "Garbage Collection",
-    "getMarkerClassName() returns correct string when defined via function");
-  equal(Utils.getMarkerClassName("Reflow"), "Layout",
-    "getMarkerClassName() returns correct string when defined via string");
+  equal(MarkerBlueprintUtils.getMarkerGenericName("Javascript"), "Function Call",
+    "getMarkerGenericName() returns correct string when defined via function");
+  equal(MarkerBlueprintUtils.getMarkerGenericName("GarbageCollection"), "Garbage Collection",
+    "getMarkerGenericName() returns correct string when defined via function");
+  equal(MarkerBlueprintUtils.getMarkerGenericName("Reflow"), "Layout",
+    "getMarkerGenericName() returns correct string when defined via string");
 
   TIMELINE_BLUEPRINT["fakemarker"] = { group: 0 };
   try {
-    Utils.getMarkerClassName("fakemarker");
-    ok(false, "getMarkerClassName() should throw when no label on blueprint.");
+    MarkerBlueprintUtils.getMarkerGenericName("fakemarker");
+    ok(false, "getMarkerGenericName() should throw when no label on blueprint.");
   } catch (e) {
-    ok(true, "getMarkerClassName() should throw when no label on blueprint.");
+    ok(true, "getMarkerGenericName() should throw when no label on blueprint.");
   }
 
   TIMELINE_BLUEPRINT["fakemarker"] = { group: 0, label: () => void 0 };
   try {
-    Utils.getMarkerClassName("fakemarker");
-    ok(false, "getMarkerClassName() should throw when label function returnd undefined.");
+    MarkerBlueprintUtils.getMarkerGenericName("fakemarker");
+    ok(false, "getMarkerGenericName() should throw when label function returnd undefined.");
   } catch (e) {
-    ok(true, "getMarkerClassName() should throw when label function returnd undefined.");
+    ok(true, "getMarkerGenericName() should throw when label function returnd undefined.");
   }
 
   delete TIMELINE_BLUEPRINT["fakemarker"];
 
   let customBlueprint = {
     UNKNOWN: {
       group: 1,
       label: "MyDefault"
     },
     custom: {
       group: 0,
       label: "MyCustom"
     }
   };
 
-  equal(Utils.getBlueprintFor({ name: "Reflow" }).label, "Layout",
-    "Utils.getBlueprintFor() should return marker def for passed in marker.");
-  equal(Utils.getBlueprintFor({ name: "Not sure!" }).label(), "Unknown",
-    "Utils.getBlueprintFor() should return a default marker def if the marker is undefined.");
+  equal(MarkerBlueprintUtils.getBlueprintFor({ name: "Reflow" }).label, "Layout",
+    "getBlueprintFor() should return marker def for passed in marker.");
+  equal(MarkerBlueprintUtils.getBlueprintFor({ name: "Not sure!" }).label(), "Unknown",
+    "getBlueprintFor() should return a default marker def if the marker is undefined.");
 
   PREFS.unregisterObserver();
 });
--- a/devtools/client/performance/views/toolbar.js
+++ b/devtools/client/performance/views/toolbar.js
@@ -56,17 +56,17 @@ var ToolbarView = {
    */
   _buildMarkersFilterPopup: function() {
     for (let [markerName, markerDetails] of Iterator(TIMELINE_BLUEPRINT)) {
       let menuitem = document.createElement("menuitem");
       menuitem.setAttribute("closemenu", "none");
       menuitem.setAttribute("type", "checkbox");
       menuitem.setAttribute("align", "center");
       menuitem.setAttribute("flex", "1");
-      menuitem.setAttribute("label", MarkerUtils.getMarkerClassName(markerName));
+      menuitem.setAttribute("label", MarkerBlueprintUtils.getMarkerGenericName(markerName));
       menuitem.setAttribute("marker-type", markerName);
       menuitem.className = `marker-color-${markerDetails.colorName}`;
 
       menuitem.addEventListener("command", this._onHiddenMarkersChanged);
 
       $("#performance-filter-menupopup").appendChild(menuitem);
     }
   },
--- a/devtools/client/themes/performance.css
+++ b/devtools/client/themes/performance.css
@@ -546,17 +546,17 @@
 }
 
 .marker-details-bullet {
   width: 8px;
   height: 8px;
   border-radius: 1px;
 }
 
-.marker-details-labelname {
+.marker-details-name-label {
   -moz-padding-end: 4px;
 }
 
 .marker-details-type {
   font-size: 1.2em;
   font-weight: bold;
 }
 
--- a/devtools/client/webconsole/test/browser.ini
+++ b/devtools/client/webconsole/test/browser.ini
@@ -310,17 +310,16 @@ skip-if = e10s # Bug 1042253 - webconsol
 [browser_webconsole_js_input_expansion.js]
 [browser_webconsole_jsterm.js]
 skip-if = e10s # Bug 1042253 - webconsole e10s tests (Linux debug timeout)
 [browser_webconsole_live_filtering_of_message_types.js]
 [browser_webconsole_live_filtering_on_search_strings.js]
 [browser_webconsole_message_node_id.js]
 [browser_webconsole_multiline_input.js]
 [browser_webconsole_netlogging.js]
-skip-if = e10s # Bug 1242234, bug 1242318
 [browser_webconsole_netlogging_basic.js]
 [browser_webconsole_netlogging_panel.js]
 [browser_webconsole_netlogging_reset_filter.js]
 [browser_webconsole_notifications.js]
 [browser_webconsole_open-links-without-callback.js]
 [browser_webconsole_promise.js]
 [browser_webconsole_output_copy_newlines.js]
 [browser_webconsole_output_order.js]
--- a/devtools/client/webconsole/test/browser_console_netlogging.js
+++ b/devtools/client/webconsole/test/browser_console_netlogging.js
@@ -7,17 +7,20 @@
 
 "use strict";
 
 const TEST_NETWORK_REQUEST_URI =
   "http://example.com/browser/devtools/client/webconsole/test/" +
   "test-network-request.html";
 
 add_task(function* () {
-  let finishedRequest = waitForFinishedRequest();
+  let finishedRequest = waitForFinishedRequest(({ request }) => {
+    return request.url === TEST_NETWORK_REQUEST_URI;
+  });
+
   const hud = yield loadPageAndGetHud(TEST_NETWORK_REQUEST_URI,
                                       "browserConsole");
   let request = yield finishedRequest;
 
   ok(request, "Page load was logged");
 
   let client = hud.ui.webConsoleClient;
   let args = [request.actor];
--- a/devtools/client/webconsole/test/browser_webconsole_bug_632817.js
+++ b/devtools/client/webconsole/test/browser_webconsole_bug_632817.js
@@ -15,16 +15,25 @@ const TEST_IMG = "http://example.com/bro
                  "test/test-image.png";
 
 const TEST_DATA_JSON_CONTENT =
   '{ id: "test JSON data", myArray: [ "foo", "bar", "baz", "biff" ] }';
 
 const TEST_URI = "data:text/html;charset=utf-8,Web Console network logging " +
                  "tests";
 
+const PAGE_REQUEST_PREDICATE =
+  ({ request }) => request.url.endsWith("test-network-request.html");
+
+const TEST_DATA_REQUEST_PREDICATE =
+  ({ request }) => request.url.endsWith("test-data.json");
+
+const XHR_WARN_REQUEST_PREDICATE =
+  ({ request }) => request.url.endsWith("sjs_cors-test-server.sjs");
+
 let hud;
 
 add_task(function*() {
   const PREF = "devtools.webconsole.persistlog";
   const NET_PREF = "devtools.webconsole.filter.networkinfo";
   const NETXHR_PREF = "devtools.webconsole.filter.netxhr";
   const MIXED_AC_PREF = "security.mixed_content.block_active_content";
   let original = Services.prefs.getBoolPref(NET_PREF);
@@ -51,79 +60,76 @@ add_task(function*() {
   yield testXhrPost();
   yield testFormSubmission();
   yield testLiveFilteringOnSearchStrings();
 });
 
 function testPageLoad() {
 
   BrowserTestUtils.loadURI(gBrowser.selectedBrowser, TEST_NETWORK_REQUEST_URI);
-  let lastRequest = yield new Promise(resolve => {
-    HUDService.lastFinishedRequest.callback = function(request) {
-      resolve(request);
-    };
-  });
+  let lastRequest = yield waitForFinishedRequest(PAGE_REQUEST_PREDICATE);
 
   // Check if page load was logged correctly.
   ok(lastRequest, "Page load was logged");
   is(lastRequest.request.url, TEST_NETWORK_REQUEST_URI,
     "Logged network entry is page load");
   is(lastRequest.request.method, "GET", "Method is correct");
 }
 
 function testXhrGet() {
   // Start the XMLHttpRequest() GET test.
   ContentTask.spawn(gBrowser.selectedBrowser, {}, function*() {
     content.wrappedJSObject.testXhrGet();
   });
 
-  let lastRequest = yield waitForFinishedRequest();
+  let lastRequest = yield waitForFinishedRequest(TEST_DATA_REQUEST_PREDICATE);
 
   ok(lastRequest, "testXhrGet() was logged");
   is(lastRequest.request.method, "GET", "Method is correct");
   ok(lastRequest.isXHR, "It's an XHR request");
 }
 
 function testXhrWarn() {
   // Start the XMLHttpRequest() warn test.
   ContentTask.spawn(gBrowser.selectedBrowser, {}, function*() {
     content.wrappedJSObject.testXhrWarn();
   });
 
-  let lastRequest = yield waitForFinishedRequest();
+  let lastRequest = yield waitForFinishedRequest(XHR_WARN_REQUEST_PREDICATE);
 
   ok(lastRequest, "testXhrWarn() was logged");
   is(lastRequest.request.method, "GET", "Method is correct");
   ok(lastRequest.isXHR, "It's an XHR request");
   is(lastRequest.securityInfo, "insecure", "It's an insecure request");
 }
 
 function testXhrPost() {
   // Start the XMLHttpRequest() POST test.
   ContentTask.spawn(gBrowser.selectedBrowser, {}, function*() {
     content.wrappedJSObject.testXhrPost();
   });
 
-  let lastRequest = yield waitForFinishedRequest();
+  let lastRequest = yield waitForFinishedRequest(TEST_DATA_REQUEST_PREDICATE);
 
   ok(lastRequest, "testXhrPost() was logged");
   is(lastRequest.request.method, "POST", "Method is correct");
   ok(lastRequest.isXHR, "It's an XHR request");
 }
 
 function testFormSubmission() {
   // Start the form submission test. As the form is submitted, the page is
   // loaded again. Bind to the load event to catch when this is done.
   ContentTask.spawn(gBrowser.selectedBrowser, {}, function*() {
     let form = content.document.querySelector("form");
     ok(form, "we have the HTML form");
     form.submit();
   });
 
-  let lastRequest = yield waitForFinishedRequest();
+  // The form POSTs to the page URL but over https (page over http).
+  let lastRequest = yield waitForFinishedRequest(PAGE_REQUEST_PREDICATE);
 
   ok(lastRequest, "testFormSubmission() was logged");
   is(lastRequest.request.method, "POST", "Method is correct");
 
   // There should be 3 network requests pointing to the HTML file.
   waitForMessages({
     webconsole: hud,
     messages: [
--- a/devtools/client/webconsole/test/browser_webconsole_netlogging.js
+++ b/devtools/client/webconsole/test/browser_webconsole_netlogging.js
@@ -9,18 +9,24 @@
 
 const TEST_NETWORK_REQUEST_URI =
   "http://example.com/browser/devtools/client/webconsole/test/" +
   "test-network-request.html";
 
 const TEST_DATA_JSON_CONTENT =
   '{ id: "test JSON data", myArray: [ "foo", "bar", "baz", "biff" ] }';
 
+const PAGE_REQUEST_PREDICATE =
+  ({ request }) => request.url.endsWith("test-network-request.html");
+
+const TEST_DATA_REQUEST_PREDICATE =
+  ({ request }) => request.url.endsWith("test-data.json");
+
 add_task(function* testPageLoad() {
-  let finishedRequest = waitForFinishedRequest();
+  let finishedRequest = waitForFinishedRequest(PAGE_REQUEST_PREDICATE);
   let hud = yield loadPageAndGetHud(TEST_NETWORK_REQUEST_URI);
   let request = yield finishedRequest;
 
   ok(request, "Page load was logged");
 
   let client = hud.ui.webConsoleClient;
   let args = [request.actor];
   const postData = yield getPacket(client, "getRequestPostData", args);
@@ -34,17 +40,17 @@ add_task(function* testPageLoad() {
     "Request body was not discarded");
   is(responseContent.content.text.indexOf("<!DOCTYPE HTML>"), 0,
     "Response body's beginning is okay");
 });
 
 add_task(function* testXhrGet() {
   let hud = yield loadPageAndGetHud(TEST_NETWORK_REQUEST_URI);
 
-  let finishedRequest = waitForFinishedRequest();
+  let finishedRequest = waitForFinishedRequest(TEST_DATA_REQUEST_PREDICATE);
   content.wrappedJSObject.testXhrGet();
   let request = yield finishedRequest;
 
   ok(request, "testXhrGet() was logged");
 
   let client = hud.ui.webConsoleClient;
   let args = [request.actor];
   const postData = yield getPacket(client, "getRequestPostData", args);
@@ -56,17 +62,17 @@ add_task(function* testXhrGet() {
     "Request body was not discarded");
   is(responseContent.content.text, TEST_DATA_JSON_CONTENT,
     "Response is correct");
 });
 
 add_task(function* testXhrPost() {
   let hud = yield loadPageAndGetHud(TEST_NETWORK_REQUEST_URI);
 
-  let finishedRequest = waitForFinishedRequest();
+  let finishedRequest = waitForFinishedRequest(TEST_DATA_REQUEST_PREDICATE);
   content.wrappedJSObject.testXhrPost();
   let request = yield finishedRequest;
 
   ok(request, "testXhrPost() was logged");
 
   let client = hud.ui.webConsoleClient;
   let args = [request.actor];
   const postData = yield getPacket(client, "getRequestPostData", args);
@@ -76,17 +82,18 @@ add_task(function* testXhrPost() {
   is(postData.postData.text, "Hello world!", "Request body was logged");
   is(responseContent.content.text, TEST_DATA_JSON_CONTENT,
     "Response is correct");
 });
 
 add_task(function* testFormSubmission() {
   let hud = yield loadPageAndGetHud(TEST_NETWORK_REQUEST_URI);
 
-  let finishedRequest = waitForFinishedRequest();
+  // The form POSTs to the page URL but over https (page over http).
+  let finishedRequest = waitForFinishedRequest(PAGE_REQUEST_PREDICATE);
   ContentTask.spawn(gBrowser.selectedBrowser, { }, `function()
   {
     let form = content.document.querySelector("form");
     form.submit();
   }`);
   let request = yield finishedRequest;
 
   ok(request, "testFormSubmission() was logged");
--- a/devtools/client/webconsole/test/browser_webconsole_netlogging_panel.js
+++ b/devtools/client/webconsole/test/browser_webconsole_netlogging_panel.js
@@ -6,17 +6,20 @@
 
 "use strict";
 
 const TEST_NETWORK_REQUEST_URI =
   "http://example.com/browser/devtools/client/webconsole/test/" +
   "test-network-request.html";
 
 add_task(function* () {
-  let finishedRequest = waitForFinishedRequest();
+  let finishedRequest = waitForFinishedRequest(({ request }) => {
+    return request.url.endsWith("test-network-request.html");
+  });
+
   const hud = yield loadPageAndGetHud(TEST_NETWORK_REQUEST_URI);
   let request = yield finishedRequest;
 
   yield hud.ui.openNetworkPanel(request.actor);
   let toolbox = gDevTools.getToolbox(hud.target);
   is(toolbox.currentToolId, "netmonitor", "Network panel was opened");
   let panel = toolbox.getCurrentPanel();
   let selected = panel.panelWin.NetMonitorView.RequestsMenu.selectedItem;
--- a/devtools/client/webconsole/test/head.js
+++ b/devtools/client/webconsole/test/head.js
@@ -1627,26 +1627,40 @@ function checkOutputForInputs(hud, input
 
   return Task.spawn(runner);
 }
 
 
 /**
  * Finish the request and resolve with the request object.
  *
+ * @param {Function} predicate A predicate function that takes the request
+ * object as an argument and returns true if the request was the expected one,
+ * false otherwise. The returned promise is resolved ONLY if the predicate
+ * matches a request. Defaults to accepting any request.
  * @return promise
  * @resolves The request object.
  */
-function waitForFinishedRequest() {
+function waitForFinishedRequest(predicate = () => true) {
   registerCleanupFunction(function() {
     HUDService.lastFinishedRequest.callback = null;
   });
 
   return new Promise(resolve => {
-    HUDService.lastFinishedRequest.callback = request => { resolve(request) };
+    HUDService.lastFinishedRequest.callback = request => {
+      // Check if this is the expected request
+      if (predicate(request)) {
+        // Match found. Clear the listener.
+        HUDService.lastFinishedRequest.callback = null;
+
+        resolve(request);
+      } else {
+        info(`Ignoring unexpected request ${JSON.stringify(request, null, 2)}`);
+      }
+    }
   });
 }
 
 /**
  * Wait for eventName on target.
  * @param {Object} target An observable object that either supports on/off or
  * addEventListener/removeEventListener
  * @param {String} eventName