mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-26 00:57:30 +09:00
Issue #1124: Remove Firefox Developer Edition code.
Removes all occurrences of MOZ_DEV_EDITION code and some helpers.
This commit is contained in:
parent
b7c0f39806
commit
1f68992bee
12 changed files with 5 additions and 223 deletions
|
|
@ -1009,12 +1009,7 @@ pref("services.sync.syncedTabs.showRemoteIcons", true);
|
||||||
|
|
||||||
pref("services.sync.sendTabToDevice.enabled", true);
|
pref("services.sync.sendTabToDevice.enabled", true);
|
||||||
|
|
||||||
// Developer edition preferences
|
|
||||||
#ifdef MOZ_DEV_EDITION
|
|
||||||
sticky_pref("lightweightThemes.selectedThemeID", "firefox-devedition@mozilla.org");
|
|
||||||
#else
|
|
||||||
sticky_pref("lightweightThemes.selectedThemeID", "");
|
sticky_pref("lightweightThemes.selectedThemeID", "");
|
||||||
#endif
|
|
||||||
|
|
||||||
// Whether the character encoding menu is under the main Firefox button. This
|
// Whether the character encoding menu is under the main Firefox button. This
|
||||||
// preference is a string so that localizers can alter it.
|
// preference is a string so that localizers can alter it.
|
||||||
|
|
|
||||||
|
|
@ -198,9 +198,7 @@ var CustomizableUIInternal = {
|
||||||
"add-ons-button",
|
"add-ons-button",
|
||||||
];
|
];
|
||||||
|
|
||||||
if (!AppConstants.MOZ_DEV_EDITION) {
|
panelPlacements.splice(-1, 0, "developer-button");
|
||||||
panelPlacements.splice(-1, 0, "developer-button");
|
|
||||||
}
|
|
||||||
|
|
||||||
let showCharacterEncoding = Services.prefs.getComplexValue(
|
let showCharacterEncoding = Services.prefs.getComplexValue(
|
||||||
"browser.menu.showCharacterEncoding",
|
"browser.menu.showCharacterEncoding",
|
||||||
|
|
@ -225,10 +223,6 @@ var CustomizableUIInternal = {
|
||||||
"home-button",
|
"home-button",
|
||||||
];
|
];
|
||||||
|
|
||||||
if (AppConstants.MOZ_DEV_EDITION) {
|
|
||||||
navbarPlacements.splice(2, 0, "developer-button");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Place this last, when createWidget is called for pocket, it will
|
// Place this last, when createWidget is called for pocket, it will
|
||||||
// append to the toolbar.
|
// append to the toolbar.
|
||||||
if (Services.prefs.getPrefType("extensions.pocket.enabled") != Services.prefs.PREF_INVALID &&
|
if (Services.prefs.getPrefType("extensions.pocket.enabled") != Services.prefs.PREF_INVALID &&
|
||||||
|
|
|
||||||
|
|
@ -1054,10 +1054,6 @@ BrowserGlue.prototype = {
|
||||||
|
|
||||||
// All initial windows have opened.
|
// All initial windows have opened.
|
||||||
_onWindowsRestored: function BG__onWindowsRestored() {
|
_onWindowsRestored: function BG__onWindowsRestored() {
|
||||||
if (AppConstants.MOZ_DEV_EDITION) {
|
|
||||||
this._createExtraDefaultProfile();
|
|
||||||
}
|
|
||||||
|
|
||||||
this._initServiceDiscovery();
|
this._initServiceDiscovery();
|
||||||
|
|
||||||
// Show update notification, if needed.
|
// Show update notification, if needed.
|
||||||
|
|
@ -1193,40 +1189,6 @@ BrowserGlue.prototype = {
|
||||||
E10SAccessibilityCheck.onWindowsRestored();
|
E10SAccessibilityCheck.onWindowsRestored();
|
||||||
},
|
},
|
||||||
|
|
||||||
_createExtraDefaultProfile: function () {
|
|
||||||
if (!AppConstants.MOZ_DEV_EDITION) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// If Developer Edition is the only installed Firefox version and no other
|
|
||||||
// profiles are present, create a second one for use by other versions.
|
|
||||||
// This helps Firefox versions earlier than 35 avoid accidentally using the
|
|
||||||
// unsuitable Developer Edition profile.
|
|
||||||
let profileService = Cc["@mozilla.org/toolkit/profile-service;1"]
|
|
||||||
.getService(Ci.nsIToolkitProfileService);
|
|
||||||
let profileCount = profileService.profileCount;
|
|
||||||
if (profileCount == 1 && profileService.selectedProfile.name != "default") {
|
|
||||||
let newProfile;
|
|
||||||
try {
|
|
||||||
newProfile = profileService.createProfile(null, "default");
|
|
||||||
profileService.defaultProfile = newProfile;
|
|
||||||
profileService.flush();
|
|
||||||
} catch (e) {
|
|
||||||
Cu.reportError("Could not create profile 'default': " + e);
|
|
||||||
}
|
|
||||||
if (newProfile) {
|
|
||||||
// We don't want a default profile with Developer Edition settings, an
|
|
||||||
// empty profile directory will do. The profile service of the other
|
|
||||||
// Firefox will populate it with its own stuff.
|
|
||||||
let newProfilePath = newProfile.rootDir.path;
|
|
||||||
OS.File.removeDir(newProfilePath).then(() => {
|
|
||||||
return OS.File.makeDir(newProfilePath);
|
|
||||||
}).then(null, e => {
|
|
||||||
Cu.reportError("Could not empty profile 'default': " + e);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_onQuitRequest: function BG__onQuitRequest(aCancelQuit, aQuitType) {
|
_onQuitRequest: function BG__onQuitRequest(aCancelQuit, aQuitType) {
|
||||||
// If user has already dismissed quit request, then do nothing
|
// If user has already dismissed quit request, then do nothing
|
||||||
if ((aCancelQuit instanceof Ci.nsISupportsPRBool) && aCancelQuit.data)
|
if ((aCancelQuit instanceof Ci.nsISupportsPRBool) && aCancelQuit.data)
|
||||||
|
|
|
||||||
|
|
@ -78,18 +78,6 @@ var gMainPane = {
|
||||||
setEventListener("chooseFolder", "command",
|
setEventListener("chooseFolder", "command",
|
||||||
gMainPane.chooseFolder);
|
gMainPane.chooseFolder);
|
||||||
|
|
||||||
if (AppConstants.MOZ_DEV_EDITION) {
|
|
||||||
let uAppData = OS.Constants.Path.userApplicationDataDir;
|
|
||||||
let ignoreSeparateProfile = OS.Path.join(uAppData, "ignore-dev-edition-profile");
|
|
||||||
|
|
||||||
setEventListener("separateProfileMode", "command", gMainPane.separateProfileModeChange);
|
|
||||||
let separateProfileModeCheckbox = document.getElementById("separateProfileMode");
|
|
||||||
setEventListener("getStarted", "click", gMainPane.onGetStarted);
|
|
||||||
|
|
||||||
OS.File.stat(ignoreSeparateProfile).then(() => separateProfileModeCheckbox.checked = false,
|
|
||||||
() => separateProfileModeCheckbox.checked = true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Notify observers that the UI is now ready
|
// Notify observers that the UI is now ready
|
||||||
Components.classes["@mozilla.org/observer-service;1"]
|
Components.classes["@mozilla.org/observer-service;1"]
|
||||||
.getService(Components.interfaces.nsIObserverService)
|
.getService(Components.interfaces.nsIObserverService)
|
||||||
|
|
@ -101,71 +89,6 @@ var gMainPane = {
|
||||||
// **STUB**
|
// **STUB**
|
||||||
},
|
},
|
||||||
|
|
||||||
separateProfileModeChange: function ()
|
|
||||||
{
|
|
||||||
if (AppConstants.MOZ_DEV_EDITION) {
|
|
||||||
function quitApp() {
|
|
||||||
Services.startup.quit(Ci.nsIAppStartup.eAttemptQuit | Ci.nsIAppStartup.eRestartNotSameProfile);
|
|
||||||
}
|
|
||||||
function revertCheckbox(error) {
|
|
||||||
separateProfileModeCheckbox.checked = !separateProfileModeCheckbox.checked;
|
|
||||||
if (error) {
|
|
||||||
Cu.reportError("Failed to toggle separate profile mode: " + error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function createOrRemoveSpecialDevEditionFile(onSuccess) {
|
|
||||||
let uAppData = OS.Constants.Path.userApplicationDataDir;
|
|
||||||
let ignoreSeparateProfile = OS.Path.join(uAppData, "ignore-dev-edition-profile");
|
|
||||||
|
|
||||||
if (separateProfileModeCheckbox.checked) {
|
|
||||||
OS.File.remove(ignoreSeparateProfile).then(onSuccess, revertCheckbox);
|
|
||||||
} else {
|
|
||||||
OS.File.writeAtomic(ignoreSeparateProfile, new Uint8Array()).then(onSuccess, revertCheckbox);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let separateProfileModeCheckbox = document.getElementById("separateProfileMode");
|
|
||||||
let button_index = confirmRestartPrompt(separateProfileModeCheckbox.checked,
|
|
||||||
0, false, true);
|
|
||||||
switch (button_index) {
|
|
||||||
case CONFIRM_RESTART_PROMPT_CANCEL:
|
|
||||||
revertCheckbox();
|
|
||||||
return;
|
|
||||||
case CONFIRM_RESTART_PROMPT_RESTART_NOW:
|
|
||||||
const Cc = Components.classes, Ci = Components.interfaces;
|
|
||||||
let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"]
|
|
||||||
.createInstance(Ci.nsISupportsPRBool);
|
|
||||||
Services.obs.notifyObservers(cancelQuit, "quit-application-requested",
|
|
||||||
"restart");
|
|
||||||
if (!cancelQuit.data) {
|
|
||||||
createOrRemoveSpecialDevEditionFile(quitApp);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Revert the checkbox in case we didn't quit
|
|
||||||
revertCheckbox();
|
|
||||||
return;
|
|
||||||
case CONFIRM_RESTART_PROMPT_RESTART_LATER:
|
|
||||||
createOrRemoveSpecialDevEditionFile();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
onGetStarted: function (aEvent) {
|
|
||||||
if (AppConstants.MOZ_DEV_EDITION) {
|
|
||||||
const Cc = Components.classes, Ci = Components.interfaces;
|
|
||||||
let wm = Cc["@mozilla.org/appshell/window-mediator;1"]
|
|
||||||
.getService(Ci.nsIWindowMediator);
|
|
||||||
let win = wm.getMostRecentWindow("navigator:browser");
|
|
||||||
|
|
||||||
if (win) {
|
|
||||||
let accountsTab = win.gBrowser.addTab("about:accounts?action=signin&entrypoint=dev-edition-setup");
|
|
||||||
win.gBrowser.selectedTab = accountsTab;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// HOME PAGE
|
// HOME PAGE
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -112,17 +112,6 @@
|
||||||
hidden="true">
|
hidden="true">
|
||||||
<caption><label>&startup.label;</label></caption>
|
<caption><label>&startup.label;</label></caption>
|
||||||
|
|
||||||
#ifdef MOZ_DEV_EDITION
|
|
||||||
<vbox id="separateProfileBox">
|
|
||||||
<checkbox id="separateProfileMode"
|
|
||||||
label="&separateProfileMode.label;"/>
|
|
||||||
<hbox align="center" class="indent">
|
|
||||||
<label id="useFirefoxSync">&useFirefoxSync.label;</label>
|
|
||||||
<label id="getStarted" class="text-link">&getStarted.label;</label>
|
|
||||||
</hbox>
|
|
||||||
</vbox>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_SHELL_SERVICE
|
#ifdef HAVE_SHELL_SERVICE
|
||||||
<vbox id="defaultBrowserBox">
|
<vbox id="defaultBrowserBox">
|
||||||
<hbox align="center">
|
<hbox align="center">
|
||||||
|
|
|
||||||
|
|
@ -304,16 +304,6 @@ var ProcessHangMonitor = {
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
|
|
||||||
if (AppConstants.MOZ_DEV_EDITION && report.hangType == report.SLOW_SCRIPT) {
|
|
||||||
buttons.push({
|
|
||||||
label: bundle.getString("processHang.button_debug.label"),
|
|
||||||
accessKey: bundle.getString("processHang.button_debug.accessKey"),
|
|
||||||
callback: function() {
|
|
||||||
ProcessHangMonitor.debugScript(win);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
nb.appendNotification(bundle.getString("processHang.label"),
|
nb.appendNotification(bundle.getString("processHang.label"),
|
||||||
"process-hang",
|
"process-hang",
|
||||||
"chrome://browser/skin/slowStartup-16.png",
|
"chrome://browser/skin/slowStartup-16.png",
|
||||||
|
|
|
||||||
|
|
@ -330,9 +330,7 @@ var gDevToolsBrowser = exports.gDevToolsBrowser = {
|
||||||
viewId: "PanelUI-developer",
|
viewId: "PanelUI-developer",
|
||||||
shortcutId: "key_devToolboxMenuItem",
|
shortcutId: "key_devToolboxMenuItem",
|
||||||
tooltiptext: "developer-button.tooltiptext2",
|
tooltiptext: "developer-button.tooltiptext2",
|
||||||
defaultArea: AppConstants.MOZ_DEV_EDITION ?
|
defaultArea: CustomizableUI.AREA_PANEL,
|
||||||
CustomizableUI.AREA_NAVBAR :
|
|
||||||
CustomizableUI.AREA_PANEL,
|
|
||||||
onViewShowing: function (aEvent) {
|
onViewShowing: function (aEvent) {
|
||||||
// Populate the subview with whatever menuitems are in the developer
|
// Populate the subview with whatever menuitems are in the developer
|
||||||
// menu. We skip menu elements, because the menu panel has no way
|
// menu. We skip menu elements, because the menu panel has no way
|
||||||
|
|
|
||||||
|
|
@ -231,11 +231,7 @@ pref("devtools.dom.enabled", false);
|
||||||
pref("devtools.webaudioeditor.inspectorWidth", 300);
|
pref("devtools.webaudioeditor.inspectorWidth", 300);
|
||||||
|
|
||||||
// Default theme ("dark" or "light")
|
// Default theme ("dark" or "light")
|
||||||
#ifdef MOZ_DEV_EDITION
|
|
||||||
sticky_pref("devtools.theme", "dark");
|
|
||||||
#else
|
|
||||||
sticky_pref("devtools.theme", "light");
|
sticky_pref("devtools.theme", "light");
|
||||||
#endif
|
|
||||||
|
|
||||||
// Web console filters
|
// Web console filters
|
||||||
pref("devtools.webconsole.filter.error", true);
|
pref("devtools.webconsole.filter.error", true);
|
||||||
|
|
|
||||||
|
|
@ -5569,10 +5569,6 @@ if test "$ACCESSIBILITY" -a "$MOZ_ENABLE_GTK" ; then
|
||||||
AC_DEFINE_UNQUOTED(ATK_REV_VERSION, $ATK_REV_VERSION)
|
AC_DEFINE_UNQUOTED(ATK_REV_VERSION, $ATK_REV_VERSION)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if test -n "$MOZ_DEV_EDITION"; then
|
|
||||||
AC_DEFINE(MOZ_DEV_EDITION)
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test "$MOZ_DEBUG"; then
|
if test "$MOZ_DEBUG"; then
|
||||||
A11Y_LOG=1
|
A11Y_LOG=1
|
||||||
fi
|
fi
|
||||||
|
|
|
||||||
|
|
@ -60,13 +60,6 @@ this.AppConstants = Object.freeze({
|
||||||
false,
|
false,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
MOZ_DEV_EDITION:
|
|
||||||
#ifdef MOZ_DEV_EDITION
|
|
||||||
true,
|
|
||||||
#else
|
|
||||||
false,
|
|
||||||
#endif
|
|
||||||
|
|
||||||
MOZ_SERVICES_HEALTHREPORT:
|
MOZ_SERVICES_HEALTHREPORT:
|
||||||
#ifdef MOZ_SERVICES_HEALTHREPORT
|
#ifdef MOZ_SERVICES_HEALTHREPORT
|
||||||
true,
|
true,
|
||||||
|
|
|
||||||
|
|
@ -425,22 +425,6 @@ nsToolkitProfileService::Init()
|
||||||
|
|
||||||
nsToolkitProfile* currentProfile = nullptr;
|
nsToolkitProfile* currentProfile = nullptr;
|
||||||
|
|
||||||
#ifdef MOZ_DEV_EDITION
|
|
||||||
nsCOMPtr<nsIFile> ignoreSeparateProfile;
|
|
||||||
rv = mAppData->Clone(getter_AddRefs(ignoreSeparateProfile));
|
|
||||||
if (NS_FAILED(rv))
|
|
||||||
return rv;
|
|
||||||
|
|
||||||
rv = ignoreSeparateProfile->AppendNative(NS_LITERAL_CSTRING("ignore-dev-edition-profile"));
|
|
||||||
if (NS_FAILED(rv))
|
|
||||||
return rv;
|
|
||||||
|
|
||||||
bool shouldIgnoreSeparateProfile;
|
|
||||||
rv = ignoreSeparateProfile->Exists(&shouldIgnoreSeparateProfile);
|
|
||||||
if (NS_FAILED(rv))
|
|
||||||
return rv;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
unsigned int c = 0;
|
unsigned int c = 0;
|
||||||
bool foundAuroraDefault = false;
|
bool foundAuroraDefault = false;
|
||||||
for (c = 0; true; ++c) {
|
for (c = 0; true; ++c) {
|
||||||
|
|
@ -501,35 +485,8 @@ nsToolkitProfileService::Init()
|
||||||
mChosen = currentProfile;
|
mChosen = currentProfile;
|
||||||
this->SetDefaultProfile(currentProfile);
|
this->SetDefaultProfile(currentProfile);
|
||||||
}
|
}
|
||||||
#ifdef MOZ_DEV_EDITION
|
|
||||||
// Use the dev-edition-default profile if this is an Aurora build and
|
|
||||||
// ignore-dev-edition-profile is not present.
|
|
||||||
if (name.EqualsLiteral("dev-edition-default") && !shouldIgnoreSeparateProfile) {
|
|
||||||
mChosen = currentProfile;
|
|
||||||
foundAuroraDefault = true;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef MOZ_DEV_EDITION
|
|
||||||
if (!foundAuroraDefault && !shouldIgnoreSeparateProfile) {
|
|
||||||
// If a single profile exists, it may not be already marked as default.
|
|
||||||
// Do it now to avoid problems when we create the dev-edition-default profile.
|
|
||||||
if (!mChosen && mFirst && !mFirst->mNext)
|
|
||||||
this->SetDefaultProfile(mFirst);
|
|
||||||
|
|
||||||
// Create a default profile for aurora, if none was found.
|
|
||||||
nsCOMPtr<nsIToolkitProfile> profile;
|
|
||||||
rv = CreateProfile(nullptr,
|
|
||||||
NS_LITERAL_CSTRING("dev-edition-default"),
|
|
||||||
getter_AddRefs(profile));
|
|
||||||
if (NS_FAILED(rv)) return rv;
|
|
||||||
mChosen = profile;
|
|
||||||
rv = Flush();
|
|
||||||
if (NS_FAILED(rv)) return rv;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!mChosen && mFirst && !mFirst->mNext) // only one profile
|
if (!mChosen && mFirst && !mFirst->mNext) // only one profile
|
||||||
mChosen = mFirst;
|
mChosen = mFirst;
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
|
|
||||||
|
|
@ -2174,9 +2174,9 @@ SelectProfile(nsIProfileLock* *aResult, nsIToolkitProfileService* aProfileSvc, n
|
||||||
return ShowProfileManager(aProfileSvc, aNative);
|
return ShowProfileManager(aProfileSvc, aNative);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef MOZ_DEV_EDITION
|
// Dev edition leftovers:
|
||||||
// If the only existing profile is the dev-edition-profile and this is not
|
// If the only existing profile is the dev-edition-profile,
|
||||||
// Developer Edition, then no valid profiles were found.
|
// then no valid profiles were found.
|
||||||
if (count == 1) {
|
if (count == 1) {
|
||||||
nsCOMPtr<nsIToolkitProfile> deProfile;
|
nsCOMPtr<nsIToolkitProfile> deProfile;
|
||||||
// GetSelectedProfile will auto-select the only profile if there's just one
|
// GetSelectedProfile will auto-select the only profile if there's just one
|
||||||
|
|
@ -2187,7 +2187,6 @@ SelectProfile(nsIProfileLock* *aResult, nsIToolkitProfileService* aProfileSvc, n
|
||||||
count = 0;
|
count = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!count) {
|
if (!count) {
|
||||||
gDoMigration = true;
|
gDoMigration = true;
|
||||||
|
|
@ -2196,25 +2195,15 @@ SelectProfile(nsIProfileLock* *aResult, nsIToolkitProfileService* aProfileSvc, n
|
||||||
// create a default profile
|
// create a default profile
|
||||||
nsCOMPtr<nsIToolkitProfile> profile;
|
nsCOMPtr<nsIToolkitProfile> profile;
|
||||||
nsresult rv = aProfileSvc->CreateProfile(nullptr, // choose a default dir for us
|
nsresult rv = aProfileSvc->CreateProfile(nullptr, // choose a default dir for us
|
||||||
#ifdef MOZ_DEV_EDITION
|
|
||||||
NS_LITERAL_CSTRING("dev-edition-default"),
|
|
||||||
#else
|
|
||||||
NS_LITERAL_CSTRING("default"),
|
NS_LITERAL_CSTRING("default"),
|
||||||
#endif
|
|
||||||
getter_AddRefs(profile));
|
getter_AddRefs(profile));
|
||||||
if (NS_SUCCEEDED(rv)) {
|
if (NS_SUCCEEDED(rv)) {
|
||||||
#ifndef MOZ_DEV_EDITION
|
|
||||||
aProfileSvc->SetDefaultProfile(profile);
|
aProfileSvc->SetDefaultProfile(profile);
|
||||||
#endif
|
|
||||||
aProfileSvc->Flush();
|
aProfileSvc->Flush();
|
||||||
rv = profile->Lock(nullptr, aResult);
|
rv = profile->Lock(nullptr, aResult);
|
||||||
if (NS_SUCCEEDED(rv)) {
|
if (NS_SUCCEEDED(rv)) {
|
||||||
if (aProfileName)
|
if (aProfileName)
|
||||||
#ifdef MOZ_DEV_EDITION
|
|
||||||
aProfileName->AssignLiteral("dev-edition-default");
|
|
||||||
#else
|
|
||||||
aProfileName->AssignLiteral("default");
|
aProfileName->AssignLiteral("default");
|
||||||
#endif
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue