diff options
Diffstat (limited to 'application/basilisk/components/customizableui')
5 files changed, 13 insertions, 447 deletions
diff --git a/application/basilisk/components/customizableui/CustomizableUI.jsm b/application/basilisk/components/customizableui/CustomizableUI.jsm index cb0f519b2..ce395121c 100644 --- a/application/basilisk/components/customizableui/CustomizableUI.jsm +++ b/application/basilisk/components/customizableui/CustomizableUI.jsm @@ -38,7 +38,6 @@ const kPrefCustomizationState = "browser.uiCustomization.state"; const kPrefCustomizationAutoAdd = "browser.uiCustomization.autoAdd"; const kPrefCustomizationDebug = "browser.uiCustomization.debug"; const kPrefDrawInTitlebar = "browser.tabs.drawInTitlebar"; -const kPrefWebIDEInNavbar = "devtools.webide.widget.inNavbarByDefault"; const kExpectedWindowURL = "chrome://browser/content/browser.xul"; @@ -158,10 +157,7 @@ var gUIStateBeforeReset = { XPCOMUtils.defineLazyGetter(this, "log", () => { let scope = {}; Cu.import("resource://gre/modules/Console.jsm", scope); - let debug; - try { - debug = Services.prefs.getBoolPref(kPrefCustomizationDebug); - } catch (ex) {} + let debug = Services.prefs.getBoolPref(kPrefCustomizationDebug, false); let consoleOptions = { maxLogLevel: debug ? "all" : "log", prefix: "CustomizableUI", @@ -200,12 +196,9 @@ var CustomizableUIInternal = { "find-button", "preferences-button", "add-ons-button", - "sync-button", ]; - if (!AppConstants.MOZ_DEV_EDITION) { - panelPlacements.splice(-1, 0, "developer-button"); - } + panelPlacements.splice(-1, 0, "developer-button"); let showCharacterEncoding = Services.prefs.getComplexValue( "browser.menu.showCharacterEncoding", @@ -230,14 +223,6 @@ var CustomizableUIInternal = { "home-button", ]; - if (AppConstants.MOZ_DEV_EDITION) { - navbarPlacements.splice(2, 0, "developer-button"); - } - - if (Services.prefs.getBoolPref(kPrefWebIDEInNavbar)) { - navbarPlacements.push("webide-button"); - } - // Place this last, when createWidget is called for pocket, it will // append to the toolbar. if (Services.prefs.getPrefType("extensions.pocket.enabled") != Services.prefs.PREF_INVALID && @@ -1915,16 +1900,10 @@ var CustomizableUIInternal = { // state immediately when a browser window opens, which is important for // other consumers of this API. loadSavedState: function() { - let state = null; - try { - state = Services.prefs.getCharPref(kPrefCustomizationState); - } catch (e) { - log.debug("No saved state found"); - // This will fail if nothing has been customized, so silently fall back to - // the defaults. - } - + let state = Services.prefs.getCharPref(kPrefCustomizationState, ""); if (!state) { + log.debug("No saved state found"); + // Nothing has been customized, so silently fall back to the defaults. return; } try { @@ -2209,10 +2188,7 @@ var CustomizableUIInternal = { this.notifyListeners("onWidgetAdded", widget.id, widget.currentArea, widget.currentPosition); } else if (widgetMightNeedAutoAdding) { - let autoAdd = true; - try { - autoAdd = Services.prefs.getBoolPref(kPrefCustomizationAutoAdd); - } catch (e) {} + let autoAdd = Services.prefs.getBoolPref(kPrefCustomizationAutoAdd, true); // If the widget doesn't have an existing placement, and it hasn't been // seen before, then add it to its default area so it can be used. diff --git a/application/basilisk/components/customizableui/CustomizableWidgets.jsm b/application/basilisk/components/customizableui/CustomizableWidgets.jsm index 642e06f0f..d4a191a97 100644 --- a/application/basilisk/components/customizableui/CustomizableWidgets.jsm +++ b/application/basilisk/components/customizableui/CustomizableWidgets.jsm @@ -23,10 +23,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "CharsetMenu", "resource://gre/modules/CharsetMenu.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils", "resource://gre/modules/PrivateBrowsingUtils.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "SyncedTabs", - "resource://services-sync/SyncedTabs.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "ContextualIdentityService", - "resource://gre/modules/ContextualIdentityService.jsm"); XPCOMUtils.defineLazyGetter(this, "CharsetBundle", function() { const kCharsetBundle = "chrome://global/locale/charsetMenu.properties"; @@ -44,10 +40,7 @@ const kWidePanelItemClass = "panel-wide-item"; XPCOMUtils.defineLazyGetter(this, "log", () => { let scope = {}; Cu.import("resource://gre/modules/Console.jsm", scope); - let debug; - try { - debug = Services.prefs.getBoolPref(kPrefCustomizationDebug); - } catch (ex) {} + let debug = Services.prefs.getBoolPref(kPrefCustomizationDebug, false); let consoleOptions = { maxLogLevel: debug ? "all" : "log", prefix: "CustomizableWidgets", @@ -290,215 +283,6 @@ const CustomizableWidgets = [ log.debug("History view is being hidden!"); } }, { - id: "sync-button", - label: "remotetabs-panelmenu.label", - tooltiptext: "remotetabs-panelmenu.tooltiptext2", - type: "view", - viewId: "PanelUI-remotetabs", - defaultArea: CustomizableUI.AREA_PANEL, - deckIndices: { - DECKINDEX_TABS: 0, - DECKINDEX_TABSDISABLED: 1, - DECKINDEX_FETCHING: 2, - DECKINDEX_NOCLIENTS: 3, - }, - onCreated(aNode) { - // Add an observer to the button so we get the animation during sync. - // (Note the observer sets many attributes, including label and - // tooltiptext, but we only want the 'syncstatus' attribute for the - // animation) - let doc = aNode.ownerDocument; - let obnode = doc.createElementNS(kNSXUL, "observes"); - obnode.setAttribute("element", "sync-status"); - obnode.setAttribute("attribute", "syncstatus"); - aNode.appendChild(obnode); - - // A somewhat complicated dance to format the mobilepromo label. - let bundle = doc.getElementById("bundle_browser"); - let formatArgs = ["android", "ios"].map(os => { - let link = doc.createElement("label"); - link.textContent = bundle.getString(`appMenuRemoteTabs.mobilePromo.${os}`); - link.setAttribute("mobile-promo-os", os); - link.className = "text-link remotetabs-promo-link"; - return link.outerHTML; - }); - let promoParentElt = doc.getElementById("PanelUI-remotetabs-mobile-promo"); - // Put it all together... - let contents = bundle.getFormattedString("appMenuRemoteTabs.mobilePromo.text2", formatArgs); - promoParentElt.innerHTML = contents; - // We manually manage the "click" event to open the promo links because - // allowing the "text-link" widget handle it has 2 problems: (1) it only - // supports button 0 and (2) it's tricky to intercept when it does the - // open and auto-close the panel. (1) can probably be fixed, but (2) is - // trickier without hard-coding here the knowledge of exactly what buttons - // it does support. - // So we allow left and middle clicks to open the link in a new tab and - // close the panel; not setting a "href" attribute prevents the text-link - // widget handling it, and we build the final URL in the click handler to - // make testing easier (ie, so tests can change the pref after the links - // were created and have the new pref value used.) - promoParentElt.addEventListener("click", e => { - let os = e.target.getAttribute("mobile-promo-os"); - if (!os || e.button > 1) { - return; - } - let link = Services.prefs.getCharPref(`identity.mobilepromo.${os}`) + "synced-tabs"; - doc.defaultView.openUILinkIn(link, "tab"); - CustomizableUI.hidePanelForNode(e.target); - }); - }, - onViewShowing(aEvent) { - let doc = aEvent.target.ownerDocument; - this._tabsList = doc.getElementById("PanelUI-remotetabs-tabslist"); - Services.obs.addObserver(this, SyncedTabs.TOPIC_TABS_CHANGED, false); - - if (SyncedTabs.isConfiguredToSyncTabs) { - if (SyncedTabs.hasSyncedThisSession) { - this.setDeckIndex(this.deckIndices.DECKINDEX_TABS); - } else { - // Sync hasn't synced tabs yet, so show the "fetching" panel. - this.setDeckIndex(this.deckIndices.DECKINDEX_FETCHING); - } - // force a background sync. - SyncedTabs.syncTabs().catch(ex => { - Cu.reportError(ex); - }); - // show the current list - it will be updated by our observer. - this._showTabs(); - } else { - // not configured to sync tabs, so no point updating the list. - this.setDeckIndex(this.deckIndices.DECKINDEX_TABSDISABLED); - } - }, - onViewHiding() { - Services.obs.removeObserver(this, SyncedTabs.TOPIC_TABS_CHANGED); - this._tabsList = null; - }, - _tabsList: null, - observe(subject, topic, data) { - switch (topic) { - case SyncedTabs.TOPIC_TABS_CHANGED: - this._showTabs(); - break; - default: - break; - } - }, - setDeckIndex(index) { - let deck = this._tabsList.ownerDocument.getElementById("PanelUI-remotetabs-deck"); - // We call setAttribute instead of relying on the XBL property setter due - // to things going wrong when we try and set the index before the XBL - // binding has been created - see bug 1241851 for the gory details. - deck.setAttribute("selectedIndex", index); - }, - - _showTabsPromise: Promise.resolve(), - // Update the tab list after any existing in-flight updates are complete. - _showTabs() { - this._showTabsPromise = this._showTabsPromise.then(() => { - return this.__showTabs(); - }); - }, - // Return a new promise to update the tab list. - __showTabs() { - let doc = this._tabsList.ownerDocument; - return SyncedTabs.getTabClients().then(clients => { - // The view may have been hidden while the promise was resolving. - if (!this._tabsList) { - return; - } - if (clients.length === 0 && !SyncedTabs.hasSyncedThisSession) { - // the "fetching tabs" deck is being shown - let's leave it there. - // When that first sync completes we'll be notified and update. - return; - } - - if (clients.length === 0) { - this.setDeckIndex(this.deckIndices.DECKINDEX_NOCLIENTS); - return; - } - - this.setDeckIndex(this.deckIndices.DECKINDEX_TABS); - this._clearTabList(); - SyncedTabs.sortTabClientsByLastUsed(clients, 50 /* maxTabs */); - let fragment = doc.createDocumentFragment(); - - for (let client of clients) { - // add a menu separator for all clients other than the first. - if (fragment.lastChild) { - let separator = doc.createElementNS(kNSXUL, "menuseparator"); - fragment.appendChild(separator); - } - this._appendClient(client, fragment); - } - this._tabsList.appendChild(fragment); - }).catch(err => { - Cu.reportError(err); - }).then(() => { - // an observer for tests. - Services.obs.notifyObservers(null, "synced-tabs-menu:test:tabs-updated", null); - }); - }, - _clearTabList () { - let list = this._tabsList; - while (list.lastChild) { - list.lastChild.remove(); - } - }, - _showNoClientMessage() { - this._appendMessageLabel("notabslabel"); - }, - _appendMessageLabel(messageAttr, appendTo = null) { - if (!appendTo) { - appendTo = this._tabsList; - } - let message = this._tabsList.getAttribute(messageAttr); - let doc = this._tabsList.ownerDocument; - let messageLabel = doc.createElementNS(kNSXUL, "label"); - messageLabel.textContent = message; - appendTo.appendChild(messageLabel); - return messageLabel; - }, - _appendClient: function (client, attachFragment) { - let doc = attachFragment.ownerDocument; - // Create the element for the remote client. - let clientItem = doc.createElementNS(kNSXUL, "label"); - clientItem.setAttribute("itemtype", "client"); - let window = doc.defaultView; - clientItem.setAttribute("tooltiptext", - window.gSyncUI.formatLastSyncDate(new Date(client.lastModified))); - clientItem.textContent = client.name; - - attachFragment.appendChild(clientItem); - - if (client.tabs.length == 0) { - let label = this._appendMessageLabel("notabsforclientlabel", attachFragment); - label.setAttribute("class", "PanelUI-remotetabs-notabsforclient-label"); - } else { - for (let tab of client.tabs) { - let tabEnt = this._createTabElement(doc, tab); - attachFragment.appendChild(tabEnt); - } - } - }, - _createTabElement(doc, tabInfo) { - let item = doc.createElementNS(kNSXUL, "toolbarbutton"); - let tooltipText = (tabInfo.title ? tabInfo.title + "\n" : "") + tabInfo.url; - item.setAttribute("itemtype", "tab"); - item.setAttribute("class", "subviewbutton"); - item.setAttribute("targetURI", tabInfo.url); - item.setAttribute("label", tabInfo.title != "" ? tabInfo.title : tabInfo.url); - item.setAttribute("image", tabInfo.icon); - item.setAttribute("tooltiptext", tooltipText); - // We need to use "click" instead of "command" here so openUILink - // respects different buttons (eg, to open in a new tab). - item.addEventListener("click", e => { - doc.defaultView.openUILink(tabInfo.url, e); - CustomizableUI.hidePanelForNode(item); - }); - return item; - }, - }, { id: "privatebrowsing-button", shortcutId: "key_privatebrowsing", defaultArea: CustomizableUI.AREA_PANEL, @@ -1050,89 +834,6 @@ const CustomizableWidgets = [ let win = aEvent.view; win.MailIntegration.sendLinkForBrowser(win.gBrowser.selectedBrowser) } - }, { - id: "containers-panelmenu", - type: "view", - viewId: "PanelUI-containers", - hasObserver: false, - onCreated: function(aNode) { - let doc = aNode.ownerDocument; - let win = doc.defaultView; - let items = doc.getElementById("PanelUI-containersItems"); - - let onItemCommand = function (aEvent) { - let item = aEvent.target; - if (item.hasAttribute("usercontextid")) { - let userContextId = parseInt(item.getAttribute("usercontextid")); - win.openUILinkIn(win.BROWSER_NEW_TAB_URL, "tab", {userContextId}); - } - }; - items.addEventListener("command", onItemCommand); - - if (PrivateBrowsingUtils.isWindowPrivate(win)) { - aNode.setAttribute("disabled", "true"); - } - - this.updateVisibility(aNode); - - if (!this.hasObserver) { - Services.prefs.addObserver("privacy.userContext.enabled", this, true); - this.hasObserver = true; - } - }, - onViewShowing: function(aEvent) { - let doc = aEvent.target.ownerDocument; - - let items = doc.getElementById("PanelUI-containersItems"); - - while (items.firstChild) { - items.firstChild.remove(); - } - - let fragment = doc.createDocumentFragment(); - let bundle = doc.getElementById("bundle_browser"); - - ContextualIdentityService.getIdentities().forEach(identity => { - let label = ContextualIdentityService.getUserContextLabel(identity.userContextId); - - let item = doc.createElementNS(kNSXUL, "toolbarbutton"); - item.setAttribute("label", label); - item.setAttribute("usercontextid", identity.userContextId); - item.setAttribute("class", "subviewbutton"); - item.setAttribute("data-identity-color", identity.color); - item.setAttribute("data-identity-icon", identity.icon); - - fragment.appendChild(item); - }); - - fragment.appendChild(doc.createElementNS(kNSXUL, "menuseparator")); - - let item = doc.createElementNS(kNSXUL, "toolbarbutton"); - item.setAttribute("label", bundle.getString("userContext.aboutPage.label")); - item.setAttribute("command", "Browser:OpenAboutContainers"); - item.setAttribute("class", "subviewbutton"); - fragment.appendChild(item); - - items.appendChild(fragment); - }, - - updateVisibility(aNode) { - aNode.hidden = !Services.prefs.getBoolPref("privacy.userContext.enabled"); - }, - - observe(aSubject, aTopic, aData) { - let {instances} = CustomizableUI.getWidget("containers-panelmenu"); - for (let {node} of instances) { - if (node) { - this.updateVisibility(node); - } - } - }, - - QueryInterface: XPCOMUtils.generateQI([ - Ci.nsISupportsWeakReference, - Ci.nsIObserver - ]), }]; let preferencesButton = { diff --git a/application/basilisk/components/customizableui/CustomizeMode.jsm b/application/basilisk/components/customizableui/CustomizeMode.jsm index 4365ddfbc..2958655d2 100644 --- a/application/basilisk/components/customizableui/CustomizeMode.jsm +++ b/application/basilisk/components/customizableui/CustomizeMode.jsm @@ -40,9 +40,7 @@ let gDebug; XPCOMUtils.defineLazyGetter(this, "log", () => { let scope = {}; Cu.import("resource://gre/modules/Console.jsm", scope); - try { - gDebug = Services.prefs.getBoolPref(kPrefCustomizationDebug); - } catch (ex) {} + gDebug = Services.prefs.getBoolPref(kPrefCustomizationDebug, false); let consoleOptions = { maxLogLevel: gDebug ? "all" : "log", prefix: "CustomizeMode", @@ -1503,10 +1501,7 @@ CustomizeMode.prototype = { if (!AppConstants.CAN_DRAW_IN_TITLEBAR) { return; } - let drawInTitlebar = true; - try { - drawInTitlebar = Services.prefs.getBoolPref(kDrawInTitlebarPref); - } catch (ex) { } + let drawInTitlebar = Services.prefs.getBoolPref(kDrawInTitlebarPref, true); let button = this.document.getElementById("customization-titlebar-visibility-button"); // Drawing in the titlebar means 'hiding' the titlebar: if (drawInTitlebar) { diff --git a/application/basilisk/components/customizableui/content/panelUI.inc.xul b/application/basilisk/components/customizableui/content/panelUI.inc.xul index e389b14bf..da8077554 100644 --- a/application/basilisk/components/customizableui/content/panelUI.inc.xul +++ b/application/basilisk/components/customizableui/content/panelUI.inc.xul @@ -20,26 +20,6 @@ oncommand="gMenuButtonUpdateBadge.onMenuPanelCommand(event);" wrap="true" hidden="true"/> - <hbox id="PanelUI-footer-fxa"> - <hbox id="PanelUI-fxa-status" - defaultlabel="&fxaSignIn.label;" - signedinTooltiptext="&fxaSignedIn.tooltip;" - tooltiptext="&fxaSignedIn.tooltip;" - errorlabel="&fxaSignInError.label;" - unverifiedlabel="&fxaUnverified.label;" - onclick="if (event.which == 1) gFxAccounts.onMenuPanelCommand();"> - <image id="PanelUI-fxa-avatar"/> - <toolbarbutton id="PanelUI-fxa-label" - fxabrandname="&syncBrand.fxAccount.label;"/> - </hbox> - <toolbarseparator/> - <toolbarbutton id="PanelUI-fxa-icon" - oncommand="gSyncUI.doSync();" - closemenu="none"> - <observes element="sync-status" attribute="syncstatus"/> - <observes element="sync-status" attribute="tooltiptext"/> - </toolbarbutton> - </hbox> <hbox id="PanelUI-footer-inner"> <toolbarbutton id="PanelUI-customize" label="&appMenuCustomize.label;" @@ -102,95 +82,6 @@ oncommand="PlacesCommandHook.showPlacesOrganizer('History'); CustomizableUI.hidePanelForNode(this);"/> </panelview> - <panelview id="PanelUI-remotetabs" flex="1" class="PanelUI-subView"> - <label value="&appMenuRemoteTabs.label;" class="panel-subview-header"/> - <vbox class="panel-subview-body"> - <!-- this widget has 3 boxes in the body, but only 1 is ever visible --> - <!-- When Sync is ready to sync --> - <vbox id="PanelUI-remotetabs-main" observes="sync-syncnow-state"> - <vbox id="PanelUI-remotetabs-buttons"> - <toolbarbutton id="PanelUI-remotetabs-view-sidebar" - class="subviewbutton" - observes="viewTabsSidebar" - label="&appMenuRemoteTabs.sidebar.label;"/> - <toolbarbutton id="PanelUI-remotetabs-syncnow" - observes="sync-status" - class="subviewbutton" - oncommand="gSyncUI.doSync();" - closemenu="none"/> - <menuseparator id="PanelUI-remotetabs-separator"/> - </vbox> - <deck id="PanelUI-remotetabs-deck"> - <!-- Sync is ready to Sync and the "tabs" engine is enabled --> - <vbox id="PanelUI-remotetabs-tabspane"> - <vbox id="PanelUI-remotetabs-tabslist" - notabsforclientlabel="&appMenuRemoteTabs.notabs.label;" - /> - </vbox> - <!-- Sync is ready to Sync but the "tabs" engine isn't enabled--> - <hbox id="PanelUI-remotetabs-tabsdisabledpane" pack="center" flex="1"> - <vbox class="PanelUI-remotetabs-instruction-box"> - <hbox pack="center"> - <image class="fxaSyncIllustration" alt=""/> - </hbox> - <label class="PanelUI-remotetabs-instruction-label">&appMenuRemoteTabs.tabsnotsyncing.label;</label> - <hbox pack="center"> - <toolbarbutton class="PanelUI-remotetabs-prefs-button" - label="&appMenuRemoteTabs.openprefs.label;" - oncommand="gSyncUI.openSetup(null, 'synced-tabs');"/> - </hbox> - </vbox> - </hbox> - <!-- Sync is ready to Sync but we are still fetching the tabs to show --> - <vbox id="PanelUI-remotetabs-fetching"> - <!-- Show intentionally blank panel, see bug 1239845 --> - </vbox> - <!-- Sync has only 1 (ie, this) device connected --> - <hbox id="PanelUI-remotetabs-nodevicespane" pack="center" flex="1"> - <vbox class="PanelUI-remotetabs-instruction-box"> - <hbox pack="center"> - <image class="fxaSyncIllustration" alt=""/> - </hbox> - <label class="PanelUI-remotetabs-instruction-title">&appMenuRemoteTabs.noclients.title;</label> - <label class="PanelUI-remotetabs-instruction-label">&appMenuRemoteTabs.noclients.subtitle;</label> - <!-- The inner HTML for PanelUI-remotetabs-mobile-promo is built at runtime --> - <label id="PanelUI-remotetabs-mobile-promo" fxAccountsBrand="&syncBrand.fxAccount.label;"/> - </vbox> - </hbox> - </deck> - </vbox> - <!-- a box to ensure contained boxes are centered horizonally --> - <hbox pack="center" flex="1"> - <!-- When Sync is not configured --> - <vbox id="PanelUI-remotetabs-setupsync" - flex="1" - align="center" - class="PanelUI-remotetabs-instruction-box" - observes="sync-setup-state"> - <image class="fxaSyncIllustration" alt=""/> - <label class="PanelUI-remotetabs-instruction-label">&appMenuRemoteTabs.notsignedin.label;</label> - <toolbarbutton class="PanelUI-remotetabs-prefs-button" - label="&appMenuRemoteTabs.signin.label;" - oncommand="gSyncUI.openSetup(null, 'synced-tabs');"/> - </vbox> - <!-- When Sync needs re-authentication. This uses the exact same messaging - as "Sync is not configured" but remains a separate box so we get - the goodness of observing broadcasters to manage the hidden states --> - <vbox id="PanelUI-remotetabs-reauthsync" - flex="1" - align="center" - class="PanelUI-remotetabs-instruction-box" - observes="sync-reauth-state"> - <image class="fxaSyncIllustration" alt=""/> - <label class="PanelUI-remotetabs-instruction-label">&appMenuRemoteTabs.notsignedin.label;</label> - <toolbarbutton class="PanelUI-remotetabs-prefs-button" - label="&appMenuRemoteTabs.signin.label;" - oncommand="gSyncUI.openSetup(null, 'synced-tabs');"/> - </vbox> - </hbox> - </vbox> - </panelview> - <panelview id="PanelUI-bookmarks" flex="1" class="PanelUI-subView"> <label value="&bookmarksMenu.label;" class="panel-subview-header"/> <vbox class="panel-subview-body"> diff --git a/application/basilisk/components/customizableui/moz.build b/application/basilisk/components/customizableui/moz.build index 034630dc9..5797a03b0 100644 --- a/application/basilisk/components/customizableui/moz.build +++ b/application/basilisk/components/customizableui/moz.build @@ -9,7 +9,6 @@ DIRS += [ ] EXTRA_JS_MODULES += [ - 'CustomizableUI.jsm', 'CustomizableWidgets.jsm', 'CustomizeMode.jsm', 'DragPositionManager.jsm', @@ -17,5 +16,9 @@ EXTRA_JS_MODULES += [ 'ScrollbarSampler.jsm', ] +EXTRA_PP_JS_MODULES += [ + 'CustomizableUI.jsm', +] + if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'cocoa'): DEFINES['CAN_DRAW_IN_TITLEBAR'] = 1 |