Merge from mozilla-central.
authorDavid Anderson <danderson@mozilla.com>
Thu, 12 Jul 2012 13:23:26 -0700
changeset 106542 35ef899801bc
parent 106541 1de2098ac6d9 (current diff)
parent 99068 f9499238bd4b (diff)
child 106543 3359300edfe7
push id23447
push userdanderson@mozilla.com
push dateTue, 11 Sep 2012 17:34:27 +0000
treeherdermozilla-central@fdfaef738a00 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone16.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge from mozilla-central.
accessible/src/base/nsARIAMap.cpp
accessible/src/base/nsARIAMap.h
accessible/src/base/nsAccessNode.cpp
accessible/src/base/nsAccessNode.h
accessible/src/generic/Accessible.cpp
accessible/src/generic/Accessible.h
accessible/src/msaa/nsAccessNodeWrap.cpp
aclocal.m4
b2g/installer/package-manifest.in
browser/app/macbuild/Contents/_CodeSignature/CodeResources
browser/app/nsBrowserApp.cpp
browser/base/content/browser.js
browser/base/content/highlighter.css
browser/base/content/test/browser_sanitizeDialog.js
browser/components/shell/src/nsWindowsShellService.cpp
browser/devtools/webconsole/HUDService.jsm
browser/devtools/webconsole/test/Makefile.in
browser/locales/en-US/chrome/browser/browser.dtd
browser/themes/winstripe/browser.css
build/mobile/devicemanagerADB.py
build/mobile/devicemanagerSUT.py
caps/src/nsPrincipal.cpp
config/autoconf.mk.in
config/system-headers
configure.in
content/base/src/nsContentSink.h
content/base/src/nsDocument.cpp
content/base/src/nsFrameLoader.cpp
content/base/src/nsWebSocket.cpp
content/base/src/nsWebSocket.h
content/canvas/src/Makefile.in
content/events/src/nsEventListenerManager.cpp
content/media/MediaEngine.h
content/media/MediaEngineDefault.cpp
content/media/MediaEngineDefault.h
content/svg/content/src/SVGLengthList.h
content/xml/document/src/nsXMLContentSink.h
docshell/base/nsDSURIContentListener.cpp
docshell/base/nsDocShell.cpp
dom/Makefile.in
dom/base/nsFocusManager.cpp
dom/base/nsGlobalWindow.cpp
dom/base/nsGlobalWindow.h
dom/base/nsJSEnvironment.cpp
dom/base/nsPIDOMWindow.h
dom/indexedDB/IDBIndex.cpp
dom/ipc/CrashReporterParent.cpp
dom/ipc/CrashReporterParent.h
dom/ipc/TabChild.cpp
dom/plugins/base/nsPluginHost.cpp
dom/plugins/base/nsPluginHost.h
dom/plugins/base/nsPluginInstanceOwner.h
dom/plugins/base/nsPluginTags.cpp
dom/plugins/base/nsPluginTags.h
dom/plugins/ipc/PluginInstanceChild.cpp
dom/plugins/ipc/PluginModuleParent.cpp
dom/plugins/ipc/PluginModuleParent.h
dom/workers/WorkerPrivate.cpp
editor/libeditor/base/nsEditor.cpp
editor/libeditor/base/nsIEditorSupport.h
editor/libeditor/html/nsHTMLEditRules.cpp
embedding/browser/webBrowser/nsDocShellTreeOwner.cpp
embedding/components/windowwatcher/src/nsWindowWatcher.cpp
embedding/components/windowwatcher/src/nsWindowWatcher.h
extensions/auth/nsAuthSambaNTLM.cpp
extensions/spellcheck/src/mozSpellChecker.cpp
gfx/angle/Makefile.in
gfx/gl/GLContext.h
gfx/gl/GLContextProviderEGL.cpp
gfx/layers/basic/BasicCanvasLayer.cpp
gfx/layers/ipc/PLayers.ipdl
gfx/layers/opengl/CanvasLayerOGL.cpp
gfx/layers/opengl/CanvasLayerOGL.h
gfx/layers/opengl/ThebesLayerOGL.cpp
gfx/thebes/gfxAndroidPlatform.cpp
gfx/thebes/gfxAndroidPlatform.h
gfx/thebes/gfxFT2FontList.cpp
ipc/glue/GeckoChildProcessHost.cpp
js/jsd/jsd_val.c
js/jsd/jsd_xpc.cpp
js/src/Makefile.in
js/src/MemoryMetrics.cpp
js/src/builtin/Eval.cpp
js/src/config/autoconf.mk.in
js/src/config/system-headers
js/src/configure.in
js/src/frontend/BytecodeCompiler.cpp
js/src/frontend/BytecodeCompiler.h
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/BytecodeEmitter.h
js/src/frontend/FoldConstants.cpp
js/src/frontend/ParseNode.cpp
js/src/frontend/ParseNode.h
js/src/frontend/Parser.cpp
js/src/frontend/Parser.h
js/src/frontend/SemanticAnalysis.cpp
js/src/gc/Barrier.h
js/src/gc/Root.h
js/src/jsanalyze.cpp
js/src/jsanalyze.h
js/src/jsapi-tests/Makefile.in
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsarray.cpp
js/src/jsatom.cpp
js/src/jsatom.h
js/src/jscntxt.cpp
js/src/jscntxt.h
js/src/jscntxtinlines.h
js/src/jscompartment.cpp
js/src/jscompartment.h
js/src/jsdate.cpp
js/src/jsdate.h
js/src/jsdbgapi.cpp
js/src/jsdbgapi.h
js/src/jsexn.cpp
js/src/jsfriendapi.cpp
js/src/jsfriendapi.h
js/src/jsfun.cpp
js/src/jsfun.h
js/src/jsgc.cpp
js/src/jsinfer.cpp
js/src/jsinfer.h
js/src/jsinferinlines.h
js/src/jsinterp.cpp
js/src/jsinterpinlines.h
js/src/jsiter.cpp
js/src/jsnum.cpp
js/src/jsnum.h
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jsobjinlines.h
js/src/json.cpp
js/src/jsopcode.cpp
js/src/jsopcode.tbl
js/src/jspropertycache.cpp
js/src/jsproxy.cpp
js/src/jsprvtd.h
js/src/jsreflect.cpp
js/src/jsscope.cpp
js/src/jsscript.cpp
js/src/jsscript.h
js/src/jsscriptinlines.h
js/src/jsstr.cpp
js/src/jsstr.h
js/src/jstypedarray.cpp
js/src/jstypedarray.h
js/src/jswrapper.cpp
js/src/jswrapper.h
js/src/jsxml.cpp
js/src/methodjit/BaseAssembler.h
js/src/methodjit/Compiler.cpp
js/src/methodjit/FastOps.cpp
js/src/methodjit/InvokeHelpers.cpp
js/src/methodjit/MethodJIT.h
js/src/methodjit/MonoIC.cpp
js/src/methodjit/PolyIC.cpp
js/src/methodjit/StubCalls.cpp
js/src/methodjit/StubCalls.h
js/src/shell/js.cpp
js/src/vm/ArgumentsObject.cpp
js/src/vm/Debugger.cpp
js/src/vm/GlobalObject.cpp
js/src/vm/RegExpObject-inl.h
js/src/vm/RegExpObject.cpp
js/src/vm/RegExpObject.h
js/src/vm/SPSProfiler.h
js/src/vm/ScopeObject-inl.h
js/src/vm/ScopeObject.cpp
js/src/vm/ScopeObject.h
js/src/vm/Stack-inl.h
js/src/vm/Stack.cpp
js/src/vm/Stack.h
js/xpconnect/src/XPCDebug.cpp
js/xpconnect/src/XPCJSRuntime.cpp
js/xpconnect/wrappers/AccessCheck.cpp
js/xpconnect/wrappers/AccessCheck.h
js/xpconnect/wrappers/WrapperFactory.cpp
js/xpconnect/wrappers/XrayWrapper.cpp
layout/base/crashtests/crashtests.list
layout/base/nsCSSFrameConstructor.cpp
layout/base/nsPresShell.cpp
layout/build/Makefile.in
layout/generic/nsFrame.cpp
layout/generic/nsHTMLReflowState.cpp
layout/generic/nsPlaceholderFrame.cpp
layout/generic/nsTextFrameThebes.cpp
layout/reftests/font-inflation/bullet-2-ref.html
layout/reftests/font-inflation/bullet-2.html
layout/style/nsCSSParser.cpp
layout/style/test/Makefile.in
layout/style/test/property_database.js
layout/style/test/test_transitions_per_property.html
layout/svg/base/src/nsSVGGlyphFrame.cpp
layout/svg/base/src/nsSVGPathGeometryFrame.cpp
layout/svg/base/src/nsSVGUtils.cpp
layout/svg/base/src/nsSVGUtils.h
layout/xul/base/src/nsMenuFrame.cpp
layout/xul/base/src/nsProgressMeterFrame.cpp
layout/xul/base/src/nsSliderFrame.cpp
layout/xul/base/src/nsSliderFrame.h
layout/xul/base/src/nsTextBoxFrame.cpp
memory/mozjemalloc/jemalloc.c
mobile/android/app/macbuild/Contents/Info.plist.in
mobile/android/app/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in
mobile/android/app/maemo/toolbar_splash.png
mobile/android/base/AndroidManifest.xml.in
mobile/android/base/GeckoApp.java
mobile/android/base/GeckoAppShell.java
mobile/android/base/Makefile.in
mobile/android/base/resources/drawable-hdpi/tabs_carat_contracted.png
mobile/android/base/resources/drawable-hdpi/tabs_carat_expanded.png
mobile/android/base/resources/drawable-hdpi/tabs_expanded_normal.png
mobile/android/base/resources/drawable-hdpi/tabs_expanded_pressed.png
mobile/android/base/resources/drawable-land-hdpi-v14/tabs_carat_contracted.png
mobile/android/base/resources/drawable-land-hdpi-v14/tabs_carat_expanded.png
mobile/android/base/resources/drawable-land-hdpi-v14/tabs_expanded_normal.png
mobile/android/base/resources/drawable-land-hdpi-v14/tabs_expanded_pressed.png
mobile/android/base/resources/drawable-land-mdpi-v14/tabs_carat_contracted.png
mobile/android/base/resources/drawable-land-mdpi-v14/tabs_carat_expanded.png
mobile/android/base/resources/drawable-land-mdpi-v14/tabs_expanded_normal.png
mobile/android/base/resources/drawable-land-mdpi-v14/tabs_expanded_pressed.png
mobile/android/base/resources/drawable-land-xhdpi-v14/tabs_carat_contracted.png
mobile/android/base/resources/drawable-land-xhdpi-v14/tabs_carat_expanded.png
mobile/android/base/resources/drawable-land-xhdpi-v14/tabs_expanded_normal.png
mobile/android/base/resources/drawable-land-xhdpi-v14/tabs_expanded_pressed.png
mobile/android/base/resources/drawable-sw600dp-hdpi/address_bar_back_button_bg.png
mobile/android/base/resources/drawable-sw600dp-hdpi/address_bar_back_button_pressed_bg.png
mobile/android/base/resources/drawable-sw600dp-hdpi/address_bar_texture_tablet.png
mobile/android/base/resources/drawable-sw600dp-hdpi/address_bar_url_default.9.png
mobile/android/base/resources/drawable-sw600dp-hdpi/address_bar_url_pressed.9.png
mobile/android/base/resources/drawable-sw600dp-hdpi/awesomebar_tab_center.9.png
mobile/android/base/resources/drawable-sw600dp-hdpi/awesomebar_tab_left.9.png
mobile/android/base/resources/drawable-sw600dp-hdpi/awesomebar_tab_right.9.png
mobile/android/base/resources/drawable-sw600dp-hdpi/ic_awesomebar_go.png
mobile/android/base/resources/drawable-sw600dp-hdpi/ic_awesomebar_search.png
mobile/android/base/resources/drawable-sw600dp-hdpi/ic_menu_bookmark_add.png
mobile/android/base/resources/drawable-sw600dp-hdpi/ic_menu_bookmark_remove.png
mobile/android/base/resources/drawable-sw600dp-hdpi/ic_menu_forward.png
mobile/android/base/resources/drawable-sw600dp-hdpi/ic_menu_reload.png
mobile/android/base/resources/drawable-sw600dp-hdpi/menu.png
mobile/android/base/resources/drawable-sw600dp-hdpi/reader.png
mobile/android/base/resources/drawable-sw600dp-hdpi/remote_tabs_off.png
mobile/android/base/resources/drawable-sw600dp-hdpi/remote_tabs_on.png
mobile/android/base/resources/drawable-sw600dp-hdpi/site_security_identified.png
mobile/android/base/resources/drawable-sw600dp-hdpi/site_security_verified.png
mobile/android/base/resources/drawable-sw600dp-hdpi/tab_new.png
mobile/android/base/resources/drawable-sw600dp-hdpi/tabs_carat_contracted.png
mobile/android/base/resources/drawable-sw600dp-hdpi/tabs_carat_expanded.png
mobile/android/base/resources/drawable-sw600dp-hdpi/tabs_expanded_normal.png
mobile/android/base/resources/drawable-sw600dp-hdpi/tabs_expanded_pressed.png
mobile/android/base/resources/drawable-sw600dp-hdpi/tabs_normal.png
mobile/android/base/resources/drawable-sw600dp-hdpi/tabs_pressed.png
mobile/android/base/resources/drawable-sw600dp-hdpi/urlbar_stop.png
mobile/android/base/resources/drawable-sw600dp-mdpi/address_bar_back_button_bg.png
mobile/android/base/resources/drawable-sw600dp-mdpi/address_bar_back_button_pressed_bg.png
mobile/android/base/resources/drawable-sw600dp-mdpi/address_bar_bg.xml
mobile/android/base/resources/drawable-sw600dp-mdpi/address_bar_texture_tablet.png
mobile/android/base/resources/drawable-sw600dp-mdpi/address_bar_url_default.9.png
mobile/android/base/resources/drawable-sw600dp-mdpi/address_bar_url_pressed.9.png
mobile/android/base/resources/drawable-sw600dp-mdpi/awesomebar_tab_center.9.png
mobile/android/base/resources/drawable-sw600dp-mdpi/awesomebar_tab_left.9.png
mobile/android/base/resources/drawable-sw600dp-mdpi/awesomebar_tab_right.9.png
mobile/android/base/resources/drawable-sw600dp-mdpi/ic_awesomebar_go.png
mobile/android/base/resources/drawable-sw600dp-mdpi/ic_awesomebar_search.png
mobile/android/base/resources/drawable-sw600dp-mdpi/ic_menu_bookmark_add.png
mobile/android/base/resources/drawable-sw600dp-mdpi/ic_menu_bookmark_remove.png
mobile/android/base/resources/drawable-sw600dp-mdpi/ic_menu_forward.png
mobile/android/base/resources/drawable-sw600dp-mdpi/ic_menu_reload.png
mobile/android/base/resources/drawable-sw600dp-mdpi/menu.png
mobile/android/base/resources/drawable-sw600dp-mdpi/reader.png
mobile/android/base/resources/drawable-sw600dp-mdpi/remote_tabs_off.png
mobile/android/base/resources/drawable-sw600dp-mdpi/remote_tabs_on.png
mobile/android/base/resources/drawable-sw600dp-mdpi/site_security_identified.png
mobile/android/base/resources/drawable-sw600dp-mdpi/site_security_verified.png
mobile/android/base/resources/drawable-sw600dp-mdpi/tab_new.png
mobile/android/base/resources/drawable-sw600dp-mdpi/tabs_carat_contracted.png
mobile/android/base/resources/drawable-sw600dp-mdpi/tabs_carat_expanded.png
mobile/android/base/resources/drawable-sw600dp-mdpi/tabs_expanded_normal.png
mobile/android/base/resources/drawable-sw600dp-mdpi/tabs_expanded_pressed.png
mobile/android/base/resources/drawable-sw600dp-mdpi/tabs_normal.png
mobile/android/base/resources/drawable-sw600dp-mdpi/tabs_pressed.png
mobile/android/base/resources/drawable-sw600dp-mdpi/urlbar_stop.png
mobile/android/base/resources/drawable-sw600dp-xhdpi/address_bar_back_button_bg.png
mobile/android/base/resources/drawable-sw600dp-xhdpi/address_bar_back_button_pressed_bg.png
mobile/android/base/resources/drawable-sw600dp-xhdpi/address_bar_texture_tablet.png
mobile/android/base/resources/drawable-sw600dp-xhdpi/address_bar_url_default.9.png
mobile/android/base/resources/drawable-sw600dp-xhdpi/address_bar_url_pressed.9.png
mobile/android/base/resources/drawable-sw600dp-xhdpi/awesomebar_tab_center.9.png
mobile/android/base/resources/drawable-sw600dp-xhdpi/awesomebar_tab_left.9.png
mobile/android/base/resources/drawable-sw600dp-xhdpi/awesomebar_tab_right.9.png
mobile/android/base/resources/drawable-sw600dp-xhdpi/ic_awesomebar_go.png
mobile/android/base/resources/drawable-sw600dp-xhdpi/ic_awesomebar_search.png
mobile/android/base/resources/drawable-sw600dp-xhdpi/ic_menu_bookmark_add.png
mobile/android/base/resources/drawable-sw600dp-xhdpi/ic_menu_bookmark_remove.png
mobile/android/base/resources/drawable-sw600dp-xhdpi/ic_menu_forward.png
mobile/android/base/resources/drawable-sw600dp-xhdpi/ic_menu_reload.png
mobile/android/base/resources/drawable-sw600dp-xhdpi/menu.png
mobile/android/base/resources/drawable-sw600dp-xhdpi/reader.png
mobile/android/base/resources/drawable-sw600dp-xhdpi/remote_tabs_off.png
mobile/android/base/resources/drawable-sw600dp-xhdpi/remote_tabs_on.png
mobile/android/base/resources/drawable-sw600dp-xhdpi/site_security_identified.png
mobile/android/base/resources/drawable-sw600dp-xhdpi/site_security_verified.png
mobile/android/base/resources/drawable-sw600dp-xhdpi/tab_new.png
mobile/android/base/resources/drawable-sw600dp-xhdpi/tabs_carat_contracted.png
mobile/android/base/resources/drawable-sw600dp-xhdpi/tabs_carat_expanded.png
mobile/android/base/resources/drawable-sw600dp-xhdpi/tabs_expanded_normal.png
mobile/android/base/resources/drawable-sw600dp-xhdpi/tabs_expanded_pressed.png
mobile/android/base/resources/drawable-sw600dp-xhdpi/tabs_normal.png
mobile/android/base/resources/drawable-sw600dp-xhdpi/tabs_pressed.png
mobile/android/base/resources/drawable-sw600dp-xhdpi/urlbar_stop.png
mobile/android/base/resources/drawable-xhdpi-v11/menu.png
mobile/android/base/resources/drawable-xhdpi-v11/tabs_carat_contracted.png
mobile/android/base/resources/drawable-xhdpi-v11/tabs_carat_expanded.png
mobile/android/base/resources/drawable-xhdpi-v11/tabs_expanded_normal.png
mobile/android/base/resources/drawable-xhdpi-v11/tabs_expanded_pressed.png
mobile/android/base/resources/drawable-xlarge-hdpi/address_bar_back_button_bg.png
mobile/android/base/resources/drawable-xlarge-hdpi/address_bar_back_button_pressed_bg.png
mobile/android/base/resources/drawable-xlarge-hdpi/address_bar_texture_tablet.png
mobile/android/base/resources/drawable-xlarge-hdpi/address_bar_url_default.9.png
mobile/android/base/resources/drawable-xlarge-hdpi/address_bar_url_pressed.9.png
mobile/android/base/resources/drawable-xlarge-hdpi/awesomebar_tab_center.9.png
mobile/android/base/resources/drawable-xlarge-hdpi/awesomebar_tab_left.9.png
mobile/android/base/resources/drawable-xlarge-hdpi/awesomebar_tab_right.9.png
mobile/android/base/resources/drawable-xlarge-hdpi/ic_awesomebar_go.png
mobile/android/base/resources/drawable-xlarge-hdpi/ic_awesomebar_search.png
mobile/android/base/resources/drawable-xlarge-hdpi/ic_menu_bookmark_add.png
mobile/android/base/resources/drawable-xlarge-hdpi/ic_menu_bookmark_remove.png
mobile/android/base/resources/drawable-xlarge-hdpi/ic_menu_forward.png
mobile/android/base/resources/drawable-xlarge-hdpi/ic_menu_reload.png
mobile/android/base/resources/drawable-xlarge-hdpi/menu.png
mobile/android/base/resources/drawable-xlarge-hdpi/reader.png
mobile/android/base/resources/drawable-xlarge-hdpi/remote_tabs_off.png
mobile/android/base/resources/drawable-xlarge-hdpi/remote_tabs_on.png
mobile/android/base/resources/drawable-xlarge-hdpi/site_security_identified.png
mobile/android/base/resources/drawable-xlarge-hdpi/site_security_verified.png
mobile/android/base/resources/drawable-xlarge-hdpi/tab_new.png
mobile/android/base/resources/drawable-xlarge-hdpi/tabs_carat_contracted.png
mobile/android/base/resources/drawable-xlarge-hdpi/tabs_carat_expanded.png
mobile/android/base/resources/drawable-xlarge-hdpi/tabs_expanded_normal.png
mobile/android/base/resources/drawable-xlarge-hdpi/tabs_expanded_pressed.png
mobile/android/base/resources/drawable-xlarge-hdpi/tabs_normal.png
mobile/android/base/resources/drawable-xlarge-hdpi/tabs_pressed.png
mobile/android/base/resources/drawable-xlarge-hdpi/urlbar_stop.png
mobile/android/base/resources/drawable-xlarge-mdpi/address_bar_back_button_bg.png
mobile/android/base/resources/drawable-xlarge-mdpi/address_bar_back_button_pressed_bg.png
mobile/android/base/resources/drawable-xlarge-mdpi/address_bar_bg.xml
mobile/android/base/resources/drawable-xlarge-mdpi/address_bar_texture_tablet.png
mobile/android/base/resources/drawable-xlarge-mdpi/address_bar_url_default.9.png
mobile/android/base/resources/drawable-xlarge-mdpi/address_bar_url_pressed.9.png
mobile/android/base/resources/drawable-xlarge-mdpi/awesomebar_tab_center.9.png
mobile/android/base/resources/drawable-xlarge-mdpi/awesomebar_tab_left.9.png
mobile/android/base/resources/drawable-xlarge-mdpi/awesomebar_tab_right.9.png
mobile/android/base/resources/drawable-xlarge-mdpi/ic_awesomebar_go.png
mobile/android/base/resources/drawable-xlarge-mdpi/ic_awesomebar_search.png
mobile/android/base/resources/drawable-xlarge-mdpi/ic_menu_bookmark_add.png
mobile/android/base/resources/drawable-xlarge-mdpi/ic_menu_bookmark_remove.png
mobile/android/base/resources/drawable-xlarge-mdpi/ic_menu_forward.png
mobile/android/base/resources/drawable-xlarge-mdpi/ic_menu_reload.png
mobile/android/base/resources/drawable-xlarge-mdpi/menu.png
mobile/android/base/resources/drawable-xlarge-mdpi/reader.png
mobile/android/base/resources/drawable-xlarge-mdpi/remote_tabs_off.png
mobile/android/base/resources/drawable-xlarge-mdpi/remote_tabs_on.png
mobile/android/base/resources/drawable-xlarge-mdpi/site_security_identified.png
mobile/android/base/resources/drawable-xlarge-mdpi/site_security_verified.png
mobile/android/base/resources/drawable-xlarge-mdpi/tab_new.png
mobile/android/base/resources/drawable-xlarge-mdpi/tabs_carat_contracted.png
mobile/android/base/resources/drawable-xlarge-mdpi/tabs_carat_expanded.png
mobile/android/base/resources/drawable-xlarge-mdpi/tabs_expanded_normal.png
mobile/android/base/resources/drawable-xlarge-mdpi/tabs_expanded_pressed.png
mobile/android/base/resources/drawable-xlarge-mdpi/tabs_normal.png
mobile/android/base/resources/drawable-xlarge-mdpi/tabs_pressed.png
mobile/android/base/resources/drawable-xlarge-mdpi/urlbar_stop.png
mobile/android/base/resources/drawable-xlarge-xhdpi/address_bar_back_button_bg.png
mobile/android/base/resources/drawable-xlarge-xhdpi/address_bar_back_button_pressed_bg.png
mobile/android/base/resources/drawable-xlarge-xhdpi/address_bar_texture_tablet.png
mobile/android/base/resources/drawable-xlarge-xhdpi/address_bar_url_default.9.png
mobile/android/base/resources/drawable-xlarge-xhdpi/address_bar_url_pressed.9.png
mobile/android/base/resources/drawable-xlarge-xhdpi/awesomebar_tab_center.9.png
mobile/android/base/resources/drawable-xlarge-xhdpi/awesomebar_tab_left.9.png
mobile/android/base/resources/drawable-xlarge-xhdpi/awesomebar_tab_right.9.png
mobile/android/base/resources/drawable-xlarge-xhdpi/ic_awesomebar_go.png
mobile/android/base/resources/drawable-xlarge-xhdpi/ic_awesomebar_search.png
mobile/android/base/resources/drawable-xlarge-xhdpi/ic_menu_bookmark_add.png
mobile/android/base/resources/drawable-xlarge-xhdpi/ic_menu_bookmark_remove.png
mobile/android/base/resources/drawable-xlarge-xhdpi/ic_menu_forward.png
mobile/android/base/resources/drawable-xlarge-xhdpi/ic_menu_reload.png
mobile/android/base/resources/drawable-xlarge-xhdpi/menu.png
mobile/android/base/resources/drawable-xlarge-xhdpi/reader.png
mobile/android/base/resources/drawable-xlarge-xhdpi/remote_tabs_off.png
mobile/android/base/resources/drawable-xlarge-xhdpi/remote_tabs_on.png
mobile/android/base/resources/drawable-xlarge-xhdpi/site_security_identified.png
mobile/android/base/resources/drawable-xlarge-xhdpi/site_security_verified.png
mobile/android/base/resources/drawable-xlarge-xhdpi/tab_new.png
mobile/android/base/resources/drawable-xlarge-xhdpi/tabs_carat_contracted.png
mobile/android/base/resources/drawable-xlarge-xhdpi/tabs_carat_expanded.png
mobile/android/base/resources/drawable-xlarge-xhdpi/tabs_expanded_normal.png
mobile/android/base/resources/drawable-xlarge-xhdpi/tabs_expanded_pressed.png
mobile/android/base/resources/drawable-xlarge-xhdpi/tabs_normal.png
mobile/android/base/resources/drawable-xlarge-xhdpi/tabs_pressed.png
mobile/android/base/resources/drawable-xlarge-xhdpi/urlbar_stop.png
mobile/android/base/resources/drawable/tabs_button_expanded.xml
mobile/android/base/resources/drawable/tabs_carat_contracted.png
mobile/android/base/resources/drawable/tabs_carat_expanded.png
mobile/android/base/resources/drawable/tabs_expanded_normal.png
mobile/android/base/resources/layout-sw600dp/awesomebar_search.xml
mobile/android/base/resources/layout-sw600dp/awesomebar_tab_indicator.xml
mobile/android/base/resources/layout-sw600dp/browser_toolbar.xml
mobile/android/base/resources/layout-sw600dp/doorhangerpopup.xml
mobile/android/base/resources/layout-sw600dp/gecko_app.xml
mobile/android/base/resources/layout-sw600dp/remote_tabs_child.xml
mobile/android/base/resources/layout-sw600dp/remote_tabs_group.xml
mobile/android/base/resources/layout-sw600dp/tabs_panel_toolbar.xml
mobile/android/base/resources/layout-sw600dp/tabs_row.xml
mobile/android/base/resources/layout-xlarge/awesomebar_search.xml
mobile/android/base/resources/layout-xlarge/awesomebar_tab_indicator.xml
mobile/android/base/resources/layout-xlarge/browser_toolbar.xml
mobile/android/base/resources/layout-xlarge/doorhangerpopup.xml
mobile/android/base/resources/layout-xlarge/gecko_app.xml
mobile/android/base/resources/layout-xlarge/remote_tabs_child.xml
mobile/android/base/resources/layout-xlarge/remote_tabs_group.xml
mobile/android/base/resources/layout-xlarge/tabs_panel_toolbar.xml
mobile/android/base/resources/layout-xlarge/tabs_row.xml
mobile/android/base/resources/menu-sw600dp/gecko_menu.xml.in
mobile/android/base/resources/menu-xlarge/gecko_menu.xml.in
mobile/android/base/resources/values-sw600dp-v14/dimens.xml
mobile/android/base/resources/values-sw600dp/dimens.xml
mobile/android/base/resources/values-sw600dp/styles.xml
mobile/android/base/resources/values-xlarge/dimens.xml
mobile/android/base/resources/values-xlarge/styles.xml
mobile/android/chrome/content/browser.js
modules/libjar/nsJARChannel.cpp
modules/libjar/nsJARChannel.h
modules/libpref/src/init/all.js
netwerk/base/src/nsSocketTransport2.cpp
netwerk/cache/nsCacheService.cpp
netwerk/cache/nsCacheService.h
netwerk/cache/nsDiskCacheDeviceSQL.cpp
netwerk/cache/nsDiskCacheDeviceSQL.h
netwerk/cache/nsMemoryCacheDevice.cpp
netwerk/cache/nsMemoryCacheDevice.h
netwerk/dns/nsDNSService2.cpp
netwerk/dns/nsHostResolver.cpp
netwerk/dns/nsHostResolver.h
netwerk/protocol/http/HttpChannelChild.cpp
netwerk/protocol/http/SpdySession2.h
netwerk/protocol/http/SpdySession3.h
netwerk/protocol/http/nsHttpChannel.cpp
netwerk/protocol/http/nsHttpChannel.h
netwerk/protocol/http/nsHttpConnection.h
netwerk/protocol/http/nsHttpConnectionMgr.cpp
netwerk/protocol/http/nsHttpConnectionMgr.h
netwerk/protocol/http/nsHttpHandler.cpp
netwerk/protocol/http/nsHttpTransaction.cpp
netwerk/protocol/http/nsHttpTransaction.h
netwerk/protocol/websocket/WebSocketChannel.cpp
netwerk/protocol/websocket/WebSocketChannel.h
netwerk/wifi/nsWifiAccessPoint.h
parser/html/nsHtml5Parser.cpp
parser/html/nsHtml5StreamParser.cpp
parser/html/nsHtml5TreeBuilderCppSupplement.h
parser/html/nsHtml5TreeBuilderHSupplement.h
parser/html/nsHtml5TreeOpExecutor.cpp
parser/html/nsHtml5TreeOpExecutor.h
parser/html/nsHtml5TreeOperation.cpp
parser/html/nsHtml5TreeOperation.h
storage/src/mozStorageConnection.cpp
storage/test/storage_test_harness.h
storage/test/test_async_callbacks_with_spun_event_loops.cpp
toolkit/components/places/History.cpp
toolkit/components/places/nsAnnotationService.h
toolkit/components/places/nsFaviconService.h
toolkit/components/places/nsNavBookmarks.h
toolkit/components/places/nsNavHistory.h
toolkit/components/places/nsNavHistoryQuery.h
toolkit/components/places/nsNavHistoryResult.cpp
toolkit/components/telemetry/TelemetryHistograms.h
toolkit/content/tests/chrome/test_scaledrag.xul
toolkit/content/widgets/videocontrols.css
toolkit/content/widgets/videocontrols.xml
toolkit/content/xul.css
toolkit/crashreporter/nsExceptionHandler.cpp
toolkit/crashreporter/nsExceptionHandler.h
toolkit/mozapps/update/test/unit/head_update.js.in
toolkit/system/windowsproxy/nsWindowsSystemProxySettings.cpp
toolkit/themes/pinstripe/global/media/videocontrols.css
toolkit/themes/winstripe/global/media/videocontrols.css
toolkit/themes/winstripe/mozapps/extensions/extensions.css
toolkit/xre/nsAppRunner.cpp
toolkit/xre/nsEmbedFunctions.cpp
toolkit/xre/nsSigHandlers.cpp
uriloader/prefetch/nsOfflineCacheUpdate.cpp
uriloader/prefetch/nsOfflineCacheUpdate.h
widget/windows/nsWindow.cpp
widget/windows/nsWindow.h
xpcom/base/nsStackWalk.cpp
xpcom/base/nsTraceRefcntImpl.cpp
xpcom/build/nsXPComInit.cpp
xpcom/build/nsXULAppAPI.h
xpcom/glue/nsCycleCollectionParticipant.h
xpcom/threads/nsThread.h
xpfe/appshell/src/nsContentTreeOwner.cpp
--- a/Makefile.in
+++ b/Makefile.in
@@ -48,16 +48,19 @@ endif
 
 ifdef MOZ_MEMORY
 tier_base_dirs += memory/mozjemalloc
 ifdef MOZ_JEMALLOC
 tier_base_dirs += memory/jemalloc
 endif
 tier_base_dirs += memory/build
 endif
+ifndef MOZ_NATIVE_ZLIB
+tier_base_dirs += modules/zlib
+endif
 tier_base_dirs += \
   mozglue \
   memory/mozalloc \
   $(NULL)
 endif
 
 ifdef COMPILE_ENVIRONMENT
 include $(topsrcdir)/$(MOZ_BUILD_APP)/build.mk
--- a/accessible/src/base/nsARIAMap.cpp
+++ b/accessible/src/base/nsARIAMap.cpp
@@ -577,17 +577,17 @@ nsRoleMapEntry nsARIAMap::gEmptyRoleMap 
   kNoReqStates
 };
 
 /**
  * Universal (Global) states:
  * The following state rules are applied to any accessible element,
  * whether there is an ARIA role or not:
  */
-EStateRule nsARIAMap::gWAIUnivStateMap[] = {
+static const EStateRule sWAIUnivStateMap[] = {
   eARIABusy,
   eARIADisabled,
   eARIAExpanded,  // Currently under spec review but precedent exists
   eARIAHasPopup,  // Note this is technically a "property"
   eARIAInvalid,
   eARIARequired,  // XXX not global, Bug 553117
   eARIANone
 };
@@ -630,17 +630,18 @@ nsAttributeCharacteristics nsARIAMap::gW
   {&nsGkAtoms::aria_setsize,           ATTR_BYPASSOBJ                 }, /* handled via groupPosition */
   {&nsGkAtoms::aria_sort,                               ATTR_VALTOKEN },
   {&nsGkAtoms::aria_valuenow,          ATTR_BYPASSOBJ                 },
   {&nsGkAtoms::aria_valuemin,          ATTR_BYPASSOBJ                 },
   {&nsGkAtoms::aria_valuemax,          ATTR_BYPASSOBJ                 },
   {&nsGkAtoms::aria_valuetext,         ATTR_BYPASSOBJ                 }
 };
 
-PRUint32 nsARIAMap::gWAIUnivAttrMapLength = NS_ARRAY_LENGTH(nsARIAMap::gWAIUnivAttrMap);
+PRUint32
+nsARIAMap::gWAIUnivAttrMapLength = NS_ARRAY_LENGTH(nsARIAMap::gWAIUnivAttrMap);
 
 nsRoleMapEntry*
 aria::GetRoleMap(nsINode* aNode)
 {
   nsIContent* content = nsCoreUtils::GetRoleContent(aNode);
   nsAutoString roles;
   if (!content ||
       !content->GetAttr(kNameSpaceID_None, nsGkAtoms::role, roles) ||
@@ -667,8 +668,19 @@ aria::GetRoleMap(nsINode* aNode)
         low = idx + 1;
     }
   }
 
   // Always use some entry if there is a non-empty role string
   // To ensure an accessible object is created
   return &sLandmarkRoleMap;
 }
+
+PRUint64
+aria::UniversalStatesFor(mozilla::dom::Element* aElement)
+{
+  PRUint64 state = 0;
+  PRUint32 index = 0;
+  while (MapToState(sWAIUnivStateMap[index], aElement, &state))
+    index++;
+
+  return state;
+}
--- a/accessible/src/base/nsARIAMap.h
+++ b/accessible/src/base/nsARIAMap.h
@@ -195,54 +195,39 @@ struct nsARIAMap
   /**
    * Empty role map entry. Used by accessibility service to create an accessible
    * if the accessible can't use role of used accessible class. For example,
    * it is used for table cells that aren't contained by table.
    */
   static nsRoleMapEntry gEmptyRoleMap;
 
   /**
-   * State map of ARIA states applied to any accessible not depending on
-   * the role.
-   */
-  static mozilla::a11y::aria::EStateRule gWAIUnivStateMap[];
-
-  /**
    * Map of attribute to attribute characteristics.
    */
   static nsAttributeCharacteristics gWAIUnivAttrMap[];
   static PRUint32 gWAIUnivAttrMapLength;
