summaryrefslogtreecommitdiffstats
path: root/browser/app
diff options
context:
space:
mode:
Diffstat (limited to 'browser/app')
-rw-r--r--browser/app/Makefile.in14
-rw-r--r--browser/app/macbuild/Contents/Info.plist.in3
-rw-r--r--browser/app/nmhproxy/Cargo.toml2
-rw-r--r--browser/app/nmhproxy/src/commands.rs162
-rw-r--r--browser/app/nmhproxy/src/main.rs9
-rw-r--r--browser/app/profile/firefox.js85
6 files changed, 225 insertions, 50 deletions
diff --git a/browser/app/Makefile.in b/browser/app/Makefile.in
index 7a09bc2494..08490ba27c 100644
--- a/browser/app/Makefile.in
+++ b/browser/app/Makefile.in
@@ -50,14 +50,17 @@ endif
endif
-# channel-prefs.js is handled separate from other prefs due to bug 756325
+ifneq (cocoa,$(MOZ_WIDGET_TOOLKIT))
+
+# channel-prefs.js has been removed on macOS.
+# channel-prefs.js is handled separately from other prefs due to bug 756325.
# DO NOT change the content of channel-prefs.js without taking the appropriate
# steps. See bug 1431342.
libs:: $(srcdir)/profile/channel-prefs.js
$(NSINSTALL) -D $(DIST)/bin/defaults/pref
$(call py_action,preprocessor channel-prefs.js,-Fsubstitution $(PREF_PPFLAGS) $(ACDEFINES) $^ -o $(DIST)/bin/defaults/pref/channel-prefs.js)
-ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
+else
MAC_APP_NAME = $(MOZ_APP_DISPLAYNAME)
@@ -81,7 +84,7 @@ MAC_BUNDLE_VERSION = $(shell $(PYTHON3) $(srcdir)/macversion.py --version=$(MOZ_
.PHONY: repackage
tools repackage:: $(DIST)/bin/$(MOZ_APP_NAME) $(objdir)/macbuild/Contents/MacOS-files.txt
- rm -rf $(dist_dest)
+ rm -rf '$(dist_dest)'
$(MKDIR) -p '$(dist_dest)/Contents/MacOS'
$(MKDIR) -p '$(dist_dest)/$(LPROJ)'
rsync -a --exclude '*.in' $(srcdir)/macbuild/Contents '$(dist_dest)' --exclude English.lproj
@@ -99,8 +102,9 @@ tools repackage:: $(DIST)/bin/$(MOZ_APP_NAME) $(objdir)/macbuild/Contents/MacOS-
cp -RL $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/document.icns '$(dist_dest)/Contents/Resources/document.icns'
$(MKDIR) -p '$(dist_dest)/Contents/Library/LaunchServices'
ifdef MOZ_UPDATER
- mv -f '$(dist_dest)/Contents/MacOS/updater.app/Contents/MacOS/org.mozilla.updater' '$(dist_dest)/Contents/Library/LaunchServices'
- ln -s ../../../../Library/LaunchServices/org.mozilla.updater '$(dist_dest)/Contents/MacOS/updater.app/Contents/MacOS/org.mozilla.updater'
+ cp -f '$(dist_dest)/Contents/MacOS/updater.app/Contents/MacOS/org.mozilla.updater' '$(dist_dest)/Contents/Library/LaunchServices'
endif
+ $(MKDIR) -p '$(dist_dest)/Contents/Frameworks'
+ mv '$(dist_dest)/Contents/Resources/ChannelPrefs.framework' '$(dist_dest)/Contents/Frameworks'
printf APPLMOZB > '$(dist_dest)/Contents/PkgInfo'
endif
diff --git a/browser/app/macbuild/Contents/Info.plist.in b/browser/app/macbuild/Contents/Info.plist.in
index 48fc32199b..53a3d0f7ea 100644
--- a/browser/app/macbuild/Contents/Info.plist.in
+++ b/browser/app/macbuild/Contents/Info.plist.in
@@ -291,5 +291,8 @@
<key>NSMicrophoneUsageDescription</key>
<string>Only sites you allow within @MAC_APP_NAME@ will be able to use the microphone.</string>
+
+ <key>NSCameraReactionEffectGesturesEnabledDefault</key>
+ <false/>
</dict>
</plist>
diff --git a/browser/app/nmhproxy/Cargo.toml b/browser/app/nmhproxy/Cargo.toml
index 14746d51b6..d432773293 100644
--- a/browser/app/nmhproxy/Cargo.toml
+++ b/browser/app/nmhproxy/Cargo.toml
@@ -10,8 +10,10 @@ name = "nmhproxy"
path = "src/main.rs"
[dependencies]
+dirs = "4"
mozbuild = "0.1"
mozilla-central-workspace-hack = { version = "0.1", features = ["nmhproxy"], optional = true }
serde = { version = "1", features = ["derive", "rc"] }
serde_json = "1.0"
+tempfile = "3"
url = "2.4"
diff --git a/browser/app/nmhproxy/src/commands.rs b/browser/app/nmhproxy/src/commands.rs
index 29c86a0dd7..b26180e8f8 100644
--- a/browser/app/nmhproxy/src/commands.rs
+++ b/browser/app/nmhproxy/src/commands.rs
@@ -4,6 +4,7 @@
use serde::{Deserialize, Serialize};
use std::io::{self, Read, Write};
+use std::path::PathBuf;
use std::process::Command;
use url::Url;
@@ -23,6 +24,7 @@ pub enum FirefoxCommand {
LaunchFirefox { url: String },
LaunchFirefoxPrivate { url: String },
GetVersion {},
+ GetInstallId {},
}
#[derive(Serialize, Deserialize)]
// {
@@ -34,6 +36,14 @@ pub struct Response {
pub result_code: u32,
}
+#[derive(Serialize, Deserialize)]
+// {
+// "installation_id": "123ABC456",
+// }
+pub struct InstallationId {
+ pub installation_id: String,
+}
+
#[repr(u32)]
pub enum ResultCode {
Success = 0,
@@ -152,6 +162,28 @@ pub fn process_command(command: &FirefoxCommand) -> std::io::Result<bool> {
Ok(true)
}
FirefoxCommand::GetVersion {} => generate_response("1", ResultCode::Success.into()),
+ FirefoxCommand::GetInstallId {} => {
+ // config_dir() evaluates to ~/Library/Application Support on macOS
+ // and %RoamingAppData% on Windows.
+ let mut json_path = match dirs::config_dir() {
+ Some(path) => path,
+ None => {
+ return generate_response(
+ "Config dir could not be found",
+ ResultCode::Error.into(),
+ )
+ }
+ };
+ #[cfg(target_os = "windows")]
+ json_path.push("Mozilla\\Firefox");
+ #[cfg(target_os = "macos")]
+ json_path.push("Firefox");
+
+ json_path.push("install_id");
+ json_path.set_extension("json");
+ let mut install_id = String::new();
+ get_install_id(&mut json_path, &mut install_id)
+ }
}
}
@@ -228,10 +260,54 @@ fn launch_firefox<C: CommandRunner>(
command.to_string()
}
+fn get_install_id(json_path: &mut PathBuf, install_id: &mut String) -> std::io::Result<bool> {
+ if !json_path.exists() {
+ return Err(std::io::Error::new(
+ std::io::ErrorKind::NotFound,
+ "Install ID file does not exist",
+ ));
+ }
+ let json_size = std::fs::metadata(&json_path)
+ .map_err(|e| std::io::Error::new(std::io::ErrorKind::NotFound, e))?
+ .len();
+ // Set a 1 KB limit for the file size.
+ if json_size <= 0 || json_size > 1024 {
+ return Err(std::io::Error::new(
+ std::io::ErrorKind::InvalidData,
+ "Install ID file has invalid size",
+ ));
+ }
+ let mut file =
+ std::fs::File::open(json_path).or_else(|_| -> std::io::Result<std::fs::File> {
+ return Err(std::io::Error::new(
+ std::io::ErrorKind::NotFound,
+ "Failed to open file",
+ ));
+ })?;
+ let mut contents = String::new();
+ match file.read_to_string(&mut contents) {
+ Ok(_) => match serde_json::from_str::<InstallationId>(&contents) {
+ Ok(id) => {
+ *install_id = id.installation_id.clone();
+ generate_response(&id.installation_id, ResultCode::Success.into())
+ }
+ Err(_) => {
+ return Err(std::io::Error::new(
+ std::io::ErrorKind::InvalidData,
+ "Failed to read installation ID",
+ ))
+ }
+ },
+ Err(_) => generate_response("Failed to read file", ResultCode::Error.into()),
+ }?;
+ Ok(true)
+}
+
#[cfg(test)]
mod tests {
use super::*;
use std::io::Cursor;
+ use tempfile::NamedTempFile;
#[test]
fn test_validate_url() {
let valid_test_cases = vec![
@@ -347,4 +423,90 @@ mod tests {
let correct_url_format = format!("-osint -private-window {}", url);
assert!(command_line.contains(correct_url_format.as_str()));
}
+
+ #[test]
+ fn test_get_install_id_valid() -> std::io::Result<()> {
+ let mut tempfile = NamedTempFile::new().unwrap();
+ let installation_id = InstallationId {
+ installation_id: "123ABC456".to_string(),
+ };
+ let json_string = serde_json::to_string(&installation_id);
+ let _ = tempfile.write_all(json_string?.as_bytes());
+ let mut install_id = String::new();
+ let result = get_install_id(&mut tempfile.path().to_path_buf(), &mut install_id);
+ assert!(result.is_ok());
+ assert_eq!(install_id, "123ABC456");
+ Ok(())
+ }
+
+ #[test]
+ fn test_get_install_id_incorrect_var() -> std::io::Result<()> {
+ #[derive(Serialize, Deserialize)]
+ pub struct IncorrectJSON {
+ pub incorrect_var: String,
+ }
+ let mut tempfile = NamedTempFile::new().unwrap();
+ let incorrect_json = IncorrectJSON {
+ incorrect_var: "incorrect_val".to_string(),
+ };
+ let json_string = serde_json::to_string(&incorrect_json);
+ let _ = tempfile.write_all(json_string?.as_bytes());
+ let mut install_id = String::new();
+ let result = get_install_id(&mut tempfile.path().to_path_buf(), &mut install_id);
+ assert!(result.is_err());
+ let error = result.err().unwrap();
+ assert_eq!(error.kind(), std::io::ErrorKind::InvalidData);
+ Ok(())
+ }
+
+ #[test]
+ fn test_get_install_id_partially_correct_vars() -> std::io::Result<()> {
+ #[derive(Serialize, Deserialize)]
+ pub struct IncorrectJSON {
+ pub installation_id: String,
+ pub incorrect_var: String,
+ }
+ let mut tempfile = NamedTempFile::new().unwrap();
+ let incorrect_json = IncorrectJSON {
+ installation_id: "123ABC456".to_string(),
+ incorrect_var: "incorrect_val".to_string(),
+ };
+ let json_string = serde_json::to_string(&incorrect_json);
+ let _ = tempfile.write_all(json_string?.as_bytes());
+ let mut install_id = String::new();
+ let result = get_install_id(&mut tempfile.path().to_path_buf(), &mut install_id);
+ // This still succeeds as the installation_id field is present
+ assert!(result.is_ok());
+ Ok(())
+ }
+
+ #[test]
+ fn test_get_install_id_file_does_not_exist() -> std::io::Result<()> {
+ let tempfile = NamedTempFile::new().unwrap();
+ let mut path = tempfile.path().to_path_buf();
+ tempfile.close()?;
+ let mut install_id = String::new();
+ let result = get_install_id(&mut path, &mut install_id);
+ assert!(result.is_err());
+ let error = result.err().unwrap();
+ assert_eq!(error.kind(), std::io::ErrorKind::NotFound);
+ Ok(())
+ }
+
+ #[test]
+ fn test_get_install_id_file_too_large() -> std::io::Result<()> {
+ let mut tempfile = NamedTempFile::new().unwrap();
+ let installation_id = InstallationId {
+ // Create a ~10 KB file
+ installation_id: String::from_utf8(vec![b'X'; 10000]).unwrap(),
+ };
+ let json_string = serde_json::to_string(&installation_id);
+ let _ = tempfile.write_all(json_string?.as_bytes());
+ let mut install_id = String::new();
+ let result = get_install_id(&mut tempfile.path().to_path_buf(), &mut install_id);
+ assert!(result.is_err());
+ let error = result.err().unwrap();
+ assert_eq!(error.kind(), std::io::ErrorKind::InvalidData);
+ Ok(())
+ }
}
diff --git a/browser/app/nmhproxy/src/main.rs b/browser/app/nmhproxy/src/main.rs
index de9cd8c2a3..02351eb0f1 100644
--- a/browser/app/nmhproxy/src/main.rs
+++ b/browser/app/nmhproxy/src/main.rs
@@ -43,9 +43,12 @@ fn main() -> Result<(), Error> {
"Failed to deserialize message JSON",
));
})?;
- commands::process_command(&native_messaging_json).or_else(|_| -> Result<bool, _> {
- commands::generate_response("Failed to process command", ResultCode::Error.into())
- .expect("JSON error");
+ commands::process_command(&native_messaging_json).or_else(|e| -> Result<bool, _> {
+ commands::generate_response(
+ format!("Failed to process command: {}", e).as_str(),
+ ResultCode::Error.into(),
+ )
+ .expect("JSON error");
return Err(Error::new(
ErrorKind::InvalidInput,
"Failed to process command",
diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js
index 32cd57b0ed..8c4b0e28e5 100644
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -356,6 +356,14 @@ pref("browser.overlink-delay", 80);
pref("browser.theme.colorway-closet", true);
+#ifdef XP_MACOSX
+#ifdef NIGHTLY_BUILD
+pref("browser.theme.macos.native-theme", true);
+#else
+pref("browser.theme.macos.native-theme", false);
+#endif
+#endif
+
// Whether expired built-in colorways themes that are active or retained
// should be allowed to check for updates and be updated to an AMO hosted
// theme with the same id (as part of preparing to remove from mozilla-central
@@ -391,7 +399,8 @@ pref("browser.urlbar.speculativeConnect.enabled", true);
// search for bookmarklets typing "javascript: " followed by the actual query.
pref("browser.urlbar.filter.javascript", true);
-// Enable a certain level of urlbar logging to the Browser Console. See Log.jsm.
+// Enable a certain level of urlbar logging to the Browser Console. See
+// ConsoleInstance.webidl.
pref("browser.urlbar.loglevel", "Error");
// the maximum number of results to show in autocomplete when doing richResults
@@ -434,7 +443,7 @@ pref("browser.search.param.search_rich_suggestions", "fen");
pref("browser.urlbar.weather.featureGate", false);
// Enable clipboard suggestions feature, the pref should be removed once stable.
-pref("browser.urlbar.clipboard.featureGate", true);
+pref("browser.urlbar.clipboard.featureGate", false);
// When false, the weather suggestion will not be fetched when a VPN is
// detected. When true, it will be fetched anyway.
@@ -718,13 +727,6 @@ pref("browser.download.clearHistoryOnDelete", 0);
pref("browser.helperApps.showOpenOptionForPdfJS", true);
pref("browser.helperApps.showOpenOptionForViewableInternally", true);
-// Whether search-config-v2 is enabled.
-#ifdef NIGHTLY_BUILD
-pref("browser.search.newSearchConfig.enabled", true);
-#else
-pref("browser.search.newSearchConfig.enabled", false);
-#endif
-
// search engines URL
pref("browser.search.searchEnginesURL", "https://addons.mozilla.org/%LOCALE%/firefox/search-engines/");
@@ -747,7 +749,11 @@ pref("browser.search.separatePrivateDefault.ui.banner.max", 0);
pref("browser.search.serpEventTelemetry.enabled", true);
// Enables search SERP telemetry page categorization.
+#ifdef NIGHTLY_BUILD
+pref("browser.search.serpEventTelemetryCategorization.enabled", true);
+#else
pref("browser.search.serpEventTelemetryCategorization.enabled", false);
+#endif
// Search Bar removal from the toolbar for users who haven’t used it in 120
// days
@@ -811,6 +817,10 @@ pref("browser.shopping.experience2023.sidebarClosedCount", 0);
// When conditions are met, shows a prompt on the shopping sidebar asking users if they want to disable auto-open behavior
pref("browser.shopping.experience2023.showKeepSidebarClosedMessage", true);
+// Enable display of megalist option in browser sidebar
+// Keep it hidden from about:config for now.
+// pref("browser.megalist.enabled", false);
+
// Enables the display of the Mozilla VPN banner in private browsing windows
pref("browser.privatebrowsing.vpnpromourl", "https://vpn.mozilla.org/?utm_source=firefox-browser&utm_medium=firefox-%CHANNEL%-browser&utm_campaign=private-browsing-vpn-link");
@@ -1094,11 +1104,7 @@ pref("privacy.history.custom", false);
// 6 - Last 24 hours
pref("privacy.sanitize.timeSpan", 1);
-#if defined(NIGHTLY_BUILD)
-pref("privacy.sanitize.useOldClearHistoryDialog", false);
-#else
pref("privacy.sanitize.useOldClearHistoryDialog", true);
-#endif
pref("privacy.sanitize.clearOnShutdown.hasMigratedToNewPrefs", false);
// flag to track migration of clear history dialog prefs, where cpd stands for
@@ -1277,9 +1283,10 @@ pref("browser.sessionstore.idleDelay", 180); // 3 minutes
pref("browser.sessionstore.privacy_level", 0);
// how many tabs can be reopened (per window)
pref("browser.sessionstore.max_tabs_undo", 25);
-// how many windows can be reopened (per session) - on non-OS X platforms this
-// pref may be ignored when dealing with pop-up windows to ensure proper startup
-pref("browser.sessionstore.max_windows_undo", 3);
+// how many windows will be saved and can be reopened per session - on non-macOS platforms this
+// pref may be ignored when dealing with pop-up windows to ensure the user actually gets
+// at least one window with a menu bar.
+pref("browser.sessionstore.max_windows_undo", 5);
// number of crashes that can occur before the about:sessionrestore page is displayed
// (this pref has no effect if more than 6 hours have passed since the last crash)
pref("browser.sessionstore.max_resumed_crashes", 1);
@@ -1422,7 +1429,11 @@ pref("browser.bookmarks.editDialog.maxRecentFolders", 7);
// On windows these levels are:
// See - security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp
// SetSecurityLevelForContentProcess() for what the different settings mean.
- pref("security.sandbox.content.level", 6);
+ #if defined(NIGHTLY_BUILD)
+ pref("security.sandbox.content.level", 7);
+ #else
+ pref("security.sandbox.content.level", 6);
+ #endif
// Pref controlling if messages relevant to sandbox violations are logged.
pref("security.sandbox.logging.enabled", false);
@@ -1678,22 +1689,16 @@ pref("browser.topsites.contile.sov.enabled", true);
pref("browser.partnerlink.attributionURL", "https://topsites.services.mozilla.com/cid/");
pref("browser.partnerlink.campaign.topsites", "amzn_2020_a1");
-// Whether to show tab level system prompts opened via nsIPrompt(Service) as
-// SubDialogs in the TabDialogBox (true) or as TabModalPrompt in the
-// TabModalPromptBox (false).
-pref("prompts.tabChromePromptSubDialog", true);
-
-// Whether to show the dialogs opened at the content level, such as
-// alert() or prompt(), using a SubDialogManager in the TabDialogBox.
-pref("prompts.contentPromptSubDialog", true);
-
-// Whether to show window-modal dialogs opened for browser windows
-// in a SubDialog inside their parent, instead of an OS level window.
-pref("prompts.windowPromptSubDialog", true);
-
// Activates preloading of the new tab url.
pref("browser.newtab.preload", true);
+// Preference to enable wallpaper selection in the Customize Menu of new tab page
+pref("browser.newtabpage.activity-stream.newtabWallpapers.enabled", false);
+
+// Current new tab page background image.
+pref("browser.newtabpage.activity-stream.newtabWallpapers.wallpaper-light", "");
+pref("browser.newtabpage.activity-stream.newtabWallpapers.wallpaper-dark", "");
+
pref("browser.newtabpage.activity-stream.newNewtabExperience.colors", "#0090ED,#FF4F5F,#2AC3A2,#FF7139,#A172FF,#FFA437,#FF2A8A");
// Activity Stream prefs that control to which page to redirect
@@ -1709,7 +1714,6 @@ pref("browser.newtabpage.activity-stream.improvesearch.topSiteSearchShortcuts",
// ASRouter provider configuration
pref("browser.newtabpage.activity-stream.asrouter.providers.cfr", "{\"id\":\"cfr\",\"enabled\":true,\"type\":\"remote-settings\",\"collection\":\"cfr\",\"updateCycleInMs\":3600000}");
-pref("browser.newtabpage.activity-stream.asrouter.providers.whats-new-panel", "{\"id\":\"whats-new-panel\",\"enabled\":false,\"type\":\"remote-settings\",\"collection\":\"whats-new-panel\",\"updateCycleInMs\":3600000}");
pref("browser.newtabpage.activity-stream.asrouter.providers.message-groups", "{\"id\":\"message-groups\",\"enabled\":true,\"type\":\"remote-settings\",\"collection\":\"message-groups\",\"updateCycleInMs\":3600000}");
pref("browser.newtabpage.activity-stream.asrouter.providers.messaging-experiments", "{\"id\":\"messaging-experiments\",\"enabled\":true,\"type\":\"remote-experiments\",\"updateCycleInMs\":3600000}");
@@ -1821,9 +1825,6 @@ pref("browser.aboutwelcome.screens", "");
// Used to enable window modal onboarding
pref("browser.aboutwelcome.showModal", false);
-// The pref that controls if the What's New panel is enabled.
-pref("browser.messaging-system.whatsNewPanel.enabled", true);
-
// Experiment Manager
// See Console.sys.mjs LOG_LEVELS for all possible values
pref("messaging-system.log", "warn");
@@ -1855,10 +1856,9 @@ pref("pdfjs.previousHandler.alwaysAskBeforeHandling", false);
// Try to convert PDFs sent as octet-stream
pref("pdfjs.handleOctetStream", true);
-pref("sidebar.companion", false);
-
// Is the sidebar positioned ahead of the content browser
pref("sidebar.position_start", true);
+pref("sidebar.revamp", false);
pref("security.protectionspopup.recordEventTelemetry", true);
pref("security.app_menu.recordEventTelemetry", true);
@@ -2510,9 +2510,6 @@ pref("identity.fxaccounts.toolbar.pxiToolbarEnabled.monitorEnabled", true);
pref("identity.fxaccounts.toolbar.pxiToolbarEnabled.relayEnabled", true);
pref("identity.fxaccounts.toolbar.pxiToolbarEnabled.vpnEnabled", true);
-// Check bundled omni JARs for corruption.
-pref("corroborator.enabled", true);
-
// Toolbox preferences
pref("devtools.toolbox.footer.height", 250);
pref("devtools.toolbox.sidebar.width", 500);
@@ -2520,7 +2517,8 @@ pref("devtools.toolbox.host", "bottom");
pref("devtools.toolbox.previousHost", "right");
pref("devtools.toolbox.selectedTool", "inspector");
pref("devtools.toolbox.zoomValue", "1");
-pref("devtools.toolbox.splitconsoleEnabled", false);
+pref("devtools.toolbox.splitconsole.enabled", true);
+pref("devtools.toolbox.splitconsole.open", false);
pref("devtools.toolbox.splitconsoleHeight", 100);
pref("devtools.toolbox.tabsOrder", "");
// This is only used for local Web Extension debugging,
@@ -2550,7 +2548,6 @@ pref("devtools.popups.debug", false);
// Toolbox Button preferences
pref("devtools.command-button-pick.enabled", true);
pref("devtools.command-button-frames.enabled", true);
-pref("devtools.command-button-splitconsole.enabled", true);
pref("devtools.command-button-responsive.enabled", true);
pref("devtools.command-button-screenshot.enabled", false);
pref("devtools.command-button-rulers.enabled", false);
@@ -3030,10 +3027,14 @@ pref("browser.mailto.dualPrompt", false);
// default mailto handler.
pref("browser.mailto.prompt.os", true);
-pref("browser.backup.enabled", false);
+// Pref to initialize the BackupService soon after startup.
+pref("browser.backup.enabled", true);
// Pref to enable the new profiles
pref("browser.profiles.enabled", false);
pref("startup.homepage_override_url_nimbus", "");
pref("startup.homepage_override_nimbus_maxVersion", "");
+
+// Pref to enable the content relevancy feature.
+pref("toolkit.contentRelevancy.enabled", false);