1
1
Fork 0

firefox: genericize module and switch to librewolf

Signed-off-by: Myned <dev@bjork.tech>
This commit is contained in:
Myned 2025-02-16 20:29:08 -06:00
parent b88fbfbcb9
commit 7760d761c7
Signed by: Myned
GPG key ID: C7224454F7881A34
8 changed files with 656 additions and 649 deletions

578
modules/firefox.nix Normal file
View file

@ -0,0 +1,578 @@
{
config,
inputs,
lib,
pkgs,
theme ? true,
...
}:
with lib; {
#!! Creates package derivation
#?? hm.programs.firefox.finalPackage
enableGnomeExtensions = config.services.gnome.gnome-browser-connector.enable;
# https://wiki.nixos.org/wiki/Firefox#Tips
nativeMessagingHosts = with pkgs; [
firefoxpwa
];
#!! Prefer policies over profiles when possible
#?? about:profiles
profiles.default = {
# https://nur.nix-community.org/repos/rycee/
extensions = with pkgs.nur.repos.rycee.firefox-addons;
optionals config.custom.minimal [
ublock-origin
]
++ optionals config.custom.full [
awesome-rss
#// betterttv
bitwarden
enhancer-for-youtube
#// firefox-color
#// gnome-shell-integration
#// improved-tube
libredirect
#// onepassword-password-manager
pwas-for-firefox
#// simple-tab-groups
sponsorblock
stylus
#// untrap-for-youtube
#// user-agent-string-switcher
# TODO: Convert to NUR addons
#// "{248e6a49-f636-4c81-9899-a456eb6291a8}" = extension "ground-news-bias-checker"; # Ground News Bias Checker
#// "select-after-closing-current@qw.linux-2g64.local" = extension "select-after-closing-current"; # Select After Closing Current
#// "myallychou@gmail.com" = extension "youtube-recommended-videos"; # Unhook: Remove YouTube Recommended Videos Comments
#// "{a0370179-acc3-452f-9530-246b6adb2768}" = extension "svelte-devtools"; # Svelte Devtools
#// "{c49b13b1-5dee-4345-925e-0c793377e3fa}" = extension "youtube-enhancer-vc"; # YouTube Enhancer
];
# TODO: Consider other themes
# https://github.com/soulhotel/FF-ULTIMA
# Import CSS theme with solarized overrides
# https://github.com/rafaelmardojai/firefox-gnome-theme
# https://github.com/rafaelmardojai/firefox-gnome-theme/blob/master/theme/colors/dark.css
userContent = mkIf theme ''
@import "${inputs.firefox-gnome-theme}/userContent.css";
'';
userChrome = mkIf theme ''
@import "${inputs.firefox-gnome-theme}/userChrome.css";
:root {
--gnome-accent: #d33682;
--gnome-window-background: #002b36;
--gnome-window-color: #93a1a1;
--gnome-view-background: #073642;
--gnome-sidebar-background: #002b36;
--gnome-secondary-sidebar-background: #002b36;
--gnome-menu-background: #073642;
--gnome-headerbar-background: #002b36;
--gnome-toolbar-icon-fill: #93a1a1;
--gnome-tabbar-tab-hover-background: #073642;
--gnome-tabbar-tab-active-background: #073642;
--gnome-tabbar-tab-active-hover-background: #073642;
}
:root:-moz-window-inactive {
--gnome-inactive-entry-color: #586e75;
--gnome-tabbar-tab-hover-background: #073642;
--gnome-tabbar-tab-active-background: #073642;
}
/* Center bookmarks */
#PlacesToolbarItems {
justify-content: center;
}
/* Disable bookmark folder icons */
.bookmark-item[container] > .toolbarbutton-icon {
display: none;
}
'';
containersForce = true;
containers = {
Master = {
color = "pink";
icon = "circle";
id = 0;
};
Edu = {
color = "orange";
icon = "fruit";
id = 1;
};
};
settings = with config.custom.settings.fonts;
{
"accessibility.browsewithcaret" = false;
"accessibility.typeaheadfind" = false;
"browser.aboutConfig.showWarning" = false;
"browser.bookmarks.restore_default_bookmarks" = false;
"browser.contentblocking.category" = "standard";
"browser.contentblocking.report.hide_vpn_banner" = true;
"browser.contentblocking.report.show_mobile_app" = false;
"browser.contentblocking.report.vpn.enabled" = false;
"browser.crashReports.unsubmittedCheck.autoSubmit2" = false;
"browser.ctrlTab.sortByRecentlyUsed" = false;
"browser.dataFeatureRecommendations.enabled" = false;
"browser.download.always_ask_before_handling_new_types" = false;
"browser.download.useDownloadDir" = true;
"browser.engagement.ctrlTab.has-used" = true;
"browser.engagement.downloads-button.has-used" = true;
"browser.engagement.fxa-toolbar-menu-button.has-used" = true;
"browser.engagement.home-button.has-used" = true;
"browser.engagement.library-button.has-used" = true;
"browser.engagement.sidebar-button.has-used" = true;
"browser.formfill.enable" = false;
"browser.link.open_newwindow.restriction" = 0; # Popups in new tab
"browser.link.open_newwindow" = 3; # New tab
"browser.messaging-system.whatsNewPanel.enabled" = false;
"browser.newtabpage.activity-stream.asrouter.userprefs.cfr.addons" = false;
"browser.newtabpage.activity-stream.asrouter.userprefs.cfr.features" = false;
"browser.newtabpage.activity-stream.discoverystream.onboardingExperience.enabled" = false;
"browser.newtabpage.activity-stream.discoverystream.topicSelection.onboarding.enabled" = false;
"browser.newtabpage.activity-stream.feeds.recommendationprovider" = false;
"browser.newtabpage.activity-stream.feeds.section.highlights" = false;
"browser.newtabpage.activity-stream.feeds.section.topstories" = false;
"browser.newtabpage.activity-stream.feeds.system.topstories" = false;
"browser.newtabpage.activity-stream.feeds.telemetry" = false;
"browser.newtabpage.activity-stream.feeds.topsites" = false;
"browser.newtabpage.activity-stream.showSearch" = false;
"browser.newtabpage.activity-stream.showSponsored" = false;
"browser.newtabpage.activity-stream.showSponsoredTopSites" = false;
"browser.newtabpage.activity-stream.showWeather" = false;
"browser.newtabpage.activity-stream.telemetry" = false;
"browser.newtabpage.enabled" = true;
"browser.ping-centre.telemetry" = false;
"browser.preferences.defaultPerformanceSettings.enabled" = true;
"browser.preferences.moreFromMozilla" = false;
"browser.quitShortcut.disabled" = true;
"browser.safebrowsing.blockedURIs.enabled" = true;
"browser.safebrowsing.downloads.enabled" = true;
"browser.safebrowsing.malware.enabled" = true;
"browser.safebrowsing.phishing.enabled" = true;
"browser.search.separatePrivateDefault" = false;
"browser.search.suggest.enabled" = true;
"browser.search.widget.inNavBar" = false;
"browser.shell.checkDefaultBrowser" = false;
"browser.startup.homepage" = "about:home";
"browser.startup.page" = 3; # Previous session
"browser.tabs.allowTabDetach" = false;
"browser.tabs.closeTabByDblclick" = true;
"browser.tabs.closeWindowWithLastTab" = false;
"browser.tabs.groups.enabled" = true;
"browser.tabs.insertAfterCurrent" = false;
"browser.tabs.insertRelatedAfterCurrent" = false;
"browser.tabs.loadInBackground" = true;
"browser.tabs.warnOnClose" = false;
"browser.tabs.warnOnCloseOtherTabs" = false;
"browser.theme.dark-private-windows" = false;
"browser.toolbars.bookmarks.showOtherBookmarks" = false;
"browser.uidensity" = 0; # Default
"browser.urlbar.quicksuggest.dataCollection.enabled" = false;
"browser.urlbar.quicksuggest.shouldShowOnboardingDialog" = false;
"browser.urlbar.suggest.addons" = true;
"browser.urlbar.suggest.bookmark" = true;
"browser.urlbar.suggest.calculator" = true;
"browser.urlbar.suggest.clipboard" = true;
"browser.urlbar.suggest.engines" = true;
"browser.urlbar.suggest.fakespot" = true;
"browser.urlbar.suggest.history" = true;
"browser.urlbar.suggest.mdn" = true;
"browser.urlbar.suggest.openpage" = true;
"browser.urlbar.suggest.pocket" = false;
"browser.urlbar.suggest.quickactions" = true;
"browser.urlbar.suggest.quicksuggest.nonsponsored" = true;
"browser.urlbar.suggest.quicksuggest.sponsored" = false;
"browser.urlbar.suggest.recentsearches" = true;
"browser.urlbar.suggest.remotetab" = true;
"browser.urlbar.suggest.searches" = true;
"browser.urlbar.suggest.topsites" = true;
"browser.urlbar.suggest.trending" = false;
"browser.urlbar.suggest.weather" = false;
"browser.urlbar.suggest.yelp" = false;
"browser.warnOnQuitShortcut" = true;
"clipboard.autocopy" = false;
"default-browser-agent.enabled" = false;
"devtools.webconsole.input.editorOnboarding" = false;
"dom.security.https_only_mode" = true;
"extensions.autoDisableScopes" = 0; # Auto-enable extensions
"extensions.formautofill.addresses.enabled" = false;
"extensions.formautofill.creditCards.enabled" = false;
"extensions.htmlaboutaddons.recommendations.enabled" = false;
"extensions.pictureinpicture.enable_picture_in_picture_overrides" = true;
"extensions.pocket.enabled" = false;
"extensions.update.autoUpdateDefault" = true;
"extensions.update.enabled" = true;
"font.default.x-unicode" = sans-serif;
"font.default.x-western" = sans-serif;
"font.name-list.emoji" = emoji; # System emoji
"font.name.monospace.x-unicode" = monospace;
"font.name.monospace.x-western" = monospace;
"font.name.sans-serif.x-unicode" = sans-serif;
"font.name.sans-serif.x-western" = sans-serif;
"font.name.serif.x-unicode" = sans-serif;
"font.name.serif.x-western" = sans-serif;
"full-screen-api.ignore-widgets" = false; # Fake fullscreen
"full-screen-api.warning.delay" = -1;
"full-screen-api.warning.timeout" = 0;
"general.autoScroll" = false;
"general.smoothScroll" = true;
"gfx.webrender.software" = config.custom.programs.looking-glass.igpu; # Reduce load on iGPU
"identity.fxaccounts.enabled" = true;
"layers.acceleration.force-enabled" = true;
"layout.css.always_underline_links" = false;
"layout.css.backdrop-filter.enabled" = true;
"layout.forms.reveal-password-button.enabled" = true;
"layout.forms.reveal-password-context-menu.enabled" = false;
"layout.spellcheckDefault" = 0; # Disabled
"media.autoplay.blocking_policy" = 1; # Transient
"media.eme.enabled" = true; # DRM
"media.ffmpeg.vaapi.enabled" = true;
"media.hardware-video-decoding.enabled" = true;
"media.hardwaremediakeys.enabled" = true;
"media.videocontrols.picture-in-picture.audio-toggle.enabled" = false;
"media.videocontrols.picture-in-picture.display-text-tracks.enabled" = true;
"media.videocontrols.picture-in-picture.display-text-tracks.toggle.enabled" = true;
"media.videocontrols.picture-in-picture.enable-when-switching-tabs.enabled" = true;
"media.videocontrols.picture-in-picture.enabled" = true;
"media.videocontrols.picture-in-picture.respect-disablePictureInPicture" = false;
"media.videocontrols.picture-in-picture.urlbar-button.enabled" = true;
"media.videocontrols.picture-in-picture.video-toggle.enabled" = true;
"media.videocontrols.picture-in-picture.video-toggle.has-used" = true;
"media.videocontrols.picture-in-picture.video-toggle.min-video-secs" = 0; # No minimum duration
"media.videocontrols.picture-in-picture.video-toggle.position" = "top";
"messaging-system.askForFeedback" = false;
"messaging-system.rsexperimentloader.enabled" = false;
"middlemouse.paste" = false;
"network.dns.disableIPv6" = false;
"network.dns.disablePrefetch" = true;
"network.dns.disablePrefetchFromHTTPS" = true;
"network.http.referer.XOriginPolicy" = 0; # Relaxed
"network.predictor.enabled" = false;
"pref.privacy.disable_button.view_passwords" = true;
"privacy.fingerprintingProtection" = false;
"privacy.globalprivacycontrol.enabled" = true;
"privacy.resistFingerprinting.autoDeclineNoUserInputCanvasPrompts" = false;
"privacy.resistFingerprinting.letterboxing" = false;
"privacy.resistFingerprinting" = false; #!! Forces light theme
"remote.prefs.recommended" = false;
"security.OCSP.require" = true;
"security.protectionspopup.recordEventTelemetry" = false;
"services.passwordSavingEnabled" = false;
"startup.homepage_override_url" = ""; # Disable
"startup.homepage_welcome_url" = ""; # Disable
"svg.context-properties.content.enabled" = true; # Dark theme icons
"toolkit.legacyUserProfileCustomizations.stylesheets" = true;
"toolkit.telemetry.archive.enabled" = false;
"toolkit.telemetry.bhrPing.enabled" = false;
"toolkit.telemetry.coverage.opt-out" = true;
"toolkit.telemetry.enabled" = false;
"toolkit.telemetry.firstShutdownPing.enabled" = false;
"toolkit.telemetry.newProfilePing.enabled" = false;
"toolkit.telemetry.pioneer-new-studies-available" = false;
"toolkit.telemetry.shutdownPingSender.enabled" = false;
"toolkit.telemetry.unified" = false;
"toolkit.telemetry.updatePing.enabled" = false;
"ui.key.menuAccessKey" = 0; # Disable menu key
"webgl.disabled" = false;
"widget.gtk.overlay-scrollbars.enabled" = true;
"widget.gtk.rounded-bottom-corners.enabled" = true;
}
// optionalAttrs theme {
# https://github.com/rafaelmardojai/firefox-gnome-theme?tab=readme-ov-file#features
"gnomeTheme.allTabsButtonOnOverflow" = true;
"gnomeTheme.bookmarksToolbarUnderTabs" = true;
};
bookmarks = [
{
name = "Nix User Repository";
keyword = "nur";
url = "https://nur.nix-community.org/";
}
{
name = "Nix Ryantm";
keyword = "nry";
url = "https://ryantm.github.io/nixpkgs/";
}
];
# https://searchfox.org/mozilla-central/rev/669329e284f8e8e2bb28090617192ca9b4ef3380/toolkit/components/search/SearchEngine.jsm#1138-1177
search = {
force = true;
default = "Kagi";
privateDefault = "Kagi";
engines = {
### Builtins
"Amazon.com" = {
metaData.hidden = true;
};
"Bing" = {
metaData.hidden = true;
};
"DuckDuckGo" = {
metaData.alias = "d";
};
"eBay" = {
metaData.hidden = true;
};
"Google" = {
metaData.alias = "g";
};
"Wikipedia (en)" = {
metaData.hidden = true;
};
### Custom
"Amazon" = {
definedAliases = ["a"];
iconUpdateURL = "https://www.amazon.com/favicon.ico";
urls = [{template = "https://www.amazon.com/s?k={searchTerms}";}];
};
"ArchWiki" = {
definedAliases = ["aw"];
iconUpdateURL = "https://wiki.archlinux.org/favicon.ico";
urls = [{template = "https://wiki.archlinux.org/index.php?search={searchTerms}";}];
};
"Brave" = {
definedAliases = ["b"];
iconUpdateURL = "https://cdn.search.brave.com/serp/v2/_app/immutable/assets/favicon.c09fe1a1.ico";
urls = [{template = "https://search.brave.com/search?q={searchTerms}";}];
};
"Docker Hub" = {
definedAliases = ["dh"];
iconUpdateURL = "https://hub.docker.com/favicon.ico";
urls = [{template = "https://hub.docker.com/search?q={searchTerms}";}];
};
"e621" = {
definedAliases = ["e"];
iconUpdateURL = "https://e621.net/favicon.ico";
urls = [{template = "https://e621.net/posts?tags={searchTerms}";}];
};
"Element Issues" = {
definedAliases = ["ei"];
iconUpdateURL = "https://github.com/favicon.ico";
urls = [{template = "https://github.com/element-hq/element-web/issues?q=is%3Aissue+is%3Aopen+{searchTerms}";}];
};
"Flathub" = {
definedAliases = ["fh"];
iconUpdateURL = "https://flathub.org/favicon.png";
urls = [{template = "https://flathub.org/apps/search?q={searchTerms}";}];
};
"Google Fonts" = {
definedAliases = ["gf"];
iconUpdateURL = "https://www.gstatic.com/images/icons/material/apps/fonts/1x/catalog/v5/favicon.svg";
urls = [{template = "https://fonts.google.com/?query={searchTerms}";}];
};
"GitHub" = {
definedAliases = ["gh"];
iconUpdateURL = "https://github.com/favicon.ico";
urls = [{template = "https://github.com/search?q={searchTerms}";}];
};
"Home Manager Issues" = {
definedAliases = ["hi"];
iconUpdateURL = "https://github.com/favicon.ico";
urls = [{template = "https://github.com/nix-community/home-manager/issues?q=is%3Aissue+is%3Aopen+{searchTerms}";}];
};
"Home Manager Options" = {
definedAliases = ["ho"];
iconUpdateURL = "https://home-manager-options.extranix.com/images/favicon.png";
urls = [{template = "https://home-manager-options.extranix.com/?query={searchTerms}&release=master";}];
};
"Hyprland Issues" = {
definedAliases = ["hyi"];
iconUpdateURL = "https://github.com/favicon.ico";
urls = [{template = "https://github.com/hyprwm/Hyprland/issues?q=is%3Aissue+is%3Aopen+{searchTerms}";}];
};
"i3 Issues" = {
definedAliases = ["ii"];
iconUpdateURL = "https://github.com/favicon.ico";
urls = [{template = "https://github.com/i3/i3/issues?q=is%3Aissue+is%3Aopen+{searchTerms}";}];
};
"Kagi" = {
definedAliases = ["k"];
iconUpdateURL = "https://kagi.com/asset/v2/favicon-32x32.png";
urls = [{template = "https://kagi.com/search?q={searchTerms}";}];
};
"Lutris" = {
definedAliases = ["l"];
iconUpdateURL = "https://lutris.net/favicon.ico";
urls = [{template = "https://lutris.net/games?q={searchTerms}";}];
};
"Lix Issues" = {
definedAliases = ["li"];
iconUpdateURL = "https://git.lix.systems/assets/img/favicon.png";
urls = [{template = "https://git.lix.systems/lix-project/lix/issues?state=open&q={searchTerms}";}];
};
"Mozilla Web Docs" = {
definedAliases = ["mdn"];
iconUpdateURL = "https://developer.mozilla.org/favicon-48x48.cbbd161b.png";
urls = [{template = "https://developer.mozilla.org/en-US/search?q={searchTerms}";}];
};
"MyNixOS Options" = {
definedAliases = ["mno"];
iconUpdateURL = "https://mynixos.com/favicon.ico";
urls = [{template = "https://mynixos.com/search?q=option+{searchTerms}";}];
};
"Nix Dev" = {
definedAliases = ["nd"];
iconUpdateURL = "https://nix.dev/manual/nix/latest/favicon.png";
urls = [{template = "https://nix.dev/manual/nix/latest?search={searchTerms}";}];
};
"NixOS Flakes" = {
definedAliases = ["nf"];
iconUpdateURL = "https://nixos.org/favicon.png";
urls = [{template = "https://search.nixos.org/flakes?channel=unstable&query={searchTerms}";}];
};
"Nix Hub" = {
definedAliases = ["nh"];
iconUpdateURL = "https://www.nixhub.io/favicon.ico";
urls = [{template = "https://www.nixhub.io/search?q={searchTerms}";}];
};
"NixOS Nixpkgs Issues" = {
definedAliases = ["ni"];
iconUpdateURL = "https://github.com/favicon.ico";
urls = [{template = "https://github.com/NixOS/nixpkgs/issues?q=is%3Aissue+is%3Aopen+{searchTerms}";}];
};
"Nix PR" = {
definedAliases = ["npr"];
urls = [{template = "https://nixpk.gs/pr-tracker.html?pr={searchTerms}";}];
};
"NixOS Options" = {
definedAliases = ["no"];
iconUpdateURL = "https://nixos.org/favicon.png";
urls = [{template = "https://search.nixos.org/options?channel=unstable&query={searchTerms}";}];
};
"Noogle Dev" = {
definedAliases = ["nod"];
iconUpdateURL = "https://noogle.dev/favicon.png";
urls = [{template = "https://noogle.dev/q?term={searchTerms}";}];
};
"NixOS Packages" = {
definedAliases = ["np"];
iconUpdateURL = "https://nixos.org/favicon.png";
urls = [{template = "https://search.nixos.org/packages?channel=unstable&query={searchTerms}";}];
};
"Niri Issues" = {
definedAliases = ["nri"];
iconUpdateURL = "https://github.com/favicon.ico";
urls = [{template = "https://github.com/YaLTeR/niri/issues?q=is%3Aissue+is%3Aopen+{searchTerms}";}];
};
"NixOS Wiki" = {
definedAliases = ["nw"];
iconUpdateURL = "https://wiki.nixos.org/favicon.ico";
urls = [{template = "https://wiki.nixos.org/w/index.php?search={searchTerms}";}];
};
"Piped" = {
definedAliases = ["p"];
iconUpdateURL = "https://piped.${config.custom.domain}/favicon.ico";
urls = [{template = "https://piped.${config.custom.domain}/results?search_query={searchTerms}";}];
};
"PCGamingWiki" = {
definedAliases = ["pc"];
iconUpdateURL = "https://static.pcgamingwiki.com/favicons/pcgamingwiki.png";
urls = [{template = "https://www.pcgamingwiki.com/w/index.php?search={searchTerms}";}];
};
"ProtonDB" = {
definedAliases = ["pdb"];
iconUpdateURL = "https://www.protondb.com/sites/protondb/images/favicon.ico";
urls = [{template = "https://www.protondb.com/search?q={searchTerms}";}];
};
"PyPI" = {
definedAliases = ["pip"];
iconUpdateURL = "https://pypi.org/static/images/favicon.35549fe8.ico";
urls = [{template = "https://pypi.org/search/?q={searchTerms}";}];
};
"Reddit" = {
definedAliases = ["r"];
iconUpdateURL = "https://www.redditstatic.com/desktop2x/img/favicon/favicon-96x96.png";
urls = [{template = "https://kagi.com/search?q=site%3Areddit.com+{searchTerms}";}];
};
"SearXNG" = {
definedAliases = ["s"];
iconUpdateURL = "https://search.${config.custom.domain}/static/themes/simple/img/favicon.png";
urls = [{template = "https://search.${config.custom.domain}/search?q={searchTerms}";}];
};
"Sway Issues" = {
definedAliases = ["si"];
iconUpdateURL = "https://github.com/favicon.ico";
urls = [{template = "https://github.com/swaywm/sway/issues?q=is%3Aissue+is%3Aopen+{searchTerms}";}];
};
"Wikipedia" = {
definedAliases = ["w"];
iconUpdateURL = "https://en.wikipedia.org/static/favicon/wikipedia.ico";
urls = [{template = "https://en.wikipedia.org/w/index.php?search={searchTerms}";}];
};
"Wolfram Alpha" = {
definedAliases = ["wa"];
iconUpdateURL = "https://www.wolframalpha.com/_next/static/images/favicon_1zbE9hjk.ico";
urls = [{template = "https://www.wolframalpha.com/input?i={searchTerms}";}];
};
"Walker Issues" = {
definedAliases = ["wi"];
iconUpdateURL = "https://github.com/favicon.ico";
urls = [{template = "https://github.com/abenz1267/walker/issues?q=is%3Aissue+is%3Aopen+{searchTerms}";}];
};
"YouTube" = {
definedAliases = ["y"];
iconUpdateURL = "https://www.youtube.com/s/desktop/f8c8418d/img/favicon.ico";
urls = [{template = "https://www.youtube.com/results?search_query={searchTerms}";}];
};
};
};
};
}