-
-  /**
-   * Return accessible state from ARIA universal states applied to the given
-   * element.
-   */
-  static PRUint64 UniversalStatesFor(mozilla::dom::Element* aElement)
-  {
-    PRUint64 state = 0;
-    PRUint32 index = 0;
-    while (mozilla::a11y::aria::MapToState(gWAIUnivStateMap[index],
-                                           aElement, &state))
-      index++;
-
-    return state;
-  }
 };
 
 namespace mozilla {
 namespace a11y {
 namespace aria {
 
 /**
  * Get the role map entry for a given DOM node. This will use the first
  * ARIA role if the role attribute provides a space delimited list of roles.
  *
  * @param aNode  [in] the DOM node to get the role map entry for
  * @return        a pointer to the role map entry for the ARIA role, or nsnull
  *                if none
  */
 nsRoleMapEntry* GetRoleMap(nsINode* aNode);
 
+/**
+ * Return accessible state from ARIA universal states applied to the given
+ * element.
+ */
+PRUint64 UniversalStatesFor(mozilla::dom::Element* aElement);
+
 } // namespace aria
 } // namespace a11y
 } // namespace mozilla
 
 #endif
--- a/accessible/src/base/nsAccessNode.cpp
+++ b/accessible/src/base/nsAccessNode.cpp
@@ -69,22 +69,16 @@ void nsAccessNode::LastRelease()
   }
   // ... then die.
   delete this;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccessNode public
 
-bool
-nsAccessNode::Init()
-{
-  return true;
-}
-
 
 void
 nsAccessNode::Shutdown()
 {
   mContent = nsnull;
   mDoc = nsnull;
 }
 
--- a/accessible/src/base/nsAccessNode.h
+++ b/accessible/src/base/nsAccessNode.h
@@ -59,21 +59,16 @@ public:
   DocAccessible* Document() const { return mDoc; }
 
   /**
    * Return the root document accessible for this accessnode.
    */
   mozilla::a11y::RootAccessible* RootAccessible() const;
 
   /**
-   * Initialize the access node object, add it to the cache.
-   */
-  virtual bool Init();
-
-  /**
    * Shutdown the access node object.
    */
   virtual void Shutdown();
 
   /**
    * Return frame for the given access node object.
    */
   virtual nsIFrame* GetFrame() const;
--- a/accessible/src/generic/Accessible.cpp
+++ b/accessible/src/generic/Accessible.cpp
@@ -189,16 +189,22 @@ Accessible::~Accessible()
 }
 
 void
 Accessible::SetRoleMapEntry(nsRoleMapEntry* aRoleMapEntry)
 {
   mRoleMapEntry = aRoleMapEntry;
 }
 
+bool
+Accessible::Init()
+{
+  return true;
+}
+
 NS_IMETHODIMP
 Accessible::GetDocument(nsIAccessibleDocument** aDocument)
 {
   NS_ENSURE_ARG_POINTER(aDocument);
 
   NS_IF_ADDREF(*aDocument = Document());
   return NS_OK;
 }
@@ -1522,17 +1528,17 @@ void
 Accessible::ApplyARIAState(PRUint64* aState) const
 {
   if (!mContent->IsElement())
     return;
 
   dom::Element* element = mContent->AsElement();
 
   // Test for universal states first
-  *aState |= nsARIAMap::UniversalStatesFor(element);
+  *aState |= aria::UniversalStatesFor(element);
 
   if (mRoleMapEntry) {
 
     // We only force the readonly bit off if we have a real mapping for the aria
     // role. This preserves the ability for screen readers to use readonly
     // (primarily on the document) as the hint for creating a virtual buffer.
     if (mRoleMapEntry->role != roles::NOTHING)
       *aState &= ~states::READONLY;
--- a/accessible/src/generic/Accessible.h
+++ b/accessible/src/generic/Accessible.h
@@ -122,16 +122,21 @@ public:
   // nsAccessNode
 
   virtual void Shutdown();
 
   //////////////////////////////////////////////////////////////////////////////
   // Public methods
 
   /**
+   * Initialize the accessible.
+   */
+  virtual bool Init();
+
+  /**
    * Get the description of this accessible.
    */
   virtual void Description(nsString& aDescription);
 
   /**
    * Get the value of this accessible.
    */
   virtual void Value(nsString& aValue);
--- a/accessible/src/jsat/AccessFu.jsm
+++ b/accessible/src/jsat/AccessFu.jsm
@@ -360,16 +360,31 @@ var AccessFu = {
       }
       case Ci.nsIAccessibleEvent.EVENT_FOCUS:
       {
         let acc = aEvent.accessible;
         let doc = aEvent.accessibleDocument;
         if (acc.role != Ci.nsIAccessibleRole.ROLE_DOCUMENT &&
             doc.role != Ci.nsIAccessibleRole.ROLE_CHROME_WINDOW)
           VirtualCursorController.moveCursorToObject(acc);
+
+        let [,extState] = Utils.getStates(acc);
+        let editableState = extState &
+          (Ci.nsIAccessibleStates.EXT_STATE_EDITABLE |
+           Ci.nsIAccessibleStates.EXT_STATE_MULTI_LINE);
+
+        if (editableState != VirtualCursorController.editableState) {
+          if (!VirtualCursorController.editableState)
+            this.presenters.forEach(
+              function(p) {
+                p.editingModeChanged(true);
+              }
+            );
+        }
+        VirtualCursorController.editableState = editableState;
         break;
       }
       default:
         break;
     }
   },
 
   /**
--- a/accessible/src/jsat/Presenters.jsm
+++ b/accessible/src/jsat/Presenters.jsm
@@ -86,17 +86,22 @@ Presenter.prototype = {
    *   virtual cursor position.
    */
   tabSelected: function tabSelected(aDocContext, aVCContext) {},
 
   /**
    * The viewport has changed, either a scroll, pan, zoom, or
    *    landscape/portrait toggle.
    */
-  viewportChanged: function viewportChanged() {}
+  viewportChanged: function viewportChanged() {},
+
+  /**
+   * We have entered or left text editing mode.
+   */
+  editingModeChanged: function editingModeChanged(aIsEditing) {}
 };
 
 /**
  * Visual presenter. Draws a box around the virtual cursor's position.
  */
 
 function VisualPresenter() {}
 
@@ -298,32 +303,18 @@ AndroidPresenter.prototype = {
 
   tabSelected: function AndroidPresenter_tabSelected(aDocContext, aVCContext) {
     // Send a pivot change message with the full context utterance for this doc.
     this.pivotChanged(aVCContext, Ci.nsIAccessiblePivot.REASON_NONE);
   },
 
   tabStateChanged: function AndroidPresenter_tabStateChanged(aDocObj,
                                                              aPageState) {
-    let stateUtterance = UtteranceGenerator.
-      genForTabStateChange(aDocObj, aPageState);
-
-    if (!stateUtterance.length)
-      return;
-
-    this.sendMessageToJava({
-      gecko: {
-        type: 'Accessibility:Event',
-        eventType: this.ANDROID_VIEW_TEXT_CHANGED,
-        text: stateUtterance,
-        addedCount: stateUtterance.join(' ').length,
-        removedCount: 0,
-        fromIndex: 0
-      }
-    });
+    this._appAnnounce(
+      UtteranceGenerator.genForTabStateChange(aDocObj, aPageState));
   },
 
   textChanged: function AndroidPresenter_textChanged(aIsInserted, aStart,
                                                      aLength, aText,
                                                      aModifiedText) {
     let androidEvent = {
       type: 'Accessibility:Event',
       eventType: this.ANDROID_VIEW_TEXT_CHANGED,
@@ -359,16 +350,36 @@ AndroidPresenter.prototype = {
         scrollX: win.scrollX,
         scrollY: win.scrollY,
         maxScrollX: win.scrollMaxX,
         maxScrollY: win.scrollMaxY
       }
     });
   },
 
+  editingModeChanged: function AndroidPresenter_editingModeChanged(aIsEditing) {
+    this._appAnnounce(UtteranceGenerator.genForEditingMode(aIsEditing));
+  },
+
+  _appAnnounce: function _appAnnounce(aUtterance) {
+    if (!aUtterance.length)
+      return;
+
+    this.sendMessageToJava({
+      gecko: {
+        type: 'Accessibility:Event',
+        eventType: this.ANDROID_VIEW_TEXT_CHANGED,
+        text: aUtterance,
+        addedCount: aUtterance.join(' ').length,
+        removedCount: 0,
+        fromIndex: 0
+      }
+    });
+  },
+
   sendMessageToJava: function AndroidPresenter_sendMessageTojava(aMessage) {
     return Cc['@mozilla.org/android/bridge;1'].
       getService(Ci.nsIAndroidBridge).
       handleGeckoMessage(JSON.stringify(aMessage));
   }
 };
 
 /**
--- a/accessible/src/jsat/Utils.jsm
+++ b/accessible/src/jsat/Utils.jsm
@@ -54,16 +54,26 @@ var Utils = {
 
   getViewport: function getViewport(aWindow) {
     switch (this.OS) {
       case 'Android':
         return aWindow.BrowserApp.selectedTab.getViewport();
       default:
         return null;
     }
+  },
+
+  getStates: function getStates(aAccessible) {
+    if (!aAccessible)
+      return [0, 0];
+
+    let state = {};
+    let extState = {};
+    aAccessible.getState(state, extState);
+    return [state.value, extState.value];
   }
 };
 
 var Logger = {
   DEBUG: 0,
   INFO: 1,
   WARNING: 2,
   ERROR: 3,
--- a/accessible/src/jsat/UtteranceGenerator.jsm
+++ b/accessible/src/jsat/UtteranceGenerator.jsm
@@ -118,16 +118,26 @@ var UtteranceGenerator = {
         return [gStringBundle.GetStringFromName('tabLoadStopped')];
       case 'reload':
         return [gStringBundle.GetStringFromName('tabReload')];
       default:
         return [];
     }
   },
 
+  /**
+   * Generates an utterance for announcing entering and leaving editing mode.
+   * @param {aIsEditing} boolean true if we are in editing mode
+   * @return {Array} The mode utterance
+   */
+  genForEditingMode: function genForEditingMode(aIsEditing) {
+    return [gStringBundle.GetStringFromName(
+              aIsEditing ? 'editingMode' : 'navigationMode')];
+  },
+
   verbosityRoleMap: {
     'menubar': INCLUDE_DESC,
     'scrollbar': INCLUDE_DESC,
     'grip': INCLUDE_DESC,
     'alert': INCLUDE_DESC | INCLUDE_NAME,
     'menupopup': INCLUDE_DESC,
     'menuitem': INCLUDE_DESC,
     'tooltip': INCLUDE_DESC,
--- a/accessible/src/jsat/VirtualCursorController.jsm
+++ b/accessible/src/jsat/VirtualCursorController.jsm
@@ -399,21 +399,18 @@ var TraversalRules = {
       return Ci.nsIAccessibleTraversalRule.FILTER_MATCH;
     },
 
     QueryInterface: XPCOMUtils.generateQI([Ci.nsIAccessibleTraversalRule])
   }
 };
 
 var VirtualCursorController = {
-  NOT_EDITABLE: 0,
-  SINGLE_LINE_EDITABLE: 1,
-  MULTI_LINE_EDITABLE: 2,
-
   exploreByTouch: false,
+  editableState: 0,
 
   attach: function attach(aWindow) {
     this.chromeWin = aWindow;
     this.chromeWin.document.addEventListener('keypress', this, true);
     this.chromeWin.document.addEventListener('mousemove', this, true);
   },
 
   detach: function detach() {
@@ -458,103 +455,107 @@ var VirtualCursorController = {
     let document = Utils.getCurrentContentDoc(this.chromeWin);
     let target = aEvent.target;
 
     switch (aEvent.keyCode) {
       case 0:
         // an alphanumeric key was pressed, handle it separately.
         // If it was pressed with either alt or ctrl, just pass through.
         // If it was pressed with meta, pass the key on without the meta.
-        if (this._isEditableText(target) ||
+        if (this.editableState ||
             aEvent.ctrlKey || aEvent.altKey || aEvent.metaKey)
           return;
 
         let key = String.fromCharCode(aEvent.charCode);
         let methodName = '', rule = {};
         try {
           [methodName, rule] = this.keyMap[key];
         } catch (x) {
           return;
         }
         this[methodName](document, false, rule);
         break;
       case aEvent.DOM_VK_END:
+        if (this.editableState) {
+          if (target.selectionEnd != target.textLength)
+            // Don't move forward if caret is not at end of entry.
+            // XXX: Fix for rtl
+            return;
+          else
+            target.blur();
+        }
         this.moveForward(document, true);
         break;
       case aEvent.DOM_VK_HOME:
+        if (this.editableState) {
+          if (target.selectionEnd != 0)
+            // Don't move backward if caret is not at start of entry.
+            // XXX: Fix for rtl
+            return;
+          else
+            target.blur();
+        }
         this.moveBackward(document, true);
         break;
       case aEvent.DOM_VK_RIGHT:
-        if (this._isEditableText(target)) {
+        if (this.editableState) {
           if (target.selectionEnd != target.textLength)
             // Don't move forward if caret is not at end of entry.
             // XXX: Fix for rtl
             return;
           else
             target.blur();
         }
         this.moveForward(document, aEvent.shiftKey);
         break;
       case aEvent.DOM_VK_LEFT:
-        if (this._isEditableText(target)) {
+        if (this.editableState) {
           if (target.selectionEnd != 0)
             // Don't move backward if caret is not at start of entry.
             // XXX: Fix for rtl
             return;
           else
             target.blur();
         }
         this.moveBackward(document, aEvent.shiftKey);
         break;
       case aEvent.DOM_VK_UP:
-        if (this._isEditableText(target) == this.MULTI_LINE_EDITABLE) {
+        if (this.editableState & Ci.nsIAccessibleStates.EXT_STATE_MULTI_LINE) {
           if (target.selectionEnd != 0)
             // Don't blur content if caret is not at start of text area.
             return;
           else
             target.blur();
         }
 
         if (Utils.OS == 'Android')
           // Return focus to native Android browser chrome.
           Cc['@mozilla.org/android/bridge;1'].
             getService(Ci.nsIAndroidBridge).handleGeckoMessage(
               JSON.stringify({ gecko: { type: 'ToggleChrome:Focus' } }));
         break;
       case aEvent.DOM_VK_RETURN:
       case aEvent.DOM_VK_ENTER:
-        if (this._isEditableText(target))
+        if (this.editableState)
           return;
         this.activateCurrent(document);
         break;
       default:
         return;
     }
 
     aEvent.preventDefault();
     aEvent.stopPropagation();
   },
 
   moveToPoint: function moveToPoint(aDocument, aX, aY) {
     this.getVirtualCursor(aDocument).moveToPoint(TraversalRules.Simple,
                                                  aX, aY, true);
   },
 
-  _isEditableText: function _isEditableText(aElement) {
-    // XXX: Support contentEditable and design mode
-    if (aElement instanceof Ci.nsIDOMHTMLInputElement &&
-        aElement.mozIsTextField(false))
-      return this.SINGLE_LINE_EDITABLE;
-
-    if (aElement instanceof Ci.nsIDOMHTMLTextAreaElement)
-      return this.MULTI_LINE_EDITABLE;
-
-    return this.NOT_EDITABLE;
-  },
-
   moveForward: function moveForward(aDocument, aLast, aRule) {
     let virtualCursor = this.getVirtualCursor(aDocument);
     if (aLast) {
       virtualCursor.moveLast(TraversalRules.Simple);
     } else {
       try {
         virtualCursor.moveNext(aRule || TraversalRules.Simple);
       } catch (x) {
--- a/accessible/src/msaa/nsAccessNodeWrap.cpp
+++ b/accessible/src/msaa/nsAccessNodeWrap.cpp
@@ -388,17 +388,16 @@ nsAccessNodeWrap::MakeAccessNode(nsINode
       NS_NOTREACHED("The node is a document which is not accessible!");
       return NULL;
     }
 
     newNode = new nsAccessNodeWrap(content, mDoc);
     if (!newNode)
       return NULL;
 
-    newNode->Init();
     iNode = static_cast<ISimpleDOMNode*>(newNode);
     iNode->AddRef();
   }
 
   return iNode;
 }
 
 
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -14,16 +14,17 @@ builtin(include, build/autoconf/mozcommo
 builtin(include, build/autoconf/acwinpaths.m4)dnl
 builtin(include, build/autoconf/lto.m4)dnl
 builtin(include, build/autoconf/gcc-pr49911.m4)dnl
 builtin(include, build/autoconf/frameptr.m4)dnl
 builtin(include, build/autoconf/compiler-opts.m4)dnl
 builtin(include, build/autoconf/expandlibs.m4)dnl
 builtin(include, build/autoconf/arch.m4)dnl
 builtin(include, build/autoconf/android.m4)dnl
+builtin(include, build/autoconf/zlib.m4)dnl
 
 MOZ_PROG_CHECKMSYS()
 
 # Read the user's .mozconfig script.  We can't do this in
 # configure.in: autoconf puts the argument parsing code above anything
 # expanded from configure.in, and we need to get the configure options
 # from .mozconfig in place before that argument parsing code.
 MOZ_READ_MOZCONFIG(.)
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -379,19 +379,16 @@ pref("dom.sms.enabled", true);
 pref("dom.mozContacts.enabled", true);
 
 // WebAlarms
 pref("dom.mozAlarms.enabled", true);
 
 // WebSettings
 pref("dom.mozSettings.enabled", true);
 
-// Ignore X-Frame-Options headers.
-pref("b2g.ignoreXFrameOptions", true);
-
 // controls if we want camera support
 pref("device.camera.enabled", true);
 pref("media.realtime_decoder.enabled", true);
 
 // "Preview" landing of bug 710563, which is bogged down in analysis
 // of talos regression.  This is a needed change for higher-framerate
 // CSS animations, and incidentally works around an apparent bug in
 // our handling of requestAnimationFrame() listeners, which are
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -38,16 +38,19 @@
 @BINPATH@/dictionaries/*
 @BINPATH@/hyphenation/*
 #ifdef XP_WIN32
 @BINPATH@/uninstall/helper.exe
 #endif
 
 [xpcom]
 @BINPATH@/dependentlibs.list
+#ifdef XP_WIN32
+@BINPATH@/@DLL_PREFIX@gkmedias@DLL_SUFFIX@
+#endif
 #ifndef MOZ_STATIC_JS
 @BINPATH@/@DLL_PREFIX@mozjs@DLL_SUFFIX@
 #endif
 @BINPATH@/@DLL_PREFIX@plc4@DLL_SUFFIX@
 @BINPATH@/@DLL_PREFIX@plds4@DLL_SUFFIX@
 @BINPATH@/@DLL_PREFIX@xpcom@DLL_SUFFIX@
 @BINPATH@/@DLL_PREFIX@nspr4@DLL_SUFFIX@
 @BINPATH@/@DLL_PREFIX@mozalloc@DLL_SUFFIX@
@@ -468,16 +471,19 @@
 @BINPATH@/components/Webapps.manifest
 @BINPATH@/components/AppsService.js
 @BINPATH@/components/AppsService.manifest
 
 @BINPATH@/components/SystemMessageInternal.js
 @BINPATH@/components/SystemMessageManager.js
 @BINPATH@/components/SystemMessageManager.manifest
 
+@BINPATH@/components/AppProtocolHandler.js
+@BINPATH@/components/AppProtocolHandler.manifest
+
 ; Modules
 @BINPATH@/modules/*
 
 ; Safe Browsing
 @BINPATH@/components/nsURLClassifier.manifest
 @BINPATH@/components/nsUrlClassifierHashCompleter.js
 @BINPATH@/components/nsUrlClassifierListManager.js
 @BINPATH@/components/nsUrlClassifierLib.js
--- a/browser/app/macbuild/Contents/_CodeSignature/CodeResources
+++ b/browser/app/macbuild/Contents/_CodeSignature/CodeResources
@@ -7,16 +7,22 @@
             <key>^Info.plist$</key>
             <true/>
             <key>^PkgInfo$</key>
             <true/>
             <key>^MacOS/</key>
             <true/>
             <key>^Resources/</key>
             <true/>
+            <key>^MacOS/distribution/.*</key><dict>
+                <key>omit</key>
+                <true/>
+                <key>weight</key>
+                <real>10</real>
+            </dict>
             <key>^MacOS/updates/.*</key><dict>
                 <key>omit</key>
                 <true/>
                 <key>weight</key>
                 <real>10</real>
             </dict>
             <key>^MacOS/active-update.xml$</key><dict>
                 <key>omit</key>
--- a/browser/app/nsBrowserApp.cpp
+++ b/browser/app/nsBrowserApp.cpp
@@ -235,50 +235,23 @@ int main(int argc, char* argv[])
 
   strcpy(++lastSlash, XPCOM_DLL);
 
   int gotCounters;
 #if defined(XP_UNIX)
   struct rusage initialRUsage;
   gotCounters = !getrusage(RUSAGE_SELF, &initialRUsage);
 #elif defined(XP_WIN)
-  // Don't change the order of these enumeration constants, the order matters
-  // for reporting telemetry data.  If new values are added adjust the
-  // STARTUP_USING_PRELOAD_TRIAL histogram.
-  enum PreloadType{ PREFETCH_PRELOAD,
-                    PREFETCH_NO_PRELOAD,
-                    NO_PREFETCH_PRELOAD,
-                    NO_PREFETCH_NO_PRELOAD };
-  PreloadType preloadType;
-
   IO_COUNTERS ioCounters;
   gotCounters = GetProcessIoCounters(GetCurrentProcess(), &ioCounters);
-
-  srand(time(NULL));
-  bool shouldUsePreload = rand() % 2 == 0;
+#endif
 
-  if (IsPrefetchDisabledViaService()) {
-    if (shouldUsePreload) {
-      preloadType = NO_PREFETCH_PRELOAD;
-    }  else {
-      preloadType = NO_PREFETCH_NO_PRELOAD;
-    }
-  } else {
-    if (shouldUsePreload) {
-      preloadType = PREFETCH_PRELOAD;
-    }  else {
-      preloadType = PREFETCH_NO_PRELOAD;
-    }
-  }
-
-  if (shouldUsePreload)
+#if !defined(XP_WIN)
+  XPCOMGlueEnablePreload();
 #endif
-  {
-      XPCOMGlueEnablePreload();
-  }
 
   rv = XPCOMGlueStartup(exePath);
   if (NS_FAILED(rv)) {
     Output("Couldn't load XPCOM.\n");
     return 255;
   }
   // Reset exePath so that it is the directory name and not the xpcom dll name
   *lastSlash = 0;
@@ -290,21 +263,16 @@ int main(int argc, char* argv[])
   }
 
   XRE_StartupTimelineRecord(mozilla::StartupTimeline::START, start);
 
 #ifdef XRE_HAS_DLL_BLOCKLIST
   XRE_SetupDllBlocklist();
 #endif
 
-#if defined(XP_WIN)
-  XRE_TelemetryAccumulate(mozilla::Telemetry::STARTUP_USING_PRELOAD_TRIAL,
-                          preloadType);
-#endif
-
   if (gotCounters) {
 #if defined(XP_WIN)
     XRE_TelemetryAccumulate(mozilla::Telemetry::EARLY_GLUESTARTUP_READ_OPS,
                             int(ioCounters.ReadOperationCount));
     XRE_TelemetryAccumulate(mozilla::Telemetry::EARLY_GLUESTARTUP_READ_TRANSFER,
                             int(ioCounters.ReadTransferCount / 1024));
     IO_COUNTERS newIoCounters;
     if (GetProcessIoCounters(GetCurrentProcess(), &newIoCounters)) {
--- a/browser/base/content/abouthome/aboutHome.css
+++ b/browser/base/content/abouthome/aboutHome.css
@@ -92,18 +92,18 @@ body[dir=rtl] #searchText {
   padding: 0 9px;
   border: 1px solid;
   border-color: hsla(210,54%,20%,.15) hsla(210,54%,20%,.17) hsla(210,54%,20%,.2);
   -moz-border-start: 1px solid transparent;
   border-radius: 0 2.5px 2.5px 0;
   box-shadow: 0 0 2px hsla(0,0%,100%,.5) inset,
               0 1px 0 hsla(0,0%,100%,.2);
   cursor: pointer;
-  -moz-transition-property: background-color, border-color, box-shadow;
-  -moz-transition-duration: 150ms;
+  transition-property: background-color, border-color, box-shadow;
+  transition-duration: 150ms;
 }
 
 body[dir=rtl] #searchSubmit {
   border-radius: 2.5px 0 0 2.5px;
 }
 
 #searchText:focus + #searchSubmit,
 #searchText + #searchSubmit:hover {
@@ -124,17 +124,17 @@ body[dir=rtl] #searchSubmit {
               0 0 0 1px hsla(0,0%,100%,.1) inset,
               0 1px 0 hsla(210,54%,20%,.03),
               0 0 4px hsla(206,100%,20%,.2);
 }
 
 #searchText + #searchSubmit:hover:active {
   box-shadow: 0 1px 1px hsla(211,79%,6%,.1) inset,
               0 0 1px hsla(211,79%,6%,.2) inset;
-  -moz-transition-duration: 0ms;
+  transition-duration: 0ms;
 }
 
 #defaultSnippet1,
 #defaultSnippet2 {
   display: block;
   min-height: 38px;
   background: 30px center no-repeat;
   padding: 6px 0;
@@ -191,35 +191,35 @@ body[narrow] #launcher[session] {
   vertical-align: top;
   white-space: normal;
   background: transparent padding-box;
   border: 1px solid transparent;
   border-radius: 2.5px;
   color: #525c66;
   font-size: 75%;
   cursor: pointer;
-  -moz-transition-property: background-color, border-color, box-shadow;
-  -moz-transition-duration: 150ms;
+  transition-property: background-color, border-color, box-shadow;
+  transition-duration: 150ms;
 }
 
 body[narrow] #launcher[session] > .launchButton {
   margin: 4px 1px;
 }
 
 .launchButton:hover {
   background-color: hsla(211,79%,6%,.03);
   border-color: hsla(210,54%,20%,.15) hsla(210,54%,20%,.17) hsla(210,54%,20%,.2);
 }
 
 .launchButton:hover:active {
   background-image: -moz-linear-gradient(hsla(211,79%,6%,.02), hsla(211,79%,6%,.05));
   border-color: hsla(210,54%,20%,.2) hsla(210,54%,20%,.23) hsla(210,54%,20%,.25);
   box-shadow: 0 1px 1px hsla(211,79%,6%,.05) inset,
               0 0 1px hsla(211,79%,6%,.1) inset;
-  -moz-transition-duration: 0ms;
+  transition-duration: 0ms;
 }
 
 .launchButton[hidden],
 #launcher:not([session]) > #restorePreviousSessionSeparator,
 #launcher:not([session]) > #restorePreviousSession {
   display: none;
 }
 
@@ -309,17 +309,17 @@ body[narrow] #restorePreviousSession::be
   width: 32px;
 }
 
 #aboutMozilla {
   display: block;
   position: relative; /* pin wordmark to edge of document, not of viewport */
   -moz-box-ordinal-group: 0;
   opacity: .5;
-  -moz-transition: opacity 150ms;
+  transition: opacity 150ms;
 }
 
 #aboutMozilla:hover {
   opacity: 1;
 }
 
 #aboutMozilla::before {
   content: url("chrome://browser/content/abouthome/mozilla.png");
--- a/browser/base/content/browser-fullScreen.js
+++ b/browser/base/content/browser-fullScreen.js
@@ -22,18 +22,23 @@ var FullScreen = {
     document.getElementById("exitFullScreenItem").hidden = !enterFS;
 #endif
 
     // On OS X Lion we don't want to hide toolbars when entering fullscreen, unless
     // we're entering DOM fullscreen, in which case we should hide the toolbars.
     // If we're leaving fullscreen, then we'll go through the exit code below to
     // make sure toolbars are made visible in the case of DOM fullscreen.
     if (enterFS && this.useLionFullScreen) {
-      if (document.mozFullScreen)
+      if (document.mozFullScreen) {
         this.showXULChrome("toolbar", false);
+      }
+      else {
+        gNavToolbox.setAttribute("inFullscreen", true);
+        document.documentElement.setAttribute("inFullscreen", true);
+      }
       return;
     }
 
     // show/hide menubars, toolbars (except the full screen toolbar)
     this.showXULChrome("toolbar", !enterFS);
 
     if (enterFS) {
       // Add a tiny toolbar to receive mouseover and dragenter events, and provide affordance.
--- a/browser/base/content/browser-menubar.inc
+++ b/browser/base/content/browser-menubar.inc
@@ -514,16 +514,17 @@
                     label="&webDeveloperMenu.label;"
                     accesskey="&webDeveloperMenu.accesskey;">
                 <menupopup id="menuWebDeveloperPopup">
                   <menuitem id="menu_devToolbar"
                             type="checkbox"
                             autocheck="false"
                             hidden="true"
                             label="&devToolbarMenu.label;"
+                            accesskey="&devToolbarMenu.accesskey;"
                             key="key_devToolbar"
                             command="Tools:DevToolbar"/>
                   <menuitem id="webConsole"
                             type="checkbox"
                             label="&webConsoleCmd.label;"
                             accesskey="&webConsoleCmd.accesskey;"
                             key="key_webConsole"
                             command="Tools:WebConsole"/>
--- a/browser/base/content/browser-sets.inc
+++ b/browser/base/content/browser-sets.inc
@@ -84,16 +84,17 @@
     <command id="cmd_fullZoomEnlarge" oncommand="FullZoom.enlarge()"/>
     <command id="cmd_fullZoomReset"   oncommand="FullZoom.reset()"/>
     <command id="cmd_fullZoomToggle"  oncommand="ZoomManager.toggleZoom();"/>
     <command id="Browser:OpenLocation" oncommand="openLocation();"/>
 
     <command id="Tools:Search" oncommand="BrowserSearch.webSearch();"/>
     <command id="Tools:Downloads" oncommand="BrowserDownloadsUI();"/>
     <command id="Tools:DevToolbar" oncommand="DeveloperToolbar.toggle();" disabled="true"/>
+    <command id="Tools:DevToolbarFocus" oncommand="DeveloperToolbar.focus();" disabled="true"/>
     <command id="Tools:WebConsole" oncommand="HUDConsoleUI.toggleHUD();"/>
     <command id="Tools:Inspect" oncommand="InspectorUI.toggleInspectorUI();" disabled="true"/>
     <command id="Tools:Debugger" oncommand="DebuggerUI.toggleDebugger();" disabled="true"/>
     <command id="Tools:RemoteDebugger" oncommand="DebuggerUI.toggleRemoteDebugger();" disabled="true"/>
     <command id="Tools:ChromeDebugger" oncommand="DebuggerUI.toggleChromeDebugger();" disabled="true"/>
     <command id="Tools:Scratchpad" oncommand="Scratchpad.openScratchpad();" disabled="true"/>
     <command id="Tools:StyleEditor" oncommand="StyleEditor.toggle();" disabled="true"/>
     <command id="Tools:ResponsiveUI" oncommand="ResponsiveUI.toggle();" disabled="true"/>
@@ -220,16 +221,18 @@
 #ifdef XP_GNOME
     <key id="key_search2" key="&searchFocusUnix.commandkey;" command="Tools:Search" modifiers="accel"/>
     <key id="key_openDownloads" key="&downloadsUnix.commandkey;" command="Tools:Downloads" modifiers="accel,shift"/>
 #else
     <key id="key_openDownloads" key="&downloads.commandkey;" command="Tools:Downloads" modifiers="accel"/>
 #endif
     <key id="key_openAddons" key="&addons.commandkey;" command="Tools:Addons" modifiers="accel,shift"/>
     <key id="key_errorConsole" key="&errorConsoleCmd.commandkey;" oncommand="toJavaScriptConsole();" modifiers="accel,shift" disabled="true"/>
+    <key id="key_devToolbar" keycode="&devToolbar.keycode;" modifiers="shift"
+         keytext="&devToolbar.keytext;" command="Tools:DevToolbarFocus"/>
     <key id="key_webConsole" key="&webConsoleCmd.commandkey;" oncommand="HUDConsoleUI.toggleHUD();"
 #ifdef XP_MACOSX
         modifiers="accel,alt"
 #else
         modifiers="accel,shift"
 #endif
     />
     <key id="key_debugger" key="&debuggerMenu.commandkey;" command="Tools:Debugger"
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -33,28 +33,28 @@ tabbrowser {
   -moz-binding: url("chrome://browser/content/tabbrowser.xml#tabbrowser-tab");
 }
 
 .tabbrowser-tab:not([pinned]) {
   -moz-box-flex: 100;
   max-width: 250px;
   min-width: 100px;
   width: 0;
-  -moz-transition: min-width 200ms ease-out,
-                   max-width 250ms ease-out,
-                   opacity 50ms ease-out 20ms /* hide the tab for the first 20ms of the max-width transition */;
+  transition: min-width 200ms ease-out,
+              max-width 250ms ease-out,
+              opacity 50ms ease-out 20ms /* hide the tab for the first 20ms of the max-width transition */;
 }
 
 .tabbrowser-tab:not([pinned]):not([fadein]) {
   max-width: 0.1px;
   min-width: 0.1px;
   opacity: 0 !important;
-  -moz-transition: min-width 200ms ease-out,
-                   max-width 250ms ease-out,
-                   opacity 50ms ease-out 180ms /* hide the tab for the last 20ms of the max-width transition */;
+  transition: min-width 200ms ease-out,
+              max-width 250ms ease-out,
+              opacity 50ms ease-out 180ms /* hide the tab for the last 20ms of the max-width transition */;
 }
 
 .tab-throbber:not([fadein]):not([pinned]),
 .tab-label:not([fadein]):not([pinned]),
 .tab-icon-image:not([fadein]):not([pinned]),
 .tab-close-button:not([fadein]):not([pinned]) {
   display: none;
 }
@@ -372,18 +372,18 @@ window[chromehidden~="toolbar"] toolbar:
   position: fixed;
   top: 0;
   left: 0;
   width: 100%;
   height: 100%;
 }
 
 #full-screen-warning-container[fade-warning-out] {
-  -moz-transition-property: opacity !important;
-  -moz-transition-duration: 500ms !important;
+  transition-property: opacity !important;
+  transition-duration: 500ms !important;
   opacity: 0.0;
 }
 
 #full-screen-warning-message {
   pointer-events: auto;
   /* We must specify a max-width, otherwise word-wrap:break-word doesn't
      work in descendant <description> and <label> elements. Bug 630864. */
   max-width: 800px;  
@@ -513,27 +513,27 @@ statuspanel[type=status] {
 
 @media all and (max-width: 800px) {
   statuspanel[type=status] {
     min-width: 33%;
   }
 }
 
 statuspanel[type=overLink] {
-  -moz-transition: opacity 120ms ease-out;
+  transition: opacity 120ms ease-out;
   direction: ltr;
 }
 
 statuspanel[inactive] {
-  -moz-transition: none;
+  transition: none;
   opacity: 0;
 }
 
 statuspanel[inactive][previoustype=overLink] {
-  -moz-transition: opacity 200ms ease-out;
+  transition: opacity 200ms ease-out;
 }
 
 .statuspanel-inner {
   height: 3em;
   width: 100%;
   -moz-box-align: end;
 }
 
@@ -584,19 +584,19 @@ vbox[anonid=browserContainer][responsive
   overflow: auto;
 }
 
 .devtools-responsiveui-toolbar:-moz-locale-dir(rtl) {
   -moz-box-pack: end;
 }
 
 stack[anonid=browserStack][responsivemode] {
-  -moz-transition-duration: 200ms;
-  -moz-transition-timing-function: linear;
+  transition-duration: 200ms;
+  transition-timing-function: linear;
 }
 
 stack[anonid=browserStack][responsivemode] {
-  -moz-transition-property: min-width, max-width, min-height, max-height;
+  transition-property: min-width, max-width, min-height, max-height;
 }
 
 stack[anonid=browserStack][responsivemode][notransition] {
-  -moz-transition: none;
+  transition: none;
 }
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1389,16 +1389,17 @@ var gBrowserInit = {
         setUrlAndSearchBarWidthForConditionalForwardButton();
     });
 
     // Enable developer toolbar?
     let devToolbarEnabled = gPrefService.getBoolPref("devtools.toolbar.enabled");
     if (devToolbarEnabled) {
       document.getElementById("menu_devToolbar").hidden = false;
       document.getElementById("Tools:DevToolbar").removeAttribute("disabled");
+      document.getElementById("Tools:DevToolbarFocus").removeAttribute("disabled");
 #ifdef MENUBAR_CAN_AUTOHIDE
       document.getElementById("appmenu_devToolbar").hidden = false;
 #endif
 
       // Show the toolbar if it was previously visible
       if (gPrefService.getBoolPref("devtools.toolbar.visible")) {
         DeveloperToolbar.show(false);
       }
@@ -6052,27 +6053,56 @@ function WindowIsClosing()
 
 /**
  * Checks if this is the last full *browser* window around. If it is, this will
  * be communicated like quitting. Otherwise, we warn about closing multiple tabs.
  * @returns true if closing can proceed, false if it got cancelled.
  */
 function warnAboutClosingWindow() {
   // Popups aren't considered full browser windows.
-  if (!toolbar.visible)
+  let isPBWindow = gPrivateBrowsingUI.privateWindow;
+  if (!isPBWindow && !toolbar.visible)
     return gBrowser.warnAboutClosingTabs(true);
 
   // Figure out if there's at least one other browser window around.
   let e = Services.wm.getEnumerator("navigator:browser");
+  let otherPBWindowExists = false;
+  let warnAboutClosingTabs = false;
   while (e.hasMoreElements()) {
     let win = e.getNext();
-    if (win != window && win.toolbar.visible)
-      return gBrowser.warnAboutClosingTabs(true);
+    if (win != window) {
+      if (isPBWindow &&
+          ("gPrivateBrowsingUI" in win) &&
+          win.gPrivateBrowsingUI.privateWindow)
+        otherPBWindowExists = true;
+      if (win.toolbar.visible)
+        warnAboutClosingTabs = true;
+      // If the current window is not in private browsing mode we don't need to 
+      // look for other pb windows, we can leave the loop when finding the 
+      // first non-popup window. If however the current window is in private 
+      // browsing mode then we need at least one other pb and one non-popup 
+      // window to break out early.
+      if ((!isPBWindow || otherPBWindowExists) && warnAboutClosingTabs)
+        break;
+    }
   }
 
+  if (isPBWindow && !otherPBWindowExists) {
+    let exitingCanceled = Cc["@mozilla.org/supports-PRBool;1"].
+                          createInstance(Ci.nsISupportsPRBool);
+    exitingCanceled.data = false;
+    Services.obs.notifyObservers(exitingCanceled,
+                                 "last-pb-context-exiting",
+                                 null);
+    if (exitingCanceled.data)
+      return false;
+  }
+  if (warnAboutClosingTabs)
+    return gBrowser.warnAboutClosingTabs(true);
+
   let os = Services.obs;
 
   let closingCanceled = Cc["@mozilla.org/supports-PRBool;1"].
                         createInstance(Ci.nsISupportsPRBool);
   os.notifyObservers(closingCanceled,
                      "browser-lastwindow-close-requested", null);
   if (closingCanceled.data)
     return false;
--- a/browser/base/content/highlighter.css
+++ b/browser/base/content/highlighter.css
@@ -20,19 +20,19 @@
 #highlighter-veil-container:not([dim]) > hbox > .highlighter-veil {
   visibility: hidden;
 }
 
 #highlighter-veil-container:not([disable-transitions]) > .highlighter-veil,
 #highlighter-veil-container:not([disable-transitions]) > #highlighter-veil-middlebox,
 #highlighter-veil-container:not([disable-transitions]) > #highlighter-veil-middlebox > .highlighter-veil,
 #highlighter-veil-container:not([disable-transitions]) > #highlighter-veil-middlebox > #highlighter-veil-transparentbox {
-  -moz-transition-property: width, height;
-  -moz-transition-duration: 0.1s;
-  -moz-transition-timing-function: linear;
+  transition-property: width, height;
+  transition-duration: 0.1s;
+  transition-timing-function: linear;
 }
 
 #highlighter-veil-bottombox,
 #highlighter-veil-rightbox {
   -moz-box-flex: 1;
 }
 
 #highlighter-veil-middlebox:-moz-locale-dir(rtl) {
@@ -48,19 +48,19 @@
  */
 
 #highlighter-nodeinfobar-container {
   position: absolute;
   max-width: 95%;
 }
 
 #highlighter-nodeinfobar-container:not([disable-transitions]) {
-  -moz-transition-property: top, left;
-  -moz-transition-duration: 0.1s;
-  -moz-transition-timing-function: linear;
+  transition-property: top, left;
+  transition-duration: 0.1s;
+  transition-timing-function: linear;
 }
 
 #highlighter-nodeinfobar-text {
   overflow: hidden;
   white-space: nowrap;
   text-overflow: ellipsis;
   direction: ltr;
 }
@@ -115,16 +115,16 @@ html|*#highlighter-nodeinfobar-tagname {
 }
 
 #inspector-layoutview-container > iframe {
   /* header size */
   height: 28px;
 }
 
 #inspector-layoutview-container:not([disable-transitions]) > iframe {
