added Linux arm64 SDK
This commit is contained in:
@@ -1,469 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013-2016 Apple Inc. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
WI.QuickConsole = class QuickConsole extends WI.View
|
||||
{
|
||||
constructor(element)
|
||||
{
|
||||
super(element);
|
||||
|
||||
this._toggleOrFocusKeyboardShortcut = new WI.KeyboardShortcut(null, WI.KeyboardShortcut.Key.Escape, this._toggleOrFocus.bind(this));
|
||||
this._toggleOrFocusKeyboardShortcut.implicitlyPreventsDefault = false;
|
||||
this._keyboardShortcutDisabled = false;
|
||||
|
||||
this._useExecutionContextOfInspectedNode = this._canUseExecutionContextOfInspectedNode();
|
||||
this._restoreSelectedExecutionContextForFrame = null;
|
||||
|
||||
this.element.classList.add("quick-console");
|
||||
this.element.addEventListener("mousedown", this._handleMouseDown.bind(this));
|
||||
this.element.addEventListener("dragover", this._handleDragOver.bind(this));
|
||||
this.element.addEventListener("drop", this._handleDrop.bind(this), true); // Ensure that dropping a DOM node doesn't copy text.
|
||||
|
||||
this.prompt = new WI.ConsolePrompt(null, "text/javascript");
|
||||
this.addSubview(this.prompt);
|
||||
|
||||
// FIXME: CodeMirror 4 has a default "Esc" key handler that always prevents default.
|
||||
// Our keyboard shortcut above will respect the default prevented and ignore the event
|
||||
// and not toggle the console. Install our own Escape key handler that will trigger
|
||||
// when the ConsolePrompt is empty, to restore toggling behavior. A better solution
|
||||
// would be for CodeMirror's event handler to pass if it doesn't do anything.
|
||||
this.prompt.escapeKeyHandlerWhenEmpty = function() { WI.toggleSplitConsole(); };
|
||||
|
||||
const navigationbarElement = null;
|
||||
this._navigationBar = new WI.NavigationBar(navigationbarElement, {sizesToFit: true});
|
||||
this.addSubview(this._navigationBar);
|
||||
|
||||
this._activeExecutionContextNavigationItemDivider = new WI.DividerNavigationItem;
|
||||
this._navigationBar.addNavigationItem(this._activeExecutionContextNavigationItemDivider);
|
||||
|
||||
this._activeExecutionContextNavigationItem = new WI.NavigationItem("active-execution-context");
|
||||
WI.addMouseDownContextMenuHandlers(this._activeExecutionContextNavigationItem.element, this._populateActiveExecutionContextNavigationItemContextMenu.bind(this));
|
||||
this._navigationBar.addNavigationItem(this._activeExecutionContextNavigationItem);
|
||||
|
||||
this._updateActiveExecutionContextDisplay();
|
||||
|
||||
WI.settings.consoleSavedResultAlias.addEventListener(WI.Setting.Event.Changed, this._handleConsoleSavedResultAliasSettingChanged, this);
|
||||
WI.settings.engineeringShowInternalExecutionContexts.addEventListener(WI.Setting.Event.Changed, this._handleEngineeringShowInternalExecutionContextsSettingChanged, this);
|
||||
|
||||
WI.Frame.addEventListener(WI.Frame.Event.PageExecutionContextChanged, this._handleFramePageExecutionContextChanged, this);
|
||||
WI.Frame.addEventListener(WI.Frame.Event.ExecutionContextsCleared, this._handleFrameExecutionContextsCleared, this);
|
||||
WI.Frame.addEventListener(WI.Frame.Event.ExecutionContextAdded, this._handleFrameExecutionContextAdded, this);
|
||||
|
||||
WI.debuggerManager.addEventListener(WI.DebuggerManager.Event.ActiveCallFrameDidChange, this._handleDebuggerActiveCallFrameDidChange, this);
|
||||
|
||||
WI.runtimeManager.addEventListener(WI.RuntimeManager.Event.ActiveExecutionContextChanged, this._handleActiveExecutionContextChanged, this);
|
||||
|
||||
WI.notifications.addEventListener(WI.Notification.TransitionPageTarget, this._handleTransitionPageTarget, this);
|
||||
|
||||
WI.targetManager.addEventListener(WI.TargetManager.Event.TargetRemoved, this._handleTargetRemoved, this);
|
||||
|
||||
WI.domManager.addEventListener(WI.DOMManager.Event.InspectedNodeChanged, this._handleInspectedNodeChanged, this);
|
||||
|
||||
WI.consoleDrawer.toggleButtonShortcutTooltip(this._toggleOrFocusKeyboardShortcut);
|
||||
WI.consoleDrawer.addEventListener(WI.ConsoleDrawer.Event.CollapsedStateChanged, this._updateStyles, this);
|
||||
WI.TabBrowser.addEventListener(WI.TabBrowser.Event.SelectedTabContentViewDidChange, this._updateStyles, this);
|
||||
|
||||
WI.whenTargetsAvailable().then(() => {
|
||||
this._updateActiveExecutionContextDisplay();
|
||||
});
|
||||
}
|
||||
|
||||
// Public
|
||||
|
||||
set keyboardShortcutDisabled(disabled)
|
||||
{
|
||||
this._keyboardShortcutDisabled = disabled;
|
||||
}
|
||||
|
||||
closed()
|
||||
{
|
||||
WI.settings.consoleSavedResultAlias.removeEventListener(WI.Setting.Event.Changed, this._handleConsoleSavedResultAliasSettingChanged, this);
|
||||
WI.settings.engineeringShowInternalExecutionContexts.removeEventListener(WI.Setting.Event.Changed, this._handleEngineeringShowInternalExecutionContextsSettingChanged, this);
|
||||
|
||||
WI.Frame.removeEventListener(WI.Frame.Event.PageExecutionContextChanged, this._handleFramePageExecutionContextChanged, this);
|
||||
WI.Frame.removeEventListener(WI.Frame.Event.ExecutionContextsCleared, this._handleFrameExecutionContextsCleared, this);
|
||||
|
||||
WI.debuggerManager.removeEventListener(WI.DebuggerManager.Event.ActiveCallFrameDidChange, this._handleDebuggerActiveCallFrameDidChange, this);
|
||||
|
||||
WI.runtimeManager.removeEventListener(WI.RuntimeManager.Event.ActiveExecutionContextChanged, this._handleActiveExecutionContextChanged, this);
|
||||
|
||||
WI.notifications.removeEventListener(WI.Notification.TransitionPageTarget, this._handleTransitionPageTarget, this);
|
||||
|
||||
WI.targetManager.removeEventListener(WI.TargetManager.Event.TargetRemoved, this._handleTargetRemoved, this);
|
||||
|
||||
WI.domManager.removeEventListener(WI.DOMManager.Event.InspectedNodeChanged, this._handleInspectedNodeChanged, this);
|
||||
|
||||
WI.consoleDrawer.removeEventListener(WI.ConsoleDrawer.Event.CollapsedStateChanged, this._updateStyles, this);
|
||||
WI.TabBrowser.removeEventListener(WI.TabBrowser.Event.SelectedTabContentViewDidChange, this._updateStyles, this);
|
||||
|
||||
super.closed();
|
||||
}
|
||||
|
||||
// Private
|
||||
|
||||
_displayNameForExecutionContext(context, maxLength = Infinity)
|
||||
{
|
||||
function truncate(string, length) {
|
||||
if (!Number.isFinite(maxLength))
|
||||
return string;
|
||||
return string.trim().truncateMiddle(length);
|
||||
}
|
||||
|
||||
if (context.type === WI.ExecutionContext.Type.Internal)
|
||||
return WI.unlocalizedString("[Internal] ") + context.name;
|
||||
|
||||
if (context.type === WI.ExecutionContext.Type.User) {
|
||||
let extensionName = WI.browserManager.extensionNameForExecutionContext(context);
|
||||
if (extensionName)
|
||||
return truncate(extensionName, maxLength);
|
||||
}
|
||||
|
||||
let target = context.target;
|
||||
if (target.type === WI.TargetType.Worker)
|
||||
return truncate(target.displayName, maxLength);
|
||||
|
||||
let frame = context.frame;
|
||||
if (frame) {
|
||||
if (context === frame.executionContextList.pageExecutionContext) {
|
||||
let resourceName = frame.mainResource.displayName;
|
||||
let frameName = frame.name;
|
||||
if (frameName) {
|
||||
// Attempt to show all of the frame name, but ensure that at least 20 characters
|
||||
// of the resource name are shown as well.
|
||||
let frameNameMaxLength = Math.max(maxLength - resourceName.length, 20);
|
||||
return WI.UIString("%s (%s)").format(truncate(frameName, frameNameMaxLength), truncate(resourceName, maxLength - frameNameMaxLength));
|
||||
}
|
||||
return truncate(resourceName, maxLength);
|
||||
}
|
||||
}
|
||||
|
||||
return truncate(context.name, maxLength);
|
||||
}
|
||||
|
||||
_resolveDesiredActiveExecutionContext(forceInspectedNode)
|
||||
{
|
||||
let executionContext = null;
|
||||
|
||||
if (this._useExecutionContextOfInspectedNode || forceInspectedNode) {
|
||||
let inspectedNode = WI.domManager.inspectedNode;
|
||||
if (inspectedNode) {
|
||||
let frame = inspectedNode.frame;
|
||||
if (frame) {
|
||||
let pageExecutionContext = frame.pageExecutionContext;
|
||||
if (pageExecutionContext)
|
||||
executionContext = pageExecutionContext;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!executionContext && WI.networkManager.mainFrame)
|
||||
executionContext = WI.networkManager.mainFrame.pageExecutionContext;
|
||||
|
||||
return executionContext || WI.mainTarget.executionContext;
|
||||
}
|
||||
|
||||
_setActiveExecutionContext(context)
|
||||
{
|
||||
let wasActive = WI.runtimeManager.activeExecutionContext === context;
|
||||
|
||||
WI.runtimeManager.activeExecutionContext = context;
|
||||
|
||||
if (wasActive)
|
||||
this._updateActiveExecutionContextDisplay();
|
||||
}
|
||||
|
||||
_updateActiveExecutionContextDisplay()
|
||||
{
|
||||
let toggleHidden = (hidden) => {
|
||||
this._activeExecutionContextNavigationItemDivider.hidden = hidden;
|
||||
this._activeExecutionContextNavigationItem.hidden = hidden;
|
||||
};
|
||||
|
||||
if (WI.debuggerManager.activeCallFrame) {
|
||||
toggleHidden(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!WI.runtimeManager.activeExecutionContext || !WI.networkManager.mainFrame) {
|
||||
toggleHidden(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (WI.networkManager.frames.length === 1 && !WI.targetManager.workerTargets.length) {
|
||||
let mainFrameContexts = WI.networkManager.mainFrame.executionContextList.contexts;
|
||||
let contextsToShow = mainFrameContexts.filter((context) => context.type !== WI.ExecutionContext.Type.Internal || WI.settings.engineeringShowInternalExecutionContexts.value);
|
||||
if (contextsToShow.length <= 1) {
|
||||
toggleHidden(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const maxLength = 40;
|
||||
|
||||
if (this._useExecutionContextOfInspectedNode) {
|
||||
this._activeExecutionContextNavigationItem.element.classList.add("automatic");
|
||||
this._activeExecutionContextNavigationItem.element.textContent = WI.UIString("Auto \u2014 %s").format(this._displayNameForExecutionContext(WI.runtimeManager.activeExecutionContext, maxLength));
|
||||
this._activeExecutionContextNavigationItem.tooltip = WI.UIString("Execution context for %s").format(WI.RuntimeManager.preferredSavedResultPrefix() + "0");
|
||||
} else {
|
||||
this._activeExecutionContextNavigationItem.element.classList.remove("automatic");
|
||||
this._activeExecutionContextNavigationItem.element.textContent = this._displayNameForExecutionContext(WI.runtimeManager.activeExecutionContext, maxLength);
|
||||
this._activeExecutionContextNavigationItem.tooltip = this._displayNameForExecutionContext(WI.runtimeManager.activeExecutionContext);
|
||||
}
|
||||
|
||||
this._activeExecutionContextNavigationItem.element.appendChild(WI.ImageUtilities.useSVGSymbol("Images/UpDownArrows.svg", "selector-arrows"));
|
||||
|
||||
toggleHidden(false);
|
||||
}
|
||||
|
||||
_populateActiveExecutionContextNavigationItemContextMenu(contextMenu)
|
||||
{
|
||||
const maxLength = 120;
|
||||
|
||||
let activeExecutionContext = WI.runtimeManager.activeExecutionContext;
|
||||
|
||||
if (this._canUseExecutionContextOfInspectedNode()) {
|
||||
let executionContextForInspectedNode = this._resolveDesiredActiveExecutionContext(true);
|
||||
contextMenu.appendCheckboxItem(WI.UIString("Auto \u2014 %s").format(this._displayNameForExecutionContext(executionContextForInspectedNode, maxLength)), () => {
|
||||
this._useExecutionContextOfInspectedNode = true;
|
||||
this._setActiveExecutionContext(executionContextForInspectedNode);
|
||||
}, this._useExecutionContextOfInspectedNode);
|
||||
|
||||
contextMenu.appendSeparator();
|
||||
}
|
||||
|
||||
let indent = 0;
|
||||
let addExecutionContext = (context) => {
|
||||
if (context.type === WI.ExecutionContext.Type.Internal && !WI.settings.engineeringShowInternalExecutionContexts.value)
|
||||
return;
|
||||
|
||||
let additionalIndent = (context.frame && context !== context.frame.executionContextList.pageExecutionContext) || context.type !== WI.ExecutionContext.Type.Normal;
|
||||
|
||||
// Mimic macOS `-[NSMenuItem setIndentationLevel]`.
|
||||
contextMenu.appendCheckboxItem(" ".repeat(indent + additionalIndent) + this._displayNameForExecutionContext(context, maxLength), () => {
|
||||
this._useExecutionContextOfInspectedNode = false;
|
||||
this._setActiveExecutionContext(context);
|
||||
}, activeExecutionContext === context);
|
||||
};
|
||||
|
||||
let addExecutionContextsForFrame = (frame) => {
|
||||
let pageExecutionContext = frame.executionContextList.pageExecutionContext;
|
||||
|
||||
let contexts = frame.executionContextList.contexts.sort((a, b) => {
|
||||
if (a === pageExecutionContext)
|
||||
return -1;
|
||||
if (b === pageExecutionContext)
|
||||
return 1;
|
||||
|
||||
const executionContextTypeRanking = [
|
||||
WI.ExecutionContext.Type.Normal,
|
||||
WI.ExecutionContext.Type.User,
|
||||
WI.ExecutionContext.Type.Internal,
|
||||
];
|
||||
return executionContextTypeRanking.indexOf(a.type) - executionContextTypeRanking.indexOf(b.type);
|
||||
});
|
||||
for (let context of contexts)
|
||||
addExecutionContext(context);
|
||||
};
|
||||
|
||||
let mainFrame = WI.networkManager.mainFrame;
|
||||
addExecutionContextsForFrame(mainFrame);
|
||||
|
||||
indent = 1;
|
||||
|
||||
let otherFrames = WI.networkManager.frames.filter((frame) => frame !== mainFrame && frame.executionContextList.pageExecutionContext);
|
||||
if (otherFrames.length) {
|
||||
contextMenu.appendHeader(WI.UIString("Frames", "Frames @ Execution Context Picker", "Title for list of HTML subframe JavaScript execution contexts"));
|
||||
|
||||
for (let frame of otherFrames)
|
||||
addExecutionContextsForFrame(frame);
|
||||
}
|
||||
|
||||
let workerTargets = WI.targetManager.workerTargets;
|
||||
if (workerTargets.length) {
|
||||
contextMenu.appendHeader(WI.UIString("Workers", "Workers @ Execution Context Picker", "Title for list of JavaScript web worker execution contexts"));
|
||||
|
||||
for (let target of workerTargets)
|
||||
addExecutionContext(target.executionContext);
|
||||
}
|
||||
}
|
||||
|
||||
_handleMouseDown(event)
|
||||
{
|
||||
if (event.target !== this.element)
|
||||
return;
|
||||
|
||||
event.preventDefault();
|
||||
this.prompt.focus();
|
||||
}
|
||||
|
||||
_handleDragOver(event)
|
||||
{
|
||||
if (event.dataTransfer.types.includes(WI.DOMTreeOutline.DOMNodeIdDragType)) {
|
||||
event.preventDefault();
|
||||
event.dataTransfer.dropEffect = "copy";
|
||||
}
|
||||
}
|
||||
|
||||
_handleDrop(event)
|
||||
{
|
||||
let domNodeId = event.dataTransfer.getData(WI.DOMTreeOutline.DOMNodeIdDragType);
|
||||
if (domNodeId) {
|
||||
event.preventDefault();
|
||||
|
||||
let domNode = WI.domManager.nodeForId(domNodeId);
|
||||
WI.RemoteObject.resolveNode(domNode, WI.RuntimeManager.ConsoleObjectGroup)
|
||||
.then((remoteObject) => {
|
||||
let text = domNode.nodeType() === Node.ELEMENT_NODE ? WI.UIString("Dropped Element") : WI.UIString("Dropped Node");
|
||||
WI.consoleLogViewController.appendImmediateExecutionWithResult(text, remoteObject, {addSpecialUserLogClass: true});
|
||||
|
||||
this.prompt.focus();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
_handleConsoleSavedResultAliasSettingChanged()
|
||||
{
|
||||
this._updateActiveExecutionContextDisplay();
|
||||
}
|
||||
|
||||
_handleEngineeringShowInternalExecutionContextsSettingChanged(event)
|
||||
{
|
||||
this._updateActiveExecutionContextDisplay();
|
||||
|
||||
if (WI.runtimeManager.activeExecutionContext.type !== WI.ExecutionContext.Type.Internal)
|
||||
return;
|
||||
|
||||
this._useExecutionContextOfInspectedNode = this._canUseExecutionContextOfInspectedNode();
|
||||
this._setActiveExecutionContext(this._resolveDesiredActiveExecutionContext());
|
||||
}
|
||||
|
||||
_handleFramePageExecutionContextChanged(event)
|
||||
{
|
||||
let frame = event.target;
|
||||
|
||||
if (this._restoreSelectedExecutionContextForFrame !== frame)
|
||||
return;
|
||||
|
||||
this._restoreSelectedExecutionContextForFrame = null;
|
||||
|
||||
this._useExecutionContextOfInspectedNode = false;
|
||||
this._setActiveExecutionContext(frame.pageExecutionContext);
|
||||
}
|
||||
|
||||
_handleFrameExecutionContextAdded(event)
|
||||
{
|
||||
this._updateActiveExecutionContextDisplay();
|
||||
}
|
||||
|
||||
_handleFrameExecutionContextsCleared(event)
|
||||
{
|
||||
let {committingProvisionalLoad, contexts} = event.data;
|
||||
|
||||
let hasActiveExecutionContext = contexts.some((context) => context === WI.runtimeManager.activeExecutionContext);
|
||||
if (!hasActiveExecutionContext) {
|
||||
this._updateActiveExecutionContextDisplay();
|
||||
return;
|
||||
}
|
||||
|
||||
// If this frame is navigating and it is selected in the UI we want to reselect its new item after navigation,
|
||||
// however when `_useExecutionContextOfInspectedNode` is true, we should keep the execution context set to `Auto`.
|
||||
if (committingProvisionalLoad && !this._restoreSelectedExecutionContextForFrame && !this._useExecutionContextOfInspectedNode) {
|
||||
this._restoreSelectedExecutionContextForFrame = event.target;
|
||||
|
||||
// As a fail safe, if the frame never gets an execution context, clear the restore value.
|
||||
setTimeout(() => {
|
||||
if (!this._restoreSelectedExecutionContextForFrame)
|
||||
return;
|
||||
this._restoreSelectedExecutionContextForFrame = null;
|
||||
|
||||
this._useExecutionContextOfInspectedNode = this._canUseExecutionContextOfInspectedNode();
|
||||
this._setActiveExecutionContext(this._resolveDesiredActiveExecutionContext());
|
||||
}, 100);
|
||||
return;
|
||||
}
|
||||
|
||||
this._useExecutionContextOfInspectedNode = this._canUseExecutionContextOfInspectedNode();
|
||||
this._setActiveExecutionContext(this._resolveDesiredActiveExecutionContext());
|
||||
}
|
||||
|
||||
_handleDebuggerActiveCallFrameDidChange(event)
|
||||
{
|
||||
this._updateActiveExecutionContextDisplay();
|
||||
}
|
||||
|
||||
_handleActiveExecutionContextChanged(event)
|
||||
{
|
||||
this._updateActiveExecutionContextDisplay();
|
||||
}
|
||||
|
||||
_handleTransitionPageTarget()
|
||||
{
|
||||
this._updateActiveExecutionContextDisplay();
|
||||
}
|
||||
|
||||
_handleTargetRemoved(event)
|
||||
{
|
||||
let {target} = event.data;
|
||||
if (target !== WI.runtimeManager.activeExecutionContext) {
|
||||
this._updateActiveExecutionContextDisplay();
|
||||
return;
|
||||
}
|
||||
|
||||
this._useExecutionContextOfInspectedNode = this._canUseExecutionContextOfInspectedNode();
|
||||
this._setActiveExecutionContext(this._resolveDesiredActiveExecutionContext());
|
||||
}
|
||||
|
||||
_handleInspectedNodeChanged(event)
|
||||
{
|
||||
if (!this._useExecutionContextOfInspectedNode)
|
||||
return;
|
||||
|
||||
this._setActiveExecutionContext(this._resolveDesiredActiveExecutionContext());
|
||||
}
|
||||
|
||||
_canUseExecutionContextOfInspectedNode()
|
||||
{
|
||||
return InspectorBackend.hasDomain("DOM");
|
||||
}
|
||||
|
||||
_toggleOrFocus(event)
|
||||
{
|
||||
if (this._keyboardShortcutDisabled)
|
||||
return;
|
||||
|
||||
if (this.prompt.focused) {
|
||||
WI.toggleSplitConsole();
|
||||
event.preventDefault();
|
||||
} else if (!WI.isEditingAnyField() && !WI.isEventTargetAnEditableField(event)) {
|
||||
this.prompt.focus();
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
_updateStyles()
|
||||
{
|
||||
this.element.classList.toggle("showing-log", WI.isShowingConsoleTab() || WI.isShowingSplitConsole());
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user