View file

@ -6,6 +6,7 @@
}:
with lib; let
cfg = config.custom;
hm = config.home-manager.users.${config.custom.username};
in {
options.custom = {
### Profiles
@ -30,7 +31,7 @@ in {
hidpi = mkOption {default = cfg.scale > 1;};
scale = mkOption {default = 1;};
border = mkOption {default = 3;};
gap = mkOption {default = 10;};
gap = mkOption {default = 15;};
padding = mkOption {default = 51;}; # ?? journalctl --user -u waybar.service | grep height:
rounding = mkOption {default = 15;};
@ -48,18 +49,8 @@ in {
browser = {
# TODO: Use lib.getExe' instead of /bin/ where possible
# HACK: Find first matching package in final home-manager list
command = mkOption {
default = "${lib.findFirst (pkg:
if (lib.hasAttr "pname" pkg)
then pkg.pname == "brave"
else false)
null
config.home-manager.users.${config.custom.username}.home.packages}/bin/brave";
};
desktop = mkOption {default = "brave.desktop";};
package = mkOption {default = pkgs.brave;};
command = mkOption {default = getExe hm.programs.librewolf.finalPackage;};
desktop = mkOption {default = "librewolf.desktop";};
};
};
}

View file

@ -209,6 +209,7 @@ in {
(class "^chromium-browser$" rules)
(class "^firefox.*$" rules)
(class "^google-chrome$" rules)
(class "^librewolf$" rules)
(class "^vivaldi.*$" rules)
(class "^zen$" rules)
];