-  -moz-transition-property: height;
-  -moz-transition-duration: 0.2s;
+  transition-property: height;
+  transition-duration: 0.2s;
 }
 
 #inspector-layoutview-container > iframe[open] {
   /* header size + layout view size: 28px + 145px */
   height: 173px;
 }
--- a/browser/base/content/newtab/newTab.css
+++ b/browser/base/content/newtab/newTab.css
@@ -63,18 +63,18 @@ input[type=button] {
 
 /* GRID */
 #newtab-grid {
   display: -moz-box;
   -moz-box-flex: 5;
   -moz-box-orient: vertical;
   min-width: 600px;
   min-height: 400px;
-  -moz-transition: 100ms ease-out;
-  -moz-transition-property: opacity;
+  transition: 100ms ease-out;
+  transition-property: opacity;
 }
 
 #newtab-grid[page-disabled] {
   opacity: 0;
 }
 
 #newtab-grid[locked],
 #newtab-grid[page-disabled] {
@@ -94,43 +94,43 @@ input[type=button] {
   display: -moz-box;
   -moz-box-flex: 1;
 }
 
 /* SITES */
 .newtab-site {
   position: relative;
   -moz-box-flex: 1;
-  -moz-transition: 100ms ease-out;
-  -moz-transition-property: top, left, opacity;
+  transition: 100ms ease-out;
+  transition-property: top, left, opacity;
 }
 
 .newtab-site[frozen] {
   position: absolute;
   pointer-events: none;
 }
 
 .newtab-site[dragged] {
-  -moz-transition-property: none;
+  transition-property: none;
   z-index: 10;
 }
 
 /* LINK + THUMBNAILS */
 .newtab-link,
 .newtab-thumbnail {
   position: absolute;
   left: 0;
   top: 0;
   right: 0;
   bottom: 0;
 }
 
 .newtab-thumbnail {
   opacity: .8;
-  -moz-transition: opacity 100ms ease-out;
+  transition: opacity 100ms ease-out;
 }
 
 .newtab-thumbnail[dragged],
 .newtab-link:-moz-focusring > .newtab-thumbnail,
 .newtab-site:hover > .newtab-link > .newtab-thumbnail {
   opacity: 1;
 }
 
@@ -145,17 +145,17 @@ input[type=button] {
   text-overflow: ellipsis;
 }
 
 /* CONTROLS */
 .newtab-control {
   position: absolute;
   top: 4px;
   opacity: 0;
-  -moz-transition: opacity 100ms ease-out;
+  transition: opacity 100ms ease-out;
 }
 
 .newtab-control:-moz-focusring,
 .newtab-site:hover > .newtab-control {
   opacity: 1;
 }
 
 .newtab-control[dragged] {
--- a/browser/base/content/tabbrowser.css
+++ b/browser/base/content/tabbrowser.css
@@ -46,10 +46,10 @@ tabpanels {
   display: none;
 }
 
 .closing-tabs-spacer {
   pointer-events: none;
 }
 
 .tabbrowser-tabs:not(:hover) > .tabbrowser-arrowscrollbox > .closing-tabs-spacer {
-  -moz-transition: width .15s ease-out;
+  transition: width .15s ease-out;
 }
--- a/browser/base/content/test/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -143,16 +143,17 @@ endif
                  browser_bug623155.js \
                  browser_bug623893.js \
                  browser_bug624734.js \
                  browser_bug647886.js \
                  browser_bug655584.js \
                  browser_bug664672.js \
                  browser_bug710878.js \
                  browser_bug719271.js \
+                 browser_bug724239.js \
                  browser_bug735471.js \
                  browser_bug743421.js \
                  browser_bug749738.js \
                  browser_bug763468.js \
                  browser_bug767836.js \
                  browser_canonizeURL.js \
                  browser_customize.js \
                  browser_findbarClose.js \
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/browser_bug724239.js
@@ -0,0 +1,28 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function test() {
+  waitForExplicitFinish();
+  BrowserOpenTab();
+
+  let tab = gBrowser.selectedTab;
+  let browser = tab.linkedBrowser;
+
+  registerCleanupFunction(function () { gBrowser.removeTab(tab); });
+
+  whenBrowserLoaded(browser, function () {
+    browser.loadURI("http://example.com/");
+
+    whenBrowserLoaded(browser, function () {
+      ok(!gBrowser.canGoBack, "about:newtab wasn't added to the session history");
+      finish();
+    });
+  });
+}
+
+function whenBrowserLoaded(aBrowser, aCallback) {
+  aBrowser.addEventListener("load", function onLoad() {
+    aBrowser.removeEventListener("load", onLoad, true);
+    executeSoon(aCallback);
+  }, true);
+}
--- a/browser/base/content/test/browser_sanitizeDialog.js
+++ b/browser/base/content/test/browser_sanitizeDialog.js
@@ -460,22 +460,16 @@ var gAllTests = [
     var localStorage = dsm.getLocalStorageForPrincipal(principal, URL);
     localStorage.setItem("test", "value");
 
     // Store something to the offline cache
     const nsICache = Components.interfaces.nsICache;
     var cs = Components.classes["@mozilla.org/network/cache-service;1"]
              .getService(Components.interfaces.nsICacheService);
     var session = cs.createSession(URL + "/manifest", nsICache.STORE_OFFLINE, nsICache.STREAM_BASED);
-    var cacheEntry = session.openCacheEntry(URL, nsICache.ACCESS_READ_WRITE, false);
-    var stream = cacheEntry.openOutputStream(0);
-    var content = "content";
-    stream.write(content, content.length);
-    stream.close();
-    cacheEntry.close();
 
     // Open the dialog
     let wh = new WindowHelper();
     wh.onload = function () {
       this.selectDuration(Sanitizer.TIMESPAN_EVERYTHING);
       // Show details
       this.toggleDetails();
       // Clear only offlineApps
@@ -501,17 +495,30 @@ var gAllTests = [
         {
           // Do not enumerate entries.
           return false;
         }
       };
       cs.visitEntries(visitor);
       is(size, 0, "offline application cache entries evicted");
     };
-    wh.open();
+
+    var cacheListener = {
+      onCacheEntryAvailable: function (entry, access, status) {
+        is(status, Cr.NS_OK);
+        var stream = entry.openOutputStream(0);
+        var content = "content";
+        stream.write(content, content.length);
+        stream.close();
+        entry.close();
+        wh.open();
+      }
+    };
+
+    session.asyncOpenCacheEntry(URL, nsICache.ACCESS_READ_WRITE, cacheListener);
   },
   function () {
     // Test for offline apps permission deletion
 
     // Prepare stuff, we will work with www.example.com
     var URL = "http://www.example.com";
 
     var ios = Cc["@mozilla.org/network/io-service;1"]
--- a/browser/components/places/tests/unit/test_clearHistory_shutdown.js
+++ b/browser/components/places/tests/unit/test_clearHistory_shutdown.js
@@ -61,19 +61,17 @@ let notificationsObserver = {
         do_check_false(stmt.executeStep());
         stmt.reset();
       });
     } finally {
       stmt.finalize();
     }
 
     // Check cache.
-    do_check_false(cacheExists(URL));
-
-    do_test_finished();
+    checkCache(URL);
   }
 }
 
 let timeInMicroseconds = Date.now() * 1000;
 
 function run_test() {
   do_test_pending();
 
@@ -100,17 +98,20 @@ function run_test() {
   print("Add visits.");
   URIS.forEach(function(aUrl) {
     PlacesUtils.history.addVisit(uri(aUrl), timeInMicroseconds++, null,
                                  PlacesUtils.history.TRANSITION_TYPED,
                                  false, 0);
   });
   print("Add cache.");
   storeCache(URL, "testData");
+}
 
+function run_test_continue()
+{
   print("Simulate and wait shutdown.");
   getDistinctNotifications().forEach(
     function (topic)
       Services.obs.addObserver(notificationsObserver, topic, false)
   );
 
   shutdownPlaces();
 
@@ -123,43 +124,51 @@ function getDistinctNotifications() {
   return [ar[i] for (i in ar) if (ar.slice(0, i).indexOf(ar[i]) == -1)];
 }
 
 function storeCache(aURL, aContent) {
   let cache = Cc["@mozilla.org/network/cache-service;1"].
               getService(Ci.nsICacheService);
   let session = cache.createSession("FTP", Ci.nsICache.STORE_ANYWHERE,
                                     Ci.nsICache.STREAM_BASED);
-  let cacheEntry =
-    session.openCacheEntry(aURL, Ci.nsICache.ACCESS_READ_WRITE, false);
 
-  cacheEntry.setMetaDataElement("servertype", "0");
-  var oStream = cacheEntry.openOutputStream(0);
+  var storeCacheListener = {
+    onCacheEntryAvailable: function (entry, access, status) {
+      do_check_eq(status, Cr.NS_OK);
+
+      entry.setMetaDataElement("servertype", "0");
+      var os = entry.openOutputStream(0);
 
-  var written = oStream.write(aContent, aContent.length);
-  if (written != aContent.length) {
-    do_throw("oStream.write has not written all data!\n" +
-             "  Expected: " + written  + "\n" +
-             "  Actual: " + aContent.length + "\n");
-  }
-  oStream.close();
-  cacheEntry.close();
+      var written = os.write(aContent, aContent.length);
+      if (written != aContent.length) {
+        do_throw("os.write has not written all data!\n" +
+                 "  Expected: " + written  + "\n" +
+                 "  Actual: " + aContent.length + "\n");
+      }
+      os.close();
+      entry.close();
+      do_execute_soon(run_test_continue);
+    }
+  };
+
+  session.asyncOpenCacheEntry(aURL,
+                              Ci.nsICache.ACCESS_READ_WRITE,
+                              storeCacheListener);
 }
 
-function cacheExists(aURL) {
+
+function checkCache(aURL) {
   let cache = Cc["@mozilla.org/network/cache-service;1"].
               getService(Ci.nsICacheService);
   let session = cache.createSession("FTP", Ci.nsICache.STORE_ANYWHERE,
                                     Ci.nsICache.STREAM_BASED);
-  try {
-    let cacheEntry =
-      session.openCacheEntry(aURL, Ci.nsICache.ACCESS_READ, true);
-  } catch (e) {
-    if (e.result == Cr.NS_ERROR_CACHE_KEY_NOT_FOUND ||
-        e.result == Cr.NS_ERROR_FAILURE)
-      return false;
- 
-    // Throw the textual error description.
-    do_throw(e);
-  }
-  cacheEntry.close();
-  return true;
+
+  var checkCacheListener = {
+    onCacheEntryAvailable: function (entry, access, status) {
+      do_check_eq(status, Cr.NS_ERROR_CACHE_KEY_NOT_FOUND);
+      do_test_finished();
+    }
+  };
+
+  session.asyncOpenCacheEntry(aURL,
+                              Ci.nsICache.ACCESS_READ,
+                              checkCacheListener);
 }
--- a/browser/components/preferences/applications.js
+++ b/browser/components/preferences/applications.js
@@ -1080,23 +1080,21 @@ var gApplicationsPane = {
    * the last one is the one that the application will use.  That may not be
    * correct, but it's how we've been doing it for years.
    *
    * Perhaps we should instead query navigator.mimeTypes for the set of types
    * supported by the application and then get the plugin from each MIME type's
    * enabledPlugin property.  But if there's a plugin for a type, we need
    * to know about it even if it isn't enabled, since we're going to give
    * the user an option to enable it.
-   * 
-   * I'll also note that my reading of nsPluginTag::RegisterWithCategoryManager
-   * suggests that enabledPlugin is only determined during registration
-   * and does not get updated when plugin.disable_full_page_plugin_for_types
-   * changes (unless modification of that preference spawns reregistration).
-   * So even if we could use enabledPlugin to get the plugin that would be used,
-   * we'd still need to check the pref ourselves to find out if it's enabled.
+   *
+   * Also note that enabledPlugin does not get updated when
+   * plugin.disable_full_page_plugin_for_types changes, so even if we could use
+   * enabledPlugin to get the plugin that would be used, we'd still need to
+   * check the pref ourselves to find out if it's enabled.
    */
   _loadPluginHandlers: function() {
     for (let i = 0; i < navigator.plugins.length; ++i) {
       let plugin = navigator.plugins[i];
       for (let j = 0; j < plugin.length; ++j) {
         let type = plugin[j].type;
 
         let handlerInfoWrapper;
--- a/browser/components/preferences/in-content/applications.js
+++ b/browser/components/preferences/in-content/applications.js
@@ -1067,23 +1067,21 @@ var gApplicationsPane = {
    * the last one is the one that the application will use.  That may not be
    * correct, but it's how we've been doing it for years.
    *
    * Perhaps we should instead query navigator.mimeTypes for the set of types
    * supported by the application and then get the plugin from each MIME type's
    * enabledPlugin property.  But if there's a plugin for a type, we need
    * to know about it even if it isn't enabled, since we're going to give
    * the user an option to enable it.
-   * 
-   * I'll also note that my reading of nsPluginTag::RegisterWithCategoryManager
-   * suggests that enabledPlugin is only determined during registration
-   * and does not get updated when plugin.disable_full_page_plugin_for_types
-   * changes (unless modification of that preference spawns reregistration).
-   * So even if we could use enabledPlugin to get the plugin that would be used,
-   * we'd still need to check the pref ourselves to find out if it's enabled.
+   *
+   * Also note that enabledPlugin does not get updated when
+   * plugin.disable_full_page_plugin_for_types changes, so even if we could use
+   * enabledPlugin to get the plugin that would be used, we'd still need to
+   * check the pref ourselves to find out if it's enabled.
    */
   _loadPluginHandlers: function() {
     for (let i = 0; i < navigator.plugins.length; ++i) {
       let plugin = navigator.plugins[i];
       for (let j = 0; j < plugin.length; ++j) {
         let type = plugin[j].type;
 
         let handlerInfoWrapper;
--- a/browser/components/shell/src/nsWindowsShellService.cpp
+++ b/browser/components/shell/src/nsWindowsShellService.cpp
@@ -223,17 +223,21 @@ GetHelperPath(nsAutoString& aPath)
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = appHelper->AppendNative(NS_LITERAL_CSTRING("uninstall"));
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = appHelper->AppendNative(NS_LITERAL_CSTRING("helper.exe"));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  return appHelper->GetPath(aPath);
+  rv = appHelper->GetPath(aPath);
+
+  aPath.Insert(L'"', 0);
+  aPath.Append(L'"');
+  return rv;
 }
 
 nsresult
 LaunchHelper(nsAutoString& aPath)
 {
   STARTUPINFOW si = {sizeof(si), 0};
   PROCESS_INFORMATION pi = {0};
 
--- a/browser/components/tabview/iq.js
+++ b/browser/components/tabview/iq.js
@@ -563,29 +563,29 @@ iQClass.prototype = {
       let cStyle = window.getComputedStyle(elem, null);
       for (let prop in css) {
         prop = prop.replace(rupper, "-$1").toLowerCase();
         iQ(elem).css(prop, cStyle.getPropertyValue(prop));
       }
     });
 
     this.css({
-      '-moz-transition-property': Object.keys(css).join(", "),
-      '-moz-transition-duration': (duration / 1000) + 's',
-      '-moz-transition-timing-function': easing
+      'transition-property': Object.keys(css).join(", "),
+      'transition-duration': (duration / 1000) + 's',
+      'transition-timing-function': easing
     });
 
     this.css(css);
 
     let self = this;
     setTimeout(function() {
       self.css({
-        '-moz-transition-property': 'none',
-        '-moz-transition-duration': '',
-        '-moz-transition-timing-function': ''
+        'transition-property': 'none',
+        'transition-duration': '',
+        'transition-timing-function': ''
       });
 
       if (typeof options.complete == "function")
         options.complete.apply(self);
     }, duration);
 
     return this;
   },
--- a/browser/components/tabview/test/browser_tabview_bug580412.js
+++ b/browser/components/tabview/test/browser_tabview_bug580412.js
@@ -22,17 +22,17 @@ function onTabViewShown() {
       ok(!TabView.isVisible(), "TabView is hidden");
       finish();
     });
   }
 
   // we need to stop the setBounds() css animation or else the test will
   // fail in single-mode because the group is newly created "ontabshown".
   let $container = contentWindow.iQ(currentActiveGroup.container);
-  $container.css("-moz-transition-property", "none");
+  $container.css("transition-property", "none");
 
   currentActiveGroup.setPosition(40, 40, true);
   currentActiveGroup.arrange({animate: false});
 
   // move down 20 so we're far enough away from the top.
   checkSnap(currentActiveGroup, 0, 20, contentWindow, function(snapped){
     is(currentActiveGroup.getBounds().top, 60, "group.top is 60px");
     ok(!snapped,"Move away from the edge");
--- a/browser/confvars.sh
+++ b/browser/confvars.sh
@@ -38,8 +38,9 @@ MOZ_APP_ID={ec8030f7-c20a-464f-9b0e-13a3
 # of values.
 ACCEPTED_MAR_CHANNEL_IDS=firefox-mozilla-central
 # The MAR_CHANNEL_ID must not contain the following 3 characters: ",\t "
 MAR_CHANNEL_ID=firefox-mozilla-central
 MOZ_PROFILE_MIGRATOR=1
 MOZ_EXTENSION_MANAGER=1
 MOZ_APP_STATIC_INI=1
 MOZ_WEBAPP_RUNTIME=1
+MOZ_MEDIA_NAVIGATOR=1
--- a/browser/devtools/commandline/GcliCommands.jsm
+++ b/browser/devtools/commandline/GcliCommands.jsm
@@ -18,23 +18,27 @@ XPCOMUtils.defineLazyModuleGetter(this, 
                                   "resource://gre/modules/NetUtil.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "LayoutHelpers",
                                   "resource:///modules/devtools/LayoutHelpers.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "console",
                                   "resource:///modules/devtools/Console.jsm");
 
+XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
+                                  "resource://gre/modules/AddonManager.jsm");
+
 let prefSvc = "@mozilla.org/preferences-service;1";
 XPCOMUtils.defineLazyGetter(this, "prefBranch", function() {
   let prefService = Cc[prefSvc].getService(Ci.nsIPrefService);
   return prefService.getBranch(null).QueryInterface(Ci.nsIPrefBranch2);
 });
 
 Cu.import("resource:///modules/devtools/GcliTiltCommands.jsm", {});
+Cu.import("resource:///modules/devtools/GcliCookieCommands.jsm", {});
 
 /**
  * A place to store the names of the commands that we have added as a result of
  * calling refreshAutoCommands(). Used by refreshAutoCommands to remove the
  * added commands.
  */
 let commands = [];
 
@@ -288,31 +292,25 @@ gcli.addCommand({
 
 /**
  * 'console clear' command
  */
 gcli.addCommand({
   name: "console clear",
   description: gcli.lookup("consoleclearDesc"),
   exec: function Command_consoleClear(args, context) {
-    let window = context.environment.chromeDocument.defaultView;
-    let hud = HUDService.getHudReferenceById(context.environment.hudId);
-
-    // Use a timeout so we also clear the reporting of the clear command
-    let threadManager = Cc["@mozilla.org/thread-manager;1"]
-        .getService(Ci.nsIThreadManager);
-    threadManager.mainThread.dispatch({
-      run: function() {
-        hud.gcliterm.clearOutput();
-      }
-    }, Ci.nsIThread.DISPATCH_NORMAL);
+    let window = context.environment.contentDocument.defaultView;
+    let hud = HUDService.getHudByWindow(window);
+    // hud will be null if the web console has not been opened for this window
+    if (hud) {
+      hud.jsterm.clearOutput();
+    }
   }
 });
 
-
 /**
  * 'console close' command
  */
 gcli.addCommand({
   name: "console close",
   description: gcli.lookup("consolecloseDesc"),
   exec: function Command_consoleClose(args, context) {
     let tab = context.environment.chromeDocument.defaultView.gBrowser.selectedTab
@@ -328,16 +326,61 @@ gcli.addCommand({
   description: gcli.lookup("consoleopenDesc"),
   exec: function Command_consoleOpen(args, context) {
     let tab = context.environment.chromeDocument.defaultView.gBrowser.selectedTab
     HUDService.activateHUDForContext(tab);
   }
 });
 
 /**
+ * Restart command
+ *
+ * @param boolean nocache
+ *        Disables loading content from cache upon restart.
+ *
+ * Examples :
+ * >> restart
+ * - restarts browser immediately
+ * >> restart --nocache
+ * - restarts immediately and starts Firefox without using cache
+ */
+gcli.addCommand({
+  name: "restart",
+  description: gcli.lookup("restartFirefoxDesc"),
+  params: [
+    {
+      name: "nocache",
+      type: "boolean",
+      defaultValue: false,
+      description: gcli.lookup("restartFirefoxNocacheDesc")
+    }
+  ],
+  returnType: "string",
+  exec: function Restart(args, context) {
+    let canceled = Cc["@mozilla.org/supports-PRBool;1"]
+                     .createInstance(Ci.nsISupportsPRBool);
+    Services.obs.notifyObservers(canceled, "quit-application-requested", "restart");
+    if (canceled.data) {
+      return gcli.lookup("restartFirefoxRequestCancelled");
+    }
+
+    // disable loading content from cache.
+    if (args.nocache) {
+      Services.appinfo.invalidateCachesOnRestart();
+    }
+
+    // restart
+    Cc['@mozilla.org/toolkit/app-startup;1']
+      .getService(Ci.nsIAppStartup)
+      .quit(Ci.nsIAppStartup.eAttemptQuit | Ci.nsIAppStartup.eRestart);
+    return gcli.lookup("restartFirefoxRestarting");
+  }
+});
+
+/**
  * 'inspect' command
  */
 gcli.addCommand({
   name: "inspect",
   description: gcli.lookup("inspectDesc"),
   manual: gcli.lookup("inspectManual"),
   params: [
     {
@@ -537,8 +580,620 @@ gcli.addCommand({
       });
     } catch (ex) {
       // If the debugger has been closed already, don't scare the user.
       promise.resolve(gcli.lookup("breakdelRemoved"));
     }
     return promise;
   }
 });
+
+/**
+ * 'export' command
+ */
+gcli.addCommand({
+  name: "export",
+  description: gcli.lookup("exportDesc"),
+});
+
+/**
+ * The 'export html' command. This command allows the user to export the page to
+ * HTML after they do DOM changes.
+ */
+gcli.addCommand({
+  name: "export html",
+  description: gcli.lookup("exportHtmlDesc"),
+  exec: function(args, context) {
+    let document = context.environment.contentDocument;
+    let window = document.defaultView;
+    let page = document.documentElement.outerHTML;
+    window.open('data:text/plain;charset=utf8,' + encodeURIComponent(page));
+  }
+});
+
+/**
+ * 'pagemod' command
+ */
+gcli.addCommand({
+  name: "pagemod",
+  description: gcli.lookup("pagemodDesc"),
+});
+
+/**
+ * The 'pagemod replace' command. This command allows the user to search and
+ * replace within text nodes and attributes.
+ */
+gcli.addCommand({
+  name: "pagemod replace",
+  description: gcli.lookup("pagemodReplaceDesc"),
+  params: [
+    {
+      name: "search",
+      type: "string",
+      description: gcli.lookup("pagemodReplaceSearchDesc"),
+    },
+    {
+      name: "replace",
+      type: "string",
+      description: gcli.lookup("pagemodReplaceReplaceDesc"),
+    },
+    {
+      name: "ignoreCase",
+      type: "boolean",
+      description: gcli.lookup("pagemodReplaceIgnoreCaseDesc"),
+    },
+    {
+      name: "selector",
+      type: "string",
+      description: gcli.lookup("pagemodReplaceSelectorDesc"),
+      defaultValue: "*:not(script):not(style):not(embed):not(object):not(frame):not(iframe):not(frameset)",
+    },
+    {
+      name: "root",
+      type: "node",
+      description: gcli.lookup("pagemodReplaceRootDesc"),
+      defaultValue: null,
+    },
+    {
+      name: "attrOnly",
+      type: "boolean",
+      description: gcli.lookup("pagemodReplaceAttrOnlyDesc"),
+    },
+    {
+      name: "contentOnly",
+      type: "boolean",
+      description: gcli.lookup("pagemodReplaceContentOnlyDesc"),
+    },
+    {
+      name: "attributes",
+      type: "string",
+      description: gcli.lookup("pagemodReplaceAttributesDesc"),
+      defaultValue: null,
+    },
+  ],
+  exec: function(args, context) {
+    let document = context.environment.contentDocument;
+    let searchTextNodes = !args.attrOnly;
+    let searchAttributes = !args.contentOnly;
+    let regexOptions = args.ignoreCase ? 'ig' : 'g';
+    let search = new RegExp(escapeRegex(args.search), regexOptions);
+    let attributeRegex = null;
+    if (args.attributes) {
+      attributeRegex = new RegExp(args.attributes, regexOptions);
+    }
+
+    let root = args.root || document;
+    let elements = root.querySelectorAll(args.selector);
+    elements = Array.prototype.slice.call(elements);
+
+    let replacedTextNodes = 0;
+    let replacedAttributes = 0;
+
+    function replaceAttribute() {
+      replacedAttributes++;
+      return args.replace;
+    }
+    function replaceTextNode() {
+      replacedTextNodes++;
+      return args.replace;
+    }
+
+    for (let i = 0; i < elements.length; i++) {
+      let element = elements[i];
+      if (searchTextNodes) {
+        for (let y = 0; y < element.childNodes.length; y++) {
+          let node = element.childNodes[y];
+          if (node.nodeType == node.TEXT_NODE) {
+            node.textContent = node.textContent.replace(search, replaceTextNode);
+          }
+        }
+      }
+
+      if (searchAttributes) {
+        if (!element.attributes) {
+          continue;
+        }
+        for (let y = 0; y < element.attributes.length; y++) {
+          let attr = element.attributes[y];
+          if (!attributeRegex || attributeRegex.test(attr.name)) {
+            attr.value = attr.value.replace(search, replaceAttribute);
+          }
+        }
+      }
+    }
+
+    return gcli.lookupFormat("pagemodReplaceResult",
+                             [elements.length, replacedTextNodes,
+                              replacedAttributes]);
+  }
+});
+
+/**
+ * 'pagemod remove' command
+ */
+gcli.addCommand({
+  name: "pagemod remove",
+  description: gcli.lookup("pagemodRemoveDesc"),
+});
+
+
+/**
+ * The 'pagemod remove element' command.
+ */
+gcli.addCommand({
+  name: "pagemod remove element",
+  description: gcli.lookup("pagemodRemoveElementDesc"),
+  params: [
+    {
+      name: "search",
+      type: "string",
+      description: gcli.lookup("pagemodRemoveElementSearchDesc"),
+    },
+    {
+      name: "root",
+      type: "node",
+      description: gcli.lookup("pagemodRemoveElementRootDesc"),
+      defaultValue: null,
+    },
+    {
+      name: 'stripOnly',
+      type: 'boolean',
+      description: gcli.lookup("pagemodRemoveElementStripOnlyDesc"),
+    },
+    {
+      name: 'ifEmptyOnly',
+      type: 'boolean',
+      description: gcli.lookup("pagemodRemoveElementIfEmptyOnlyDesc"),
+    },
+  ],
+  exec: function(args, context) {
+    let document = context.environment.contentDocument;
+    let root = args.root || document;
+    let elements = Array.prototype.slice.call(root.querySelectorAll(args.search));
+
+    let removed = 0;
+    for (let i = 0; i < elements.length; i++) {
+      let element = elements[i];
+      let parentNode = element.parentNode;
+      if (!parentNode || !element.removeChild) {
+        continue;
+      }
+      if (args.stripOnly) {
+        while (element.hasChildNodes()) {
+          parentNode.insertBefore(element.childNodes[0], element);
+        }
+      }
+      if (!args.ifEmptyOnly || !element.hasChildNodes()) {
+        element.parentNode.removeChild(element);
+        removed++;
+      }
+    }
+
+    return gcli.lookupFormat("pagemodRemoveElementResultMatchedAndRemovedElements",
+                             [elements.length, removed]);
+  }
+});
+
+/**
+ * The 'pagemod remove attribute' command.
+ */
+gcli.addCommand({
+  name: "pagemod remove attribute",
+  description: gcli.lookup("pagemodRemoveAttributeDesc"),
+  params: [
+    {
+      name: "searchAttributes",
+      type: "string",
+      description: gcli.lookup("pagemodRemoveAttributeSearchAttributesDesc"),
+    },
+    {
+      name: "searchElements",
+      type: "string",
+      description: gcli.lookup("pagemodRemoveAttributeSearchElementsDesc"),
+    },
+    {
+      name: "root",
+      type: "node",
+      description: gcli.lookup("pagemodRemoveAttributeRootDesc"),
+      defaultValue: null,
+    },
+    {
+      name: "ignoreCase",
+      type: "boolean",
+      description: gcli.lookup("pagemodRemoveAttributeIgnoreCaseDesc"),
+    },
+  ],
+  exec: function(args, context) {
+    let document = context.environment.contentDocument;
+
+    let root = args.root || document;
+    let regexOptions = args.ignoreCase ? 'ig' : 'g';
+    let attributeRegex = new RegExp(args.searchAttributes, regexOptions);
+    let elements = root.querySelectorAll(args.searchElements);
+    elements = Array.prototype.slice.call(elements);
+
+    let removed = 0;
+    for (let i = 0; i < elements.length; i++) {
+      let element = elements[i];
+      if (!element.attributes) {
+        continue;
+      }
+
+      var attrs = Array.prototype.slice.call(element.attributes);
+      for (let y = 0; y < attrs.length; y++) {
+        let attr = attrs[y];
+        if (attributeRegex.test(attr.name)) {
+          element.removeAttribute(attr.name);
+          removed++;
+        }
+      }
+    }
+
+    return gcli.lookupFormat("pagemodRemoveAttributeResult",
+                             [elements.length, removed]);
+  }
+});
+
+
+/**
+ * Make a given string safe to use  in a regular expression.
+ *
+ * @param string aString
+ *        The string you want to use in a regex.
+ * @return string
+ *         The equivalent of |aString| but safe to use in a regex.
+ */
+function escapeRegex(aString) {
+  return aString.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
+}
+
+/**
+ * 'addon' command.
+ */
+gcli.addCommand({
+  name: "addon",
+  description: gcli.lookup("addonDesc")
+});
+
+/**
+ * 'addon list' command.
+ */
+gcli.addCommand({
+  name: "addon list",
+  description: gcli.lookup("addonListDesc"),
+  params: [{
+    name: 'type',
+    type: {
+      name: 'selection',
+      data: ["dictionary", "extension", "locale", "plugin", "theme", "all"]
+    },
+    defaultValue: 'all',
+    description: gcli.lookup("addonListTypeDesc"),
+  }],
+  exec: function(aArgs, context) {
+    function representEnabledAddon(aAddon) {
+      return "<li><![CDATA[" + aAddon.name + "\u2002" + aAddon.version +
+      getAddonStatus(aAddon) + "]]></li>";
+    }
+
+    function representDisabledAddon(aAddon) {
+      return "<li class=\"gcli-addon-disabled\">" +
+        "<![CDATA[" + aAddon.name + "\u2002" + aAddon.version + aAddon.version +
+        "]]></li>";
+    }
+
+    function getAddonStatus(aAddon) {
+      let operations = [];
+
+      if (aAddon.pendingOperations & AddonManager.PENDING_ENABLE) {
+        operations.push("PENDING_ENABLE");
+      }
+
+      if (aAddon.pendingOperations & AddonManager.PENDING_DISABLE) {
+        operations.push("PENDING_DISABLE");
+      }
+
+      if (aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL) {
+        operations.push("PENDING_UNINSTALL");
+      }
+
+      if (aAddon.pendingOperations & AddonManager.PENDING_INSTALL) {
+        operations.push("PENDING_INSTALL");
+      }
+
+      if (aAddon.pendingOperations & AddonManager.PENDING_UPGRADE) {
+        operations.push("PENDING_UPGRADE");
+      }
+
+      if (operations.length) {
+        return " (" + operations.join(", ") + ")";
+      }
+      return "";
+    }
+
+    /**
+     * Compares two addons by their name. Used in sorting.
+     */
+    function compareAddonNames(aNameA, aNameB) {
+      return String.localeCompare(aNameA.name, aNameB.name);
+    }
+
+    /**
+     * Resolves the promise which is the scope (this) of this function, filling
+     * it with an HTML representation of the passed add-ons.
+     */
+    function list(aType, aAddons) {
+      if (!aAddons.length) {
+        this.resolve(gcli.lookup("addonNoneOfType"));
+      }
+
+      // Separate the enabled add-ons from the disabled ones.
+      let enabledAddons = [];
+      let disabledAddons = [];
+
+      aAddons.forEach(function(aAddon) {
+        if (aAddon.isActive) {
+          enabledAddons.push(aAddon);
+        } else {
+          disabledAddons.push(aAddon);
+        }
+      });
+
+      let header;
+      switch(aType) {
+        case "dictionary":
+          header = gcli.lookup("addonListDictionaryHeading");
+          break;
+        case "extension":
+          header = gcli.lookup("addonListExtensionHeading");
+          break;
+        case "locale":
+          header = gcli.lookup("addonListLocaleHeading");
+          break;
+        case "plugin":
+          header = gcli.lookup("addonListPluginHeading");
+          break;
+        case "theme":
+          header = gcli.lookup("addonListThemeHeading");
+        case "all":
+          header = gcli.lookup("addonListAllHeading");
+          break;
+        default:
+          header = gcli.lookup("addonListUnknownHeading");
+      }
+
+      // Map and sort the add-ons, and create an HTML list.
+      this.resolve(header +
+        "<ol>" +
+        enabledAddons.sort(compareAddonNames).map(representEnabledAddon).join("") +
+        disabledAddons.sort(compareAddonNames).map(representDisabledAddon).join("") +
+        "</ol>");
+    }
+
+    // Create the promise that will be resolved when the add-on listing has
+    // been finished.
+    let promise = context.createPromise();
+    let types = aArgs.type == "all" ? null : [aArgs.type];
+    AddonManager.getAddonsByTypes(types, list.bind(promise, aArgs.type));
+    return promise;
+  }
+});
+
+// We need a list of addon names for the enable and disable commands. Because
+// getting the name list is async we do not add the commands until we have the
+// list.
+AddonManager.getAllAddons(function addonAsync(aAddons) {
+  // We listen for installs to keep our addon list up to date. There is no need
+  // to listen for uninstalls because uninstalled addons are simply disabled
+  // until restart (to enable undo functionality).
+  AddonManager.addAddonListener({
+    onInstalled: function(aAddon) {
+      addonNameCache.push({
+        name: representAddon(aAddon).replace(/\s/g, "_"),
+        value: aAddon.name
+      });
+    },
+    onUninstalled: function(aAddon) {
+      let name = representAddon(aAddon).replace(/\s/g, "_");
+
+      for (let i = 0; i < addonNameCache.length; i++) {
+        if(addonNameCache[i].name == name) {
+          addonNameCache.splice(i, 1);
+          break;
+        }
+      }
+    },
+  });
+
+  /**
+   * Returns a string that represents the passed add-on.
+   */
+  function representAddon(aAddon) {
+    let name = aAddon.name + " " + aAddon.version;
+    return name.trim();
+  }
+
+  let addonNameCache = [];
+
+  // The name parameter, used in "addon enable" and "addon disable."
+  let nameParameter = {
+    name: "name",
+    type: {
+      name: "selection",
+      lookup: addonNameCache
+    },
+    description: gcli.lookup("addonNameDesc")
+  };
+
+  for (let addon of aAddons) {
+    addonNameCache.push({
+      name: representAddon(addon).replace(/\s/g, "_"),
+      value: addon.name
+    });
+  }
+
+  /**
+   * 'addon enable' command.
+   */
+  gcli.addCommand({
+    name: "addon enable",
+    description: gcli.lookup("addonEnableDesc"),
+    params: [nameParameter],
+    exec: function(aArgs, context) {
+      /**
+       * Enables the addon in the passed list which has a name that matches
+       * according to the passed name comparer, and resolves the promise which
+       * is the scope (this) of this function to display the result of this
+       * enable attempt.
+       */
+      function enable(aName, addons) {
+        // Find the add-on.
+        let addon = null;
+        addons.some(function(candidate) {
+          if (candidate.name == aName) {
+            addon = candidate;
+            return true;
+          } else {
+            return false;
+          }
+        });
+
+        let name = representAddon(addon);
+
+        if (!addon.userDisabled) {
+          this.resolve("<![CDATA[" +
+            gcli.lookupFormat("addonAlreadyEnabled", [name]) + "]]>");
+        } else {
+          addon.userDisabled = false;
+          // nl-nl: {$1} is ingeschakeld.
+          this.resolve("<![CDATA[" +
+            gcli.lookupFormat("addonEnabled", [name]) + "]]>");
+        }
+      }
+
+      let promise = context.createPromise();
+      // List the installed add-ons, enable one when done listing.
+      AddonManager.getAllAddons(enable.bind(promise, aArgs.name));
+      return promise;
+    }
+  });
+
+  /**
+   * 'addon disable' command.
+   */
+  gcli.addCommand({
+    name: "addon disable",
+    description: gcli.lookup("addonDisableDesc"),
+    params: [nameParameter],
+    exec: function(aArgs, context) {
+      /**
+       * Like enable, but ... you know ... the exact opposite.
+       */
+      function disable(aName, addons) {
+        // Find the add-on.
+        let addon = null;
+        addons.some(function(candidate) {
+          if (candidate.name == aName) {
+            addon = candidate;
+            return true;
+          } else {
+            return false;
+          }
+        });
+
+        let name = representAddon(addon);
+
+        if (addon.userDisabled) {
+          this.resolve("<![CDATA[" +
+            gcli.lookupFormat("addonAlreadyDisabled", [name]) + "]]>");
+        } else {
+          addon.userDisabled = true;
+          // nl-nl: {$1} is uitgeschakeld.
+          this.resolve("<![CDATA[" +
+            gcli.lookupFormat("addonDisabled", [name]) + "]]>");
+        }
+      }
+
+      let promise = context.createPromise();
+      // List the installed add-ons, disable one when done listing.
+      AddonManager.getAllAddons(disable.bind(promise, aArgs.name));
+      return promise;
+    }
+  });
+  Services.obs.notifyObservers(null, "gcli_addon_commands_ready", null);
+});
+
+/* Responsive Mode commands */
+(function gcli_cmd_resize_container() {
+  function gcli_cmd_resize(args, context) {
+    let browserDoc = context.environment.chromeDocument;
+    let browserWindow = browserDoc.defaultView;
+    let mgr = browserWindow.ResponsiveUI.ResponsiveUIManager;
+    mgr.handleGcliCommand(browserWindow,
+                          browserWindow.gBrowser.selectedTab,
+                          this.name,
+                          args);
+  }
+
+  gcli.addCommand({
+    name: 'resize',
+    description: gcli.lookup('resizeModeDesc')
+  });
+
+  gcli.addCommand({
+    name: 'resize on',
+    description: gcli.lookup('resizeModeOnDesc'),
+    manual: gcli.lookup('resizeModeManual'),
+    exec: gcli_cmd_resize
+  });
+
+  gcli.addCommand({
+    name: 'resize off',
+    description: gcli.lookup('resizeModeOffDesc'),
+    manual: gcli.lookup('resizeModeManual'),
+    exec: gcli_cmd_resize
+  });
+
+  gcli.addCommand({
+    name: 'resize toggle',
+    description: gcli.lookup('resizeModeToggleDesc'),
+    manual: gcli.lookup('resizeModeManual'),
+    exec: gcli_cmd_resize
+  });
+
+  gcli.addCommand({
+    name: 'resize to',
+    description: gcli.lookup('resizeModeToDesc'),
+    params: [
+      {
+        name: 'width',
+        type: 'number',
+        description: gcli.lookup("resizePageArgWidthDesc"),
+      },
+      {
+        name: 'height',
+        type: 'number',
+        description: gcli.lookup("resizePageArgHeightDesc"),
+      },
+    ],
+    exec: gcli_cmd_resize
+  });
+})();
new file mode 100644
--- /dev/null
+++ b/browser/devtools/commandline/GcliCookieCommands.jsm
@@ -0,0 +1,204 @@
+/* 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/. */
+
+
+let EXPORTED_SYMBOLS = [ ];
+
+Components.utils.import("resource:///modules/devtools/gcli.jsm");
+
+
+// We should really be using nsICookieManager so we can read more than just the
+// key/value of cookies. The difficulty is filtering the cookies that are
+// relevant to the current page. See
+// https://github.com/firebug/firebug/blob/master/extension/content/firebug/cookies/cookieObserver.js#L123
+// For details on how this is done with Firebug
+
+/**
+ * 'cookie' command
+ */
+gcli.addCommand({
+  name: "cookie",
+  description: gcli.lookup("cookieDesc"),
+  manual: gcli.lookup("cookieManual")
+});
+
+/**
+ * The template for the 'cookie list' command.
+ */
+var cookieListHtml = "" +
+  "<table>" +
+  "  <tr>" +
+  "    <th>" + gcli.lookup("cookieListOutKey") + "</th>" +
+  "    <th>" + gcli.lookup("cookieListOutValue") + "</th>" +
+  "    <th>" + gcli.lookup("cookieListOutActions") + "</th>" +
+  "  </tr>" +
+  "  <tr foreach='cookie in ${cookies}'>" +
+  "    <td>${cookie.key}</td>" +
+  "    <td>${cookie.value}</td>" +
+  "    <td>" +
+  "      <span class='gcli-out-shortcut'" +
+  "          onclick='${onclick}' ondblclick='${ondblclick}'" +
+  "          data-command='cookie set ${cookie.key}'" +
+  "          >" + gcli.lookup("cookieListOutEdit") + "</span>" +
+  "      <span class='gcli-out-shortcut'" +
+  "          onclick='${onclick}' ondblclick='${ondblclick}'" +
+  "          data-command='cookie remove ${cookie.key}'" +
+  "          >" + gcli.lookup("cookieListOutRemove") + "</span>" +
+  "    </td>" +
+  "  </tr>" +
+  "</table>" +
+  "";
+
+/**
+ * 'cookie list' command
+ */
+gcli.addCommand({
+  name: "cookie list",
+  description: gcli.lookup("cookieListDesc"),
+  manual: gcli.lookup("cookieListManual"),
+  returnType: "string",
+  exec: function Command_cookieList(args, context) {
+    // Parse out an array of { key:..., value:... } objects for each cookie
+    var doc = context.environment.contentDocument;
+    var cookies = doc.cookie.split("; ").map(function(cookieStr) {
+      var equalsPos = cookieStr.indexOf("=");
+      return {
+        key: cookieStr.substring(0, equalsPos),
+        value: cookieStr.substring(equalsPos + 1)
+      };
+    });
+
+    return context.createView({
+      html: cookieListHtml,
+      data: {
+        cookies: cookies,
+        onclick: createUpdateHandler(context),
+        ondblclick: createExecuteHandler(context),
+      }
+    });
+  }
+});
+
+/**
+ * 'cookie remove' command
+ */
+gcli.addCommand({
+  name: "cookie remove",
+  description: gcli.lookup("cookieRemoveDesc"),
+  manual: gcli.lookup("cookieRemoveManual"),
+  params: [
+    {
+      name: "key",
+      type: "string",
+      description: gcli.lookup("cookieRemoveKeyDesc"),
+    }
+  ],
+  exec: function Command_cookieRemove(args, context) {
+    let document = context.environment.contentDocument;
+    let expDate = new Date();
+    expDate.setDate(expDate.getDate() - 1);
+    document.cookie = escape(args.key) + "=; expires=" + expDate.toGMTString();
+  }
+});
+
+/**
+ * 'cookie set' command
+ */
+gcli.addCommand({
+  name: "cookie set",
+  description: gcli.lookup("cookieSetDesc"),
+  manual: gcli.lookup("cookieSetManual"),
+  params: [
+    {
+      name: "key",
+      type: "string",
+      description: gcli.lookup("cookieSetKeyDesc")
+    },
+    {
+      name: "value",
+      type: "string",
+      description: gcli.lookup("cookieSetValueDesc")
+    },
+    {
+      group: gcli.lookup("cookieSetOptionsDesc"),
+      params: [
+        {
+          name: "path",
+          type: "string",
+          defaultValue: "/",
+          description: gcli.lookup("cookieSetPathDesc")
+        },
+        {
+          name: "domain",
+          type: "string",
+          defaultValue: null,
+          description: gcli.lookup("cookieSetDomainDesc")
+        },
+        {
+          name: "secure",
+          type: "boolean",
+          description: gcli.lookup("cookieSetSecureDesc")
+        }
+      ]
+    }
+  ],
+  exec: function Command_cookieSet(args, context) {
+    let document = context.environment.contentDocument;
+
+    document.cookie = escape(args.key) + "=" + escape(args.value) +
+            (args.domain ? "; domain=" + args.domain : "") +
+            (args.path ? "; path=" + args.path : "") +
+            (args.secure ? "; secure" : ""); 
+  }
+});
+
+/**
+ * Helper to find the 'data-command' attribute and call some action on it.
+ * @see |updateCommand()| and |executeCommand()|
+ */
+function withCommand(element, action) {
+  var command = element.getAttribute("data-command");
+  if (!command) {
+    command = element.querySelector("*[data-command]")
+            .getAttribute("data-command");
+  }
+
+  if (command) {
+    action(command);
+  }
+  else {
+    console.warn("Missing data-command for " + util.findCssSelector(element));
+  }
+}
+
+/**
+ * Create a handler to update the requisition to contain the text held in the
+ * first matching data-command attribute under the currentTarget of the event.
+ * @param context Either a Requisition or an ExecutionContext or another object
+ * that contains an |update()| function that follows a similar contract.
+ */
+function createUpdateHandler(context) {
+  return function(ev) {
+    withCommand(ev.currentTarget, function(command) {
+      context.update(command);
+    });
+  }
+}
+
+/**
+ * Create a handler to execute the text held in the data-command attribute
+ * under the currentTarget of the event.
+ * @param context Either a Requisition or an ExecutionContext or another object
+ * that contains an |update()| function that follows a similar contract.
+ */
+function createExecuteHandler(context) {
+  return function(ev) {
+    withCommand(ev.currentTarget, function(command) {
+      context.exec({
+        visible: true,
+        typed: command
+      });
+    });
+  }
+}
--- a/browser/devtools/commandline/gcli.jsm
+++ b/browser/devtools/commandline/gcli.jsm
@@ -5287,24 +5287,24 @@ CommandAssignment.prototype.getStatus = 
 };
 
 exports.CommandAssignment = CommandAssignment;
 
 
 /**
  * Special assignment used when ignoring parameters that don't have a home
  */
-function UnassignedAssignment(requisition, arg, isIncompleteName) {
+function UnassignedAssignment(requisition, arg) {
   this.param = new canon.Parameter({
     name: '__unassigned',
     description: l10n.lookup('cliOptions'),
     type: {
       name: 'param',
       requisition: requisition,
-      isIncompleteName: isIncompleteName
+      isIncompleteName: (arg.text.charAt(0) === '-')
     },
   });
   this.paramIndex = -1;
   this.onAssignmentChange = util.createEvent('UnassignedAssignment.onAssignmentChange');
 
   this.conversion = this.param.type.parse(arg);
   this.conversion.assign(this);
 }
@@ -5533,18 +5533,25 @@ Requisition.prototype.cloneAssignments =
  * There is no such thing as an INCOMPLETE overall status because the
  * definition of INCOMPLETE takes into account the cursor position to say 'this
  * isn't quite ERROR because the user can fix it by typing', however overall,
  * this is still an error status.
  */
 Requisition.prototype.getStatus = function() {
   var status = Status.VALID;
   if (this._unassigned.length !== 0) {
-    return Status.ERROR;
-  }
+    var isAllIncomplete = true;
+    this._unassigned.forEach(function(assignment) {
+      if (!assignment.param.type.isIncompleteName) {
+        isAllIncomplete = false;
+      }
+    });
+    status = isAllIncomplete ? Status.INCOMPLETE : Status.ERROR;
+  }
+
   this.getAssignments(true).forEach(function(assignment) {
     var assignStatus = assignment.getStatus();
     if (assignStatus > status) {
       status = assignStatus;
     }
   }, this);
   if (status === Status.INCOMPLETE) {
     status = Status.ERROR;
@@ -6353,17 +6360,17 @@ Requisition.prototype._split = function(
   // This could probably be re-written to consume args as we go
 };
 
 /**
  * Add all the passed args to the list of unassigned assignments.
  */
 Requisition.prototype._addUnassignedArgs = function(args) {
   args.forEach(function(arg) {
-    this._unassigned.push(new UnassignedAssignment(this, arg, false));
+    this._unassigned.push(new UnassignedAssignment(this, arg));
   }.bind(this));
 };
 
 /**
  * Work out which arguments are applicable to which parameters.
  */
 Requisition.prototype._assign = function(args) {
   this._unassigned = [];
@@ -6396,30 +6403,30 @@ Requisition.prototype._assign = function
       var conversion = assignment.param.type.parse(arg);
       assignment.setConversion(conversion);
       return;
     }
   }
 
   // Positional arguments can still be specified by name, but if they are
   // then we need to ignore them when working them out positionally
-  var names = this.getParameterNames();
+  var unassignedParams = this.getParameterNames();
 
   // We collect the arguments used in arrays here before assigning
   var arrayArgs = {};
 
   // Extract all the named parameters
   this.getAssignments(false).forEach(function(assignment) {
     // Loop over the arguments
     // Using while rather than loop because we remove args as we go
     var i = 0;
     while (i < args.length) {
       if (assignment.param.isKnownAs(args[i].text)) {
         var arg = args.splice(i, 1)[0];
-        names = names.filter(function(test) {
+        unassignedParams = unassignedParams.filter(function(test) {
           return test !== assignment.param.name;
         });
 
         // boolean parameters don't have values, default to false
         if (assignment.param.type instanceof BooleanType) {
           arg = new TrueNamedArgument(null, arg);
         }
         else {
@@ -6446,17 +6453,17 @@ Requisition.prototype._assign = function
       else {
         // Skip this parameter and handle as a positional parameter
         i++;
       }
     }
   }, this);
 
   // What's left are positional parameters assign in order
-  names.forEach(function(name) {
+  unassignedParams.forEach(function(name) {
     var assignment = this.getAssignment(name);
 
     // If not set positionally, and we can't set it non-positionally,
     // we have to default it to prevent previous values surviving
     if (!assignment.param.isPositionalAllowed) {
       assignment.setBlank();
       return;
     }
@@ -6480,17 +6487,17 @@ Requisition.prototype._assign = function
         var arg = args.splice(0, 1)[0];
         // --foo and -f are named parameters, -4 is a number. So '-' is either
         // the start of a named parameter or a number depending on the context
         var isIncompleteName = assignment.param.type instanceof NumberType ?
             /-[-a-zA-Z_]/.test(arg.text) :
             arg.text.charAt(0) === '-';
 
         if (isIncompleteName) {
-          this._unassigned.push(new UnassignedAssignment(this, arg, true));
+          this._unassigned.push(new UnassignedAssignment(this, arg));
         }
         else {
           var conversion = assignment.param.type.parse(arg);
           assignment.setConversion(conversion);
         }
       }
     }
   }, this);
@@ -7038,16 +7045,20 @@ FocusManager.prototype._checkShow = func
   }
 };
 
 /**
  * Calculate if we should be showing or hidden taking into account all the
  * available inputs
  */
 FocusManager.prototype._shouldShowTooltip = function() {
+  if (!this._hasFocus) {
+    return { visible: false, reason: '!hasFocus' };
+  }
+
   if (eagerHelper.value === Eagerness.NEVER) {
     return { visible: false, reason: 'eagerHelper !== NEVER' };
   }
 
   if (eagerHelper.value === Eagerness.ALWAYS) {
     return { visible: true, reason: 'eagerHelper !== ALWAYS' };
   }
 
@@ -7066,16 +7077,20 @@ FocusManager.prototype._shouldShowToolti
   return { visible: false, reason: 'default' };
 };
 
 /**
  * Calculate if we should be showing or hidden taking into account all the
  * available inputs
  */
 FocusManager.prototype._shouldShowOutput = function() {
+  if (!this._hasFocus) {
+    return { visible: false, reason: '!hasFocus' };
+  }
+
   if (this._recentOutput) {
     return { visible: true, reason: 'recentOutput' };
   }
 
   return { visible: false, reason: 'default' };
 };
 
 exports.FocusManager = FocusManager;
@@ -9722,17 +9737,17 @@ Completer.prototype.update = function(ev
  */
 Completer.prototype._getCompleterTemplateData = function() {
   var input = this.inputter.getInputState();
 
   // directTabText is for when the current input is a prefix of the completion
   // arrowTabText is for when we need to use an -> to show what will be used
   var directTabText = '';
   var arrowTabText = '';
-  var current = this.inputter.assignment;
+  var current = this.requisition.getAssignmentAt(input.cursor.start);
 
   if (input.typed.trim().length !== 0) {
     var prediction = current.conversion.getPredictionAt(this.choice);
     if (prediction) {
       var tabText = prediction.name;
       var existing = current.arg.text;
 
       if (existing !== tabText) {
--- a/browser/devtools/commandline/test/Makefile.in
+++ b/browser/devtools/commandline/test/Makefile.in
@@ -7,29 +7,35 @@ DEPTH     = ../../../..
 topsrcdir = @top_srcdir@
 srcdir    = @srcdir@
 VPATH     = @srcdir@
 relativesrcdir  = browser/devtools/commandline/test
 
 include $(DEPTH)/config/autoconf.mk
 
 MOCHITEST_BROWSER_FILES = \
+  browser_gcli_addon.js \
   browser_gcli_break.js \
   browser_gcli_commands.js \
+  browser_gcli_cookie.js \
   browser_gcli_edit.js \
   browser_gcli_inspect.js \
   browser_gcli_integrate.js \
+  browser_gcli_pagemod_export.js \
   browser_gcli_pref.js \
+  browser_gcli_responsivemode.js \
+  browser_gcli_restart.js \
   browser_gcli_settings.js \
   browser_gcli_web.js \
   head.js \
   $(NULL)
 
 MOCHITEST_BROWSER_FILES += \
   browser_gcli_break.html \
   browser_gcli_inspect.html \
   resources_inpage.js \
   resources_inpage1.css \
   resources_inpage2.css \
   resources.html \
   $(NULL)
 
 include $(topsrcdir)/config/rules.mk
+
new file mode 100644
--- /dev/null
+++ b/browser/devtools/commandline/test/browser_gcli_addon.js
@@ -0,0 +1,43 @@
+function test() {
+  DeveloperToolbarTest.test("about:blank", function GAT_test() {
+    function GAT_ready() {
+      Services.obs.removeObserver(GAT_ready, "gcli_addon_commands_ready", false);
+
+      DeveloperToolbarTest.checkInputStatus({
+        typed: "addon list dictionary",
+        status: "VALID"
+      });
+      DeveloperToolbarTest.checkInputStatus({
+        typed: "addon list extension",
+        status: "VALID"
+      });
+      DeveloperToolbarTest.checkInputStatus({
+        typed: "addon list locale",
+        status: "VALID"
+      });
+      DeveloperToolbarTest.checkInputStatus({
+        typed: "addon list plugin",
+        status: "VALID"
+      });
+      DeveloperToolbarTest.checkInputStatus({
+        typed: "addon list theme",
+        status: "VALID"
+      });
+      DeveloperToolbarTest.checkInputStatus({
+        typed: "addon list all",
+        status: "VALID"
+      });
+      DeveloperToolbarTest.checkInputStatus({
+        typed: "addon disable Test_Plug-in_1.0.0.0",
+        status: "VALID"
+      });
+      DeveloperToolbarTest.checkInputStatus({
+        typed: "addon enable Test_Plug-in_1.0.0.0",
+        status: "VALID"
+      });
+      DeveloperToolbarTest.exec({ completed: false });
+      finish();
+    }
+    Services.obs.addObserver(GAT_ready, "gcli_addon_commands_ready", false);
+  });
+}
--- a/browser/devtools/commandline/test/browser_gcli_commands.js
+++ b/browser/devtools/commandline/test/browser_gcli_commands.js
@@ -6,50 +6,59 @@
 let imported = {};
 Components.utils.import("resource:///modules/HUDService.jsm", imported);
 
 const TEST_URI = "data:text/html;charset=utf-8,gcli-commands";
 
 function test() {
   DeveloperToolbarTest.test(TEST_URI, function(browser, tab) {
     testEcho();
-    testConsoleClear();
-    testConsoleOpenClose(tab);
+    testConsole(tab);
 
     imported = undefined;
     finish();
   });
 }
 
 function testEcho() {
   DeveloperToolbarTest.exec({
     typed: "echo message",
     args: { message: "message" },
     outputMatch: /^message$/,
   });
 }
 
-function testConsoleClear() {
-  DeveloperToolbarTest.exec({
-    typed: "console clear",
-    args: {},
-    blankOutput: true,
-  });
-}
-
-function testConsoleOpenClose(tab) {
+function testConsole(tab) {
   DeveloperToolbarTest.exec({
     typed: "console open",
     args: {},
     blankOutput: true,
   });
 
   let hud = imported.HUDService.getHudByWindow(content);
   ok(hud.hudId in imported.HUDService.hudReferences, "console open");
 
+  hud.jsterm.execute("pprint(window)");
+
+  /*
+  // The web console is async and we can't force it with hud._flushMessageQueue
+  // So we are skipping the test for output until we have an event to wait on
+  let labels = hud.jsterm.outputNode.querySelectorAll(".webconsole-msg-output");
+  ok(labels.length > 0, "output for pprint(window)");
+  */
+
+  DeveloperToolbarTest.exec({
+    typed: "console clear",
+    args: {},
+    blankOutput: true,
+  });
+
+  let labels = hud.jsterm.outputNode.querySelectorAll(".webconsole-msg-output");
+  is(labels.length, 0, "no output in console");
+
   DeveloperToolbarTest.exec({
     typed: "console close",
     args: {},
     blankOutput: true,
   });
 
   ok(!(hud.hudId in imported.HUDService.hudReferences), "console closed");
 }
new file mode 100644
--- /dev/null
+++ b/browser/devtools/commandline/test/browser_gcli_cookie.js
@@ -0,0 +1,68 @@
+/* Any copyright is dedicated to the Public Domain.
+* http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that the cookie commands works as they should
+
+const TEST_URI = "data:text/html;charset=utf-8,gcli-cookie";
+
+function test() {
+  DeveloperToolbarTest.test(TEST_URI, function(browser, tab) {
+    testCookieCommands();
+    finish();
+  });
+}
+
+function testCookieCommands() {
+  DeveloperToolbarTest.checkInputStatus({
+    typed: "cook",
+    directTabText: "ie",
+    status: "ERROR"
+  });
+
+  DeveloperToolbarTest.checkInputStatus({
+    typed: "cookie l",
+    directTabText: "ist",
+    status: "ERROR"
+  });
+
+  DeveloperToolbarTest.checkInputStatus({
+    typed: "cookie list",
+    status: "VALID",
+    emptyParameters: [ ]
+  });
+
+  DeveloperToolbarTest.checkInputStatus({
+    typed: "cookie remove",
+    status: "ERROR",
+    emptyParameters: [ " <key>" ]
+  });
+
+  DeveloperToolbarTest.checkInputStatus({
+    typed: "cookie set",
+    status: "ERROR",
+    emptyParameters: [ " <key>", " <value>" ],
+  });
+
+  DeveloperToolbarTest.exec({
+    typed: "cookie set fruit banana",
+    args: {
+      key: "fruit",
+      value: "banana",
+      path: "/",
+      domain: null,
+      secure: false
+    },
+    blankOutput: true,
+  });
+
+  DeveloperToolbarTest.exec({
+    typed: "cookie list",
+    outputMatch: /Key/
+  });
+
+  DeveloperToolbarTest.exec({
+    typed: "cookie remove fruit",
+    args: { key: "fruit" },
+    blankOutput: true,
+  });
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/commandline/test/browser_gcli_pagemod_export.js
@@ -0,0 +1,272 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that the inspect command works as it should
+
+const TEST_URI = "http://example.com/browser/browser/devtools/commandline/test/browser_gcli_inspect.html";
+
+function test() {
+  let initialHtml = "";
+
+  DeveloperToolbarTest.test(TEST_URI, function(browser, tab) {
+    initialHtml = content.document.documentElement.innerHTML;
+
+    testExportHtml();
+    testPageModReplace();
+    testPageModRemoveElement();
+    testPageModRemoveAttribute();
+    finish();
+  });
+
+  function testExportHtml() {
+    DeveloperToolbarTest.checkInputStatus({
+      typed: "export html",
+      status: "VALID"
+    });
+
+    let oldOpen = content.open;
+    let openURL = "";
+    content.open = function(aUrl) {
+      openURL = aUrl;
+    };
+
+    DeveloperToolbarTest.exec({ blankOutput: true });
+
+    openURL = decodeURIComponent(openURL);
+
+    isnot(openURL.indexOf('<html lang="en">'), -1, "export html works: <html>");
+    isnot(openURL.indexOf("<title>GCLI"), -1, "export html works: <title>");
+    isnot(openURL.indexOf('<p id="someid">#'), -1, "export html works: <p>");
+
+    content.open = oldOpen;
+  }
+
+  function getContent() {
+    return content.document.documentElement.innerHTML;
+  }
+
+  function resetContent() {
+    content.document.documentElement.innerHTML = initialHtml;
+  }
+
+  function testPageModReplace() {
+    DeveloperToolbarTest.checkInputStatus({
+      typed: "pagemod replace",
+      emptyParameters: [" <search>", " <replace>", " [ignoreCase]",
+                        " [selector]", " [root]", " [attrOnly]",
+                        " [contentOnly]", " [attributes]"],
+      status: "ERROR"
+    });
+
+    DeveloperToolbarTest.checkInputStatus({
+      typed: "pagemod replace some foo",
+      emptyParameters: [" [ignoreCase]", " [selector]", " [root]",
+                        " [attrOnly]", " [contentOnly]", " [attributes]"],
+      status: "VALID"
+    });
+
+    DeveloperToolbarTest.checkInputStatus({
+      typed: "pagemod replace some foo true",
+      emptyParameters: [" [selector]", " [root]", " [attrOnly]",
+                        " [contentOnly]", " [attributes]"],
+      status: "VALID"
+    });
+
+    DeveloperToolbarTest.checkInputStatus({
+      typed: "pagemod replace some foo true --attrOnly",
+      emptyParameters: [" [selector]", " [root]", " [contentOnly]",
+                        " [attributes]"],
+      status: "VALID"
+    });
+
+    DeveloperToolbarTest.exec({
+      typed: "pagemod replace sOme foOBar",
+      outputMatch: /^[^:]+: 13\. [^:]+: 0\. [^:]+: 0\.\s*$/
+    });
+
+    is(getContent(), initialHtml, "no change in the page");
+
+    DeveloperToolbarTest.exec({
+      typed: "pagemod replace sOme foOBar true",
+      outputMatch: /^[^:]+: 13\. [^:]+: 2\. [^:]+: 2\.\s*$/
+    });
+
+    isnot(getContent().indexOf('<p class="foOBarclass">.foOBarclass'), -1,
+          ".someclass changed to .foOBarclass");
+    isnot(getContent().indexOf('<p id="foOBarid">#foOBarid'), -1,
+          "#someid changed to #foOBarid");
+
+    resetContent();
+
+    DeveloperToolbarTest.exec({
+      typed: "pagemod replace some foobar --contentOnly",
+      outputMatch: /^[^:]+: 13\. [^:]+: 2\. [^:]+: 0\.\s*$/
+    });
+
+    isnot(getContent().indexOf('<p class="someclass">.foobarclass'), -1,
+          ".someclass changed to .foobarclass (content only)");
+    isnot(getContent().indexOf('<p id="someid">#foobarid'), -1,
+          "#someid changed to #foobarid (content only)");
+
+    resetContent();
+
+    DeveloperToolbarTest.exec({
+      typed: "pagemod replace some foobar --attrOnly",
+      outputMatch: /^[^:]+: 13\. [^:]+: 0\. [^:]+: 2\.\s*$/
+    });
+
+    isnot(getContent().indexOf('<p class="foobarclass">.someclass'), -1,
+          ".someclass changed to .foobarclass (attr only)");
+    isnot(getContent().indexOf('<p id="foobarid">#someid'), -1,
+          "#someid changed to #foobarid (attr only)");
+
+    resetContent();
+
+    DeveloperToolbarTest.exec({
+      typed: "pagemod replace some foobar --root head",
+      outputMatch: /^[^:]+: 2\. [^:]+: 0\. [^:]+: 0\.\s*$/
+    });
+
+    is(getContent(), initialHtml, "nothing changed");
+
+    DeveloperToolbarTest.exec({
+      typed: "pagemod replace some foobar --selector .someclass,div,span",
+      outputMatch: /^[^:]+: 4\. [^:]+: 1\. [^:]+: 1\.\s*$/
+    });
+
+    isnot(getContent().indexOf('<p class="foobarclass">.foobarclass'), -1,
+          ".someclass changed to .foobarclass");
+    isnot(getContent().indexOf('<p id="someid">#someid'), -1,
+          "#someid did not change");
+
+    resetContent();
+  }
+
+  function testPageModRemoveElement() {
+    DeveloperToolbarTest.checkInputStatus({
+      typed: "pagemod remove",
+      status: "ERROR"
+    });
+
+    DeveloperToolbarTest.checkInputStatus({
+      typed: "pagemod remove element",
+      emptyParameters: [" <search>", " [root]", " [stripOnly]", " [ifEmptyOnly]"],
+      status: "ERROR"
+    });
+
+    DeveloperToolbarTest.checkInputStatus({
+      typed: "pagemod remove element foo",
+      emptyParameters: [" [root]", " [stripOnly]", " [ifEmptyOnly]"],
+      status: "VALID"
+    });
+
+    DeveloperToolbarTest.exec({
+      typed: "pagemod remove element p",
+      outputMatch: /^[^:]+: 3\. [^:]+: 3\.\s*$/
+    });
+
+    is(getContent().indexOf('<p class="someclass">'), -1, "p.someclass removed");
+    is(getContent().indexOf('<p id="someid">'), -1, "p#someid removed");
+    is(getContent().indexOf("<p><strong>"), -1, "<p> wrapping <strong> removed");
+    isnot(getContent().indexOf("<span>"), -1, "<span> not removed");
+
+    resetContent();
+
+    DeveloperToolbarTest.exec({
+      typed: "pagemod remove element p head",
+      outputMatch: /^[^:]+: 0\. [^:]+: 0\.\s*$/
+    });
+
+    is(getContent(), initialHtml, "nothing changed in the page");
+
+    DeveloperToolbarTest.exec({
+      typed: "pagemod remove element p --ifEmptyOnly",
+      outputMatch: /^[^:]+: 3\. [^:]+: 0\.\s*$/
+    });
+
+    is(getContent(), initialHtml, "nothing changed in the page");
+
+    DeveloperToolbarTest.exec({
+      typed: "pagemod remove element meta,title --ifEmptyOnly",
+      outputMatch: /^[^:]+: 2\. [^:]+: 1\.\s*$/
+    });
+
+    is(getContent().indexOf("<meta charset="), -1, "<meta> removed");
+    isnot(getContent().indexOf("<title>"), -1, "<title> not removed");
+
+    resetContent();
+
+    DeveloperToolbarTest.exec({
+      typed: "pagemod remove element p --stripOnly",
+      outputMatch: /^[^:]+: 3\. [^:]+: 3\.\s*$/
+    });
+
+    is(getContent().indexOf('<p class="someclass">'), -1, "p.someclass removed");
+    is(getContent().indexOf('<p id="someid">'), -1, "p#someid removed");
+    is(getContent().indexOf("<p><strong>"), -1, "<p> wrapping <strong> removed");
+    isnot(getContent().indexOf(".someclass"), -1, ".someclass still exists");
+    isnot(getContent().indexOf("#someid"), -1, "#someid still exists");
+    isnot(getContent().indexOf("<strong>p"), -1, "<strong> still exists");
+
+    resetContent();
+  }
+
+  function testPageModRemoveAttribute() {
+    DeveloperToolbarTest.checkInputStatus({
+      typed: "pagemod remove attribute",
+      emptyParameters: [" <searchAttributes>", " <searchElements>", " [root]", " [ignoreCase]"],
+      status: "ERROR"
+    });
+
+    DeveloperToolbarTest.checkInputStatus({
+      typed: "pagemod remove attribute foo bar",
+      emptyParameters: [" [root]", " [ignoreCase]"],
+      status: "VALID"
+    });
+
+    DeveloperToolbarTest.exec({
+      typed: "pagemod remove attribute foo bar",
+      outputMatch: /^[^:]+: 0\. [^:]+: 0\.\s*$/
+    });
+
+    is(getContent(), initialHtml, "nothing changed in the page");
+
+    DeveloperToolbarTest.exec({
+      typed: "pagemod remove attribute foo p",
+      outputMatch: /^[^:]+: 3\. [^:]+: 0\.\s*$/
+    });
+
+    is(getContent(), initialHtml, "nothing changed in the page");
+
+    DeveloperToolbarTest.exec({
+      typed: "pagemod remove attribute id p,span",
+      outputMatch: /^[^:]+: 5\. [^:]+: 1\.\s*$/
+    });
+
+    is(getContent().indexOf('<p id="someid">#someid'), -1,
+       "p#someid attribute removed");
+    isnot(getContent().indexOf("<p>#someid"), -1,
+       "p with someid content still exists");
+
+    resetContent();
+
+    DeveloperToolbarTest.exec({
+      typed: "pagemod remove attribute Class p",
+      outputMatch: /^[^:]+: 3\. [^:]+: 0\.\s*$/
+    });
+
+    is(getContent(), initialHtml, "nothing changed in the page");
+
+    DeveloperToolbarTest.exec({
+      typed: "pagemod remove attribute Class p --ignoreCase",
+      outputMatch: /^[^:]+: 3\. [^:]+: 1\.\s*$/
+    });
+
+    is(getContent().indexOf('<p class="someclass">.someclass'), -1,
+       "p.someclass attribute removed");
+    isnot(getContent().indexOf("<p>.someclass"), -1,
+       "p with someclass content still exists");
+
+    resetContent();
+  }
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/commandline/test/browser_gcli_responsivemode.js
@@ -0,0 +1,58 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function test() {
+  DeveloperToolbarTest.test("about:blank", function GAT_test() {
+    DeveloperToolbarTest.checkInputStatus({
+      typed: "resize toggle",
+      status: "VALID"
+    });
+    DeveloperToolbarTest.exec();
+    ok(isOpen(), "responsive mode is open");
+
+    DeveloperToolbarTest.checkInputStatus({
+      typed: "resize toggle",
+      status: "VALID"
+    });
+    DeveloperToolbarTest.exec();
+    ok(isClosed(), "responsive mode is closed");
+
+    DeveloperToolbarTest.checkInputStatus({
+      typed: "resize on",
+      status: "VALID"
+    });
+    DeveloperToolbarTest.exec();
+    ok(isOpen(), "responsive mode is open");
+
+    DeveloperToolbarTest.checkInputStatus({
+      typed: "resize off",
+      status: "VALID"
+    });
+    DeveloperToolbarTest.exec();
+    ok(isClosed(), "responsive mode is closed");
+
+    DeveloperToolbarTest.checkInputStatus({
+      typed: "resize to 400 400",
+      status: "VALID"
+    });
+    DeveloperToolbarTest.exec();
+    ok(isOpen(), "responsive mode is open");
+
+    DeveloperToolbarTest.checkInputStatus({
+      typed: "resize off",
+      status: "VALID"
+    });
+    DeveloperToolbarTest.exec();
+    ok(isClosed(), "responsive mode is closed");
+
+    executeSoon(finish);
+  });
+
+  function isOpen() {
+    return !!gBrowser.selectedTab.__responsiveUI;
+  }
+
+  function isClosed() {
+    return !isOpen();
+  }
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/commandline/test/browser_gcli_restart.js
@@ -0,0 +1,48 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that restart command works properly (input wise)
+
+const TEST_URI = "data:text/html;charset=utf-8,gcli-command-restart";
+
+function test() {
+  DeveloperToolbarTest.test(TEST_URI, function(browser, tab) {
+    testRestart();
+    finish();
+  });
+}
+
+function testRestart() {
+  DeveloperToolbarTest.checkInputStatus({
+    typed:  "restart",
+    markup: "VVVVVVV",
+    status: "VALID",
+    emptyParameters: [ " [nocache]" ],
+  });
+
+  DeveloperToolbarTest.checkInputStatus({
+    typed:  "restart ",
+    markup: "VVVVVVVV",
+    status: "VALID",
+    directTabText: "false"
+  });
+
+  DeveloperToolbarTest.checkInputStatus({
+    typed:  "restart t",
+    markup: "VVVVVVVVI",
+    status: "ERROR",
+    directTabText: "rue"
+  });
+
+  DeveloperToolbarTest.checkInputStatus({
+    typed:  "restart --nocache",
+    markup: "VVVVVVVVVVVVVVVVV",
+    status: "VALID"
+  });
+
+  DeveloperToolbarTest.checkInputStatus({
+    typed:  "restart --noca",
+    markup: "VVVVVVVVEEEEEE",
+    status: "ERROR",
+  });
+}
--- a/browser/devtools/commandline/test/browser_gcli_web.js
+++ b/browser/devtools/commandline/test/browser_gcli_web.js
@@ -1058,54 +1058,54 @@ exports.check = function(checks) {
       if (paramName === 'command') {
         assignment = requisition.commandAssignment;
       }
       else {
         assignment = requisition.getAssignment(paramName);
       }
 
       if (assignment == null) {
-        test.ok(false, 'Unknown parameter: ' + paramName);
+        test.ok(false, 'Unknown arg: ' + paramName);
         return;
       }
 
       if (check.value) {
         test.is(assignment.value,
                 check.value,
-                'checkStatus value for ' + paramName);
+                'arg[\'' + paramName + '\'].value');
       }
 
       if (check.name) {
         test.is(assignment.value.name,
                 check.name,
-                'checkStatus name for ' + paramName);
+                'arg[\'' + paramName + '\'].name');
       }
 
       if (check.type) {
         test.is(assignment.arg.type,
                 check.type,
-                'checkStatus type for ' + paramName);
+                'arg[\'' + paramName + '\'].type');
       }
 
       if (check.arg) {
         test.is(assignment.arg.toString(),
                 check.arg,
-                'checkStatus arg for ' + paramName);
+                'arg[\'' + paramName + '\'].arg');
       }
 
       if (check.status) {
         test.is(assignment.getStatus().toString(),
                 check.status,
-                'checkStatus status for ' + paramName);
+                'arg[\'' + paramName + '\'].status');
       }
 
       if (check.message) {
         test.is(assignment.getMessage(),
                 check.message,
-                'checkStatus message for ' + paramName);
+                'arg[\'' + paramName + '\'].message');
       }
     });
   }
 };
 
 /**
  * Execute a command:
  *
@@ -1728,16 +1728,17 @@ exports.setup = function() {
   canon.addCommand(exports.tsnExtend);
   canon.addCommand(exports.tsnDeep);
   canon.addCommand(exports.tsnDeepDown);
   canon.addCommand(exports.tsnDeepDownNested);
   canon.addCommand(exports.tsnDeepDownNestedCmd);
   canon.addCommand(exports.tselarr);
   canon.addCommand(exports.tsm);
   canon.addCommand(exports.tsg);
+  canon.addCommand(exports.tscook);
 };
 
 exports.shutdown = function() {
   canon.removeCommand(exports.tsv);
   canon.removeCommand(exports.tsr);
   canon.removeCommand(exports.tse);
   canon.removeCommand(exports.tsj);
   canon.removeCommand(exports.tsb);
@@ -1751,16 +1752,17 @@ exports.shutdown = function() {
   canon.removeCommand(exports.tsnExtend);
   canon.removeCommand(exports.tsnDeep);
   canon.removeCommand(exports.tsnDeepDown);
   canon.removeCommand(exports.tsnDeepDownNested);
   canon.removeCommand(exports.tsnDeepDownNestedCmd);
   canon.removeCommand(exports.tselarr);
   canon.removeCommand(exports.tsm);
   canon.removeCommand(exports.tsg);
+  canon.removeCommand(exports.tscook);
 
   types.deregisterType(exports.optionType);
   types.deregisterType(exports.optionValue);
 };
 
 
 exports.option1 = { type: types.getType('string') };
 exports.option2 = { type: types.getType('number') };
@@ -1970,16 +1972,56 @@ exports.tsg = {
           description: 'num param'
         }
       ]
     }
   ],
   exec: createExec('tsg')
 };
 
+exports.tscook = {
+  name: 'tscook',
+  description: 'param group test to catch problems with cookie command',
+  params: [
+    {
+      name: 'key',
+      type: 'string',
+      description: 'tscookKeyDesc'
+    },
+    {
+      name: 'value',
+      type: 'string',
+      description: 'tscookValueDesc'
+    },
+    {
+      group: 'tscookOptionsDesc',
+      params: [
+        {
+          name: 'path',
+          type: 'string',
+          defaultValue: '/',
+          description: 'tscookPathDesc'
+        },
+        {
+          name: 'domain',
+          type: 'string',
+          defaultValue: null,
+          description: 'tscookDomainDesc'
+        },
+        {
+          name: 'secure',
+          type: 'boolean',
+          description: 'tscookSecureDesc'
+        }
+      ]
+    }
+  ],
+  exec: createExec('tscook')
+};
+
 
 });
 /*
  * Copyright 2012, Mozilla Foundation and contributors
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
@@ -2880,16 +2922,50 @@ exports.testCompleted = function(options
       solo: { value: undefined, status: 'INCOMPLETE' },
       txt1: { value: 'fred', status: 'VALID' },
       bool: { value: undefined, status: 'VALID' },
       txt2: { value: undefined, status: 'VALID' },
       num: { value: undefined, status: 'VALID' }
     }
   });
 
+  helpers.setInput('tscook key value --path path --');
+  helpers.check({
+    input:  'tscook key value --path path --',
+    markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVII',
+    directTabText: 'domain',
+    arrowTabText: '',
+    status: 'ERROR',
+    emptyParameters: [ ],
+    args: {
+      key: { value: 'key', status: 'VALID' },
+      value: { value: 'value', status: 'VALID' },
+      path: { value: 'path', status: 'VALID' },
+      domain: { value: undefined, status: 'VALID' },
+      secure: { value: false, status: 'VALID' }
+    }
+  });
+
+  helpers.setInput('tscook key value --path path --domain domain --');
+  helpers.check({
+    input:  'tscook key value --path path --domain domain --',
+    markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVII',
+    directTabText: 'secure',
+    arrowTabText: '',
+    status: 'ERROR',
+    emptyParameters: [ ],
+    args: {
+      key: { value: 'key', status: 'VALID' },
+      value: { value: 'value', status: 'VALID' },
+      path: { value: 'path', status: 'VALID' },
+      domain: { value: 'domain', status: 'VALID' },
+      secure: { value: false, status: 'VALID' }
+    }
+  });
+
   // Expand out to christmas tree command line
 };
 
 exports.testIncomplete = function(options) {
   var requisition = options.display.requisition;
 
   helpers.setInput('tsm a a -');
   helpers.check({
--- a/browser/devtools/responsivedesign/responsivedesign.jsm
+++ b/browser/devtools/responsivedesign/responsivedesign.jsm
@@ -29,16 +29,48 @@ let ResponsiveUIManager = {
    */
   toggle: function(aWindow, aTab) {
     if (aTab.__responsiveUI) {
       aTab.__responsiveUI.close();
     } else {
       aTab.__responsiveUI = new ResponsiveUI(aWindow, aTab);
     }
   },
+
+  /**
+   * Handle gcli commands.
+   *
+   * @param aWindow the browser window.
+   * @param aTab the tab targeted.
+   * @param aCommand the command name.
+   * @param aArgs command arguments.
+   */
+  handleGcliCommand: function(aWindow, aTab, aCommand, aArgs) {
+    switch (aCommand) {
+      case "resize to":
+        if (!aTab.__responsiveUI) {
+          aTab.__responsiveUI = new ResponsiveUI(aWindow, aTab);
+        }
+        aTab.__responsiveUI.setSize(aArgs.width, aArgs.height);
+        break;
+      case "resize on":
+        if (!aTab.__responsiveUI) {
+          aTab.__responsiveUI = new ResponsiveUI(aWindow, aTab);
+        }
+        break;
+      case "resize off":
+        if (aTab.__responsiveUI) {
+          aTab.__responsiveUI.close();
+        }
+        break;
+      case "resize toggle":
+          this.toggle(aWindow, aTab);
+      default:
+    }
+  },
 }
 
 let presets = [
   // Phones
   {key: "320x480", width: 320, height: 480},    // iPhone, B2G, with <meta viewport>
   {key: "360x640", width: 360, height: 640},    // Android 4, phones, with <meta viewport>
 
   // Tablets
@@ -371,18 +403,18 @@ ResponsiveUI.prototype = {
 
   /**
    * Change the size of the browser.
    *
    * @param aWidth width of the browser.
    * @param aHeight height of the browser.
    */
   setSize: function RUI_setSize(aWidth, aHeight) {
-    this.currentWidth = aWidth;
-    this.currentHeight = aHeight;
+    this.currentWidth = Math.min(Math.max(aWidth, MIN_WIDTH), MAX_WIDTH);
+    this.currentHeight = Math.min(Math.max(aHeight, MIN_HEIGHT), MAX_WIDTH);
 
     // We resize the containing stack.
     let style = "max-width: %width;" +
                 "min-width: %width;" +
                 "max-height: %height;" +
                 "min-height: %height;";
 
     style = style.replace(/%width/g, this.currentWidth + "px");
--- a/browser/devtools/shared/DeveloperToolbar.jsm
+++ b/browser/devtools/shared/DeveloperToolbar.jsm
@@ -106,16 +106,29 @@ DeveloperToolbar.prototype.toggle = func
   if (this.visible) {
     this.hide();
   } else {
     this.show(true);
   }
 };
 
 /**
+ * Called from browser.xul in response to menu-click or keyboard shortcut to
+ * toggle the toolbar
+ */
+DeveloperToolbar.prototype.focus = function DT_focus()
+{
+  if (this.visible) {
+    this._input.focus();
+  } else {
+    this.show(true);
+  }
+};
+
+/**
  * Even if the user has not clicked on 'Got it' in the intro, we only show it
  * once per session.
  * Warning this is slightly messed up because this.DeveloperToolbar is not the
  * same as this.DeveloperToolbar when in browser.js context.
  */
 DeveloperToolbar.introShownThisSession = false;
 
 /**
--- a/browser/devtools/styleeditor/StyleEditor.jsm
+++ b/browser/devtools/styleeditor/StyleEditor.jsm
@@ -31,20 +31,20 @@ const UPDATE_STYLESHEET_THROTTLE_DELAY =
 const STYLESHEET_EXPANDO = "-moz-styleeditor-stylesheet-";
 
 const TRANSITIONS_PREF = "devtools.styleeditor.transitions";
 
 const TRANSITION_CLASS = "moz-styleeditor-transitioning";
 const TRANSITION_DURATION_MS = 500;
 const TRANSITION_RULE = "\
 :root.moz-styleeditor-transitioning, :root.moz-styleeditor-transitioning * {\
--moz-transition-duration: " + TRANSITION_DURATION_MS + "ms !important; \
--moz-transition-delay: 0ms !important;\
--moz-transition-timing-function: ease-out !important;\
--moz-transition-property: all !important;\
+transition-duration: " + TRANSITION_DURATION_MS + "ms !important; \
+transition-delay: 0ms !important;\
+transition-timing-function: ease-out !important;\
+transition-property: all !important;\
 }";
 
 /**
  * Style Editor module-global preferences
  */
 const TRANSITIONS_ENABLED = Services.prefs.getBoolPref(TRANSITIONS_PREF);
 
 
--- a/browser/devtools/webconsole/HUDService-content.js
+++ b/browser/devtools/webconsole/HUDService-content.js
@@ -284,17 +284,18 @@ let Manager = {
         ConsoleListener.init(aMessage);
         break;
       case "NetworkMonitor":
         NetworkMonitor.init(aMessage);
         break;
       case "LocationChange":
         ConsoleProgressListener.startMonitor(ConsoleProgressListener
                                              .MONITOR_LOCATION_CHANGE);
-        ConsoleProgressListener.sendLocation();
+        ConsoleProgressListener.sendLocation(this.window.location.href,
+                                             this.window.document.title);
         break;
       default:
         Cu.reportError("Web Console content: unknown feature " + aFeature);
         break;
     }
 
     this._enabledFeatures.push(aFeature);
   },
@@ -2220,17 +2221,17 @@ let NetworkMonitor = {
     let entry = aHttpActivity.log.entries[0];
     let harTimings = entry.timings;
 
     // Not clear how we can determine "blocked" time.
     harTimings.blocked = -1;
 
     // DNS timing information is available only in when the DNS record is not
     // cached.
-    harTimings.dns = timings.STATUS_RESOLVING ?
+    harTimings.dns = timings.STATUS_RESOLVING && timings.STATUS_RESOLVED ?
                      timings.STATUS_RESOLVED.last -
                      timings.STATUS_RESOLVING.first : -1;
 
     if (timings.STATUS_CONNECTING_TO && timings.STATUS_CONNECTED_TO) {
       harTimings.connect = timings.STATUS_CONNECTED_TO.last -
                            timings.STATUS_CONNECTING_TO.first;
     }
     else if (timings.STATUS_SENDING_TO) {
@@ -2466,44 +2467,56 @@ let ConsoleProgressListener = {
    * Check if the current window.top location is changing, given the arguments
    * of nsIWebProgressListener.onStateChange. If that is the case, the remote
    * Web Console instance is notified.
    * @private
    */
   _checkLocationChange:
   function CPL__checkLocationChange(aProgress, aRequest, aState, aStatus)
   {
+    let isStart = aState & Ci.nsIWebProgressListener.STATE_START;
     let isStop = aState & Ci.nsIWebProgressListener.STATE_STOP;
     let isNetwork = aState & Ci.nsIWebProgressListener.STATE_IS_NETWORK;
     let isWindow = aState & Ci.nsIWebProgressListener.STATE_IS_WINDOW;
 
     // Skip non-interesting states.
-    if (!isStop || !isNetwork || !isWindow ||
+    if (!isNetwork || !isWindow ||
         aProgress.DOMWindow != Manager.window) {
       return;
     }
 
-    this.sendLocation();
+    if (isStart && aRequest instanceof Ci.nsIChannel) {
+      this.sendLocation(aRequest.URI.spec, "");
+    }
+    else if (isStop) {
+      this.sendLocation(Manager.window.location.href,
+                        Manager.window.document.title);
+    }
   },
 
   onLocationChange: function() {},
   onStatusChange: function() {},
   onProgressChange: function() {},
   onSecurityChange: function() {},
 
   /**
    * Send the location of the current top window to the remote Web Console.
    * A "WebConsole:LocationChange" message is sent. The JSON object holds two
    * properties: location and title.
+   *
+   * @param string aLocation
+   *        Current page address.
+   * @param string aTitle
+   *        Current page title.
    */
-  sendLocation: function CPL_sendLocation()
+  sendLocation: function CPL_sendLocation(aLocation, aTitle)
   {
     let message = {
-      "location": Manager.window.location.href,
-      "title": Manager.window.document.title,
+      "location": aLocation,
+      "title": aTitle,
     };
     Manager.sendMessage("WebConsole:LocationChange", message);
   },
 
   /**
    * Destroy the ConsoleProgressListener.
    */
   destroy: function CPL_destroy()
--- a/browser/devtools/webconsole/HUDService.jsm
+++ b/browser/devtools/webconsole/HUDService.jsm
@@ -5,16 +5,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 
 const CONSOLEAPI_CLASS_ID = "{b49c18f8-3379-4fc0-8c90-d7772c1a9ff3}";
 
+const MIXED_CONTENT_LEARN_MORE = "https://developer.mozilla.org/en/Security/MixedContent";
+
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
 var EXPORTED_SYMBOLS = ["HUDService", "ConsoleUtils"];
 
 XPCOMUtils.defineLazyServiceGetter(this, "clipboardHelper",
                                    "@mozilla.org/widget/clipboardhelper;1",
                                    "nsIClipboardHelper");
@@ -2145,28 +2147,36 @@ HeadsUpDisplay.prototype = {
     urlNode.setAttribute("flex", "1");
     urlNode.setAttribute("title", request.url);
     urlNode.setAttribute("value", request.url);
     urlNode.classList.add("hud-clickable");
     urlNode.classList.add("webconsole-msg-body-piece");
     urlNode.classList.add("webconsole-msg-url");
     linkNode.appendChild(urlNode);
 
+    let severity = SEVERITY_LOG;
+    if(this.isMixedContentLoad(request.url, this.contentLocation)) {
+      urlNode.classList.add("webconsole-mixed-content");
+      this.makeMixedContentNode(linkNode);
+      //If we define a SEVERITY_SECURITY in the future, switch this to SEVERITY_SECURITY
+      severity = SEVERITY_WARNING;
+    }
+
     let statusNode = this.chromeDocument.createElementNS(XUL_NS, "label");
     statusNode.setAttribute("value", "");
     statusNode.classList.add("hud-clickable");
     statusNode.classList.add("webconsole-msg-body-piece");
     statusNode.classList.add("webconsole-msg-status");
     linkNode.appendChild(statusNode);
 
     let clipboardText = request.method + " " + request.url;
 
     let messageNode = ConsoleUtils.createMessageNode(this.chromeDocument,
                                                      CATEGORY_NETWORK,
-                                                     SEVERITY_LOG,
+                                                     severity,
                                                      msgNode,
                                                      this.hudId,
                                                      null,
                                                      null,
                                                      clipboardText);
 
     messageNode._connectionId = entry.connection;
 
@@ -2946,16 +2956,63 @@ HeadsUpDisplay.prototype = {
     this.positionMenuitems.below.removeEventListener("command",
       this._positionConsoleBelow, false);
     this.positionMenuitems.window.removeEventListener("command",
       this._positionConsoleWindow, false);
 
     this.closeButton.removeEventListener("command",
       this.closeButtonOnCommand, false);
   },
+
+  /**
+   * Determine whether the request should display a Mixed Content warning
+   *
+   * @param string request
+   *        location of the requested content
+   * @param string contentLocation
+   *        location of the current page
+   * @return bool
+   *         True if the content is mixed, false if not
+   */
+  isMixedContentLoad: function HUD_isMixedContentLoad(request, contentLocation) {
+    try {
+      let requestURIObject = Services.io.newURI(request, null, null);
+      let contentWindowURI = Services.io.newURI(contentLocation, null, null);
+      return (contentWindowURI.scheme == "https" && requestURIObject.scheme != "https");
+    } catch(e) {
+      return false;
+    }
+  },
+
+  /**
+   * Create a mixedContentWarningNode and add it the webconsole output.
+   *
+   * @param linkNode
+   *        parent to the requested urlNode
+   */
+  makeMixedContentNode: function HUD_makeMixedContentNode(linkNode) {
+    let mixedContentWarning = "[" + l10n.getStr("webConsoleMixedContentWarning") + "]";
+
+    //mixedContentWarning message links to a Learn More page
+    let mixedContentWarningNode = this.chromeDocument.createElement("label");
+    mixedContentWarningNode.setAttribute("value", mixedContentWarning);
+    mixedContentWarningNode.setAttribute("title", mixedContentWarning);
+
+    //UI for mixed content warning.
+    mixedContentWarningNode.classList.add("hud-clickable");
+    mixedContentWarningNode.classList.add("webconsole-mixed-content-link");
+
+    linkNode.appendChild(mixedContentWarningNode);
+
+    mixedContentWarningNode.addEventListener("click", function(aEvent) {
+      this.chromeWindow.openUILinkIn(MIXED_CONTENT_LEARN_MORE, "tab");
+      aEvent.preventDefault();
+      aEvent.stopPropagation();
+    }.bind(this));
+  },
 };
 
 /**
  * Creates a DOM Node factory for XUL nodes - as well as textNodes
  * @param aFactoryType "xul" or "text"
  * @param ignored This parameter is currently ignored, and will be removed
  * See bug 594304
  * @param aDocument The document, the factory is to generate nodes from
--- a/browser/devtools/webconsole/WebConsoleUtils.jsm
+++ b/browser/devtools/webconsole/WebConsoleUtils.jsm
@@ -241,28 +241,31 @@ var WebConsoleUtils = {
       case "regexp":
         output = aResult.toString();
         break;
       case "null":
       case "undefined":
         output = type;
         break;
       default:
-        if (aResult.toSource) {
-          try {
+        try {
+          if (aResult.toSource) {
             output = aResult.toSource();
-          } catch (ex) { }
+          }
+          if (!output || output == "({})") {
+            output = aResult + "";
+          }
         }
-        if (!output || output == "({})") {
-          output = aResult.toString();
+        catch (ex) {
+          output = ex;
         }
         break;
     }
 
-    return output;
+    return output + "";
   },
 
   /**
    * Format a string for output.
    *
    * @param string aString
    *        The string you want to display.
    * @return string
--- a/browser/devtools/webconsole/test/Makefile.in
+++ b/browser/devtools/webconsole/test/Makefile.in
@@ -104,16 +104,18 @@ MOCHITEST_BROWSER_FILES = \
 	browser_webconsole_bug_664131_console_group.js \
 	browser_webconsole_bug_704295.js \
 	browser_webconsole_bug_658368_time_methods.js \
 	browser_webconsole_bug_622303_persistent_filters.js \
 	browser_webconsole_window_zombie.js \
 	browser_cached_messages.js \
 	browser_bug664688_sandbox_update_after_navigation.js \
 	browser_webconsole_menustatus.js \
+	browser_result_format_as_string.js \
+	browser_webconsole_bug_737873_mixedcontent.js \
 	head.js \
 	$(NULL)
 
 MOCHITEST_BROWSER_FILES += \
 	test-console.html \
 	test-network.html \
 	test-network-request.html \
 	test-mutation.html \
@@ -176,11 +178,13 @@ MOCHITEST_BROWSER_FILES += \
 	test-bug-585956-console-trace.html \
 	test-bug-644419-log-limits.html \
 	test-bug-632275-getters.html \
 	test-bug-646025-console-file-location.html \
 	test-file-location.js \
 	test-bug-658368-time-methods.html \
 	test-webconsole-error-observer.html \
 	test-for-of.html \
+	test-result-format-as-string.html \
+	test-bug-737873-mixedcontent.html \
 	$(NULL)
 
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_result_format_as_string.js
@@ -0,0 +1,49 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Make sure that JS eval result are properly formatted as strings.
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-result-format-as-string.html";
+
+function test()
+{
+  waitForExplicitFinish();
+
+  addTab(TEST_URI);
+
+  gBrowser.selectedBrowser.addEventListener("load", function onLoad() {
+    gBrowser.selectedBrowser.removeEventListener("load", onLoad, true);
+    openConsole(null, performTest);
+  }, true);
+}
+
+function performTest(hud)
+{
+  hud.jsterm.clearOutput(true);
+
+  hud.jsterm.execute("document.querySelector('p')");
+  waitForSuccess({
+    name: "eval result shown",
+    validatorFn: function()
+    {
+      return hud.outputNode.querySelector(".webconsole-msg-output");
+    },
+    successFn: function()
+    {
+      is(hud.outputNode.textContent.indexOf("bug772506_content"), -1,
+            "no content element found");
+      ok(!hud.outputNode.querySelector("div"), "no div element found");
+
+      let msg = hud.outputNode.querySelector(".webconsole-msg-output");
+      ok(msg, "eval output node found");
+      isnot(msg.textContent.indexOf("HTMLDivElement"), -1,
+            "HTMLDivElement string found");
+      EventUtils.synthesizeMouseAtCenter(msg, {type: "mousemove"});
+      ok(!gBrowser._bug772506, "no content variable");
+
+      finishTest();
+    },
+    failureFn: finishTest,
+  });
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_737873_mixedcontent.js
@@ -0,0 +1,80 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * Contributor(s):
+ *  Tanvi Vyas <tanvi@mozilla.com>
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+// Tests that the Web Console Mixed Content messages are displayed
+
+const TEST_HTTPS_URI = "https://example.com/browser/browser/devtools/webconsole/test/test-bug-737873-mixedcontent.html";
+
+function test() {
+  addTab("data:text/html,Web Console basic network logging test");
+  browser.addEventListener("load", onLoad, true);
+}
+
+function onLoad(aEvent) {
+  browser.removeEventListener("load", onLoad, true);
+  openConsole(null, testMixedContent);
+}
+
+function testMixedContent(hud) {
+  content.location = TEST_HTTPS_URI;
+  var aOutputNode = hud.outputNode;
+
+  waitForSuccess(
+    {
+      name: "mixed content warning displayed successfully",
+      validatorFn: function() {
+        return ( aOutputNode.querySelector(".webconsole-mixed-content") );
+      },
+
+      successFn: function() {
+
+        //tests on the urlnode
+        let node = aOutputNode.querySelector(".webconsole-mixed-content");
+        ok(testSeverity(node), "Severity type is SEVERITY_WARNING.");
+
+        //tests on the warningNode
+        let warningNode = aOutputNode.querySelector(".webconsole-mixed-content-link");
+        is(warningNode.value, "[Mixed Content]", "Message text is accurate." );
+        testClickOpenNewTab(warningNode);
+
+        finishTest();
+      },
+
+      failureFn: finishTest,
+    }
+  );
+
+}
+
+function testSeverity(node) {
+  let linkNode = node.parentNode;
+  let msgNode = linkNode.parentNode;
+  let bodyNode = msgNode.parentNode;
+  let finalNode = bodyNode.parentNode;
+
+  return finalNode.classList.contains("webconsole-msg-warn");
+}
+
+function testClickOpenNewTab(warningNode) {
+  /* Invoke the click event and check if a new tab would open to the correct page */
+  let linkOpened = false;
+  let oldOpenUILinkIn = window.openUILinkIn;
+
+  window.openUILinkIn = function(aLink) {
+   if (aLink == "https://developer.mozilla.org/en/Security/MixedContent");
+     linkOpened = true;
+  }
+
+  EventUtils.synthesizeMouse(warningNode, 2, 2, {});
+
+  ok(linkOpened, "Clicking the Mixed Content Warning node opens the desired page");
+
+  window.openUILinkIn = oldOpenUILinkIn;
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-737873-mixedcontent.html
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML>
+<html dir="ltr" xml:lang="en-US" lang="en-US"><head>
+    <title>Mixed Content test - http on https</title>
+    <script src="testscript.js"></script>
+    <!--
+       - Any copyright is dedicated to the Public Domain.
+       - http://creativecommons.org/publicdomain/zero/1.0/
+       -->
+  </head>
+  <body>
+    <iframe src = "http://example.com"></iframe>
+  </body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-result-format-as-string.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="utf-8">
+    <title>Web Console test: jsterm eval format as a string</title>
+    <!-- Any copyright is dedicated to the Public Domain.
+         http://creativecommons.org/publicdomain/zero/1.0/ -->
+  </head>
+  <body>
+    <p>Make sure js eval results are formatted as strings.</p>
+    <script>
+      document.querySelector("p").toSource = function() {
+        var element = document.createElement("div");
+        element.textContent = "bug772506_content";
+        element.setAttribute("onmousemove",
+          "(function () {" +
+          "  gBrowser._bug772506 = 'foobar';" +
+          "})();"
+        );
+        return element;
+      };
+    </script>
+  </body>
+</html>
--- a/browser/installer/Makefile.in
+++ b/browser/installer/Makefile.in
@@ -61,18 +61,18 @@ DEFINES += -D_MSC_VER=$(_MSC_VER)
 endif
 
 ifeq ($(MOZ_CHROME_FILE_FORMAT),jar)
 DEFINES += -DJAREXT=.jar
 else
 DEFINES += -DJAREXT=
 endif
 
-ifdef MOZ_ANGLE
-DEFINES += -DMOZ_ANGLE=$(MOZ_ANGLE)
+ifdef MOZ_ANGLE_RENDERER
+DEFINES += -DMOZ_ANGLE_RENDERER=$(MOZ_ANGLE_RENDERER)
 DEFINES += -DMOZ_D3DX9_DLL=$(MOZ_D3DX9_DLL)
 DEFINES += -DMOZ_D3DCOMPILER_DLL=$(MOZ_D3DCOMPILER_DLL)
 endif
 
 include $(topsrcdir)/ipc/app/defs.mk
 DEFINES += -DMOZ_CHILD_PROCESS_NAME=$(MOZ_CHILD_PROCESS_NAME)
 
 # Set MSVC dlls version to package, if any.
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -90,16 +90,19 @@
 @BINPATH@/msvcp90.dll
 @BINPATH@/msvcr90.dll
 #elif MOZ_MSVC_REDIST == 1600
 @BINPATH@/msvcp100.dll
 @BINPATH@/msvcr100.dll
 #elif MOZ_MSVC_REDIST == 1700
 @BINPATH@/msvcp110.dll
 @BINPATH@/msvcr110.dll
+#ifdef MOZ_METRO
+@BINPATH@/vccorlib110.dll
+#endif
 #endif
 #endif
 #endif
 
 [browser]
 ; [Base Browser Files]
 #ifndef XP_UNIX
 @BINPATH@/@MOZ_APP_NAME@.exe
@@ -466,16 +469,19 @@
 @BINPATH@/components/messageWakeupService.js
 @BINPATH@/components/messageWakeupService.manifest
 @BINPATH@/components/SettingsManager.js
 @BINPATH@/components/SettingsManager.manifest
 @BINPATH@/components/Webapps.js
 @BINPATH@/components/Webapps.manifest
 @BINPATH@/components/AppsService.js
 @BINPATH@/components/AppsService.manifest
+@BINPATH@/components/nsDOMIdentity.js
+@BINPATH@/components/nsIDService.js
+@BINPATH@/components/Identity.manifest
 
 @BINPATH@/components/ContactManager.js
 @BINPATH@/components/ContactManager.manifest
 @BINPATH@/components/AlarmsManager.js
 @BINPATH@/components/AlarmsManager.manifest
 #ifdef ENABLE_MARIONETTE
 @BINPATH@/chrome/marionette@JAREXT@
 @BINPATH@/chrome/marionette.manifest
@@ -500,17 +506,17 @@
 #endif
 
 ; GNOME hooks
 #ifdef MOZ_ENABLE_GNOME_COMPONENT
 @BINPATH@/components/@DLL_PREFIX@mozgnome@DLL_SUFFIX@
 #endif
 
 ; ANGLE GLES-on-D3D rendering library
-#ifdef MOZ_ANGLE
+#ifdef MOZ_ANGLE_RENDERER
 @BINPATH@/libEGL.dll
 @BINPATH@/libGLESv2.dll
 @BINPATH@/@MOZ_D3DX9_DLL@
 @BINPATH@/@MOZ_D3DCOMPILER_DLL@
 #endif
 
 ; [Browser Chrome Files]
 @BINPATH@/chrome/browser@JAREXT@
@@ -689,16 +695,18 @@ bin/components/@DLL_PREFIX@nkgnomevfs@DL
 #ifdef XP_WIN
 @BINPATH@/webapp-uninstaller@BIN_SUFFIX@
 #endif
 @BINPATH@/webapprt-stub@BIN_SUFFIX@
 @BINPATH@/webapprt/webapprt.ini
 @BINPATH@/webapprt/chrome.manifest
 @BINPATH@/webapprt/chrome/webapprt@JAREXT@
 @BINPATH@/webapprt/chrome/webapprt.manifest
+@BINPATH@/webapprt/chrome/@AB_CD@@JAREXT@
+@BINPATH@/webapprt/chrome/@AB_CD@.manifest
 @BINPATH@/webapprt/components/CommandLineHandler.js
 @BINPATH@/webapprt/components/ContentPermission.js
 @BINPATH@/webapprt/components/ContentPolicy.js
 @BINPATH@/webapprt/components/DirectoryProvider.js
 @BINPATH@/webapprt/components/components.manifest
 @BINPATH@/webapprt/defaults/preferences/prefs.js
 @BINPATH@/webapprt/modules/WebappRT.jsm
 @BINPATH@/webapprt/modules/WebappsHandler.jsm
--- a/browser/installer/removed-files.in
+++ b/browser/installer/removed-files.in
@@ -1383,16 +1383,19 @@ xpicleanup@BIN_SUFFIX@
   #endif
   #if MOZ_MSVC_REDIST != 1600
     msvcp100.dll
     msvcr100.dll
   #endif
   #if MOZ_MSVC_REDIST != 1700
     msvcp110.dll
     msvcr110.dll
+    #ifdef MOZ_METRO
+      vccorlib110.dll
+    #endif
   #endif
   plugins/npnul32.dll
 #endif
 @DLL_PREFIX@xpcom_core@DLL_SUFFIX@
 components/@DLL_PREFIX@jar50@DLL_SUFFIX@
 #ifdef XP_WIN
   components/xpinstal.dll
 #else
--- a/browser/installer/windows/nsis/installer.nsi
+++ b/browser/installer/windows/nsis/installer.nsi
@@ -369,17 +369,17 @@ Section "-Application" APP_IDX
     ${EndIf}
   ${EndIf}
 
   ${If} $InstallMaintenanceService == "1"
     ; The user wants to install the maintenance service, so execute
     ; the pre-packaged maintenance service installer. 
     ; This option can only be turned on if the user is an admin so there
     ; is no need to use ExecShell w/ verb runas to enforce elevated.
-    nsExec::Exec "$INSTDIR\maintenanceservice_installer.exe" 
+    nsExec::Exec "$\"$INSTDIR\maintenanceservice_installer.exe$\""
   ${EndIf}
 !endif
 
   ; These need special handling on uninstall since they may be overwritten by
   ; an install into a different location.
   StrCpy $0 "Software\Microsoft\Windows\CurrentVersion\App Paths\${FileMainEXE}"
   ${WriteRegStr2} $TmpVal "$0" "" "$INSTDIR\${FileMainEXE}" 0
   ${WriteRegStr2} $TmpVal "$0" "Path" "$INSTDIR" 0
@@ -692,17 +692,17 @@ Function CheckExistingInstall
 FunctionEnd
 
 Function LaunchApp
   ClearErrors
   ${GetParameters} $0
   ${GetOptions} "$0" "/UAC:" $1
   ${If} ${Errors}
     ${ManualCloseAppPrompt} "${WindowClass}" "$(WARN_MANUALLY_CLOSE_APP_LAUNCH)"
-    Exec "$INSTDIR\${FileMainEXE}"
+    Exec "$\"$INSTDIR\${FileMainEXE}$\""
   ${Else}
     GetFunctionAddress $0 LaunchAppFromElevatedProcess
     UAC::ExecCodeSegment $0
   ${EndIf}
 FunctionEnd
 
 Function LaunchAppFromElevatedProcess
   ${ManualCloseAppPrompt} "${WindowClass}" "$(WARN_MANUALLY_CLOSE_APP_LAUNCH)"
@@ -711,17 +711,17 @@ Function LaunchAppFromElevatedProcess
   ; from an elevated installer since $INSTDIR will not be set in this installer
   ${StrFilter} "${FileMainEXE}" "+" "" "" $R9
   ReadRegStr $0 HKLM "Software\Clients\StartMenuInternet\$R9\DefaultIcon" ""
   ${GetPathFromString} "$0" $0
   ${GetParent} "$0" $1
   ; Set our current working directory to the application's install directory
   ; otherwise the 7-Zip temp directory will be in use and won't be deleted.
   SetOutPath "$1"
-  Exec "$0"
+  Exec "$\"$0$\""
 FunctionEnd
 
 ################################################################################
 # Language
 
 !insertmacro MOZ_MUI_LANGUAGE 'baseLocale'
 !verbose push
 !verbose 3
--- a/browser/installer/windows/nsis/shared.nsh
+++ b/browser/installer/windows/nsis/shared.nsh
@@ -109,17 +109,17 @@
     ; and we need a return result back to the service when run that way.
     ${If} $5 == ""
       ; An install of maintenance service was never attempted.
       ; We know we are an Admin and that we have write access into HKLM
       ; based on the above checks, so attempt to just run the EXE.
       ; In the worst case, in case there is some edge case with the 
       ; IsAdmin check and the permissions check, the maintenance service
       ; will just fail to be attempted to be installed. 
-      nsExec::Exec "$INSTDIR\maintenanceservice_installer.exe" 
+      nsExec::Exec "$\"$INSTDIR\maintenanceservice_installer.exe$\""
     ${EndIf}
   ${EndIf}
 !endif
 
 !macroend
 !define PostUpdate "!insertmacro PostUpdate"
 
 !macro SetAsDefaultAppGlobal
--- a/browser/locales/Makefile.in
+++ b/browser/locales/Makefile.in
@@ -174,22 +174,25 @@ repackage-win32-installer-%:
 else
 repackage-win32-installer-%: ;
 endif
 
 
 clobber-zip:
 	$(RM) $(STAGEDIST)/chrome/$(AB_CD).jar \
 	  $(STAGEDIST)/chrome/$(AB_CD).manifest \
+	  $(STAGEDIST)/webapprt/chrome/$(AB_CD).jar \
+	  $(STAGEDIST)/webapprt/chrome/$(AB_CD).manifest \
 	  $(STAGEDIST)/$(PREF_DIR)/firefox-l10n.js
 	$(RM) -rf  $(STAGEDIST)/searchplugins \
 	  $(STAGEDIST)/dictionaries \
 	  $(STAGEDIST)/hyphenation \
 	  $(STAGEDIST)/defaults/profile \
-	  $(STAGEDIST)/chrome/$(AB_CD)
+	  $(STAGEDIST)/chrome/$(AB_CD) \
+	  $(STAGEDIST)/webapprt/chrome/$(AB_CD)
 
 
 langpack: langpack-$(AB_CD)
 
 # This is a generic target that will make a langpack, repack ZIP (+tarball)
 # builds, and repack an installer if applicable. It is called from the
 # tinderbox scripts. Alter it with caution.
 
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -232,16 +232,19 @@ These should match what Safari and other
 <!ENTITY scratchpad.accesskey         "s">
 <!ENTITY scratchpad.keycode           "VK_F4">
 <!ENTITY scratchpad.keytext           "F4">
 
 <!ENTITY inspectCloseButton.tooltiptext "Close Inspector">
 
 <!ENTITY devToolbarCloseButton.tooltiptext "Close Developer Toolbar">
 <!ENTITY devToolbarMenu.label              "Developer Toolbar">
+<!ENTITY devToolbarMenu.accesskey          "v">
+<!ENTITY devToolbar.keycode                "VK_F2">
+<!ENTITY devToolbar.keytext                "F2">
 
 <!ENTITY webConsoleButton.label "Web Console">
 <!ENTITY inspectorButton.label "Inspector">
 
 <!ENTITY inspectorHTMLCopyInner.label       "Copy Inner HTML">
 <!ENTITY inspectorHTMLCopyInner.accesskey   "I">
 
 <!ENTITY inspectorHTMLCopyOuter.label       "Copy Outer HTML">
--- a/browser/locales/en-US/chrome/browser/devtools/gclicommands.properties
+++ b/browser/locales/en-US/chrome/browser/devtools/gclicommands.properties
@@ -75,16 +75,34 @@ screenshotDelayManual=The time to wait (
 # a dialog when the user is using this command.
 screenshotFullPageDesc=Entire webpage? (true/false)
 
 # LOCALIZATION NOTE (screenshotFullscreenManual) A fuller description of the
 # 'fullscreen' parameter to the 'screenshot' command, displayed when the user
 # asks for help on what it does.
 screenshotFullPageManual=True if the screenshot should also include parts of the webpage which are outside the current scrolled bounds.
 
+# LOCALIZATION NOTE (restartFirefoxDesc) A very short description of the
+# 'restart' command. This string is designed to be shown in a menu alongside the
+# command name, which is why it should be as short as possible.
+restartFirefoxDesc=Restart Firefox
+
+# LOCALIZATION NOTE (restartFirefoxNocacheDesc) A very short string to
+# describe the 'nocache' parameter to the 'restart' command, which is
+# displayed in a dialog when the user is using this command.
+restartFirefoxNocacheDesc=Disables loading content from cache upon restart
+
+# LOCALIZATION NOTE (restartFirefoxRequestCancelled) A string dispalyed to the
+# user when a scheduled restart has been aborted by the user.
+restartFirefoxRequestCancelled=Restart request cancelled by user.
+
+# LOCALIZATION NOTE (restartFirefoxRestarting) A string dispalyed to the
+# user when a restart has been initiated without a delay.
+restartFirefoxRestarting=Restarting Firefox...
+
 # LOCALIZATION NOTE (inspectDesc) A very short description of the 'inspect'
 # command. See inspectManual for a fuller description of what it does. This
 # string is designed to be shown in a menu alongside the command name, which
 # is why it should be as short as possible.
 inspectDesc=Inspect a node
 
 # LOCALIZATION NOTE (inspectManual) A fuller description of the 'inspect'
 # command, displayed when the user asks for help on what it does.
@@ -328,17 +346,348 @@ editManual2=Edit one of the resources th
 # when the user is using this command.
 editResourceDesc=URL to edit
 
 # LOCALIZATION NOTE (editLineToJumpToDesc) A very short string to describe the
 # 'line' parameter to the 'edit' command, which is displayed in a dialog
 # when the user is using this command.
 editLineToJumpToDesc=Line to jump to
 
+# LOCALIZATION NOTE (resizePageDesc) A very short string to describe the
+# 'resizepage' command. This string is designed to be shown in a menu
+# alongside the command name, which is why it should be as short as possible.
+resizePageDesc=Resize the page
+
+# LOCALIZATION NOTE (resizePageArgWidthDesc) A very short string to describe the
+# 'width' parameter to the 'resizepage' command, which is displayed in a dialog
+# when the user is using this command.
+resizePageArgWidthDesc=Width in pixels
+
+# LOCALIZATION NOTE (resizePageArgWidthDesc) A very short string to describe the
+# 'height' parameter to the 'resizepage' command, which is displayed in a dialog
+# when the user is using this command.
+resizePageArgHeightDesc=Height in pixels
+
+# LOCALIZATION NOTE (resizeModeOnDesc) A very short string to describe the
+# 'resizeon ' command. This string is designed to be shown in a menu
+# alongside the command name, which is why it should be as short as possible.
+resizeModeOnDesc=Enter Responsive Design Mode
+
+# LOCALIZATION NOTE (resizeModeOffDesc) A very short string to describe the
+# 'resize off' command. This string is designed to be shown in a menu
+# alongside the command name, which is why it should be as short as possible.
+resizeModeOffDesc=Exit Responsive Design Mode
+
+# LOCALIZATION NOTE (resizeModeToggleDesc) A very short string to describe the
+# 'resize toggle' command. This string is designed to be shown in a menu
+# alongside the command name, which is why it should be as short as possible.
+resizeModeToggleDesc=Toggle Responsive Design Mode
+
+# LOCALIZATION NOTE (resizeModeToDesc) A very short string to describe the
+# 'resize to' command. This string is designed to be shown in a menu
+# alongside the command name, which is why it should be as short as possible.
+resizeModeToDesc=Alter page size
+
+# LOCALIZATION NOTE (resizeModeDesc) A very short string to describe the
+# 'resize' command. This string is designed to be shown in a menu
+# alongside the command name, which is why it should be as short as possible.
+resizeModeDesc=Control Responsive Design Mode
+
+# LOCALIZATION NOTE (resizeModeManual) A fuller description of the 'resize'
+# command, displayed when the user asks for help on what it does.
+resizeModeManual=Responsive websites respond to their environment, so they look good on a mobile display, a cinema display and everything in-between. Responsive Design Mode allows you to easily test a variety of page sizes in Firefox without needing to resize your whole browser.
+
 # LOCALIZATION NOTE (cmdDesc) A very short description of the 'cmd'
 # command. This string is designed to be shown in a menu alongside the command
 # name, which is why it should be as short as possible.
 cmdDesc=Manipulate the commands
 
 # LOCALIZATION NOTE (cmdRefreshDesc) A very short description of the 'cmd refresh'
 # command. This string is designed to be shown in a menu alongside the command
 # name, which is why it should be as short as possible.
 cmdRefreshDesc=Re-read mozcmd directory
+
+# LOCALIZATION NOTE (addonDesc) A very short description of the 'addon'
+# command. This string is designed to be shown in a menu alongside the command
+# name, which is why it should be as short as possible.
+addonDesc=Manipulate add-ons
+
+# LOCALIZATION NOTE (addonListDesc) A very short description of the 'addon list'
+# command. This string is designed to be shown in a menu alongside the command
+# name, which is why it should be as short as possible.
+addonListDesc=List installed add-ons
+
+# LOCALIZATION NOTE (addonListTypeDesc) A very short description of the
+# 'addon list <type>' command. This string is designed to be shown in a menu
+# alongside the command name, which is why it should be as short as possible.
+addonListTypeDesc=Select an addon type
+
+# LOCALIZATION NOTE (addonListDictionaryHeading, addonListExtensionHeading,
+# addonListLocaleHeading, addonListPluginHeading, addonListThemeHeading,
+# addonListUnknownHeading) Used in the output of the 'addon list' command as the
+# first line of output.
+addonListDictionaryHeading=The following dictionaries are currently installed:
+addonListExtensionHeading=The following extensions are currently installed:
+addonListLocaleHeading=The following locales are currently installed:
+addonListPluginHeading=The following plugins are currently installed:
+addonListThemeHeading=The following themes are currently installed:
+addonListAllHeading=The following addons are currently installed:
+addonListUnknownHeading=The following addons of the selected type are currently installed:
+
+# LOCALIZATION NOTE (addonNameDesc) A very short description of the
+# name parameter of numerous addon commands. This string is designed to be shown
+# in a menu alongside the command name, which is why it should be as short as
+# possible.
+addonNameDesc=The name of the add-on
+
+# LOCALIZATION NOTE (addonNoneOfType) Used in the output of the 'addon list'
+# command when a search for addons of a particular type were not found.
+addonNoneOfType=There are no addons of that type installed.
+
+# LOCALIZATION NOTE (addonEnableDesc) A very short description of the
+# 'addon enable <type>' command. This string is designed to be shown in a menu
+# alongside the command name, which is why it should be as short as possible.
+addonEnableDesc=Enable the specified add-on
+
+# LOCALIZATION NOTE (addonAlreadyEnabled) Used in the output of the
+# 'addon enable' command when an attempt is made to enable an addon is already
+# enabled.
+addonAlreadyEnabled=%S is already enabled.
+
+# LOCALIZATION NOTE (addonEnabled) Used in the output of the 'addon enable'
+# command when an addon is enabled.
+addonEnabled=%S enabled.
+
+# LOCALIZATION NOTE (addonDisableDesc) A very short description of the
+# 'addon disable <type>' command. This string is designed to be shown in a menu
+# alongside the command name, which is why it should be as short as possible.
+addonDisableDesc=Disable the specified add-on
+
+# LOCALIZATION NOTE (addonAlreadyDisabled) Used in the output of the
+# 'addon disable' command when an attempt is made to disable an addon is already
+# disabled.
+addonAlreadyDisabled=%S is already disabled.
+
+# LOCALIZATION NOTE (addonDisabled) Used in the output of the 'addon disable'
+# command when an addon is disabled.
+addonDisabled=%S disabled.
+
+# LOCALIZATION NOTE (exportDesc) A very short description of the 'export'
+# command. This string is designed to be shown in a menu alongside the command
+# name, which is why it should be as short as possible.
+exportDesc=Export resources
+
+# LOCALIZATION NOTE (exportHtmlDesc) A very short description of the 'export
+# html' command. This string is designed to be shown in a menu alongside the
+# command name, which is why it should be as short as possible.
+exportHtmlDesc=Export HTML from page
+
+# LOCALIZATION NOTE (pagemodDesc) A very short description of the 'pagemod'
+# command. This string is designed to be shown in a menu alongside the command
+# name, which is why it should be as short as possible.
+pagemodDesc=Make page changes
+
+# LOCALIZATION NOTE (pagemodReplaceDesc) A very short description of the
+# 'pagemod replace' command. This string is designed to be shown in a menu
+# alongside the command name, which is why it should be as short as possible.
+pagemodReplaceDesc=Search and replace in page elements
+
+# LOCALIZATION NOTE (pagemodReplaceSearchDesc) A very short string to describe
+# the 'search' parameter to the 'pagemod replace' command, which is displayed in
+# a dialog when the user is using this command.
+pagemodReplaceSearchDesc=What to search for
+
+# LOCALIZATION NOTE (pagemodReplaceReplaceDesc) A very short string to describe
+# the 'replace' parameter to the 'pagemod replace' command, which is displayed in
+# a dialog when the user is using this command.
+pagemodReplaceReplaceDesc=Replacement string
+
+# LOCALIZATION NOTE (pagemodReplaceIgnoreCaseDesc) A very short string to
+# describe the 'ignoreCase' parameter to the 'pagemod replace' command, which is
+# displayed in a dialog when the user is using this command.
+pagemodReplaceIgnoreCaseDesc=Perform case-insensitive search
+
+# LOCALIZATION NOTE (pagemodReplaceRootDesc) A very short string to describe the
+# 'root' parameter to the 'pagemod replace' command, which is displayed in
+# a dialog when the user is using this command.
+pagemodReplaceRootDesc=CSS selector to root of search
+
+# LOCALIZATION NOTE (pagemodReplaceSelectorDesc) A very short string to describe
+# the 'selector' parameter to the 'pagemod replace' command, which is displayed
+# in a dialog when the user is using this command.
+pagemodReplaceSelectorDesc=CSS selector to match in search
+
+# LOCALIZATION NOTE (pagemodReplaceAttributesDesc) A very short string to
+# describe the 'attributes' parameter to the 'pagemod replace' command, which is
+# displayed in a dialog when the user is using this command.
+pagemodReplaceAttributesDesc=Attribute match regexp
+
+# LOCALIZATION NOTE (pagemodReplaceAttrOnlyDesc) A very short string to describe
+# the 'attrOnly' parameter to the 'pagemod replace' command, which is displayed
+# in a dialog when the user is using this command.
+pagemodReplaceAttrOnlyDesc=Restrict search to attributes
+
+# LOCALIZATION NOTE (pagemodReplaceContentOnlyDesc) A very short string to
+# describe the 'contentOnly' parameter to the 'pagemod replace' command, which
+# is displayed in a dialog when the user is using this command.
+pagemodReplaceContentOnlyDesc=Restrict search to text nodes
+
+# LOCALIZATION NOTE (pagemodReplaceResultMatchedElements) A string displayed as
+# the result of the 'pagemod replace' command.
+pagemodReplaceResult=Elements matched by selector: %1$S. Replaces in text nodes: %2$S. Replaces in attributes: %3$S.
+
+# LOCALIZATION NOTE (pagemodRemoveDesc) A very short description of the
+# 'pagemod remove' command. This string is designed to be shown in a menu
+# alongside the command name, which is why it should be as short as possible.
+pagemodRemoveDesc=Remove elements and attributes from page
+
+# LOCALIZATION NOTE (pagemodRemoveElementDesc) A very short description of the
+# 'pagemod remove element' command. This string is designed to be shown in
+# a menu alongside the command name, which is why it should be as short as
+# possible.
+pagemodRemoveElementDesc=Remove elements from page
+
+# LOCALIZATION NOTE (pagemodRemoveElementSearchDesc) A very short string to
+# describe the 'search' parameter to the 'pagemod remove element' command, which
+# is displayed in a dialog when the user is using this command.
+pagemodRemoveElementSearchDesc=CSS selector specifying elements to remove
+
+# LOCALIZATION NOTE (pagemodRemoveElementRootDesc) A very short string to
+# describe the 'root' parameter to the 'pagemod remove element' command, which
+# is displayed in a dialog when the user is using this command.
+pagemodRemoveElementRootDesc=CSS selector specifying root of search
+
+# LOCALIZATION NOTE (pagemodRemoveElementStripOnlyDesc) A very short string to
+# describe the 'stripOnly' parameter to the 'pagemod remove element' command,
+# which is displayed in a dialog when the user is using this command.
+pagemodRemoveElementStripOnlyDesc=Remove element, but leave content
+
+# LOCALIZATION NOTE (pagemodRemoveElementIfEmptyOnlyDesc) A very short string to
+# describe the 'ifEmptyOnly' parameter to the 'pagemod remove element' command,
+# which is displayed in a dialog when the user is using this command.
+pagemodRemoveElementIfEmptyOnlyDesc=Remove only empty elements
+
+# LOCALIZATION NOTE (pagemodRemoveElementResultMatchedAndRemovedElements)
+# A string displayed as the result of the 'pagemod remove element' command.
+pagemodRemoveElementResultMatchedAndRemovedElements=Elements matched by selector: %1$S. Elements removed: %2$S.
+
+# LOCALIZATION NOTE (pagemodRemoveAttributeDesc) A very short description of the
+# 'pagemod remove attribute' command. This string is designed to be shown in
+# a menu alongside the command name, which is why it should be as short as
+# possible.
+pagemodRemoveAttributeDesc=Remove matching atributes
+
+# LOCALIZATION NOTE (pagemodRemoveAttributeSearchAttributesDesc) A very short
+# string to describe the 'searchAttributes' parameter to the 'pagemod remove
+# attribute' command, which is displayed in a dialog when the user is using this
+# command.
+pagemodRemoveAttributeSearchAttributesDesc=Regexp specifying attributes to remove
+
+# LOCALIZATION NOTE (pagemodRemoveAttributeSearchElementsDesc) A very short
+# string to describe the 'searchElements' parameter to the 'pagemod remove
+# attribute' command, which is displayed in a dialog when the user is using this
+# command.
+pagemodRemoveAttributeSearchElementsDesc=CSS selector of elements to include
+
+# LOCALIZATION NOTE (pagemodRemoveAttributeRootDesc) A very short string to
+# describe the 'root' parameter to the 'pagemod remove attribute' command, which
+# is displayed in a dialog when the user is using this command.
+pagemodRemoveAttributeRootDesc=CSS selector of root of search
+
+# LOCALIZATION NOTE (pagemodRemoveAttributeIgnoreCaseDesc) A very short string
+# to describe the 'ignoreCase' parameter to the 'pagemod remove attribute'
+# command, which is displayed in a dialog when the user is using this command.
+pagemodRemoveAttributeIgnoreCaseDesc=Perform case-insensitive search
+
+# LOCALIZATION NOTE (pagemodRemoveAttributeResult) A string displayed as the
+# result of the 'pagemod remove attribute' command.
+pagemodRemoveAttributeResult=Elements matched by selector: %1$S. Attributes removed: %2$S.
+
+# LOCALIZATION NOTE (cookieDesc) A very short description of the 'cookie'
+# command. See cookieManual for a fuller description of what it does. This
+# string is designed to be shown in a menu alongside the command name, which
+# is why it should be as short as possible.
+cookieDesc=Display and alter cookies
+
+# LOCALIZATION NOTE (cookieManual) A fuller description of the 'cookie'
+# command, displayed when the user asks for help on what it does.
+cookieManual=Commands to list, create, delete and alter cookies for the current domain.
+
+# LOCALIZATION NOTE (cookieListDesc) A very short description of the
+# 'cookie list' command. This string is designed to be shown in a menu
+# alongside the command name, which is why it should be as short as possible.
+cookieListDesc=Display cookies
+
+# LOCALIZATION NOTE (cookieListManual) A fuller description of the 'cookie list'
+# command, displayed when the user asks for help on what it does.
+cookieListManual=Display a list of the cookies relevant to the current page.
+
+# LOCALIZATION NOTE (cookieListOutKey) A heading used in the output from the
+# 'cookie list' command above a list of cookie keys
+cookieListOutKey=Key
+
+# LOCALIZATION NOTE (cookieListOutValue) A heading used in the output from the
+# 'cookie list' command above a list of cookie values
+cookieListOutValue=Value
+
+# LOCALIZATION NOTE (cookieListOutActions) A heading used in the output from the
+# 'cookie list' command above a list of actions to take on cookies
+cookieListOutActions=Actions
+
+# LOCALIZATION NOTE (cookieListOutEdit) A title used in the output from the
+# 'cookie list' command on a button which can be used to edit cookie values
+cookieListOutEdit=Edit
+
+# LOCALIZATION NOTE (cookieListOutRemove) A title used in the output from the
+# 'cookie list' command on a button which can be used to remove cookies
+cookieListOutRemove=Remove
+
+# LOCALIZATION NOTE (cookieRemoveDesc) A very short description of the
+# 'cookie remove' command. This string is designed to be shown in a menu
+# alongside the command name, which is why it should be as short as possible.
+cookieRemoveDesc=Remove a cookie
+
+# LOCALIZATION NOTE (cookieRemoveManual) A fuller description of the 'cookie remove'
+# command, displayed when the user asks for help on what it does.
+cookieRemoveManual=Remove a cookie, given its key
+
+# LOCALIZATION NOTE (cookieRemoveKeyDesc) A very short string to describe the
+# 'key' parameter to the 'cookie remove' command, which is displayed in a dialog
+# when the user is using this command.
+cookieRemoveKeyDesc=The key of the cookie to remove
+
+# LOCALIZATION NOTE (cookieSetDesc) A very short description of the
+# 'cookie set' command. This string is designed to be shown in a menu
+# alongside the command name, which is why it should be as short as possible.
+cookieSetDesc=Set a cookie
+
+# LOCALIZATION NOTE (cookieSetManual) A fuller description of the 'cookie set'
+# command, displayed when the user asks for help on what it does.
+cookieSetManual=Set a cookie by specifying a key name, it's value and optionally one or more of the following attributes: expires (max-age in seconds or the expires date in GMTString format), path, domain, secure
+
+# LOCALIZATION NOTE (cookieSetKeyDesc) A very short string to describe the
+# 'key' parameter to the 'cookie set' command, which is displayed in a dialog
+# when the user is using this command.
+cookieSetKeyDesc=The key of the cookie to set
+
+# LOCALIZATION NOTE (cookieSetValueDesc) A very short string to describe the
+# 'value' parameter to the 'cookie set' command, which is displayed in a dialog
+# when the user is using this command.
+cookieSetValueDesc=The value of the cookie to set
+
+# LOCALIZATION NOTE (cookieSetOptionsDesc) The title of a set of options to
+# the 'cookie set' command, displayed as a heading to the list of option.
+cookieSetOptionsDesc=Options
+
+# LOCALIZATION NOTE (cookieSetPathDesc) A very short string to describe the
+# 'path' parameter to the 'cookie set' command, which is displayed in a dialog
+# when the user is using this command.
+cookieSetPathDesc=The path of the cookie to set
+
+# LOCALIZATION NOTE (cookieSetDomainDesc) A very short string to describe the
+# 'domain' parameter to the 'cookie set' command, which is displayed in a dialog
+# when the user is using this command.
+cookieSetDomainDesc=The domain of the cookie to set
+
+# LOCALIZATION NOTE (cookieSetSecureDesc) A very short string to describe the
+# 'secure' parameter to the 'cookie set' command, which is displayed in a dialog
+# when the user is using this command.
+cookieSetSecureDesc=Only transmitted over https
--- a/browser/locales/en-US/chrome/browser/devtools/webconsole.properties
+++ b/browser/locales/en-US/chrome/browser/devtools/webconsole.properties
@@ -145,16 +145,21 @@ webConsolePositionBelow=Below
 webConsolePositionWindow=Window
 
 # LOCALIZATION NOTE (webConsoleWindowTitleAndURL): The Web Console floating
 # panel title, followed by the web page URL.
 # For RTL languages you need to set the LRM in the string to give the URL
 # the correct direction.
 webConsoleWindowTitleAndURL=Web Console - %S
 
+# LOCALIZATION NOTE (webConsoleMixedContentWarning): Message displayed after a
+# URL in the Web Console that has been flagged for Mixed Content (i.e. http
+# content in an https page)
+webConsoleMixedContentWarning=Mixed Content
+
 # LOCALIZATION NOTE (scratchpad.linkText):
 # The text used in the right hand side of the web console command line when
 # Javascript is being entered, to indicate how to jump into scratchpad mode
 scratchpad.linkText=Shift+RETURN - Open in Scratchpad
 
 # LOCALIZATION NOTE (gcliterm.instanceLabel): The console displays
 # objects using their type (from the constructor function) in this descriptive
 # string
--- a/browser/locales/jar.mn
+++ b/browser/locales/jar.mn
@@ -115,12 +115,13 @@
 % override chrome://mozapps/locale/downloads/settingsChange.dtd chrome://browser/locale/downloads/settingsChange.dtd
 % locale testpilot @AB_CD@ %locale/feedback/
     locale/feedback/main.dtd                       (%feedback/main.dtd)
     locale/feedback/main.properties                (%feedback/main.properties)
 % locale pdf.js @AB_CD@ %locale/pdfviewer/
     locale/pdfviewer/viewer.properties             (%pdfviewer/viewer.properties)
     locale/pdfviewer/chrome.properties             (%pdfviewer/chrome.properties)
 #ifdef MOZ_WEBAPP_RUNTIME
+../webapprt/chrome/@AB_CD@.jar:
 % locale webapprt @AB_CD@ %locale/webapprt/
     locale/webapprt/webapp.dtd                     (%webapprt/webapp.dtd)
     locale/webapprt/webapp.properties              (%webapprt/webapp.properties)
 #endif
--- a/browser/themes/gnomestripe/browser.css
+++ b/browser/themes/gnomestripe/browser.css
@@ -581,17 +581,17 @@ toolbar[mode="full"] .toolbarbutton-1 > 
 #forward-button[disabled] {
   list-style-image: url("moz-icon://stock/gtk-go-forward-ltr?size=toolbar&state=disabled");
 }
 #forward-button[disabled]:-moz-locale-dir(rtl) {
   list-style-image: url("moz-icon://stock/gtk-go-forward-rtl?size=toolbar&state=disabled");
 }
 
 @conditionalForwardWithUrlbar@:not([switchingtabs]) > #forward-button {
-  -moz-transition: @forwardTransitionLength@ ease-out;
+  transition: @forwardTransitionLength@ ease-out;
 }
 
 @conditionalForwardWithUrlbar@ > #forward-button[disabled] {
   -moz-transform: scale(0);
   opacity: 0;
   pointer-events: none;
 }
 
@@ -933,18 +933,18 @@ toolbar[iconsize="small"] #feed-button {
   -moz-margin-start: -@conditionalForwardWithUrlbarWidth_small@px;
 }
 
 @conditionalForwardWithUrlbar@ + #urlbar-container > #urlbar {
   pointer-events: all;
 }
 
 @conditionalForwardWithUrlbar@:not([switchingtabs]) + #urlbar-container > #urlbar {
-  -moz-transition: margin-left @forwardTransitionLength@ ease-out,
-                   margin-right @forwardTransitionLength@ ease-out;
+  transition: margin-left @forwardTransitionLength@ ease-out,
+              margin-right @forwardTransitionLength@ ease-out;
 }
 
 @conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container > #urlbar:-moz-locale-dir(ltr) {
   margin-left: -@conditionalForwardWithUrlbarWidth@px;
 }
 @conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container > #urlbar:-moz-locale-dir(rtl) {
   margin-right: -@conditionalForwardWithUrlbarWidth@px;
 }
@@ -1637,23 +1637,23 @@ richlistitem[type~="action"][actiontype=
 .tabbrowser-arrowscrollbox > .scrollbutton-up {
   -moz-border-start: 0;
   -moz-border-end: 2px solid transparent;
 }
 
 .tabbrowser-arrowscrollbox > .scrollbutton-down {
   -moz-border-start: 2px solid transparent;
   -moz-border-end: 0;
-  -moz-transition: 1s box-shadow ease-out;
+  transition: 1s box-shadow ease-out;
   border-radius: 4px;
 }
 
 .tabbrowser-arrowscrollbox > .scrollbutton-down[notifybgtab] {
   box-shadow: 0 0 5px 5px Highlight inset;
-  -moz-transition: none;
+  transition: none;
 }
 
 .tabbrowser-arrowscrollbox > .scrollbutton-up:not([disabled]):-moz-locale-dir(ltr),
 .tabbrowser-arrowscrollbox > .scrollbutton-down:not([disabled]):-moz-locale-dir(rtl) {
   border-width: 0 2px 0 0;
   border-style: solid;
   -moz-border-image: url("chrome://browser/skin/tabbrowser/tab-overflow-border.png") 0 2 0 2 fill;
 }
--- a/browser/themes/gnomestripe/devtools/debugger.css
+++ b/browser/themes/gnomestripe/devtools/debugger.css
@@ -98,27 +98,27 @@
  */
 
 .variable {
   -moz-margin-start: 1px;
   -moz-margin-end: 1px;
   margin-top: 2px;
   border-bottom: 1px dotted #ddd;
   border-radius: 8px;
-  -moz-transition: background 1s ease-in-out;
+  transition: background 1s ease-in-out;
   background: #fff;
 }
 
 .variable[changed] {
-  -moz-transition-duration: 0.4s;
+  transition-duration: 0.4s;
   background: rgba(255, 255, 0, 0.65);
 }
 
 .variable[added] {
-  -moz-transition-duration: 0.4s;
+  transition-duration: 0.4s;
   background: rgba(0, 255, 0, 0.15);
 }
 
 .variable > .title > .arrow {
   margin-top: -2px;
 }
 
 .variable > .title > .name {
--- a/browser/themes/gnomestripe/devtools/gcli.css
+++ b/browser/themes/gnomestripe/devtools/gcli.css
@@ -124,8 +124,13 @@
   color: hsl(25,78%,50%);
 }
 
 .gcli-menu-more {
   font-size: 80%;
   text-align: right;
   -moz-padding-end: 8px;
 }
+
+.gcli-addon-disabled {
+  opacity: 0.6;
+  text-decoration: line-through;
+}
--- a/browser/themes/gnomestripe/devtools/webconsole.css
+++ b/browser/themes/gnomestripe/devtools/webconsole.css
@@ -3,17 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 .hud-box {
   border-bottom: 1px solid #aaa;
   text-shadow: none;
 }
 
 .hud-box.animated {
-  -moz-transition: height 100ms;
+  transition: height 100ms;
 }
 
 .hud-splitter {
   box-shadow: 0 -1px 0 0 ThreeDShadow inset, 0 0 0 10px -moz-Dialog inset;
 }
 
 .hud-outer-wrapper {
   width: 100%;
@@ -89,16 +89,25 @@
   margin-top: 0;
   margin-bottom: 0;
   -moz-margin-start: 0;
   -moz-margin-end: 6px;
   width: 10em;
   text-align: end;
 }
 
+.webconsole-mixed-content {
+  color: #FF0000;
+}
+
+.webconsole-mixed-content-link {
+  color: #0000EE;
+  margin: 0;
+}
+
 .hud-msg-node[selected="true"] > .webconsole-timestamp,
 .hud-msg-node[selected="true"] > .webconsole-location {
   color: inherit;
 }
 
 .jsterm-input-node,
 .jsterm-complete-node {
   font: 12px "DejaVu Sans Mono", monospace;
--- a/browser/themes/gnomestripe/downloads/downloads.css
+++ b/browser/themes/gnomestripe/downloads/downloads.css
@@ -15,17 +15,17 @@
   color: inherit;
 }
 
 #downloadsPanel:not([hasdownloads]) > #downloadsListBox {
   display: none;
 }
 
 #downloadsHistory {
-  background: inherit;
+  background: transparent;
   color: -moz-nativehyperlinktext;
   cursor: pointer;
 }
 
 #downloadsPanel[hasdownloads] > #downloadsHistory {
   border-top: 1px solid ThreeDShadow;
   background-image: -moz-linear-gradient(hsla(0,0%,0%,.15), hsla(0,0%,0%,.08) 6px);
 }
--- a/browser/themes/gnomestripe/newtab/newTab.css
+++ b/browser/themes/gnomestripe/newtab/newTab.css
@@ -39,17 +39,17 @@
 
 /* CELLS */
 .newtab-cell {
   -moz-margin-end: 20px;
   background-color: rgba(255,255,255,.2);
   border: 1px solid;
   border-color: rgba(8,22,37,.12) rgba(8,22,37,.14) rgba(8,22,37,.16);
   border-radius: 1px;
-  -moz-transition: border-color 100ms ease-out;
+  transition: border-color 100ms ease-out;
 }
 
 .newtab-cell:empty {
   border: 1px dashed;
   border-color: rgba(8,22,37,.15) rgba(8,22,37,.17) rgba(8,22,37,.19);
 }
 
 .newtab-cell:last-child {
@@ -58,26 +58,26 @@
 
 .newtab-cell:hover:not(:empty):not([dragged]) {
   border-color: rgba(8,22,37,.25) rgba(8,22,37,.27) rgba(8,22,37,.3);
 }
 
 /* SITES */
 .newtab-site {
   text-decoration: none;
-  -moz-transition-property: top, left, opacity, box-shadow, background-color;
+  transition-property: top, left, opacity, box-shadow, background-color;
 }
 
 .newtab-site:hover,
 .newtab-site[dragged] {
   box-shadow: 0 0 10px rgba(8,22,37,.3);
 }
 
 .newtab-site[dragged] {
-  -moz-transition-property: box-shadow, background-color;
+  transition-property: box-shadow, background-color;
   background-color: rgb(242,242,242);
 }
 
 /* THUMBNAILS */
 .newtab-thumbnail {
   background-origin: padding-box;
   background-clip: padding-box;
   background-repeat: no-repeat;
--- a/browser/themes/gnomestripe/tabview/tabview.css
+++ b/browser/themes/gnomestripe/tabview/tabview.css
@@ -121,19 +121,19 @@ html[dir=rtl] .expander {
 
 .expander:hover {
   opacity: 1.0;
 }
 
 .close:hover,
 .expander:hover,
 .appTabIcon:hover {
-  -moz-transition-property: opacity;
-  -moz-transition-duration: 0.5s;
-  -moz-transition-timing-function: ease-out;
+  transition-property: opacity;
+  transition-duration: 0.5s;
+  transition-timing-function: ease-out;
 }
 
 .favicon img:hover, 
 .close img:hover, 
 .expander img:hover {
   opacity: 1;
   border: none;
 }
--- a/browser/themes/pinstripe/browser.css
+++ b/browser/themes/pinstripe/browser.css
@@ -521,17 +521,17 @@ toolbar[mode="icons"] #forward-button {
 }
 
 @conditionalForwardWithUrlbar@ > #forward-button:-moz-lwtheme {
   -moz-padding-start: 2px;
   -moz-padding-end: 0;
 }
 
 @conditionalForwardWithUrlbar@:not([switchingtabs]) > #forward-button {
-  -moz-transition: opacity @forwardTransitionLength@ ease-out;
+  transition: opacity @forwardTransitionLength@ ease-out;
 }
 
 @conditionalForwardWithUrlbar@ > #forward-button:hover:active:not(:-moz-lwtheme) {
   background-image: -moz-linear-gradient(hsl(0,0%,74%), hsl(0,0%,61%));
   box-shadow: inset rgba(0,0,0,.3) 0 -6px 10px,
               inset #000 0 1px 3px,
               inset rgba(0,0,0,.2) 0 1px 3px,
               0 1px 0 hsla(0,0%,100%,.2);
@@ -890,17 +890,17 @@ toolbar[mode="icons"] #zoom-in-button {
 
 @conditionalForwardWithUrlbar@ + #urlbar-container > #urlbar {
   -moz-border-start: none;
   margin-left: 0;
   pointer-events: all;
 }
 
 @conditionalForwardWithUrlbar@:not([switchingtabs]) + #urlbar-container > #urlbar {
-  -moz-transition: margin-left @forwardTransitionLength@ ease-out;
+  transition: margin-left @forwardTransitionLength@ ease-out;
 }
 
 @conditionalForwardWithUrlbar@ + #urlbar-container > #urlbar:-moz-locale-dir(ltr) {
   border-top-left-radius: 0;
   border-bottom-left-radius: 0;
 }
 
 @conditionalForwardWithUrlbar@ + #urlbar-container > #urlbar:-moz-locale-dir(rtl) {
@@ -913,17 +913,17 @@ toolbar[mode="icons"] #zoom-in-button {
 }
 
 @conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container > #urlbar {
   margin-left: -@conditionalForwardWithUrlbarWidth@px;
 }
 
 @conditionalForwardWithUrlbar@[forwarddisabled]:hover:not([switchingtabs]) + #urlbar-container > #urlbar {
   /* delay the hiding of the forward button when hovered to avoid accidental clicks on the url bar */
-  -moz-transition-delay: 100s;
+  transition-delay: 100s;
 }
 
 @conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) + #urlbar-container > #urlbar {
   /* when not hovered anymore, trigger a new transition to hide the forward button immediately */
   margin-left: -@conditionalForwardWithUrlbarWidth@.01px;
 }
 
 @conditionalForwardWithUrlbar@ + #urlbar-container:-moz-locale-dir(rtl),
@@ -956,28 +956,28 @@ toolbar[mode="icons"] #zoom-in-button {
   border-radius: 0;
 }
 
 @conditionalForwardWithUrlbar@ + #urlbar-container > #urlbar > #identity-box {
   border-radius: 0;
 }
 
 @conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr) {
-  -moz-transition: 0s padding-left;
+  transition: 0s padding-left;
   padding-left: 10px;
 }
 
 @conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) {
-  -moz-transition: 0s padding-right;
+  transition: 0s padding-right;
   padding-right: 10px;
 }
 
 @conditionalForwardWithUrlbar@[forwarddisabled]:hover:not([switchingtabs]) + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box {
   /* delay the hiding of the forward button when hovered to avoid accidental clicks on the url bar */
-  -moz-transition-delay: 100s;
+  transition-delay: 100s;
 }
 
 @conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr) {
   padding-left: 10.01px;
 }
 
 @conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) {
   padding-right: 10.01px;
@@ -1668,19 +1668,19 @@ toolbarbutton.chevron > .toolbarbutton-m
   list-style-image: url("chrome://browser/skin/tabbrowser/loading.png");
 }
 
 .tabbrowser-tab:not(:hover) > .tab-stack > .tab-content > .tab-icon-image:not([selected="true"]) {
   opacity: .8;
 }
 
 .tabbrowser-tab:not([pinned]):not([fadein]) {
-  -moz-transition: min-width 200ms ease-out /* copied from browser/base/content/browser.css */,
-                   max-width 250ms ease-out /* copied from browser/base/content/browser.css */,
-                   opacity 50ms ease-out 100ms /* hide the tab for the last 100ms of the max-width transition */;
+  transition: min-width 200ms ease-out /* copied from browser/base/content/browser.css */,
+              max-width 250ms ease-out /* copied from browser/base/content/browser.css */,
+              opacity 50ms ease-out 100ms /* hide the tab for the last 100ms of the max-width transition */;
 }
 
 .tab-stack {
   /* ensure stable tab height with and without toolbarbuttons on the tab bar */
   height: 26px;
 }
 
 .tabbrowser-tab,
@@ -2010,22 +2010,22 @@ toolbarbutton.chevron > .toolbarbutton-m
 }
 
 .tabbrowser-arrowscrollbox > .scrollbutton-up {
   -moz-border-end: 2px solid transparent;
 }
 
 .tabbrowser-arrowscrollbox > .scrollbutton-down {
   -moz-border-start: 2px solid transparent;
-  -moz-transition: 1s background-color ease-out;
+  transition: 1s background-color ease-out;
 }
 
 .tabbrowser-arrowscrollbox > .scrollbutton-down[notifybgtab] {
   background-color: Highlight;
-  -moz-transition: none;
+  transition: none;
 }
 
 .tabbrowser-arrowscrollbox > .scrollbutton-up:-moz-locale-dir(ltr),
 .tabbrowser-arrowscrollbox > .scrollbutton-down:-moz-locale-dir(rtl) {
   list-style-image: url("chrome://browser/skin/tabbrowser/tab-arrow-left.png");
 }
 
 .tabbrowser-arrowscrollbox > .scrollbutton-down:-moz-locale-dir(ltr),
@@ -2732,16 +2732,30 @@ panel[dimmed="true"] {
   -moz-border-start: 1px solid #242b33;
   min-width: 0;
   width: 3px;
   background-color: transparent;
   -moz-margin-end: -3px;
   position: relative;
 }
 
+/* Lion Fullscreen window styling */
+@media (-moz-mac-lion-theme) {
+  #navigator-toolbox[inFullscreen][tabsontop="true"]:not(:-moz-lwtheme)::before {
+    height: 36px;
+  }
+  #main-window[inFullscreen]:-moz-lwtheme {
+    /* This additional padding matches the change in height in the pseudo-element
+     * above. The rules combined force the top 22px of the background image to
+     * be hidden, so there image doesn't jump around with the loss of the titlebar */
+    padding-top: 11px;
+    background-position: right -11px;
+  }
+}
+
 #devtools-sidebar-box {
   background-color: -moz-Field;
 }
 
 /* Highlighter - Node Infobar */
 
 #highlighter-nodeinfobar {
   color: hsl(200, 100%, 65%);