View file

@ -33,12 +33,13 @@ with lib; {
appimage.enable = true;
chromium.enable = true;
dconf.enable = true;
firefox.enable = true;
#// firefox.enable = true;
#// foot.enable = true;
gamescope.enable = true;
#// gnome-terminal.enable = true;
#// kdeconnect.enable = true;
kitty.enable = true;
librewolf.enable = true;
nautilus.enable = true;
nvtop.enable = true;
wezterm.enable = true;
@ -60,7 +61,6 @@ with lib; {
#// gtklock.enable = true;
hyprlock.enable = true;
libreoffice.enable = true;
#// librewolf.enable = true;
localsend.enable = true;
logseq.enable = true;
mangohud.enable = true;

View file

@ -1,617 +0,0 @@
{
config,
inputs,
lib,
pkgs,
...
}:
with lib; let
cfg = config.custom.programs.firefox;
in {
options.custom.programs.firefox.enable = mkOption {default = false;};
config.home-manager.users.${config.custom.username} = mkIf cfg.enable {
# TODO: Switch to librewolf when supported by module
# https://github.com/nix-community/home-manager/pull/5128
#!! Creates package derivation
#?? config.home-manager.users.${config.custom.username}.programs.firefox.finalPackage
# https://www.mozilla.org/en-US/firefox/developer
programs.firefox = {
enable = true;
package = pkgs.firefox-esr-128;
# nativeMessagingHosts = with pkgs; [
# firefoxpwa
# gnome-browser-connector
# ];
#!! Prefer policy over profile
#?? about:profiles
profiles.default = {
# Import CSS theme with solarized overrides
# https://github.com/rafaelmardojai/firefox-gnome-theme/blob/master/theme/colors/dark.css
userChrome = ''
@import "firefox-gnome-theme/userChrome.css";
:root {
--gnome-accent: #6c71c4;
--gnome-window-background: #002b36;
--gnome-window-color: #93a1a1;
--gnome-view-background: #073642;
--gnome-sidebar-background: #002b36;
--gnome-secondary-sidebar-background: #002b36;
--gnome-menu-background: #073642;
--gnome-headerbar-background: #002b36;
--gnome-toolbar-icon-fill: #93a1a1;
--gnome-tabbar-tab-hover-background: #073642;
--gnome-tabbar-tab-active-background: #073642;
--gnome-tabbar-tab-active-hover-background: #073642;
}
:root:-moz-window-inactive {
--gnome-inactive-entry-color: #586e75;
--gnome-tabbar-tab-hover-background: #073642;
--gnome-tabbar-tab-active-background: #073642;
}
/* Center bookmarks */
#PlacesToolbarItems {
justify-content: center;
}
/* Disable bookmark folder icons */
.bookmark-item[container] > .toolbarbutton-icon {
display: none;
}
'';
userContent = ''@import "firefox-gnome-theme/userContent.css";'';
settings = {
# https://github.com/rafaelmardojai/firefox-gnome-theme?tab=readme-ov-file#features
"gnomeTheme.bookmarksToolbarUnderTabs" = true;
#// "gnomeTheme.systemIcons" = true;
"font.default.x-unicode" = config.custom.settings.fonts.sans-serif;
"font.default.x-western" = config.custom.settings.fonts.sans-serif;
"font.name-list.emoji" = config.custom.settings.fonts.emoji; # System emoji
"font.name.monospace.x-unicode" = config.custom.settings.fonts.monospace;
"font.name.monospace.x-western" = config.custom.settings.fonts.monospace;
"font.name.sans-serif.x-unicode" = config.custom.settings.fonts.sans-serif;
"font.name.sans-serif.x-western" = config.custom.settings.fonts.sans-serif;
"font.name.serif.x-unicode" = config.custom.settings.fonts.sans-serif;
"font.name.serif.x-western" = config.custom.settings.fonts.sans-serif;
"full-screen-api.ignore-widgets" = false; # Fake fullscreen
"full-screen-api.warning.delay" = -1;
"full-screen-api.warning.timeout" = 0;
"middlemouse.paste" = false;
"privacy.donottrackheader.enabled" = true;
"privacy.fingerprintingProtection" = false;
"privacy.globalprivacycontrol.enabled" = true;
"svg.context-properties.content.enabled" = true; # Dark theme icons
};
};
# https://mozilla.github.io/policy-templates
policies = {
CaptivePortal = false;
DisableFirefoxStudies = true;
DisableFormHistory = true;
DisableMasterPasswordCreation = true;
DisablePocket = true;
DisableSetDesktopBackground = true;
DisableTelemetry = true;
DNSOverHTTPS = {
Enabled = false;
Locked = true;
};
DontCheckDefaultBrowser = true;
# https://mozilla.github.io/policy-templates/#extensionsettings
#?? https://addons.mozilla.org/en-US/firefox
#?? about:support#addons
ExtensionSettings = let
extension = id: {
install_url = "https://addons.mozilla.org/firefox/downloads/latest/${id}/latest.xpi";
installation_mode = "normal_installed";
};
in
mkMerge [
(mkIf config.custom.minimal {
"uBlock0@raymondhill.net" = extension "ublock-origin"; # uBlock Origin
})
(mkIf config.custom.full {
"{d634138d-c276-4fc8-924b-40a0ea21d284}" = extension "1password-x-password-manager"; # 1Password: Password Manager
#// "firefox@betterttv.net" = extension "betterttv"; # BetterTTV
#// "{446900e4-71c2-419f-a6a7-df9c091e268b}" = extension "bitwarden-password-manager"; # Bitwarden
#// "FirefoxColor@mozilla.com" = extension "firefox-color"; # Firefox Color
#// "chrome-gnome-shell@gnome.org" = extension "gnome-shell-integration"; # GNOME Shell Integration
#// "{248e6a49-f636-4c81-9899-a456eb6291a8}" = extension "ground-news-bias-checker"; # Ground News Bias Checker
#// "{3c6bf0cc-3ae2-42fb-9993-0d33104fdcaf}" = extension "youtube-addon"; # ImprovedTube
#// "7esoorv3@alefvanoon.anonaddy.me" = extension "libredirect"; # LibRedirect
#// "firefoxpwa@filips.si" = extension "pwas-for-firefox"; # Progressive Web Apps for Firefox
"select-after-closing-current@qw.linux-2g64.local" = extension "select-after-closing-current"; # Select After Closing Current
"myallychou@gmail.com" = extension "youtube-recommended-videos"; # Unhook: Remove YouTube Recommended Videos Comments
"simple-tab-groups@drive4ik" = extension "simple-tab-groups"; # Simple Tab Groups
"sponsorBlocker@ajay.app" = extension "sponsorblock"; # SponsorBlock
"{7a7a4a92-a2a0-41d1-9fd7-1e92480d612d}" = extension "styl-us"; # Stylus
#// "{a0370179-acc3-452f-9530-246b6adb2768}" = extension "svelte-devtools"; # Svelte Devtools
"uBlock0@raymondhill.net" = extension "ublock-origin"; # uBlock Origin
#// "{2662ff67-b302-4363-95f3-b050218bd72c}" = extension "untrap-for-youtube"; # UnTrap for YouTube
#// "{a6c4a591-f1b2-4f03-b3ff-767e5bedf4e7}" = extension "user-agent-string-switcher"; # User-Agent Switcher and Manager
#// "{c49b13b1-5dee-4345-925e-0c793377e3fa}" = extension "youtube-enhancer-vc"; # YouTube Enhancer
})
];
FirefoxHome = {
Highlights = false;
Pocket = false;
Search = false;
Snippets = false;
SponsoredPocket = false;
SponsoredTopSites = false;
TopSites = false;
Locked = true;
};
FirefoxSuggest = {
ImproveSuggest = false;
SponsoredSuggestions = false;
WebSuggestions = false;
Locked = true;
};
HardwareAcceleration = true;
Homepage = {
StartPage = "previous-session";
Locked = true;
};
NetworkPrediction = false;
NoDefaultBookmarks = true;
OfferToSaveLogins = false;
OverrideFirstRunPage = "";
PasswordManagerEnabled = false;
Permissions = {
Autoplay.Default = "block-audio-video";
Location.BlockNewRequests = true;
};
PictureInPicture = {
Enabled = true;
Locked = true;
};
PopupBlocking.Default = true;
#!! Only certain preferences are supported via policies
# https://mozilla.github.io/policy-templates/#preferences
#?? about:config
Preferences = let
locked = value: {
Value = value;
Status = "locked";
};
in {
"accessibility.browsewithcaret" = locked false;
"accessibility.typeaheadfind" = locked false;
"browser.aboutConfig.showWarning" = locked false;
"browser.contentblocking.category" = locked "standard";
"browser.crashReports.unsubmittedCheck.autoSubmit2" = locked false;
"browser.ctrlTab.sortByRecentlyUsed" = locked false;
"browser.download.always_ask_before_handling_new_types" = locked false;
"browser.download.useDownloadDir" = locked true;
"browser.link.open_newwindow" = locked 3; # New tab
"browser.link.open_newwindow.restriction" = locked 0; # Popups in new tab
"browser.newtabpage.enabled" = locked true;
"browser.preferences.defaultPerformanceSettings.enabled" = locked true;
"browser.quitShortcut.disabled" = locked true;
"browser.search.widget.inNavBar" = locked false;
"browser.startup.homepage" = locked "about:home";
"browser.startup.page" = locked 3; # Previous session
"browser.tabs.allowTabDetach" = locked false;
"browser.tabs.closeTabByDblclick" = locked true;
"browser.tabs.closeWindowWithLastTab" = locked false;
"browser.tabs.insertAfterCurrent" = locked false;
"browser.tabs.insertRelatedAfterCurrent" = locked false;
"browser.tabs.loadInBackground" = locked true;
"browser.tabs.warnOnClose" = locked false;
"browser.tabs.warnOnCloseOtherTabs" = locked false;
"browser.theme.dark-private-windows" = locked false;
"browser.toolbars.bookmarks.showOtherBookmarks" = locked false;
"browser.uidensity" = locked 0;
"browser.warnOnQuitShortcut" = locked true;
"dom.security.https_only_mode" = locked true;
"extensions.formautofill.addresses.enabled" = locked false;
"extensions.formautofill.creditCards.enabled" = locked false;
"general.autoScroll" = locked false;
"general.smoothScroll" = locked true;
"gfx.webrender.software" = locked config.custom.programs.looking-glass.igpu; # Reduce load on iGPU
"layers.acceleration.force-enabled" = locked true;
"layout.css.always_underline_links" = locked false;
"layout.css.backdrop-filter.enabled" = locked true;
"layout.spellcheckDefault" = locked 0; # Disabled
"media.eme.enabled" = locked true; # DRM
"media.ffmpeg.vaapi.enabled" = locked true;
"media.hardwaremediakeys.enabled" = locked true;
"media.hardware-video-decoding.enabled" = locked true;
#// "media.rdd-process.enabled" = locked false; # RDD sandbox #!! Insecure
"toolkit.legacyUserProfileCustomizations.stylesheets" = locked true;
"ui.key.menuAccessKey" = locked 0; # Disable menu key
"widget.gtk.overlay-scrollbars.enabled" = locked true;
"widget.gtk.rounded-bottom-corners.enabled" = locked true;
};
SearchBar = "unified";
# https://mozilla.github.io/policy-templates/#searchengines-this-policy-is-only-available-on-the-esr
SearchEngines = {
Default = "Kagi";
Add = [
{
Name = "Amazon";
Alias = "a";
IconURL = "https://www.amazon.com/favicon.ico";
URLTemplate = "https://www.amazon.com/s?k={searchTerms}";
}
{
Name = "ArchWiki";
Alias = "aw";
IconURL = "https://wiki.archlinux.org/favicon.ico";
URLTemplate = "https://wiki.archlinux.org/index.php?search={searchTerms}";
}
{
Name = "Brave";
Alias = "b";
IconURL = "https://cdn.search.brave.com/serp/v2/_app/immutable/assets/favicon.c09fe1a1.ico";
URLTemplate = "https://search.brave.com/search?q={searchTerms}";
}
{
Name = "Duck";
Alias = "d";
IconURL = "https://duckduckgo.com/favicon.ico";
URLTemplate = "https://duckduckgo.com/?q={searchTerms}";
SuggestURLTemplate = "https://duckduckgo.com/ac/?type=list&q={searchTerms}";
}
{
Name = "Docker Hub";
Alias = "dh";
IconURL = "https://hub.docker.com/favicon.ico";
URLTemplate = "https://hub.docker.com/search?q={searchTerms}";
}
{
Name = "e621";
Alias = "e";
IconURL = "https://e621.net/favicon.ico";
URLTemplate = "https://e621.net/posts?tags={searchTerms}";
}
{
Name = "Element Issues";
Alias = "ei";
IconURL = "https://github.com/favicon.ico";
URLTemplate = "https://github.com/element-hq/element-web/issues?q=is%3Aissue+is%3Aopen+{searchTerms}";
}
{
Name = "Flathub";
Alias = "fh";
IconURL = "https://flathub.org/favicon.png";
URLTemplate = "https://flathub.org/apps/search?q={searchTerms}";
}
{
Name = "Google";
Alias = "g";
IconURL = "https://www.google.com/favicon.ico";
URLTemplate = "https://www.google.com/search?q={searchTerms}";
}
{
Name = "Google Fonts";
Alias = "gf";
IconURL = "https://www.gstatic.com/images/icons/material/apps/fonts/1x/catalog/v5/favicon.svg";
URLTemplate = "https://fonts.google.com/?query={searchTerms}";
}
{
Name = "GitHub";
Alias = "gh";
IconURL = "https://github.com/favicon.ico";
URLTemplate = "https://github.com/search?q={searchTerms}";
}
{
Name = "Home Manager Issues";
Alias = "hi";
IconURL = "https://github.com/favicon.ico";
URLTemplate = "https://github.com/nix-community/home-manager/issues?q=is%3Aissue+is%3Aopen+{searchTerms}";
}
{
Name = "Home Manager Options";
Alias = "ho";
IconURL = "https://home-manager-options.extranix.com/images/favicon.png";
URLTemplate = "https://home-manager-options.extranix.com/?query={searchTerms}&release=master";
}
{
Name = "Hyprland Issues";
Alias = "hyi";
IconURL = "https://github.com/favicon.ico";
URLTemplate = "https://github.com/hyprwm/Hyprland/issues?q=is%3Aissue+is%3Aopen+{searchTerms}";
}
{
Name = "i3 Issues";
Alias = "ii";
IconURL = "https://github.com/favicon.ico";
URLTemplate = "https://github.com/i3/i3/issues?q=is%3Aissue+is%3Aopen+{searchTerms}";
}
{
Name = "Kagi";
Alias = "k";
IconURL = "https://kagi.com/asset/v2/favicon-32x32.png";
URLTemplate = "https://kagi.com/search?q={searchTerms}";
SuggestURLTemplate = "https://kagi.com/api/autosuggest?q={searchTerms}";
}
{
Name = "Lutris";
Alias = "l";
IconURL = "https://lutris.net/favicon.ico";
URLTemplate = "https://lutris.net/games?q={searchTerms}";
}
{
Name = "Lix Issues";
Alias = "li";
IconURL = "https://git.lix.systems/assets/img/favicon.png";
URLTemplate = "https://git.lix.systems/lix-project/lix/issues?state=open&q={searchTerms}";
}
{
Name = "Mozilla Web Docs";
Alias = "mdn";
IconURL = "https://developer.mozilla.org/favicon-48x48.cbbd161b.png";
URLTemplate = "https://developer.mozilla.org/en-US/search?q={searchTerms}";
}
{
Name = "MyNixOS Options";
Alias = "mno";
IconURL = "https://mynixos.com/favicon.ico";
URLTemplate = "https://mynixos.com/search?q=option+{searchTerms}";
}
{
Name = "Nix Dev";
Alias = "nd";
IconURL = "https://nix.dev/manual/nix/latest/favicon.png";
URLTemplate = "https://nix.dev/manual/nix/latest?search={searchTerms}";
}
{
Name = "NixOS Flakes";
Alias = "nf";
IconURL = "https://nixos.org/favicon.png";
URLTemplate = "https://search.nixos.org/flakes?channel=unstable&query={searchTerms}";
}
{
Name = "Nix Hub";
Alias = "nh";
IconURL = "https://www.nixhub.io/favicon.ico";
URLTemplate = "https://www.nixhub.io/search?q={searchTerms}";
}
{
Name = "NixOS Nixpkgs Issues";
Alias = "ni";
IconURL = "https://github.com/favicon.ico";
URLTemplate = "https://github.com/NixOS/nixpkgs/issues?q=is%3Aissue+is%3Aopen+{searchTerms}";
}
{
Name = "Nix PR";
Alias = "npr";
URLTemplate = "https://nixpk.gs/pr-tracker.html?pr={searchTerms}";
}
{
Name = "NixOS Options";
Alias = "no";
IconURL = "https://nixos.org/favicon.png";
URLTemplate = "https://search.nixos.org/options?channel=unstable&query={searchTerms}";
}
{
Name = "Noogle Dev";
Alias = "nod";
IconURL = "https://noogle.dev/favicon.png";
URLTemplate = "https://noogle.dev/q?term={searchTerms}";
}
{
Name = "NixOS Packages";
Alias = "np";
IconURL = "https://nixos.org/favicon.png";
URLTemplate = "https://search.nixos.org/packages?channel=unstable&query={searchTerms}";
}
{
Name = "Niri Issues";
Alias = "nri";
IconURL = "https://github.com/favicon.ico";
URLTemplate = "https://github.com/YaLTeR/niri/issues?q=is%3Aissue+is%3Aopen+{searchTerms}";
}
{
Name = "NixOS Wiki";
Alias = "nw";
IconURL = "https://wiki.nixos.org/favicon.ico";
URLTemplate = "https://wiki.nixos.org/w/index.php?search={searchTerms}";
}
{
Name = "Piped";
Alias = "p";
IconURL = "https://piped.${config.custom.domain}/favicon.ico";
URLTemplate = "https://piped.${config.custom.domain}/results?search_query={searchTerms}";
}
{
Name = "PCGamingWiki";
Alias = "pc";
IconURL = "https://static.pcgamingwiki.com/favicons/pcgamingwiki.png";
URLTemplate = "https://www.pcgamingwiki.com/w/index.php?search={searchTerms}";
}
{
Name = "ProtonDB";
Alias = "pdb";
IconURL = "https://www.protondb.com/sites/protondb/images/favicon.ico";
URLTemplate = "https://www.protondb.com/search?q={searchTerms}";
}
{
Name = "PyPI";
Alias = "pip";
IconURL = "https://pypi.org/static/images/favicon.35549fe8.ico";
URLTemplate = "https://pypi.org/search/?q={searchTerms}";
}
{
Name = "Reddit";
Alias = "r";
IconURL = "https://www.redditstatic.com/desktop2x/img/favicon/favicon-96x96.png";
URLTemplate = "https://kagi.com/search?q=site%3Areddit.com+{searchTerms}";
}
{
Name = "SearXNG";
Alias = "s";
IconURL = "https://search.${config.custom.domain}/static/themes/simple/img/favicon.png";
URLTemplate = "https://search.${config.custom.domain}/search?q={searchTerms}";
}
{
Name = "Sway Issues";
Alias = "si";
IconURL = "https://github.com/favicon.ico";
URLTemplate = "https://github.com/swaywm/sway/issues?q=is%3Aissue+is%3Aopen+{searchTerms}";
}
{
Name = "Wikipedia";
Alias = "w";
IconURL = "https://en.wikipedia.org/static/favicon/wikipedia.ico";
URLTemplate = "https://en.wikipedia.org/w/index.php?search={searchTerms}";
}
{
Name = "Wolfram Alpha";
Alias = "wa";
IconURL = "https://www.wolframalpha.com/_next/static/images/favicon_1zbE9hjk.ico";
URLTemplate = "https://www.wolframalpha.com/input?i={searchTerms}";
}
{
Name = "Walker Issues";
Alias = "wi";
IconURL = "https://github.com/favicon.ico";
URLTemplate = "https://github.com/abenz1267/walker/issues?q=is%3Aissue+is%3Aopen+{searchTerms}";
}
{
Name = "YouTube";
Alias = "y";
IconURL = "https://www.youtube.com/s/desktop/f8c8418d/img/favicon.ico";
URLTemplate = "https://www.youtube.com/results?search_query={searchTerms}";
}
];
Remove = [
"Amazon.com"
"Bing"
"DuckDuckGo"
"eBay"
"Google"
"Wikipedia (en)"
];
};
SearchSuggestEnabled = true;
ShowHomeButton = true;
UserMessaging = {
ExtensionRecommendations = false;
FeatureRecommendations = false;
MoreFromMozilla = false;
SkipOnboarding = false;
UrlbarInterventions = false;
WhatsNew = false;
Locked = true;
};
};
};
home.file = {
# TODO: Consider other themes
# https://github.com/soulhotel/FF-ULTIMA
# CSS theme to import into profile
# https://github.com/rafaelmardojai/firefox-gnome-theme
".mozilla/firefox/default/chrome/firefox-gnome-theme".source = inputs.firefox-gnome-theme;
# Imperative symlinks intended to be synced
"Downloads/stg" = mkIf config.custom.full {
source = config.home-manager.users.${config.custom.username}.lib.file.mkOutOfStoreSymlink "${config.custom.sync}/common/config/extensions/Simple Tab Groups";
};
# Work around icon dissociation due to missing --name flag in actions
# https://github.com/micheleg/dash-to-dock/issues/1968
#!! Keep updated with upstream desktop file
#?? cat /etc/profiles/per-user/myned/share/applications/firefox-esr.desktop
# ".local/share/applications/firefox-esr.desktop".text = ''
# [Desktop Entry]
# Actions=new-private-window;new-window;profile-manager-window
# Categories=Network;WebBrowser
# Exec=firefox --name firefox %U
# GenericName=Web Browser
# Icon=firefox
# MimeType=text/html;text/xml;application/xhtml+xml;application/vnd.mozilla.xul+xml;x-scheme-handler/http;x-scheme-handler/https
# Name=Firefox ESR
# StartupNotify=true
# StartupWMClass=firefox
# Terminal=false
# Type=Application
# Version=1.4
# [Desktop Action new-private-window]
# Exec=firefox --name firefox --private-window %U
# Name=New Private Window
# [Desktop Action new-window]
# Exec=firefox --name firefox --new-window %U
# Name=New Window
# [Desktop Action profile-manager-window]
# Exec=firefox --name firefox --ProfileManager
# Name=Profile Manager
# '';
};
};
}

View file

@ -0,0 +1,35 @@
{
config,
inputs,
lib,
pkgs,
...
}:
with lib; let
cfg = config.custom.programs.firefox;
in {
options.custom.programs.firefox = {
enable = mkOption {default = false;};
};
config = mkIf cfg.enable {
home-manager.sharedModules = [
{
# https://www.mozilla.org/en-US/firefox/developer
programs.firefox = mkMerge [
(import "${inputs.self}/modules/firefox.nix" {inherit config inputs lib pkgs;})
{
enable = true;
}
];
home.file = {
".mozilla/profiles.ini" = {
force = true;
};
};
}
];
};
}

View file

@ -0,0 +1,36 @@
{
config,
inputs,
lib,
pkgs,
...
}:
with lib; let
cfg = config.custom.programs.librewolf;
in {
options.custom.programs.librewolf = {
enable = mkOption {default = false;};
};
config = mkIf cfg.enable {
home-manager.sharedModules = [
{
# https://librewolf.net/
# https://codeberg.org/librewolf
programs.librewolf = mkMerge [
(import "${inputs.self}/modules/firefox.nix" {inherit config inputs lib pkgs;})
{
enable = true;
}
];
home.file = {
".librewolf/profiles.ini" = {
force = true;
};
};
}
];
};
}

View file

@ -1,17 +0,0 @@
{
config,
lib,
...
}:
with lib; let
cfg = config.custom.programs.librewolf;
in {
options.custom.programs.librewolf.enable = mkOption {default = false;};
config.home-manager.users.${config.custom.username} = mkIf cfg.enable {
# https://codeberg.org/librewolf
# TODO: Revisit when extensions can be managed declaratively
# https://github.com/nix-community/home-manager/issues/2803
programs.librewolf.enable = true;
};
}