--- a/browser/themes/pinstripe/devtools/debugger.css
+++ b/browser/themes/pinstripe/devtools/debugger.css
@@ -100,27 +100,27 @@
  */
 
 .variable {
   -moz-margin-start: 1px;
   -moz-margin-end: 1px;
   margin-top: 2px;
   border-bottom: 1px dotted #ddd;
   border-radius: 8px;
-  -moz-transition: background 1s ease-in-out;
+  transition: background 1s ease-in-out;
   background: #fff;
 }
 
 .variable[changed] {
-  -moz-transition-duration: 0.4s;
+  transition-duration: 0.4s;
   background: rgba(255, 255, 0, 0.65);
 }
 
 .variable[added] {
-  -moz-transition-duration: 0.4s;
+  transition-duration: 0.4s;
   background: rgba(0, 255, 0, 0.15);
 }
 
 .variable > .title > .arrow {
   margin-top: -2px;
 }
 
 .variable > .title > .name {
--- a/browser/themes/pinstripe/devtools/gcli.css
+++ b/browser/themes/pinstripe/devtools/gcli.css
@@ -126,8 +126,13 @@
   color: hsl(25,78%,50%);
 }
 
 .gcli-menu-more {
   font-size: 80%;
   text-align: right;
   -moz-padding-end: 8px;
 }
+
+.gcli-addon-disabled {
+  opacity: 0.6;
+  text-decoration: line-through;
+}
--- a/browser/themes/pinstripe/devtools/webconsole.css
+++ b/browser/themes/pinstripe/devtools/webconsole.css
@@ -5,17 +5,17 @@
 %include ../shared.inc
 
 .hud-box {
   border-bottom: 1px solid #aaa;
   text-shadow: none;
 }
 
 .hud-box.animated {
-  -moz-transition: height 100ms;
+  transition: height 100ms;
 }
 
 .hud-splitter {
   border-bottom: solid #a5a5a5 1px;
   background: url("chrome://global/skin/splitter/dimple.png") no-repeat center,
     -moz-linear-gradient(top, #fcfcfc, #dfdfdf);
 }
 
@@ -249,16 +249,25 @@
 .webconsole-msg-console.webconsole-msg-warn {
   -moz-image-region: rect(24px, 24px, 32px, 16px);
 }
 
 .webconsole-msg-console.webconsole-msg-info {
   -moz-image-region: rect(24px, 32px, 32px, 24px);
 }
 
+.webconsole-mixed-content {
+  color: #FF0000;
+}
+
+.webconsole-mixed-content-link {
+  color: #0000EE;
+  margin: 0;
+}
+
 /* Input and output styles */
 .webconsole-msg-input > .webconsole-msg-icon-container,
 .webconsole-msg-output > .webconsole-msg-icon-container {
   border-left: solid #808080 6px;
 }
 
 .webconsole-msg-input {
   -moz-image-region: rect(24px, 40px, 32px, 32px);
--- a/browser/themes/pinstripe/downloads/downloads.css
+++ b/browser/themes/pinstripe/downloads/downloads.css
@@ -15,17 +15,17 @@
   color: inherit;
 }
 
 #downloadsPanel:not([hasdownloads]) > #downloadsListBox {
   display: none;
 }
 
 #downloadsHistory {
-  background: inherit;
+  background: transparent;
   border-bottom-left-radius: 6px;
   border-bottom-right-radius: 6px;
   color: hsl(210,100%,75%);
   cursor: pointer;
 }
 
 #downloadsPanel:not([hasdownloads]) > #downloadsHistory {
   border-top-left-radius: 6px;
--- a/browser/themes/pinstripe/newtab/newTab.css
+++ b/browser/themes/pinstripe/newtab/newTab.css
@@ -39,17 +39,17 @@
 
 /* CELLS */
 .newtab-cell {
   -moz-margin-end: 20px;
   background-color: rgba(255,255,255,.2);
   border: 1px solid;
   border-color: rgba(8,22,37,.12) rgba(8,22,37,.14) rgba(8,22,37,.16);
   border-radius: 1px;
-  -moz-transition: border-color 100ms ease-out;
+  transition: border-color 100ms ease-out;
 }
 
 .newtab-cell:empty {
   border: 1px dashed;
   border-color: rgba(8,22,37,.15) rgba(8,22,37,.17) rgba(8,22,37,.19);
 }
 
 .newtab-cell:last-child {
@@ -58,26 +58,26 @@
 
 .newtab-cell:hover:not(:empty):not([dragged]) {
   border-color: rgba(8,22,37,.25) rgba(8,22,37,.27) rgba(8,22,37,.3);
 }
 
 /* SITES */
 .newtab-site {
   text-decoration: none;
-  -moz-transition-property: top, left, opacity, box-shadow, background-color;
+  transition-property: top, left, opacity, box-shadow, background-color;
 }
 
 .newtab-site:hover,
 .newtab-site[dragged] {
   box-shadow: 0 0 10px rgba(8,22,37,.3);
 }
 
 .newtab-site[dragged] {
-  -moz-transition-property: box-shadow, background-color;
+  transition-property: box-shadow, background-color;
   background-color: rgb(242,242,242);
 }
 
 /* THUMBNAILS */
 .newtab-thumbnail {
   background-origin: padding-box;
   background-clip: padding-box;
   background-repeat: no-repeat;
--- a/browser/themes/pinstripe/tabview/tabview.css
+++ b/browser/themes/pinstripe/tabview/tabview.css
@@ -102,33 +102,33 @@ html[dir=rtl] .close {
 }
 
 .expander {
   bottom: 8px;
   right: 6px;
   width: 16px;
   height: 16px;
   background: url(chrome://global/skin/icons/resizer.png) no-repeat;
-  -moz-transition-property: opacity;
-  -moz-transition-duration: 0.5s;
-  -moz-transition-timing-function: ease-out;
+  transition-property: opacity;
+  transition-duration: 0.5s;
+  transition-timing-function: ease-out;
   opacity: 0.2;
 }
 
 html[dir=rtl] .expander {
   right: auto;
   left: 6px;
   -moz-transform: scaleX(-1);
 }
 
 .expander:hover,
 .appTabIcon:hover {
-  -moz-transition-property: opacity;
-  -moz-transition-duration: 0.5s;
-  -moz-transition-timing-function: ease-out;
+  transition-property: opacity;
+  transition-duration: 0.5s;
+  transition-timing-function: ease-out;
   opacity: 1.0;
 }
 
 .favicon img:hover, 
 .expander img:hover {
   opacity: 1;
   border: none;
 }
--- a/browser/themes/winstripe/browser.css
+++ b/browser/themes/winstripe/browser.css
@@ -354,17 +354,17 @@
     border-top: 1px solid #d6e5f5;
     border-bottom: none;
   }
 
   .appmenu-edit-button:not([disabled]):hover {
     border: 1px solid #b8d6fb;
     box-shadow: inset 0 0 1px white;
     background: -moz-linear-gradient(#fafbfd, #ebf3fd);
-    -moz-transition: .2s ease-in;
+    transition: .2s ease-in;
   }
 }
 
 #appmenuSecondaryPane-spacer {
   min-height: 1em;
 }
 
 #appmenu-editmenu {
@@ -694,18 +694,18 @@ toolbar[mode=full] .toolbarbutton-1 > .t
   padding: 2px 6px;
   background: hsla(210,32%,93%,0) padding-box;
   border-radius: 2px;
   border: 1px solid;
   border-color: hsla(210,54%,20%,0) hsla(210,54%,20%,0) hsla(210,54%,20%,0);
   box-shadow: 0 1px hsla(0,0%,100%,0) inset,
               0 1px hsla(210,54%,20%,0),
               0 0 2px hsla(210,54%,20%,0);
-  -moz-transition-property: background-color, border-color, box-shadow;
-  -moz-transition-duration: 150ms;
+  transition-property: background-color, border-color, box-shadow;
+  transition-duration: 150ms;
 }
 
 @navbarLargeIcons@ .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-icon,
 @navbarLargeIcons@ .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
   padding: 3px 7px;
 }
 
 @navbarLargeIcons@ .toolbarbutton-1[type=menu]:not(#back-button):not(#forward-button):not(#feed-button) > .toolbarbutton-icon,
@@ -774,26 +774,26 @@ toolbar[mode=full] .toolbarbutton-1 > .t
   background-color: hsla(210,54%,20%,.15);
   border-color: hsla(210,54%,20%,.3) hsla(210,54%,20%,.35) hsla(210,54%,20%,.4);
   box-shadow: 0 1px 1px hsla(210,54%,20%,.1) inset,
               0 0 1px hsla(210,54%,20%,.2) inset,
               /* allows winstripe-keyhole-forward-clip-path to be used for non-hover as well as hover: */
               0 1px 0 hsla(210,54%,20%,0),
               0 0 2px hsla(210,54%,20%,0);
   text-shadow: none;
-  -moz-transition: none;
+  transition: none;
 }
 
 @navbarLargeIcons@ .toolbarbutton-1:-moz-any(:hover,[open]) > .toolbarbutton-menubutton-dropmarker:not([disabled]) > .dropmarker-icon {
   -moz-border-start-color: hsla(210,54%,20%,.35);
 }
 
 @navbarLargeIcons@ .toolbarbutton-1[checked]:not(:active):hover > .toolbarbutton-icon {
   background-color: rgba(90%,90%,90%,.4);
-  -moz-transition: background-color .4s;
+  transition: background-color .4s;
 }
 
 :-moz-any(#TabsToolbar, #addon-bar) .toolbarbutton-1,
 :-moz-any(#TabsToolbar, #addon-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-button,
 .tabbrowser-arrowscrollbox > .scrollbutton-up,
 .tabbrowser-arrowscrollbox > .scrollbutton-down {
   -moz-appearance: none;
   border-style: none;
@@ -858,17 +858,17 @@ toolbar[mode=full] .toolbarbutton-1 > .t
   -moz-margin-start: -6px !important;
   border-left-style: none;
   border-radius: 0;
   padding-left: 7px;
   padding-right: 3px;
 }
 
 @conditionalForwardWithUrlbar@:not([switchingtabs]) > #forward-button {
-  -moz-transition: opacity @forwardTransitionLength@ ease-out;
+  transition: opacity @forwardTransitionLength@ ease-out;
 }
 
 @conditionalForwardWithUrlbar@:not(:hover) > #forward-button[disabled] {
   opacity: 0;
 }
 
 @conditionalForwardWithUrlbar@ > #back-button {
   -moz-image-region: rect(18px, 20px, 38px, 0);
@@ -893,18 +893,18 @@ toolbar[mode=full] .toolbarbutton-1 > .t
   border-radius: 10000px;
   padding: 5px;
   border: none;
   background-image: -moz-linear-gradient(hsla(0,0%,100%,.6), hsla(0,0%,100%,.1));
   box-shadow: 0 1px 0 hsla(0,0%,100%,.3) inset,
               0 0 0 1px hsla(0,0%,100%,.3) inset,
               0 0 0 1px hsla(210,54%,20%,.25),
               0 1px 0 hsla(210,54%,20%,.35);
-  -moz-transition-property: background-color, box-shadow;
-  -moz-transition-duration: 250ms;
+  transition-property: background-color, box-shadow;
+  transition-duration: 250ms;
 }
 
 @conditionalForwardWithUrlbar@ > #back-button:not([disabled="true"]):not([open="true"]):not(:active):hover > .toolbarbutton-icon {
   background-color: hsla(210,48%,96%,.75);
   box-shadow: 0 1px 0 hsla(0,0%,100%,.3) inset,
               0 0 0 1px hsla(0,0%,100%,.3) inset,
               0 0 0 1px hsla(210,54%,20%,.3),
               0 1px 0 hsla(210,54%,20%,.4),
@@ -913,23 +913,23 @@ toolbar[mode=full] .toolbarbutton-1 > .t
 
 @conditionalForwardWithUrlbar@ > #back-button:not([disabled="true"]):hover:active > .toolbarbutton-icon,
 @conditionalForwardWithUrlbar@ > #back-button[open="true"] > .toolbarbutton-icon {
   background-color: hsla(210,54%,20%,.15);
   box-shadow: 0 1px 1px hsla(210,54%,20%,.1) inset,
               0 0 1px hsla(210,54%,20%,.2) inset,
               0 0 0 1px hsla(210,54%,20%,.4),
               0 1px 0 hsla(210,54%,20%,.2);
-  -moz-transition: none;
+  transition: none;
 }
 
 @conditionalForwardWithUrlbar@ > #back-button[disabled] > .toolbarbutton-icon {
   box-shadow: 0 0 0 1px hsla(210,54%,20%,.55),
               0 1px 0 hsla(210,54%,20%,.65);
-  -moz-transition: none;
+  transition: none;
 }
 
 .unified-nav-back[_moz-menuactive]:-moz-locale-dir(ltr),
 .unified-nav-forward[_moz-menuactive]:-moz-locale-dir(rtl) {
   list-style-image: url("chrome://browser/skin/menu-back.png") !important;
 }
 
 .unified-nav-forward[_moz-menuactive]:-moz-locale-dir(ltr),
@@ -1197,17 +1197,17 @@ toolbar[mode=full] .toolbarbutton-1 > .t
 
 @conditionalForwardWithUrlbar@ + #urlbar-container > #urlbar {
   -moz-border-start: none;
   margin-left: 0;
   pointer-events: all;
 }
 
 @conditionalForwardWithUrlbar@:not([switchingtabs]) + #urlbar-container > #urlbar {
-  -moz-transition: margin-left @forwardTransitionLength@ ease-out;
+  transition: margin-left @forwardTransitionLength@ ease-out;
 }
 
 @conditionalForwardWithUrlbar@ + #urlbar-container > #urlbar:-moz-locale-dir(ltr) {
   border-top-left-radius: 0;
   border-bottom-left-radius: 0;
 }
 
 @conditionalForwardWithUrlbar@ + #urlbar-container > #urlbar:-moz-locale-dir(rtl) {
@@ -1220,17 +1220,17 @@ toolbar[mode=full] .toolbarbutton-1 > .t
 }
 
 @conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container > #urlbar {
   margin-left: -@conditionalForwardWithUrlbarWidth@px;
 }
 
 @conditionalForwardWithUrlbar@[forwarddisabled]:hover:not([switchingtabs]) + #urlbar-container > #urlbar {
   /* delay the hiding of the forward button when hovered to avoid accidental clicks on the url bar */
-  -moz-transition-delay: 100s;
+  transition-delay: 100s;
 }
 
 @conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) + #urlbar-container > #urlbar {
   /* when not hovered anymore, trigger a new transition to hide the forward button immediately */
   margin-left: -@conditionalForwardWithUrlbarWidth@.01px;
 }
 
 @conditionalForwardWithUrlbar@ + #urlbar-container:-moz-locale-dir(rtl),
@@ -1336,27 +1336,27 @@ html|*.urlbar-input:-moz-lwtheme:-moz-pl
 }
 
 @conditionalForwardWithUrlbar@ + #urlbar-container > #urlbar > #identity-box {
   border-radius: 0;
 }
 
 @conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr) {
   padding-left: 5px;
-  -moz-transition: padding-left;
+  transition: padding-left;
 }
 
 @conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) {
   padding-right: 5px;
-  -moz-transition: padding-right;
+  transition: padding-right;
 }
 
 @conditionalForwardWithUrlbar@[forwarddisabled]:hover:not([switchingtabs]) + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box {
   /* forward button hiding is delayed when hovered */
-  -moz-transition-delay: 100s;
+  transition-delay: 100s;
 }
 
 @conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr) {
   /* when not hovered anymore, trigger a new non-delayed transition to react to the forward button hiding */
   padding-left: 5.01px;
 }
 
 @conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) {
@@ -1960,22 +1960,22 @@ richlistitem[type~="action"][actiontype=
 }
 
 .tabbrowser-arrowscrollbox > .scrollbutton-up:-moz-locale-dir(rtl),
 .tabbrowser-arrowscrollbox > .scrollbutton-down:-moz-locale-dir(ltr) {
   -moz-transform: scaleX(-1);
 }
 
 .tabbrowser-arrowscrollbox > .scrollbutton-down {
-  -moz-transition: 1s background-color ease-out;
+  transition: 1s background-color ease-out;
 }
 
 .tabbrowser-arrowscrollbox > .scrollbutton-down[notifybgtab] {
   background-color: Highlight;
-  -moz-transition: none;
+  transition: none;
 }
 
 .tabbrowser-arrowscrollbox > .scrollbutton-up:not([disabled]),
 .tabbrowser-arrowscrollbox > .scrollbutton-down:not([disabled]) {
   border-width: 0 2px 0 0;
   border-style: solid;
   -moz-border-image: url("chrome://browser/skin/tabbrowser/tab-overflow-border.png") 0 2 0 2 fill;
 }
--- a/browser/themes/winstripe/devtools/common.css
+++ b/browser/themes/winstripe/devtools/common.css
@@ -87,19 +87,19 @@
   background-color: transparent;
   background-image: url(magnifying-glass.png), -moz-linear-gradient(hsla(210,16%,76%,.15), hsla(210,16%,76%,.35));
   background-repeat: no-repeat;
   background-position: 4px center, top left, top left;
   padding-top: 0;
   padding-bottom: 0;
   -moz-padding-start: 18px;
   -moz-padding-end: 12px;
-  -moz-transition-property: background-color, border-color, box-shadow;
-  -moz-transition-duration: 150ms;
-  -moz-transition-timing-function: ease;
+  transition-property: background-color, border-color, box-shadow;
+  transition-duration: 150ms;
+  transition-timing-function: ease;
   color: inherit;
 }
 
 .devtools-searchinput[focused] {
   border-color: hsl(200,70%,40%) hsl(200,75%,37%) hsl(200,80%,35%);
   background-origin: padding-box;
   background-clip: padding-box;
   box-shadow: inset 0 0 0 1px hsla(211,68%,6%,.1);
--- a/browser/themes/winstripe/devtools/debugger.css
+++ b/browser/themes/winstripe/devtools/debugger.css
@@ -98,27 +98,27 @@
  */
 
 .variable {
   -moz-margin-start: 1px;
   -moz-margin-end: 1px;
   margin-top: 2px;
   border-bottom: 1px dotted #ddd;
   border-radius: 8px;
-  -moz-transition: background 1s ease-in-out;
+  transition: background 1s ease-in-out;
   background: #fff;
 }
 
 .variable[changed] {
-  -moz-transition-duration: 0.4s;
+  transition-duration: 0.4s;
   background: rgba(255, 255, 0, 0.65);
 }
 
 .variable[added] {
-  -moz-transition-duration: 0.4s;
+  transition-duration: 0.4s;
   background: rgba(0, 255, 0, 0.15);
 }
 
 .variable > .title > .arrow {
   margin-top: -2px;
 }
 
 .variable > .title > .name {
--- a/browser/themes/winstripe/devtools/gcli.css
+++ b/browser/themes/winstripe/devtools/gcli.css
@@ -124,8 +124,13 @@
   color: hsl(25,78%,50%);
 }
 
 .gcli-menu-more {
   font-size: 80%;
   text-align: right;
   -moz-padding-end: 8px;
 }
+
+.gcli-addon-disabled {
+  opacity: 0.6;
+  text-decoration: line-through;
+}
--- a/browser/themes/winstripe/devtools/webconsole.css
+++ b/browser/themes/winstripe/devtools/webconsole.css
@@ -3,17 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 .hud-box {
   border-bottom: 1px solid #aaa;
   text-shadow: none;
 }
 
 .hud-box.animated {
-  -moz-transition: height 100ms;
+  transition: height 100ms;
 }
 
 .hud-splitter {
   border-top: none;
 }
 
 .hud-outer-wrapper {
   width: 100%;
@@ -200,16 +200,25 @@
 .webconsole-msg-console.webconsole-msg-warn {
   -moz-image-region: rect(24px, 24px, 32px, 16px);
 }
 
 .webconsole-msg-console.webconsole-msg-info {
   -moz-image-region: rect(24px, 32px, 32px, 24px);
 }
 
+.webconsole-mixed-content {
+  color: #FF0000;
+}
+
+.webconsole-mixed-content-link {
+  color: #0000EE;
+  margin: 0;
+}
+
 /* Input and output styles */
 .webconsole-msg-input > .webconsole-msg-icon-container,
 .webconsole-msg-output > .webconsole-msg-icon-container {
   border-left: solid #808080 6px;
 }
 
 .webconsole-msg-input {
   -moz-image-region: rect(24px, 40px, 32px, 32px);
--- a/browser/themes/winstripe/downloads/downloads.css
+++ b/browser/themes/winstripe/downloads/downloads.css
@@ -25,17 +25,17 @@
 #downloadsListBox {
   width: 60ch;
   background-color: transparent;
   padding: 4px;
   color: inherit;
 }
 
 #downloadsHistory {
-  background: inherit;
+  background: transparent;
   color: -moz-nativehyperlinktext;
   cursor: pointer;
 }
 
 #downloadsHistory > .button-box {
   margin: 1em;
 }
 
--- a/browser/themes/winstripe/newtab/newTab.css
+++ b/browser/themes/winstripe/newtab/newTab.css
@@ -39,17 +39,17 @@
 
 /* CELLS */
 .newtab-cell {
   -moz-margin-end: 20px;
   background-color: rgba(255,255,255,.2);
   border: 1px solid;
   border-color: rgba(8,22,37,.12) rgba(8,22,37,.14) rgba(8,22,37,.16);
   border-radius: 1px;
-  -moz-transition: border-color 100ms ease-out;
+  transition: border-color 100ms ease-out;
 }
 
 .newtab-cell:empty {
   border: 1px dashed;
   border-color: rgba(8,22,37,.15) rgba(8,22,37,.17) rgba(8,22,37,.19);
 }
 
 .newtab-cell:last-child {
@@ -58,26 +58,26 @@
 
 .newtab-cell:hover:not(:empty):not([dragged]) {
   border-color: rgba(8,22,37,.25) rgba(8,22,37,.27) rgba(8,22,37,.3);
 }
 
 /* SITES */
 .newtab-site {
   text-decoration: none;
-  -moz-transition-property: top, left, opacity, box-shadow, background-color;
+  transition-property: top, left, opacity, box-shadow, background-color;
 }
 
 .newtab-site:hover,
 .newtab-site[dragged] {
   box-shadow: 0 0 10px rgba(8,22,37,.3);
 }
 
 .newtab-site[dragged] {
-  -moz-transition-property: box-shadow, background-color;
+  transition-property: box-shadow, background-color;
   background-color: rgb(242,242,242);
 }
 
 /* THUMBNAILS */
 .newtab-thumbnail {
   background-origin: padding-box;
   background-clip: padding-box;
   background-repeat: no-repeat;
--- a/browser/themes/winstripe/tabview/tabview.css
+++ b/browser/themes/winstripe/tabview/tabview.css
@@ -103,33 +103,33 @@ html[dir=rtl] .close {
 }
 
 .expander {
   bottom: 6px;
   right: 6px;
   width: 16px;
   height: 16px;
   background: url(chrome://global/skin/icons/resizer.png) no-repeat;
-  -moz-transition-property: opacity;
-  -moz-transition-duration: 0.5s;
-  -moz-transition-timing-function: ease-out;
+  transition-property: opacity;
+  transition-duration: 0.5s;
+  transition-timing-function: ease-out;
   opacity: 0.2;
 }
 
 html[dir=rtl] .expander {
   right: auto;
   left: 6px;
   -moz-transform: scaleX(-1);
 }
 
 .expander:hover,
 .appTabIcon:hover {
-  -moz-transition-property: opacity;
-  -moz-transition-duration: 0.5s;
-  -moz-transition-timing-function: ease-out;
+  transition-property: opacity;
+  transition-duration: 0.5s;
+  transition-timing-function: ease-out;
   opacity: 1.0;
 }
 
 .favicon img:hover, 
 .close img:hover, 
 .expander img:hover {
   opacity: 1;
   border: none;
new file mode 100644
--- /dev/null
+++ b/build/autoconf/zlib.m4
@@ -0,0 +1,54 @@
+dnl This Source Code Form is subject to the terms of the Mozilla Public
+dnl License, v. 2.0. If a copy of the MPL was not distributed with this
+dnl file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+dnl Usage: MOZ_ZLIB_CHECK([version])
+
+AC_DEFUN([MOZ_ZLIB_CHECK],
+[
+
+MOZZLIB=$1
+
+MOZ_ARG_WITH_STRING(system-zlib,
+[  --with-system-zlib[=PFX]
+                          Use system libz [installed at prefix PFX]],
+    ZLIB_DIR=$withval)
+
+if test -z "$MOZ_ZLIB_LIBS$MOZ_ZLIB_CFLAGS$SKIP_LIBRARY_CHECKS"; then
+    _SAVE_CFLAGS=$CFLAGS
+    _SAVE_LDFLAGS=$LDFLAGS
+    _SAVE_LIBS=$LIBS
+
+    if test -n "${ZLIB_DIR}" -a "${ZLIB_DIR}" != "yes"; then
+        MOZ_ZLIB_CFLAGS="-I${ZLIB_DIR}/include"
+        MOZ_ZLIB_LIBS="-L${ZLIB_DIR}/lib"
+        CFLAGS="$MOZ_ZLIB_CFLAGS $CFLAGS"
+        LDFLAGS="$MOZ_ZLIB_LIBS $LDFLAGS"
+    fi
+    if test -z "$ZLIB_DIR" -o "$ZLIB_DIR" = no; then
+        MOZ_NATIVE_ZLIB=
+    else
+        AC_CHECK_LIB(z, gzread, [MOZ_NATIVE_ZLIB=1 MOZ_ZLIB_LIBS="$MOZ_ZLIB_LIBS -lz"],
+            [MOZ_NATIVE_ZLIB=])
+        if test "$MOZ_NATIVE_ZLIB" = 1; then
+            MOZZLIBNUM=`echo $MOZZLIB | awk -F. changequote(<<, >>)'{printf "0x%x\n", (((<<$>>1 * 16 + <<$>>2) * 16) + <<$>>3) * 16 + <<$>>4}'changequote([, ])`
+            AC_TRY_COMPILE([ #include <stdio.h>
+                             #include <string.h>
+                             #include <zlib.h> ],
+                           [ #if ZLIB_VERNUM < $MOZZLIBNUM
+                             #error "Insufficient zlib version ($MOZZLIBNUM required)."
+                             #endif ],
+                           MOZ_NATIVE_ZLIB=1,
+                           AC_MSG_ERROR([Insufficient zlib version for --with-system-zlib ($MOZZLIB required)]))
+        fi
+    fi
+    CFLAGS=$_SAVE_CFLAGS
+    LDFLAGS=$_SAVE_LDFLAGS
+    LIBS=$_SAVE_LIBS
+fi
+
+AC_SUBST(MOZ_ZLIB_CFLAGS)
+AC_SUBST(MOZ_ZLIB_LIBS)
+AC_SUBST(MOZ_NATIVE_ZLIB)
+
+])
--- a/build/automationutils.py
+++ b/build/automationutils.py
@@ -453,27 +453,25 @@ class ShutdownLeakLogger(object):
       self.seenShutdown = True
 
   def parse(self):
     leakingTests = self._parseLeakingTests()
 
     if leakingTests:
       totalWindows = sum(len(test["leakedWindows"]) for test in leakingTests)
       totalDocShells = sum(len(test["leakedDocShells"]) for test in leakingTests)
-      msgType = "INFO" if totalWindows + totalDocShells <= self.MAX_LEAK_COUNT else "UNEXPECTED-FAIL"
-      self.logger.info("TEST-%s | ShutdownLeaks | leaked %d DOMWindow(s) and %d DocShell(s) until shutdown", msgType, totalWindows, totalDocShells)
+      msgType = "TEST-INFO" if totalWindows + totalDocShells <= self.MAX_LEAK_COUNT else "TEST-UNEXPECTED-FAIL"
+      self.logger.info("%s | ShutdownLeaks | leaked %d DOMWindow(s) and %d DocShell(s) until shutdown", msgType, totalWindows, totalDocShells)
 
     for test in leakingTests:
-      self.logger.info("\n[%s]", test["fileName"])
-
       for url, count in self._zipLeakedWindows(test["leakedWindows"]):
-        self.logger.info("  %d window(s) [url = %s]", count, url)
+        self.logger.info("%s | %s | leaked %d window(s) until shutdown [url = %s]", msgType, test["fileName"], count, url)
 
       if test["leakedDocShells"]:
-        self.logger.info("  %d docShell(s)", len(test["leakedDocShells"]))
+        self.logger.info("%s | %s | leaked %d docShell(s) until shutdown", msgType, test["fileName"], len(test["leakedDocShells"]))
 
   def _logWindow(self, line):
     created = line[:2] == "++"
     id = self._parseValue(line, "serial")
 
     # log line has invalid format
     if not id:
       return
--- a/build/mobile/b2gautomation.py
+++ b/build/mobile/b2gautomation.py
@@ -82,16 +82,21 @@ class B2GRemoteAutomation(Automation):
         dumpDir = tempfile.mkdtemp()
         self._devicemanager.getDirectory(self._remoteProfile + '/minidumps/', dumpDir)
         automationutils.checkForCrashes(dumpDir, symbolsPath, self.lastTestSeen)
         try:
           shutil.rmtree(dumpDir)
         except:
           print "WARNING: unable to remove directory: %s" % (dumpDir)
 
+    def initializeProfile(self, profileDir, extraPrefs = [], useServerLocations = False):
+        # add b2g specific prefs
+        extraPrefs.extend(["browser.manifestURL='dummy (bug 772307)'"])
+        return Automation.initializeProfile(self, profileDir, extraPrefs, useServerLocations)
+
     def buildCommandLine(self, app, debuggerInfo, profileDir, testURL, extraArgs):
         # if remote profile is specified, use that instead
         if (self._remoteProfile):
             profileDir = self._remoteProfile
 
         cmd, args = Automation.buildCommandLine(self, app, debuggerInfo, profileDir, testURL, extraArgs)
 
         return app, args
--- a/build/mobile/devicemanagerADB.py
+++ b/build/mobile/devicemanagerADB.py
@@ -7,29 +7,29 @@ from devicemanager import DeviceManager,
 import re
 import os
 import sys
 import tempfile
 
 class DeviceManagerADB(DeviceManager):
 
   def __init__(self, host=None, port=20701, retrylimit=5, packageName='fennec',
-               adbPath='adb', deviceSerial=None):
+               adbPath='adb', deviceSerial=None, deviceRoot=None):
     self.host = host
     self.port = port
     self.retrylimit = retrylimit
     self.retries = 0
     self._sock = None
     self.useRunAs = False
     self.haveRoot = False
     self.useDDCopy = False
     self.useZip = False
     self.packageName = None
     self.tempDir = None
-    self.deviceRoot = None
+    self.deviceRoot = deviceRoot
 
     # the path to adb, or 'adb' to assume that it's on the PATH
     self.adbPath = adbPath
 
     # The serial number of the device to use with adb, used in cases
     # where multiple devices are being managed by the same adb instance.
     self.deviceSerial = deviceSerial
 
@@ -532,16 +532,23 @@ class DeviceManagerADB(DeviceManager):
     return data.split()[3]
 
   def getLocalHash(self, filename):
     data = p = subprocess.Popen(["ls", "-l", filename], stdout=subprocess.PIPE).stdout.read()
     return data.split()[4]
 
   # Internal method to setup the device root and cache its value
   def setupDeviceRoot(self):
+    # if self.deviceRoot is already set, create it if necessary, and use it
+    if self.deviceRoot:
+      if not self.dirExists(self.deviceRoot):
+        if not self.mkDir(self.deviceRoot):
+          raise DMError("Unable to create device root %s" % self.deviceRoot)
+      return
+
     # /mnt/sdcard/tests is preferred to /data/local/tests, but this can be
     # over-ridden by creating /data/local/tests
     testRoot = "/data/local/tests"
     if (self.dirExists(testRoot)):
       self.deviceRoot = testRoot
       return
 
     for (basePath, subPath) in [('/mnt/sdcard', 'tests'),
--- a/build/mobile/devicemanagerSUT.py
+++ b/build/mobile/devicemanagerSUT.py
@@ -30,45 +30,42 @@ class DeviceManagerSUT(DeviceManager):
   port = 0
   debug = 2 
   retries = 0
   tempRoot = os.getcwd()
   base_prompt = '$>'
   base_prompt_re = '\$\>'
   prompt_sep = '\x00'
   prompt_regex = '.*(' + base_prompt_re + prompt_sep + ')'
-  agentErrorRE = re.compile('^##AGENT-WARNING##.*')
+  agentErrorRE = re.compile('^##AGENT-WARNING##\ ?(.*)')
 
   # TODO: member variable to indicate error conditions.
   # This should be set to a standard error from the errno module.
   # So, for example, when an error occurs because of a missing file/directory,
   # before returning, the function would do something like 'self.error = errno.ENOENT'.
   # The error would be set where appropriate--so sendCMD() could set socket errors,
   # pushFile() and other file-related commands could set filesystem errors, etc.
 
-  def __init__(self, host, port = 20701, retrylimit = 5):
+  def __init__(self, host, port = 20701, retrylimit = 5, deviceRoot = None):
     self.host = host
     self.port = port
     self.retrylimit = retrylimit
     self.retries = 0
     self._sock = None
+    self.deviceRoot = deviceRoot
     if self.getDeviceRoot() == None:
         raise BaseException("Failed to connect to SUT Agent and retrieve the device root.")
 
   def _cmdNeedsResponse(self, cmd):
     """ Not all commands need a response from the agent:
-        * if the cmd matches the pushRE then it is the first half of push
-          and therefore we want to wait until the second half before looking
-          for a response
         * rebt obviously doesn't get a response
         * uninstall performs a reboot to ensure starting in a clean state and
           so also doesn't look for a response
     """
-    noResponseCmds = [re.compile('^push .*$'),
-                      re.compile('^rebt'),
+    noResponseCmds = [re.compile('^rebt'),
                       re.compile('^uninst .*$'),
                       re.compile('^pull .*$')]
 
     for c in noResponseCmds:
       if (c.match(cmd)):
         return False
 
     # If the command is not in our list, then it gets a response
@@ -114,53 +111,53 @@ class DeviceManagerSUT(DeviceManager):
                          re.compile('^uninst .*$')]
 
     for c in socketClosingCmds:
       if (c.match(cmd)):
         return True
 
     return False
 
-  def sendCmds(self, cmdlist, outputfile, timeout = None, newline = True):
+  def sendCmds(self, cmdlist, outputfile, timeout = None):
     '''
     a wrapper for _doCmds that loops up to self.retrylimit iterations.
     this allows us to move the retry logic outside of the _doCmds() to make it
     easier for debugging in the future.
     note that since cmdlist is a list of commands, they will all be retried if
     one fails.  this is necessary in particular for pushFile(), where we don't want
     to accidentally send extra data if a failure occurs during data transmission.
     '''
     done = False
     while self.retries < self.retrylimit:
       try:
-        self._doCmds(cmdlist, outputfile, timeout, newline)
+        self._doCmds(cmdlist, outputfile, timeout)
         return
       except AgentError, err:
         # re-raise error if it's fatal (i.e. the device got the command but
         # couldn't execute it). retry otherwise
         if err.fatal:
           raise err
         if self.debug >= 2:
           print err
         self.retries += 1
 
     raise AgentError("unable to connect to %s after %s attempts" % (self.host, self.retrylimit))
 
-  def runCmds(self, cmdlist, timeout = None, newline = True):
+  def runCmds(self, cmdlist, timeout = None):
     '''
     similar to sendCmds, but just returns any output as a string instead of
     writing to a file. this is normally what you want to call to send a set
     of commands to the agent
     '''
     outputfile = StringIO.StringIO()
-    self.sendCmds(cmdlist, outputfile, timeout, newline)
+    self.sendCmds(cmdlist, outputfile, timeout)
     outputfile.seek(0)
     return outputfile.read()
 
-  def _doCmds(self, cmdlist, outputfile, timeout, newline):
+  def _doCmds(self, cmdlist, outputfile, timeout):
     promptre = re.compile(self.prompt_regex + '$')
     shouldCloseSocket = False
     recvGuard = 1000
 
     if not self._sock:
       try:
         if self.debug >= 1:
           print "reconnecting socket"
@@ -173,59 +170,67 @@ class DeviceManagerSUT(DeviceManager):
         self._sock.connect((self.host, int(self.port)))
         self._sock.recv(1024)
       except socket.error, msg:
         self._sock.close()
         self._sock = None
         raise AgentError("unable to connect socket: "+str(msg))
 
     for cmd in cmdlist:
-      if newline: cmd += '\r\n'
+      cmdline = '%s\r\n' % cmd['cmd']
 
       try:
-        numbytes = self._sock.send(cmd)
-        if (numbytes != len(cmd)):
-          raise AgentError("ERROR: our cmd was %s bytes and we only sent %s" % (len(cmd),
-                                                                                numbytes))
-        if (self.debug >= 4): print "send cmd: " + str(cmd)
+        sent = self._sock.send(cmdline)
+        if sent != len(cmdline):
+          raise AgentError("ERROR: our cmd was %s bytes and we "
+                           "only sent %s" % (len(cmdline), sent))
+        if cmd.get('data'):
+          sent = self._sock.send(cmd['data'])
+          if sent != len(cmd['data']):
+              raise AgentError("ERROR: we had %s bytes of data to send, but "
+                               "only sent %s" % (len(cmd['data'], sent)))
+
+        if (self.debug >= 4): print "sent cmd: " + str(cmd['cmd'])
       except socket.error, msg:
         self._sock.close()
         self._sock = None
         if self.debug >= 1:
-          print "Error sending data to socket. cmd="+str(cmd)+"; err="+str(msg)
+          print "Error sending data to socket. cmd="+str(cmd['cmd'])+"; err="+str(msg)
         return False
 
       # Check if the command should close the socket
-      shouldCloseSocket = self._shouldCmdCloseSocket(cmd)
+      shouldCloseSocket = self._shouldCmdCloseSocket(cmd['cmd'])
 
       # Handle responses from commands
-      if (self._cmdNeedsResponse(cmd)):
+      if (self._cmdNeedsResponse(cmd['cmd'])):
         found = False
         loopguard = 0
         data = ""
 
         while (found == False and (loopguard < recvGuard)):
           temp = ''
           if (self.debug >= 4): print "recv'ing..."
 
           # Get our response
           try:
             temp = self._sock.recv(1024)
             if (self.debug >= 4): print "response: " + str(temp)
           except socket.error, msg:
             self._sock.close()
             self._sock = None
-            raise AgentError("Error receiving data from socket. cmd="+str(cmd)+"; err="+str(msg))
+            raise AgentError("Error receiving data from socket. cmd="+str(cmd['cmd'])+"; err="+str(msg))
 
           data += temp
 
           # If something goes wrong in the agent it will send back a string that
-          # starts with '##AGENT-ERROR##'
-          if self.agentErrorRE.match(data):
-            raise AgentError("Agent Error processing command: %s" % cmd, fatal=True)
+          # starts with '##AGENT-WARNING##'
+          errorMatch = self.agentErrorRE.match(data)
+          if errorMatch:
+            raise AgentError("Agent Error processing command '%s'; err='%s'" %
+                             (cmd['cmd'], errorMatch.group(1)), fatal=True)
 
           for line in data.splitlines():
             if promptre.match(line):
               found = True
               data = self._stripPrompt(data)
               break
 
           # periodically flush data to output file to make sure it doesn't get
@@ -256,19 +261,19 @@ class DeviceManagerSUT(DeviceManager):
   # failure: None
   def shell(self, cmd, outputfile, env=None, cwd=None):
     cmdline = subprocess.list2cmdline(cmd)
     if env:
       cmdline = '%s %s' % (self.formatEnvString(env), cmdline)
 
     try:
       if cwd:
-        self.sendCmds(['execcwd %s %s' % (cwd, cmdline)], outputfile)
+        self.sendCmds([{ 'cmd': 'execcwd %s %s' % (cwd, cmdline) }], outputfile)
       else:
-        self.sendCmds(['exec su -c "%s"' % cmdline], outputfile)
+        self.sendCmds([{ 'cmd': 'exec su -c "%s"' % cmdline }], outputfile)
     except AgentError:
       return None
 
     # dig through the output to get the return code
     lastline = _pop_last_line(outputfile)
     if lastline:
       m = re.search('return code \[([0-9]+)\]', lastline)
       if m:
@@ -301,19 +306,21 @@ class DeviceManagerSUT(DeviceManager):
     if (self.debug >= 3): print "sending: push " + destname
     
     filesize = os.path.getsize(localname)
     f = open(localname, 'rb')
     data = f.read()
     f.close()
 
     try:
-      retVal = self.runCmds(['push ' + destname + ' ' + str(filesize) + '\r\n', data], newline = False)
-    except AgentError:
-      retVal = False
+      retVal = self.runCmds([{ 'cmd': 'push ' + destname + ' ' + str(filesize),
+                               'data': data }])
+    except AgentError, e:
+      print "error pushing file: %s" % e.msg
+      return False
   
     if (self.debug >= 3): print "push returned: " + str(retVal)
 
     validated = False
     if (retVal):
       retline = retVal.strip()
       if (retline == None):
         # Then we failed to get back a hash from agent, try manual validation
@@ -338,17 +345,17 @@ class DeviceManagerSUT(DeviceManager):
   # returns:
   #  success: directory name
   #  failure: None
   def mkDir(self, name):
     if (self.dirExists(name)):
       return name
     else:
       try:
-        retVal = self.runCmds(['mkdr ' + name])
+        retVal = self.runCmds([{ 'cmd': 'mkdr ' + name }])
       except AgentError:
         retVal = None
       return retVal
 
   # make directory structure on the device
   # external function
   # returns:
   #  success: directory structure that we created
@@ -391,17 +398,17 @@ class DeviceManagerSUT(DeviceManager):
   # external function
   # returns:
   #  success: True
   #  failure: False
   def dirExists(self, dirname):
     match = ".*" + dirname.replace('^', '\^') + "$"
     dirre = re.compile(match)
     try:
-      data = self.runCmds(['cd ' + dirname, 'cwd'])
+      data = self.runCmds([ { 'cmd': 'cd ' + dirname }, { 'cmd': 'cwd' }])
     except AgentError:
       return False
 
     found = False
     for d in data.splitlines():
       if (dirre.match(d)):
         found = True
 
@@ -427,59 +434,59 @@ class DeviceManagerSUT(DeviceManager):
   # returns:
   #  success: array of filenames, ['file1', 'file2', ...]
   #  failure: []
   def listFiles(self, rootdir):
     rootdir = rootdir.rstrip('/')
     if (self.dirExists(rootdir) == False):
       return []
     try:
-      data = self.runCmds(['cd ' + rootdir, 'ls'])
+      data = self.runCmds([{ 'cmd': 'cd ' + rootdir }, { 'cmd': 'ls' }])
     except AgentError:
       return []
 
     files = filter(lambda x: x, data.splitlines())
     if len(files) == 1 and files[0] == '<empty>':
       # special case on the agent: empty directories return just the string "<empty>"
       return []
     return files
 
   # external function
   # returns:
   #  success: output of telnet, i.e. "removing file: /mnt/sdcard/tests/test.txt"
   #  failure: None
   def removeFile(self, filename):
     if (self.debug>= 2): print "removing file: " + filename
     try:
-      retVal = self.runCmds(['rm ' + filename])
+      retVal = self.runCmds([{ 'cmd': 'rm ' + filename }])
     except AgentError:
       return None
 
     return retVal
   
   # does a recursive delete of directory on the device: rm -Rf remoteDir
   # external function
   # returns:
   #  success: output of telnet, i.e. "removing file: /mnt/sdcard/tests/test.txt"
   #  failure: None
   def removeDir(self, remoteDir):
     try:
-      retVal = self.runCmds(['rmdr ' + remoteDir])
+      retVal = self.runCmds([{ 'cmd': 'rmdr ' + remoteDir }])
     except AgentError:
       return None
 
     return retVal
 
   # external function
   # returns:
   #  success: array of process tuples
   #  failure: []
   def getProcessList(self):
     try:
-      data = self.runCmds(['ps'])
+      data = self.runCmds([{ 'cmd': 'ps' }])
     except AgentError:
       return []
 
     files = []
     for line in data.splitlines():
       if line:
         pidproc = line.strip().split()
         if (len(pidproc) == 2):
@@ -502,17 +509,17 @@ class DeviceManagerSUT(DeviceManager):
     if (self.debug >= 2): print "FIRE PROC: '" + appname + "'"
 
     if (self.processExist(appname) != None):
       print "WARNING: process %s appears to be running already\n" % appname
       if (failIfRunning):
         return None
     
     try:
-      data = self.runCmds(['exec ' + appname])
+      data = self.runCmds([{ 'cmd': 'exec ' + appname }])
     except AgentError:
       return None
 
     # wait up to 30 seconds for process to start up
     timeslept = 0
     while (timeslept <= 30):
       process = self.processExist(appname)
       if (process is not None):
@@ -551,41 +558,41 @@ class DeviceManagerSUT(DeviceManager):
   # external function
   # returns:
   #  success: True
   #  failure: False
   def killProcess(self, appname, forceKill=False):
     if forceKill:
       print "WARNING: killProcess(): forceKill parameter unsupported on SUT"
     try:
-      data = self.runCmds(['kill ' + appname])
+      data = self.runCmds([{ 'cmd': 'kill ' + appname }])
     except AgentError:
       return False
 
     return True
 
   # external function
   # returns:
   #  success: tmpdir, string
   #  failure: None
   def getTempDir(self):
     try:
-      data = self.runCmds(['tmpd'])
+      data = self.runCmds([{ 'cmd': 'tmpd' }])
     except AgentError:
       return None
 
     return data.strip()
 
   # external function
   # returns:
   #  success: filecontents
   #  failure: None
   def catFile(self, remoteFile):
     try:
-      data = self.runCmds(['cat ' + remoteFile])
+      data = self.runCmds([{ 'cmd': 'cat ' + remoteFile }])
     except AgentError:
       return None
 
     return data
 
   # external function
   # returns:
   #  success: output of pullfile, string
@@ -644,17 +651,17 @@ class DeviceManagerSUT(DeviceManager):
     prompt = self.base_prompt + self.prompt_sep
     buffer = ''
     
     # expected return value:
     # <filename>,<filesize>\n<filedata>
     # or, if error,
     # <filename>,-1\n<error message>
     try:
-      data = self.runCmds(['pull ' + remoteFile])
+      data = self.runCmds([{ 'cmd': 'pull ' + remoteFile }])
     except AgentError:
       return None
 
     # read metadata; buffer the rest
     metadata, sep, buffer = read_until_char('\n', buffer, 'could not find metadata')
     if not metadata:
       return None
     if self.debug >= 3:
@@ -763,17 +770,17 @@ class DeviceManagerSUT(DeviceManager):
 
   # external function
   # returns:
   #  success: True
   #  failure: False
   #  Throws a FileError exception when null (invalid dir/filename)
   def isDir(self, remotePath):
     try:
-      data = self.runCmds(['isdir ' + remotePath])
+      data = self.runCmds([{ 'cmd': 'isdir ' + remotePath }])
     except AgentError:
       # normally there should be no error here; a nonexistent file/directory will
       # return the string "<filename>: No such file or directory".
       # However, I've seen AGENT-WARNING returned before. 
       return False
 
     retVal = data.strip()
     if not retVal:
@@ -799,17 +806,17 @@ class DeviceManagerSUT(DeviceManager):
   
   # return the md5 sum of a remote file
   # internal function
   # returns:
   #  success: MD5 hash for given filename
   #  failure: None
   def getRemoteHash(self, filename):
     try:
-      data = self.runCmds(['hash ' + filename])
+      data = self.runCmds([{ 'cmd': 'hash ' + filename }])
     except AgentError:
       return None
 
     retVal = None
     if data:
       retVal = data.strip()
     if (self.debug >= 3): print "remote hash returned: '" + retVal + "'"
     return retVal
@@ -827,32 +834,36 @@ class DeviceManagerSUT(DeviceManager):
   #       /reftest
   #       /mochitest
   #
   # external function
   # returns:
   #  success: path for device root
   #  failure: None
   def getDeviceRoot(self):
-    try:
-      data = self.runCmds(['testroot'])
-    except:
-      return None
+    if self.deviceRoot:
+      deviceRoot = self.deviceRoot
+    else:
+      try:
+        data = self.runCmds([{ 'cmd': 'testroot' }])
+      except:
+        return None
 
-    deviceRoot = data.strip() + '/tests'
+      deviceRoot = data.strip() + '/tests'
 
     if (not self.dirExists(deviceRoot)):
       if (self.mkDir(deviceRoot) == None):
         return None
 
-    return deviceRoot
+    self.deviceRoot = deviceRoot
+    return self.deviceRoot
 
   def getAppRoot(self, packageName):
     try:
-      data = self.runCmds(['getapproot '+packageName])
+      data = self.runCmds([{ 'cmd': 'getapproot '+packageName }])
     except:
       return None
 
     return data.strip()
 
   # external function
   # returns:
   #  success: output of unzip command
@@ -870,17 +881,17 @@ class DeviceManagerSUT(DeviceManager):
     elif self.fileExists('/' + filename):
       dir = '/' + filename
     elif self.fileExists(devroot + '/' + filename):
       dir = devroot + '/' + filename
     else:
       return None
 
     try:
-      data = self.runCmds(['cd ' + dir, 'unzp ' + filename])
+      data = self.runCmds([{ 'cmd': 'cd ' + dir }, { 'cmd': 'unzp ' + filename }])
     except AgentError:
       return None
 
     return data
 
   # external function
   # returns:
   #  success: status from test agent
@@ -891,27 +902,28 @@ class DeviceManagerSUT(DeviceManager):
     if (self.debug > 3): print "INFO: sending rebt command"
     callbacksvrstatus = None    
 
     if (ipAddr is not None):
     #create update.info file:
       try:
         destname = '/data/data/com.mozilla.SUTAgentAndroid/files/update.info'
         data = "%s,%s\rrebooting\r" % (ipAddr, port)
-        self.runCmds(['push ' + destname + ' ' + str(len(data)) + '\r\n', data], newline = False)
+        self.runCmds([{ 'cmd': 'push %s %s' % (destname, len(data)),
+                        'data': data }])
       except AgentError:
         return None
 
       ip, port = self.getCallbackIpAndPort(ipAddr, port)
       cmd += " %s %s" % (ip, port)
       # Set up our callback server
       callbacksvr = callbackServer(ip, port, self.debug)
 
     try:
-      status = self.runCmds([cmd])
+      status = self.runCmds([{ 'cmd': cmd }])
     except AgentError:
       return None
 
     if (ipAddr is not None):
       status = callbacksvr.disconnect()
 
     if (self.debug > 3): print "INFO: rebt- got status back: " + str(status)
     return status
@@ -938,17 +950,17 @@ class DeviceManagerSUT(DeviceManager):
     collapseSpaces = re.compile('  +')
 
     directives = ['os','id','uptime','systime','screen','rotation','memory','process',
                   'disk','power']
     if (directive in directives):
       directives = [directive]
 
     for d in directives:
-      data = self.runCmds(['info ' + d])
+      data = self.runCmds([{ 'cmd': 'info ' + d }])
       if (data is None):
         continue
       data = collapseSpaces.sub(' ', data)
       result[d] = data.split('\n')
 
     # Get rid of any 0 length members of the arrays
     for k, v in result.iteritems():
       result[k] = filter(lambda x: x != '', result[k])
@@ -975,17 +987,17 @@ class DeviceManagerSUT(DeviceManager):
   # returns:
   #  success: output from agent for inst command
   #  failure: None
   def installApp(self, appBundlePath, destPath=None):
     cmd = 'inst ' + appBundlePath
     if destPath:
       cmd += ' ' + destPath
     try:
-      data = self.runCmds([cmd])
+      data = self.runCmds([{ 'cmd': cmd }])
     except AgentError:
       return None
 
     f = re.compile('Failure')
     for line in data.split():
       if (f.match(line)):
         return data
     return None
@@ -1001,17 +1013,17 @@ class DeviceManagerSUT(DeviceManager):
   # returns:
   #  success: True
   #  failure: None
   def uninstallAppAndReboot(self, appName, installPath=None):
     cmd = 'uninst ' + appName
     if installPath:
       cmd += ' ' + installPath
     try:
-      data = self.runCmds([cmd])
+      data = self.runCmds([{ 'cmd': cmd }])
     except AgentError:
       return None
 
     if (self.debug > 3): print "uninstallAppAndReboot: " + str(data)
     return True
 
   """
   Updates the application on the device.
@@ -1046,17 +1058,17 @@ class DeviceManagerSUT(DeviceManager):
       ip, port = self.getCallbackIpAndPort(ipAddr, port)
       cmd += " %s %s" % (ip, port)
       # Set up our callback server
       callbacksvr = callbackServer(ip, port, self.debug)
 
     if (self.debug >= 3): print "INFO: updateApp using command: " + str(cmd)
 
     try:
-      status = self.runCmds([cmd])
+      status = self.runCmds([{ 'cmd': cmd }])
     except AgentError:
       return None
 
     if ipAddr is not None:
       status = callbacksvr.disconnect()
 
     if (self.debug >= 3): print "INFO: updateApp: got status back: " + str(status)
 
@@ -1066,17 +1078,17 @@ class DeviceManagerSUT(DeviceManager):
     return the current time on the device
   """
   # external function
   # returns:
   #  success: time in ms
   #  failure: None
   def getCurrentTime(self):
     try:
-      data = self.runCmds(['clok'])
+      data = self.runCmds([{ 'cmd': 'clok' }])
     except AgentError:
       return None
 
     return data.strip()
 
   """
     Connect the ipaddress and port for a callback ping.  Defaults to current IP address
     And ports starting at 30000.
@@ -1170,30 +1182,30 @@ class DeviceManagerSUT(DeviceManager):
     if (width < 100 or width > 9999):
       return False
 
     if (height < 100 or height > 9999):
       return False
 
     if (self.debug >= 3): print "INFO: adjusting screen resolution to %s, %s and rebooting" % (width, height)
     try:
-      self.runCmds(["exec setprop persist.tegra.dpy%s.mode.width %s" % (screentype, width)])
-      self.runCmds(["exec setprop persist.tegra.dpy%s.mode.height %s" % (screentype, height)])
+      self.runCmds([{ 'cmd': "exec setprop persist.tegra.dpy%s.mode.width %s" % (screentype, width) }])
+      self.runCmds([{ 'cmd': "exec setprop persist.tegra.dpy%s.mode.height %s" % (screentype, height) }])
     except AgentError:
       return False
 
     return True
 
   # external function
   # returns:
   #  success: True
   #  failure: False
   def chmodDir(self, remoteDir):
     try:
-      self.runCmds(["chmod "+remoteDir])
+      self.runCmds([{ 'cmd': "chmod "+remoteDir }])
     except AgentError:
       return False
     return True
 
 gCallbackData = ''
 
 class myServer(SocketServer.TCPServer):
   allow_reuse_address = True
--- a/build/mobile/sutagent/android/DoCommand.java
+++ b/build/mobile/sutagent/android/DoCommand.java
@@ -78,16 +78,17 @@ import android.content.pm.ServiceInfo;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Build;
 import android.os.Debug;
 import android.os.Environment;
 import android.os.StatFs;
 import android.os.SystemClock;
+import android.text.TextUtils;
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.view.Surface;
 import android.view.WindowManager;
 
 public class DoCommand {
 
     String lineSep = System.getProperty("line.separator");
@@ -3479,17 +3480,17 @@ private void CancelNotification()
 
     public String StartPrg(String [] progArray, OutputStream out)
         {
         String sRet = "";
         int    lcv = 0;
 
         try
             {
-            pProc = Runtime.getRuntime().exec(progArray);
+            pProc = Runtime.getRuntime().exec(this.getSuArgs(TextUtils.join(" ", progArray)));
             RedirOutputThread outThrd = new RedirOutputThread(pProc, out);
             outThrd.start();
             while (lcv < 30) {
                 try {
                     outThrd.join(10000);
                     int nRetCode = pProc.exitValue();
                     sRet = "return code [" + nRetCode + "]";
                     break;
--- a/build/mobile/sutagent/android/SUTAgentAndroid.java
+++ b/build/mobile/sutagent/android/SUTAgentAndroid.java
@@ -28,16 +28,17 @@ import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
 import android.net.Uri;
 import android.net.wifi.SupplicantState;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
 import android.net.wifi.WifiManager.WifiLock;
 import android.os.BatteryManager;
+import android.os.Build.VERSION;
 import android.os.Bundle;
 import android.os.Handler;
 import android.telephony.TelephonyManager;
 import android.util.Log;
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.View;
 import android.view.View.OnClickListener;
@@ -120,35 +121,51 @@ public class SUTAgentAndroid extends Act
         SUTAgentAndroid.Pool = dc.GetIniData("Registration Server", "POOL", sIniFile);
 
         tv = (TextView) this.findViewById(R.id.Textview01);
 
         if (getLocalIpAddress() == null)
             setUpNetwork(sIniFile);
 
         String macAddress = "Unknown";
-        try {
-            NetworkInterface iface = NetworkInterface.getByInetAddress(InetAddress.getAllByName(getLocalIpAddress())[0]);
-            if (iface != null)
-                {
-                    byte[] mac = iface.getHardwareAddress();
-                    if (mac != null)
-                        {
-                            StringBuilder sb = new StringBuilder();
-                            Formatter f = new Formatter(sb);
-                            for (int i = 0; i < mac.length; i++)
-                                {
-                                    f.format("%02x%s", mac[i], (i < mac.length - 1) ? ":" : "");
-                                }
-                            macAddress = sUniqueID = sb.toString();
-                        }
-                }
+        if (android.os.Build.VERSION.SDK_INT > 8) {
+            try {
+                NetworkInterface iface = NetworkInterface.getByInetAddress(InetAddress.getAllByName(getLocalIpAddress())[0]);
+                if (iface != null)
+                    {
+                        byte[] mac = iface.getHardwareAddress();
+                        if (mac != null)
+                            {
+                                StringBuilder sb = new StringBuilder();
+                                Formatter f = new Formatter(sb);
+                                for (int i = 0; i < mac.length; i++)
+                                    {
+                                        f.format("%02x%s", mac[i], (i < mac.length - 1) ? ":" : "");
+                                    }
+                                macAddress = sUniqueID = sb.toString();
+                            }
+                    }
+            }
+            catch (UnknownHostException ex) {}
+            catch (SocketException ex) {}
         }
-        catch (UnknownHostException ex) {}
-        catch (SocketException ex) {}
+        else
+            {
+                // Fall back to getting info from wifiman on older versions of Android,
+                // which don't support the NetworkInterface interface
+                WifiManager wifiMan = (WifiManager)getSystemService(Context.WIFI_SERVICE);
+                if (wifiMan != null)
+                    {
+                        WifiInfo wifi = wifiMan.getConnectionInfo();
+                        if (wifi != null)
+                            macAddress = wifi.getMacAddress();
+                        if (macAddress != null)
+                            sUniqueID = macAddress;
+                    }
+            }
 
         if (sUniqueID == null)
             {
             BluetoothAdapter ba = BluetoothAdapter.getDefaultAdapter();
             if ((ba != null) && (ba.isEnabled() != true))
                 {
                 ba.enable();
                 while(ba.getState() != BluetoothAdapter.STATE_ON)
--- a/build/pymake/pymake/parserdata.py
+++ b/build/pymake/pymake/parserdata.py
@@ -24,17 +24,17 @@ class Location(object):
     def offset(self, s, start, end):
         """
         Returns a new location offset by
         the specified string.
         """
 
         if start == end:
             return self
-        
+
         skiplines = s.count('\n', start, end)
         line = self.line + skiplines
         if skiplines:
             lastnl = s.rfind('\n', start, end)
             assert lastnl != -1
             start = lastnl + 1
             column = 0
         else:
@@ -93,35 +93,53 @@ def parsecommandlineargs(args):
                                      targetexp=None, source=data.Variables.SOURCE_COMMANDLINE))
         else:
             r.append(a)
 
     return stmts, r, ' '.join(overrides)
 
 class Statement(object):
     """
-    A statement is an abstract object representing a single "chunk" of makefile syntax. Subclasses
-    must implement the following method:
+    Represents parsed make file syntax.
 
-    def execute(self, makefile, context)
+    This is an abstract base class. Child classes are expected to implement
+    `execute()`.
     """
 
+    def execute(self, makefile, context):
+        raise Exception("Must implement execute() in child classes.")
+
 class DummyRule(object):
     __slots__ = ()
 
     def addcommand(self, r):
         pass
 
 class Rule(Statement):
+    """
+    Rules represent how to make specific targets.
+
+    See https://www.gnu.org/software/make/manual/make.html#Rules.
+
+    An individual rule is composed of a target, dependencies, and a recipe.
+    This class only contains references to the first 2. The recipe will be
+    contained in Command classes which follow this one in a stream of Statement
+    instances.
+
+    Instances also contain a boolean property `doublecolon` which says whether
+    this is a doublecolon rule. Doublecolon rules are rules that are always
+    executed, if they are evaluated. Normally, rules are only executed if their
+    target is out of date.
+    """
     __slots__ = ('targetexp', 'depexp', 'doublecolon')
 
     def __init__(self, targetexp, depexp, doublecolon):
         assert isinstance(targetexp, (data.Expansion, data.StringExpansion))
         assert isinstance(depexp, (data.Expansion, data.StringExpansion))
-        
+
         self.targetexp = targetexp
         self.depexp = depexp
         self.doublecolon = doublecolon
 
     def execute(self, makefile, context):
         atargets = data.stripdotslashes(self.targetexp.resolvesplit(makefile, makefile.variables))
         targets = [data.Pattern(p) for p in _expandwildcards(makefile, atargets)]
 
@@ -149,16 +167,25 @@ class Rule(Statement):
             makefile.foundtarget(targets[0].gettarget())
 
         context.currule = rule
 
     def dump(self, fd, indent):
         print >>fd, "%sRule %s: %s" % (indent, self.targetexp, self.depexp)
 
 class StaticPatternRule(Statement):
+    """
+    Static pattern rules are rules which specify multiple targets based on a
+    string pattern.
+
+    See https://www.gnu.org/software/make/manual/make.html#Static-Pattern
+
+    They are like `Rule` instances except an added property, `patternexp` is
+    present. It contains the Expansion which represents the rule pattern.
+    """
     __slots__ = ('targetexp', 'patternexp', 'depexp', 'doublecolon')
 
     def __init__(self, targetexp, patternexp, depexp, doublecolon):
         assert isinstance(targetexp, (data.Expansion, data.StringExpansion))
         assert isinstance(patternexp, (data.Expansion, data.StringExpansion))
         assert isinstance(depexp, (data.Expansion, data.StringExpansion))
 
         self.targetexp = targetexp
@@ -195,16 +222,26 @@ class StaticPatternRule(Statement):
 
         makefile.foundtarget(targets[0])
         context.currule = rule
 
     def dump(self, fd, indent):
         print >>fd, "%sStaticPatternRule %s: %s: %s" % (indent, self.targetexp, self.patternexp, self.depexp)
 
 class Command(Statement):
+    """
+    Commands are things that get executed by a rule.
+
+    A rule's recipe is composed of 0 or more Commands.
+
+    A command is simply an expansion. Commands typically represent strings to
+    be executed in a shell (e.g. via system()). Although, since make files
+    allow arbitrary shells to be used for command execution, this isn't a
+    guarantee.
+    """
     __slots__ = ('exp',)
 
     def __init__(self, exp):
         assert isinstance(exp, (data.Expansion, data.StringExpansion))
         self.exp = exp
 
     def execute(self, makefile, context):
         assert context.currule is not None
@@ -212,16 +249,36 @@ class Command(Statement):
             raise data.DataError("rules not allowed in includedeps", self.exp.loc)
 
         context.currule.addcommand(self.exp)
 
     def dump(self, fd, indent):
         print >>fd, "%sCommand %s" % (indent, self.exp,)
 
 class SetVariable(Statement):
+    """
+    Represents a variable assignment.
+
+    Variable assignment comes in two different flavors.
+
+    Simple assignment has the form:
+
+      <Expansion> <Assignment Token> <string>
+
+    e.g. FOO := bar
+
+    These correspond to the fields `vnameexp`, `token`, and `value`. In
+    addition, `valueloc` will be a Location and `source` will be a
+    pymake.data.Variables.SOURCE_* constant.
+
+    There are also target-specific variables. These are variables that only
+    apply in the context of a specific target. They are like the aforementioned
+    assignment except the `targetexp` field is set to an Expansion representing
+    the target they apply to.
+    """
     __slots__ = ('vnameexp', 'token', 'value', 'valueloc', 'targetexp', 'source')
 
     def __init__(self, vnameexp, token, value, valueloc, targetexp, source=None):
         assert isinstance(vnameexp, (data.Expansion, data.StringExpansion))
         assert isinstance(value, str)
         assert targetexp is None or isinstance(targetexp, (data.Expansion, data.StringExpansion))
 
         if source is None:
@@ -275,22 +332,35 @@ class SetVariable(Statement):
 
             v.set(vname, flavor, self.source, value)
 
     def dump(self, fd, indent):
         print >>fd, "%sSetVariable<%s> %s %s\n%s %r" % (indent, self.valueloc, self.vnameexp, self.token, indent, self.value)
 
 class Condition(object):
     """
-    An abstract "condition", either ifeq or ifdef, perhaps negated. Subclasses must implement:
+    An abstract "condition", either ifeq or ifdef, perhaps negated.
+
+    See https://www.gnu.org/software/make/manual/make.html#Conditional-Syntax
+
+    Subclasses must implement:
 
     def evaluate(self, makefile)
     """
 
 class EqCondition(Condition):
+    """
+    Represents an ifeq or ifneq conditional directive.
+
+    This directive consists of two Expansions which are compared for equality.
+
+    The `expected` field is a bool indicating what the condition must evaluate
+    to in order for its body to be executed. If True, this is an "ifeq"
+    conditional directive. If False, an "ifneq."
+    """
     __slots__ = ('exp1', 'exp2', 'expected')
 
     def __init__(self, exp1, exp2):
         assert isinstance(exp1, (data.Expansion, data.StringExpansion))
         assert isinstance(exp2, (data.Expansion, data.StringExpansion))
 
         self.expected = True
         self.exp1 = exp1
@@ -300,16 +370,25 @@ class EqCondition(Condition):
         r1 = self.exp1.resolvestr(makefile, makefile.variables)
         r2 = self.exp2.resolvestr(makefile, makefile.variables)
         return (r1 == r2) == self.expected
 
     def __str__(self):
         return "ifeq (expected=%s) %s %s" % (self.expected, self.exp1, self.exp2)
 
 class IfdefCondition(Condition):
+    """
+    Represents an ifdef or ifndef conditional directive.
+
+    This directive consists of a single expansion which represents the name of
+    a variable (without the leading '$') which will be checked for definition.
+
+    The `expected` field is a bool and has the same behavior as EqCondition.
+    If it is True, this represents a "ifdef" conditional. If False, "ifndef."
+    """
     __slots__ = ('exp', 'expected')
 
     def __init__(self, exp):
         assert isinstance(exp, (data.Expansion, data.StringExpansion))
         self.exp = exp
         self.expected = True
 
     def evaluate(self, makefile):
@@ -320,27 +399,41 @@ class IfdefCondition(Condition):
             return not self.expected
 
         return (len(value) > 0) == self.expected
 
     def __str__(self):
         return "ifdef (expected=%s) %s" % (self.expected, self.exp)
 
 class ElseCondition(Condition):
+    """
+    Represents the transition between branches in a ConditionBlock.
+    """
     __slots__ = ()
 
     def evaluate(self, makefile):
         return True
 
     def __str__(self):
         return "else"
 
 class ConditionBlock(Statement):
     """
-    A list of conditions: each condition has an associated list of statements.
+    A set of related Conditions.
+
+    This is essentially a list of 2-tuples of (Condition, list(Statement)).
+
+    The parser creates a ConditionBlock for all statements related to the same
+    conditional group. If iterating over the parser's output, where you think
+    you would see an ifeq, you will see a ConditionBlock containing an IfEq. In
+    other words, the parser collapses separate statements into this container
+    class.
+
+    ConditionBlock instances may exist within other ConditionBlock if the
+    conditional logic is multiple levels deep.
     """
     __slots__ = ('loc', '_groups')
 
     def __init__(self, loc, condition):
         self.loc = loc
         self._groups = []
         self.addcondition(loc, condition)
 
@@ -384,16 +477,25 @@ class ConditionBlock(Statement):
 
     def __len__(self):
         return len(self._groups)
 
     def __getitem__(self, i):
         return self._groups[i]
 
 class Include(Statement):
+    """
+    Represents the include directive.
+
+    See https://www.gnu.org/software/make/manual/make.html#Include
+
+    The file to be included is represented by the Expansion defined in the
+    field `exp`. `required` is a bool indicating whether execution should fail
+    if the specified file could not be processed.
+    """
     __slots__ = ('exp', 'required', 'deps')
 
     def __init__(self, exp, required, weak):
         assert isinstance(exp, (data.Expansion, data.StringExpansion))
         self.exp = exp
         self.required = required
         self.weak = weak
 
@@ -401,16 +503,21 @@ class Include(Statement):
         files = self.exp.resolvesplit(makefile, makefile.variables)
         for f in files:
             makefile.include(f, self.required, loc=self.exp.loc, weak=self.weak)
 
     def dump(self, fd, indent):
         print >>fd, "%sInclude %s" % (indent, self.exp)
 
 class VPathDirective(Statement):
+    """
+    Represents the vpath directive.
+
+    See https://www.gnu.org/software/make/manual/make.html#Selective-Search
+    """
     __slots__ = ('exp',)
 
     def __init__(self, exp):
         assert isinstance(exp, (data.Expansion, data.StringExpansion))
         self.exp = exp
 
     def execute(self, makefile, context):
         words = list(data.stripdotslashes(self.exp.resolvesplit(makefile, makefile.variables)))
@@ -429,16 +536,28 @@ class VPathDirective(Statement):
                                  if dir != ''))
                 if len(dirs):
<