diff --git a/.npmrc b/.npmrc index 182a5846b90..74507e103e0 100644 --- a/.npmrc +++ b/.npmrc @@ -1,7 +1,7 @@ runtime = electron target_arch = x64 -brave_electron_version = 5.0.6 -chromedriver_version = 2.33 -target = v5.0.6 +brave_electron_version = 5.1.0 +chromedriver_version = 2.35 +target = v5.1.0 disturl=https://brave-laptop-binaries.s3.amazonaws.com/atom-shell/dist/ build_from_source = true diff --git a/app/browser/reducers/ledgerReducer.js b/app/browser/reducers/ledgerReducer.js index c4942d6f795..9ff932db3b2 100644 --- a/app/browser/reducers/ledgerReducer.js +++ b/app/browser/reducers/ledgerReducer.js @@ -4,11 +4,13 @@ const Immutable = require('immutable') const {BrowserWindow} = require('electron') +const {getWebContents} = require('../webContentsCache') // Constants const appConstants = require('../../../js/constants/appConstants') const windowConstants = require('../../../js/constants/windowConstants') const settings = require('../../../js/constants/settings') +const tabActionConstants = require('../../common/constants/tabAction') // State const ledgerState = require('../../common/state/ledgerState') @@ -369,22 +371,20 @@ const ledgerReducer = (state, action, immutableAction) => { state = ledgerApi.pageDataChanged(state) break } - case windowConstants.WINDOW_GOT_RESPONSE_DETAILS: + case tabActionConstants.FINISH_NAVIGATION: { if (!getSetting(settings.PAYMENTS_ENABLED)) { break } - // Only capture response for the page (not sub resources, like images, JavaScript, etc) - if (action.getIn(['details', 'resourceType']) === 'mainFrame') { - const pageUrl = action.getIn(['details', 'newURL']) - - // create a page view event if this is a page load on the active tabId - const lastActiveTabId = pageDataState.getLastActiveTabId(state) - const tabId = action.get('tabId') + // create a page view event if this is a page load on the active tabId + const lastActiveTabId = pageDataState.getLastActiveTabId(state) + const tabId = action.get('tabId') + const tab = getWebContents(tabId) + if (tab && !tab.isDestroyed()) { if (!lastActiveTabId || tabId === lastActiveTabId) { state = ledgerApi.pageDataChanged(state, { - location: pageUrl, + location: tab.getURL(), tabId }) } diff --git a/app/browser/tabs.js b/app/browser/tabs.js index e9e62702716..80d8d491d5d 100644 --- a/app/browser/tabs.js +++ b/app/browser/tabs.js @@ -3,7 +3,6 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ const appActions = require('../../js/actions/appActions') -const windowActions = require('../../js/actions/windowActions') const tabActions = require('../common/actions/tabActions') const config = require('../../js/constants/config') const Immutable = require('immutable') @@ -715,12 +714,6 @@ const api = { appActions.updatePassword(username, origin, tabId) }) - tab.on('did-get-response-details', (evt, status, newURL, originalURL, httpResponseCode, requestMethod, referrer, headers, resourceType) => { - if (resourceType === 'mainFrame') { - windowActions.gotResponseDetails(tabId, {status, newURL, originalURL, httpResponseCode, requestMethod, referrer, resourceType}) - } - }) - tab.on('media-started-playing', (e) => { let tabValue = getTabValue(tabId) if (tabValue) { diff --git a/app/common/state/contextMenuState.js b/app/common/state/contextMenuState.js index 31840aa9830..aa4b5cf356e 100644 --- a/app/common/state/contextMenuState.js +++ b/app/common/state/contextMenuState.js @@ -5,6 +5,7 @@ const Immutable = require('immutable') const assert = require('assert') const { makeImmutable, isMap } = require('./immutableUtil') +const uuid = require('uuid') const validateState = function (state) { state = makeImmutable(state) @@ -12,31 +13,34 @@ const validateState = function (state) { return state } +let contextMenuDetail = Immutable.Map() + const api = { setContextMenu: (windowState, detail) => { detail = makeImmutable(detail) windowState = validateState(windowState) if (!detail) { - if (windowState.getIn(['contextMenuDetail', 'type']) === 'hamburgerMenu') { + if (contextMenuDetail.get('type') === 'hamburgerMenu') { windowState = windowState.set('hamburgerMenuWasOpen', true) } else { windowState = windowState.set('hamburgerMenuWasOpen', false) } + contextMenuDetail = Immutable.Map() windowState = windowState.delete('contextMenuDetail') } else { if (!(detail.get('type') === 'hamburgerMenu' && windowState.get('hamburgerMenuWasOpen'))) { - windowState = windowState.set('contextMenuDetail', detail) + contextMenuDetail = detail + windowState = windowState.set('contextMenuDetail', uuid()) } windowState = windowState.set('hamburgerMenuWasOpen', false) } - return windowState }, getContextMenu: (windowState) => { windowState = validateState(windowState) - return windowState.get('contextMenuDetail', Immutable.Map()) + return contextMenuDetail }, selectedIndex: (windowState) => { diff --git a/app/common/tracing.js b/app/common/tracing.js index 747a1ac3d11..7a07012ddf7 100644 --- a/app/common/tracing.js +++ b/app/common/tracing.js @@ -52,7 +52,7 @@ exports.trace = (obj, ...args) => { } return function (...fnArgs) { metadata.name = propKey - muon.crashReporter.setCrashKeyValue('javascript-info', JSON.stringify(metadata)) + muon.crashReporter.setJavascriptInfoCrashValue(JSON.stringify(metadata)) let result, end, exception const start = timer.now() try { @@ -64,7 +64,7 @@ exports.trace = (obj, ...args) => { metadata.stack = e.stack != null ? e.stack : e.name + ': ' + e.message exception = e } - muon.crashReporter.setCrashKeyValue('javascript-info', JSON.stringify(metadata)) + muon.crashReporter.setJavascriptInfoCrashValue(JSON.stringify(metadata)) if (exception) { muon.crashReporter.dumpWithoutCrashing() throw exception diff --git a/app/crash-herald.js b/app/crash-herald.js index 682bc53b14b..de23e0e6458 100644 --- a/app/crash-herald.js +++ b/app/crash-herald.js @@ -8,19 +8,13 @@ const {app} = require('electron') const version = app.getVersion() const channel = Channel.channel() -const crashKeys = { - '_version': version, - 'channel': channel -} - const initCrashKeys = () => { // set muon-app-version switch to pass version to renderer processes app.commandLine.appendSwitch('muon-app-version', version) app.commandLine.appendSwitch('muon-app-channel', channel) - for (let key in crashKeys) { - muon.crashReporter.setCrashKeyValue(key, crashKeys[key]) - } + muon.crashReporter.setVersionCrashValue(version) + muon.crashReporter.setChannelCrashValue(channel) } exports.init = (enabled) => { diff --git a/app/filtering.js b/app/filtering.js index a863d6a0d34..1ac18a063f9 100644 --- a/app/filtering.js +++ b/app/filtering.js @@ -582,12 +582,6 @@ function registerForDownloadListener (session) { const hostWebContents = webContents.hostWebContents || webContents const win = BrowserWindow.fromWebContents(hostWebContents) || BrowserWindow.getFocusedWindow() - // TODO(bridiver) - move this fix to muon - const controller = webContents.controller() - if (controller && controller.isValid() && controller.isInitialNavigation()) { - webContents.forceClose() - } - item.setPrompt(getSetting(settings.DOWNLOAD_ALWAYS_ASK) || false) const downloadId = item.getGuid() diff --git a/app/index.js b/app/index.js index 5388932c3b0..010782d343c 100644 --- a/app/index.js +++ b/app/index.js @@ -16,7 +16,7 @@ const telemetry = require('./telemetry') telemetry.setCheckpoint('init') const handleUncaughtError = (stack, message) => { - muon.crashReporter.setCrashKeyValue('javascript-info', JSON.stringify({stack, message})) + muon.crashReporter.setJavascriptInfoCrashValue(JSON.stringify({stack, message})) muon.crashReporter.dumpWithoutCrashing() if (!ready) { diff --git a/app/renderer/components/common/browserButton.js b/app/renderer/components/common/browserButton.js index 739911fc1c8..145ca5dc63d 100644 --- a/app/renderer/components/common/browserButton.js +++ b/app/renderer/components/common/browserButton.js @@ -168,8 +168,8 @@ const styles = StyleSheet.create({ browserButton_primaryColor: { background: globalStyles.button.primary.background, - borderLeft: '2px solid transparent', - borderRight: '2px solid transparent', + borderLeft: `2px solid ${globalStyles.button.primary.gradientColor1}`, + borderRight: `2px solid ${globalStyles.button.primary.gradientColor2}`, borderTop: `2px solid ${globalStyles.button.primary.gradientColor1}`, borderBottom: `2px solid ${globalStyles.button.primary.gradientColor2}`, cursor: 'pointer', diff --git a/app/renderer/components/common/contextMenu/contextMenu.js b/app/renderer/components/common/contextMenu/contextMenu.js index 0cd139fae4e..7fee3668926 100644 --- a/app/renderer/components/common/contextMenu/contextMenu.js +++ b/app/renderer/components/common/contextMenu/contextMenu.js @@ -15,6 +15,9 @@ const windowActions = require('../../../../../js/actions/windowActions') // Constants const keyCodes = require('../../../../common/constants/keyCodes') +// State +const contextMenuState = require('../../../../common/state/contextMenuState') + // Utils const frameStateUtil = require('../../../../../js/state/frameStateUtil') const {separatorMenuItem} = require('../../../../common/commonMenu') @@ -218,7 +221,7 @@ class ContextMenu extends React.Component { const currentWindow = state.get('currentWindow') const activeFrame = frameStateUtil.getActiveFrame(currentWindow) || Immutable.Map() const selectedIndex = currentWindow.getIn(['ui', 'contextMenu', 'selectedIndex'], null) - const contextMenuDetail = currentWindow.get('contextMenuDetail', Immutable.Map()) + const contextMenuDetail = contextMenuState.getContextMenu(currentWindow) const props = {} props.lastZoomPercentage = activeFrame.get('lastZoomPercentage') diff --git a/app/renderer/components/common/contextMenu/contextMenuItem.js b/app/renderer/components/common/contextMenu/contextMenuItem.js index 3d5a0bec824..ed6eb3f1e52 100644 --- a/app/renderer/components/common/contextMenu/contextMenuItem.js +++ b/app/renderer/components/common/contextMenu/contextMenuItem.js @@ -304,7 +304,8 @@ const styles = StyleSheet.create({ }, item: { - maxWidth: '420px', + maxWidth: 'inherit', + minWidth: 'inherit', paddingTop: '6px', paddingRight: '10px', paddingBottom: '6px', diff --git a/app/renderer/components/frame/frame.js b/app/renderer/components/frame/frame.js index 1ce7897ee17..a247bcb1416 100644 --- a/app/renderer/components/frame/frame.js +++ b/app/renderer/components/frame/frame.js @@ -24,6 +24,7 @@ const windowStore = require('../../../../js/stores/windowStore') const appStoreRenderer = require('../../../../js/stores/appStoreRenderer') // State +const contextMenuState = require('../../../common/state/contextMenuState') const siteSettings = require('../../../../js/state/siteSettings') const siteSettingsState = require('../../../common/state/siteSettingsState') const tabState = require('../../../common/state/tabState') @@ -866,7 +867,7 @@ class Frame extends React.Component { const allSiteSettings = siteSettingsState.getAllSiteSettings(state, isPrivate) const frameSiteSettings = siteSettings.getSiteSettingsForURL(allSiteSettings, location) || Immutable.Map() - const contextMenu = currentWindow.get('contextMenuDetail') + const contextMenu = contextMenuState.getContextMenu(currentWindow) const tab = tabId && tabId > -1 && tabState.getByTabId(state, tabId) const props = {} diff --git a/docs/state.md b/docs/state.md index ec7f5abcb1d..292d301267d 100644 --- a/docs/state.md +++ b/docs/state.md @@ -677,7 +677,7 @@ WindowStore }, cleanedOnShutdown: boolean, // whether app data was successfully cleared on shutdown closedFrames: [], // holds the same type of frame objects as frames - contextMenuDetail: { + contextMenuDetail: { // currently using uuid hack to avoid serializing click function in template bottom: number, // the bottom position of the context menu left: number, // the left position of the context menu maxHeight: number, // the maximum height of the context menu diff --git a/img/windows/win10_close.svg b/img/windows/win10_close.svg index 4b13c389c2e..623e749f9a8 100644 --- a/img/windows/win10_close.svg +++ b/img/windows/win10_close.svg @@ -1 +1 @@ -win10_close \ No newline at end of file +win10_close diff --git a/img/windows/win10_close_white.svg b/img/windows/win10_close_white.svg index 06a79e1480d..92a12b9d766 100644 --- a/img/windows/win10_close_white.svg +++ b/img/windows/win10_close_white.svg @@ -1 +1 @@ -win10_close_white \ No newline at end of file +win10_close_white diff --git a/img/windows/win10_expand.svg b/img/windows/win10_expand.svg index db90536216c..8963d2f205f 100644 --- a/img/windows/win10_expand.svg +++ b/img/windows/win10_expand.svg @@ -1 +1 @@ -win10_expand \ No newline at end of file +win10_expand diff --git a/img/windows/win10_minimize.svg b/img/windows/win10_minimize.svg index 194eb2cfa40..240bae94661 100644 --- a/img/windows/win10_minimize.svg +++ b/img/windows/win10_minimize.svg @@ -1 +1 @@ -win10_minimize \ No newline at end of file +win10_minimize diff --git a/img/windows/win10_restore.svg b/img/windows/win10_restore.svg index 88bd3851d09..73694077ce1 100644 --- a/img/windows/win10_restore.svg +++ b/img/windows/win10_restore.svg @@ -1 +1 @@ -win10_restore \ No newline at end of file +win10_restore diff --git a/js/actions/windowActions.js b/js/actions/windowActions.js index ca02820f052..821ca8b4168 100644 --- a/js/actions/windowActions.js +++ b/js/actions/windowActions.js @@ -550,9 +550,16 @@ const windowActions = { * @param {Object} detail - The context menu detail */ setContextMenuDetail: function (detail) { + // TODO(darkdh): This is a hack to prevent dispatch from serializing + // click function in template. `contextMenuDetail` is just a uuid to trigger + // state update for new menu + const Immutable = require('immutable') + const contextMenuState = require('../../app/common/state/contextMenuState') + let state = contextMenuState.setContextMenu(Immutable.Map(), detail) + const contextMenuDetail = state.get('contextMenuDetail') dispatch({ actionType: windowConstants.WINDOW_SET_CONTEXT_MENU_DETAIL, - detail + contextMenuDetail }) }, @@ -955,20 +962,6 @@ const windowActions = { }) }, - /** - * Used to get response details (such as the HTTP response code) from a response - * See `eventStore.js` for an example use-case - * @param {number} tabId - the tab id to set - * @param {Object} details - object containing response details - */ - gotResponseDetails: function (tabId, details) { - dispatch({ - actionType: windowConstants.WINDOW_GOT_RESPONSE_DETAILS, - tabId, - details - }) - }, - /** * Fired when the mouse clicks or hovers over a bookmark folder in the bookmarks toolbar * @param {number} folderId - from the siteDetail for the bookmark folder diff --git a/js/constants/appConfig.js b/js/constants/appConfig.js index 54684d2d086..faa2cf1ffa9 100644 --- a/js/constants/appConfig.js +++ b/js/constants/appConfig.js @@ -19,7 +19,7 @@ module.exports = { name: 'Brave', contactUrl: 'mailto:support+laptop@brave.com', quitTimeout: isTest ? 3 * 1000 : 10 * 1000, - sessionSaveInterval: 1000 * 60 * 5, + sessionSaveInterval: process.env.BRAVE_SESSION_SAVE_INTERVAL * 1000 || 1000 * 60 * 5, resourceNames: { ADBLOCK: 'adblock', SAFE_BROWSING: 'safeBrowsing', diff --git a/js/constants/windowConstants.js b/js/constants/windowConstants.js index 9318e2bcb89..2eee5779bc3 100644 --- a/js/constants/windowConstants.js +++ b/js/constants/windowConstants.js @@ -73,7 +73,6 @@ const windowConstants = { WINDOW_RESET_MENU_STATE: _, WINDOW_SET_MENUBAR_SELECTED_INDEX: _, WINDOW_SET_LAST_FOCUSED_SELECTOR: _, - WINDOW_GOT_RESPONSE_DETAILS: _, WINDOW_SET_BOOKMARKS_TOOLBAR_SELECTED_FOLDER_ID: _, WINDOW_SET_MODAL_DIALOG_DETAIL: _, WINDOW_WIDEVINE_SITE_ACCESSED_WITHOUT_INSTALL: _, diff --git a/js/stores/windowStore.js b/js/stores/windowStore.js index baa9ab4ece9..1ca09074bf2 100644 --- a/js/stores/windowStore.js +++ b/js/stores/windowStore.js @@ -480,21 +480,28 @@ const doAction = (action) => { windowState = windowState.delete('bookmarkFolderDetail') break case windowConstants.WINDOW_AUTOFILL_SELECTION_CLICKED: + windowState = contextMenuState.setContextMenu(windowState) ipc.send('autofill-selection-clicked', action.tabId, action.value, action.frontEndId, action.index) - windowState = windowState.delete('contextMenuDetail') break case windowConstants.WINDOW_AUTOFILL_POPUP_HIDDEN: - if (!action.detail && - windowState.getIn(['contextMenuDetail', 'type']) === 'autofill' && - windowState.getIn(['contextMenuDetail', 'tabId']) === action.tabId) { - windowState = windowState.delete('contextMenuDetail') - if (action.notify) { - ipc.send('autofill-popup-hidden', action.tabId) + { + const contextMenuDetail = contextMenuState.getContextMenu(windowState) + if (!action.detail && + contextMenuDetail.get('type') === 'autofill' && + contextMenuDetail.get('tabId') === action.tabId) { + windowState = contextMenuState.setContextMenu(windowState) + if (action.notify) { + ipc.send('autofill-popup-hidden', action.tabId) + } } + break } - break case windowConstants.WINDOW_SET_CONTEXT_MENU_DETAIL: - windowState = contextMenuState.setContextMenu(windowState, action.detail) + if (action.contextMenuDetail) { + windowState = windowState.set('contextMenuDetail', action.contextMenuDetail) + } else { + windowState = windowState.delete('contextMenuDetail') + } break case windowConstants.WINDOW_SET_POPUP_WINDOW_DETAIL: if (!action.detail) { diff --git a/less/button.less b/less/button.less index bb1fe78153f..b12f734a932 100644 --- a/less/button.less +++ b/less/button.less @@ -82,7 +82,8 @@ span.buttonSeparator { &.primaryButton { background: linear-gradient(@braveLightOrange, @braveOrange); - border: 2px solid transparent; + border-left: 2px solid @braveLightOrange; + border-right: 2px solid @braveOrange; border-top: 2px solid @braveLightOrange; border-bottom: 2px solid @braveOrange; box-shadow: @buttonShadow; diff --git a/package-lock.json b/package-lock.json index 13eeb2c552d..f7feeab575a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30,15 +30,6 @@ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" }, - "abstract-leveldown": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-2.6.3.tgz", - "integrity": "sha512-2++wDf/DYqkPR3o5tbfdhF96EfMApo1GpPfzOsR/ZYXdkSmELlvOOEAl9iKkRsktMPHdGjO4rtkBpf2I7TiTeA==", - "dev": true, - "requires": { - "xtend": "4.0.1" - } - }, "accepts": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", @@ -2705,7 +2696,7 @@ "resolved": "https://registry.npmjs.org/bunyan/-/bunyan-1.8.12.tgz", "integrity": "sha1-8VDw9nSKvdcq6uhPBEA74u8RN5c=", "requires": { - "dtrace-provider": "0.8.6", + "dtrace-provider": "github:brave/node-dtrace-provider#a7cdc53514e631ce536ef7fe0d526af17e246b53", "moment": "2.20.1", "mv": "2.1.1", "safe-json-stringify": "1.1.0" @@ -4600,15 +4591,6 @@ } } }, - "deferred-leveldown": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/deferred-leveldown/-/deferred-leveldown-1.2.2.tgz", - "integrity": "sha512-uukrWD2bguRtXilKt6cAWKyoXrTSMo5m7crUdLfWQmu8kIm88w3QZoUL+6nhpfKVmhHANER6Re3sKoNoZ3IKMA==", - "dev": true, - "requires": { - "abstract-leveldown": "2.6.3" - } - }, "define-properties": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz", @@ -4922,12 +4904,9 @@ } }, "dtrace-provider": { - "version": "0.8.6", - "resolved": "https://registry.npmjs.org/dtrace-provider/-/dtrace-provider-0.8.6.tgz", - "integrity": "sha1-QooiOv4DQl0s1tY0f99AxmkDVj0=", - "optional": true, + "version": "github:brave/node-dtrace-provider#a7cdc53514e631ce536ef7fe0d526af17e246b53", "requires": { - "nan": "2.9.2" + "nan": "2.8.0" } }, "duplexer2": { @@ -5202,6 +5181,55 @@ } } }, + "electron-download": { + "version": "github:brave/electron-download#409b65caff14edeef1daa36a7445ba6334658d7c", + "dev": true, + "requires": { + "debug": "2.6.9", + "home-path": "1.0.5", + "minimist": "1.2.0", + "mkdirp": "0.5.1", + "mv": "2.1.1", + "nugget": "1.6.2", + "path-exists": "1.0.0", + "rc": "1.2.5" + }, + "dependencies": { + "nugget": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/nugget/-/nugget-1.6.2.tgz", + "integrity": "sha1-iMpuA7pXBqmRc/XaCQJZPWvK4Qc=", + "dev": true, + "requires": { + "debug": "2.6.9", + "minimist": "1.2.0", + "pretty-bytes": "1.0.4", + "progress-stream": "1.2.0", + "request": "2.83.0", + "single-line-log": "0.4.1", + "throttleit": "0.0.2" + } + }, + "path-exists": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-1.0.0.tgz", + "integrity": "sha1-1aiZjrce83p0w06w2eum6HjuoIE=", + "dev": true + }, + "single-line-log": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/single-line-log/-/single-line-log-0.4.1.tgz", + "integrity": "sha1-h6VWSfdJ14PsDc2AToFA2Yc8fO4=", + "dev": true + }, + "throttleit": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-0.0.2.tgz", + "integrity": "sha1-z+34jmDADdlpe2H90qg0OptoDq8=", + "dev": true + } + } + }, "electron-download-tf": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/electron-download-tf/-/electron-download-tf-4.3.4.tgz", @@ -5414,20 +5442,6 @@ "integrity": "sha1-HUixB9ghJqLz4hHC6iX4A7pVGyE=", "dev": true }, - "electron-download": { - "version": "github:brave/electron-download#409b65caff14edeef1daa36a7445ba6334658d7c", - "dev": true, - "requires": { - "debug": "2.6.9", - "home-path": "1.0.5", - "minimist": "1.2.0", - "mkdirp": "0.5.1", - "mv": "2.1.1", - "nugget": "1.6.2", - "path-exists": "1.0.0", - "rc": "1.2.5" - } - }, "electron-osx-sign": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/electron-osx-sign/-/electron-osx-sign-0.3.2.tgz", @@ -5471,27 +5485,6 @@ "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=", "dev": true }, - "nugget": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/nugget/-/nugget-1.6.2.tgz", - "integrity": "sha1-iMpuA7pXBqmRc/XaCQJZPWvK4Qc=", - "dev": true, - "requires": { - "debug": "2.6.9", - "minimist": "1.2.0", - "pretty-bytes": "1.0.4", - "progress-stream": "1.2.0", - "request": "2.83.0", - "single-line-log": "0.4.1", - "throttleit": "0.0.2" - } - }, - "path-exists": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-1.0.0.tgz", - "integrity": "sha1-1aiZjrce83p0w06w2eum6HjuoIE=", - "dev": true - }, "plist": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/plist/-/plist-1.2.0.tgz", @@ -5504,18 +5497,6 @@ "xmldom": "0.1.27" } }, - "single-line-log": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/single-line-log/-/single-line-log-0.4.1.tgz", - "integrity": "sha1-h6VWSfdJ14PsDc2AToFA2Yc8fO4=", - "dev": true - }, - "throttleit": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-0.0.2.tgz", - "integrity": "sha1-z+34jmDADdlpe2H90qg0OptoDq8=", - "dev": true - }, "xmlbuilder": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-4.0.0.tgz", @@ -5533,55 +5514,6 @@ "requires": { "electron-download": "github:brave/electron-download#409b65caff14edeef1daa36a7445ba6334658d7c", "extract-zip": "1.6.6" - }, - "dependencies": { - "electron-download": { - "version": "github:brave/electron-download#409b65caff14edeef1daa36a7445ba6334658d7c", - "dev": true, - "requires": { - "debug": "2.6.9", - "home-path": "1.0.5", - "minimist": "1.2.0", - "mkdirp": "0.5.1", - "mv": "2.1.1", - "nugget": "1.6.2", - "path-exists": "1.0.0", - "rc": "1.2.5" - } - }, - "nugget": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/nugget/-/nugget-1.6.2.tgz", - "integrity": "sha1-iMpuA7pXBqmRc/XaCQJZPWvK4Qc=", - "dev": true, - "requires": { - "debug": "2.6.9", - "minimist": "1.2.0", - "pretty-bytes": "1.0.4", - "progress-stream": "1.2.0", - "request": "2.83.0", - "single-line-log": "0.4.1", - "throttleit": "0.0.2" - } - }, - "path-exists": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-1.0.0.tgz", - "integrity": "sha1-1aiZjrce83p0w06w2eum6HjuoIE=", - "dev": true - }, - "single-line-log": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/single-line-log/-/single-line-log-0.4.1.tgz", - "integrity": "sha1-h6VWSfdJ14PsDc2AToFA2Yc8fO4=", - "dev": true - }, - "throttleit": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-0.0.2.tgz", - "integrity": "sha1-z+34jmDADdlpe2H90qg0OptoDq8=", - "dev": true - } } }, "electron-publish": { @@ -5661,6 +5593,34 @@ "iconv-lite": "0.4.19" } }, + "encoding-down": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/encoding-down/-/encoding-down-4.0.0.tgz", + "integrity": "sha512-jyhdwd61FJEXJQk9KaaUIXXoe6Uix15lBGY/pBv1qEqFgOuzSwgREeb0eaP7ZdA7C3rNFBhs6Fj/RifNkLCaFw==", + "dev": true, + "requires": { + "abstract-leveldown": "4.0.3", + "level-codec": "8.0.0", + "level-errors": "1.0.5" + }, + "dependencies": { + "abstract-leveldown": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-4.0.3.tgz", + "integrity": "sha512-qsIHFQy0u17JqSY+3ZUT+ykqxYY17yOfvAsLkFkw8kSQqi05d1jyj0bCuSX6sjYlXuY9cKpgUt5EudQdP4aXyA==", + "dev": true, + "requires": { + "xtend": "4.0.1" + } + }, + "level-codec": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/level-codec/-/level-codec-8.0.0.tgz", + "integrity": "sha512-gNZlo1HRHz0BWxzGCyNf7xntAs2HKOPvvRBWtXsoDvEX4vMYnSTBS6ZnxoaiX7nhxSBPpegRa8CQ/hnfGBKk3Q==", + "dev": true + } + } + }, "end-of-stream": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", @@ -7436,7 +7396,7 @@ "dev": true, "optional": true, "requires": { - "nan": "2.9.2", + "nan": "2.8.0", "node-pre-gyp": "0.6.39" }, "dependencies": { @@ -10704,7 +10664,7 @@ "optional": true, "requires": { "browserify-sha3": "0.0.1", - "sha3": "1.2.0" + "sha3": "github:brave/node-sha3#d44d293e997c061560c2bd8a41451ab979e5a4ca" } }, "killable": { @@ -10994,125 +10954,109 @@ } }, "level": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/level/-/level-1.7.0.tgz", - "integrity": "sha1-Q0ZKOounOy895WokKSgFFG2iE6E=", - "dev": true, - "requires": { - "level-packager": "1.2.1", - "leveldown": "1.7.2" - } - }, - "level-codec": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/level-codec/-/level-codec-7.0.1.tgz", - "integrity": "sha512-Ua/R9B9r3RasXdRmOtd+t9TCOEIIlts+TN/7XTT2unhDaL6sJn83S3rUyljbr6lVtw49N3/yA0HHjpV6Kzb2aQ==", - "dev": true - }, - "level-errors": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/level-errors/-/level-errors-1.0.5.tgz", - "integrity": "sha512-/cLUpQduF6bNrWuAC4pwtUKA5t669pCsCi2XbmojG2tFeOr9j6ShtdDCtFFQO1DRt+EVZhx9gPzP9G2bUaG4ig==", - "dev": true, - "requires": { - "errno": "0.1.7" - } - }, - "level-iterator-stream": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/level-iterator-stream/-/level-iterator-stream-1.3.1.tgz", - "integrity": "sha1-5Dt4sagUPm+pek9IXrjqUwNS8u0=", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/level/-/level-2.1.2.tgz", + "integrity": "sha512-BPcWD6a1oNSXU9b9V/rCaYfmDGhoJ7AezgZ7IKOrR5d9TXz0GRtGNFWm6rCfo3Y36w3nUeP9OefFvy13YiSoYQ==", "dev": true, "requires": { - "inherits": "2.0.3", - "level-errors": "1.0.5", - "readable-stream": "1.1.14", - "xtend": "4.0.1" + "level-packager": "2.1.1", + "leveldown": "2.1.1", + "opencollective": "1.0.3" }, "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true + "abstract-leveldown": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-4.0.3.tgz", + "integrity": "sha512-qsIHFQy0u17JqSY+3ZUT+ykqxYY17yOfvAsLkFkw8kSQqi05d1jyj0bCuSX6sjYlXuY9cKpgUt5EudQdP4aXyA==", + "dev": true, + "requires": { + "xtend": "4.0.1" + } }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "deferred-leveldown": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/deferred-leveldown/-/deferred-leveldown-3.0.0.tgz", + "integrity": "sha512-ajbXqRPMXRlcdyt0TuWqknOJkp1JgQjGB7xOl2V+ebol7/U11E9h3/nCZAtN1M7djmAJEIhypCUc1tIWxdQAuQ==", + "dev": true, + "requires": { + "abstract-leveldown": "4.0.3" + } + }, + "level-errors": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/level-errors/-/level-errors-1.1.2.tgz", + "integrity": "sha512-Sw/IJwWbPKF5Ai4Wz60B52yj0zYeqzObLh8k1Tk88jVmD51cJSKWSYpRyhVIvFzZdvsPqlH5wfhp/yxdsaQH4w==", + "dev": true, + "requires": { + "errno": "0.1.7" + } + }, + "level-iterator-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/level-iterator-stream/-/level-iterator-stream-2.0.0.tgz", + "integrity": "sha512-TWOYw8HR5mhj6xwoVLo0yu26RPL6v28KgvhK1kY1CJf9LyL+rJXjx99zhORTYhN9ysOBIH+iaxAiqRteA+C1/g==", "dev": true, "requires": { - "core-util-is": "1.0.2", "inherits": "2.0.3", - "isarray": "0.0.1", - "string_decoder": "0.10.31" + "readable-stream": "2.3.4", + "xtend": "4.0.1" } }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true - } - } - }, - "level-packager": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/level-packager/-/level-packager-1.2.1.tgz", - "integrity": "sha1-Bn/t/Qcrf+PGvsYIDAy9SmsuEfQ=", - "dev": true, - "requires": { - "levelup": "1.3.9" - } - }, - "leveldown": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/leveldown/-/leveldown-1.7.2.tgz", - "integrity": "sha1-XjRnuyfuJGpKe429j7KxYgam64s=", - "dev": true, - "requires": { - "abstract-leveldown": "2.6.3", - "bindings": "1.2.1", - "fast-future": "1.0.2", - "nan": "2.6.2", - "prebuild-install": "2.5.1" - }, - "dependencies": { - "bindings": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.2.1.tgz", - "integrity": "sha1-FK1hE4EtLTfXLme0ystLtyZQXxE=", - "dev": true + "level-packager": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/level-packager/-/level-packager-2.1.1.tgz", + "integrity": "sha512-6l3G6dVkmdvHwOJrEA9d9hL6SSFrzwjQoLP8HsvohOgfY/8Z9LyTKNCM5Gc84wtsUWCuIHu6r+S6WrCtTWUJCw==", + "dev": true, + "requires": { + "encoding-down": "4.0.0", + "levelup": "2.0.2" + } }, - "nan": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.6.2.tgz", - "integrity": "sha1-5P805slf37WuzAjeZZb0NgWn20U=", - "dev": true + "leveldown": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/leveldown/-/leveldown-2.1.1.tgz", + "integrity": "sha512-JNMCTSchq1YtQLMGePmT07UE7hIIYR4GHpZI7+nUXbM9XgNtRAwcBGhnyJyITwpTILTkUcNPBKZ9lZmTUj2E3g==", + "dev": true, + "requires": { + "abstract-leveldown": "3.0.0", + "bindings": "1.3.0", + "fast-future": "1.0.2", + "nan": "2.8.0", + "prebuild-install": "2.5.1" + }, + "dependencies": { + "abstract-leveldown": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-3.0.0.tgz", + "integrity": "sha512-KUWx9UWGQD12zsmLNj64/pndaz4iJh/Pj7nopgkfDG6RlCcbMZvT6+9l7dchK4idog2Is8VdC/PvNbFuFmalIQ==", + "dev": true, + "requires": { + "xtend": "4.0.1" + } + } + } + }, + "levelup": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/levelup/-/levelup-2.0.2.tgz", + "integrity": "sha512-us+nTLUyd/eLnclYYddOCdAVw1hnymGx/9p4Jr5ThohStsjLqMVmbYiz6/SYFZEPXNF+AKQSvh6fA2e2KZpC8w==", + "dev": true, + "requires": { + "deferred-leveldown": "3.0.0", + "level-errors": "1.1.2", + "level-iterator-stream": "2.0.0", + "xtend": "4.0.1" + } } } }, - "levelup": { - "version": "1.3.9", - "resolved": "https://registry.npmjs.org/levelup/-/levelup-1.3.9.tgz", - "integrity": "sha512-VVGHfKIlmw8w1XqpGOAGwq6sZm2WwWLmlDcULkKWQXEA5EopA8OBNJ2Ck2v6bdk8HeEZSbCSEgzXadyQFm76sQ==", + "level-errors": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/level-errors/-/level-errors-1.0.5.tgz", + "integrity": "sha512-/cLUpQduF6bNrWuAC4pwtUKA5t669pCsCi2XbmojG2tFeOr9j6ShtdDCtFFQO1DRt+EVZhx9gPzP9G2bUaG4ig==", "dev": true, "requires": { - "deferred-leveldown": "1.2.2", - "level-codec": "7.0.1", - "level-errors": "1.0.5", - "level-iterator-stream": "1.3.1", - "prr": "1.0.1", - "semver": "5.4.1", - "xtend": "4.0.1" - }, - "dependencies": { - "semver": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", - "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==", - "dev": true - } + "errno": "0.1.7" } }, "levn": { @@ -12156,9 +12100,9 @@ } }, "nan": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.9.2.tgz", - "integrity": "sha512-ltW65co7f3PQWBDbqVvaU1WtFJUsNW7sWWm4HINhbMQIyVyzIeyZ8toX5TC5eeooE6piZoaEh4cZkueSKG3KYw==" + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.8.0.tgz", + "integrity": "sha1-7XFfP+neArV6XmJS2QqWZ14fCFo=" }, "nanomatch": { "version": "1.2.9", @@ -12952,6 +12896,132 @@ "mimic-fn": "1.2.0" } }, + "opencollective": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/opencollective/-/opencollective-1.0.3.tgz", + "integrity": "sha1-ruY3K8KBRFg2kMPKja7PwSDdDvE=", + "dev": true, + "requires": { + "babel-polyfill": "6.23.0", + "chalk": "1.1.3", + "inquirer": "3.0.6", + "minimist": "1.2.0", + "node-fetch": "1.6.3", + "opn": "4.0.2" + }, + "dependencies": { + "ansi-escapes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", + "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=", + "dev": true + }, + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "babel-polyfill": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.23.0.tgz", + "integrity": "sha1-g2TKYt+Or7gwSZ9pkXdGbDsDSZ0=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "core-js": "2.5.3", + "regenerator-runtime": "0.10.5" + } + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + } + }, + "inquirer": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.0.6.tgz", + "integrity": "sha1-4EqqnQW3o8ubD0B9BDdfBEcZA0c=", + "dev": true, + "requires": { + "ansi-escapes": "1.4.0", + "chalk": "1.1.3", + "cli-cursor": "2.1.0", + "cli-width": "2.2.0", + "external-editor": "2.1.0", + "figures": "2.0.0", + "lodash": "4.17.5", + "mute-stream": "0.0.7", + "run-async": "2.3.0", + "rx": "4.1.0", + "string-width": "2.1.1", + "strip-ansi": "3.0.1", + "through": "2.3.8" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "node-fetch": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.6.3.tgz", + "integrity": "sha1-3CNO3WSJmC1Y6PDbT2lQKavNjAQ=", + "dev": true, + "requires": { + "encoding": "0.1.12", + "is-stream": "1.1.0" + } + }, + "opn": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/opn/-/opn-4.0.2.tgz", + "integrity": "sha1-erwi5kTf9jsKltWrfyeQwPAavJU=", + "dev": true, + "requires": { + "object-assign": "4.1.1", + "pinkie-promise": "2.0.1" + } + }, + "regenerator-runtime": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz", + "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" + }, + "dependencies": { + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "3.0.0" + } + } + } + } + } + }, "opn": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/opn/-/opn-5.2.0.tgz", @@ -14572,7 +14642,7 @@ "create-hash": "1.1.3", "drbg.js": "1.0.1", "elliptic": "6.4.0", - "nan": "2.9.2", + "nan": "2.8.0", "prebuild-install": "2.5.1", "safe-buffer": "5.1.1" } @@ -15707,7 +15777,7 @@ "create-hash": "1.1.3", "drbg.js": "1.0.1", "elliptic": "6.4.0", - "nan": "2.9.2", + "nan": "2.8.0", "prebuild-install": "2.5.1" } }, @@ -15898,12 +15968,9 @@ } }, "sha3": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/sha3/-/sha3-1.2.0.tgz", - "integrity": "sha1-aYnxtwpJhwWHajc+LGKs6WqpOZo=", - "optional": true, + "version": "github:brave/node-sha3#d44d293e997c061560c2bd8a41451ab979e5a4ca", "requires": { - "nan": "2.9.2" + "nan": "2.8.0" } }, "shebang-command": { diff --git a/package.json b/package.json index f6292c9b731..70ca0eff977 100644 --- a/package.json +++ b/package.json @@ -97,6 +97,7 @@ "compare-versions": "^3.0.1", "date-fns": "^1.29.0", "deepmerge": "^2.0.1", + "dtrace-provider": "brave/node-dtrace-provider", "electron-localshortcut": "^0.6.0", "electron-squirrel-startup": "brave/electron-squirrel-startup", "emoji-regex": "^6.5.1", @@ -108,6 +109,7 @@ "immutablepatch": "brave/immutable-js-patch", "l20n": "^3.5.1", "lru-cache": "^1.0.0", + "nan": "2.8.0", "niceware": "^1.0.4", "parse-torrent": "^5.8.1", "prettier-bytes": "^1.0.3", @@ -121,6 +123,7 @@ "react-dom": "^15.5.4", "react-select": "^0.9.1", "react-transition-group": "^2.2.1", + "sha3": "brave/node-sha3", "snazzy": "^7.0.0", "string.prototype.endswith": "^0.2.0", "string.prototype.startswith": "^0.2.0", @@ -172,7 +175,7 @@ "jsonfile": "^2.2.3", "less": "^2.5.3", "less-loader": "^2.2.1", - "level": "^1.7.0", + "level": "^2.1.1", "mkdirp": "^0.5.1", "mocha": "^2.3.4", "mockery": "^2.1.0", diff --git a/tools/cibuild.py b/tools/cibuild.py index a9f93ef21a0..0a9ba93090e 100755 --- a/tools/cibuild.py +++ b/tools/cibuild.py @@ -4,8 +4,8 @@ import subprocess import sys import os.path -MUON_VERSION = '5.0.6' -CHROMEDRIVER_VERSION = '2.33' +MUON_VERSION = '5.1.0' +CHROMEDRIVER_VERSION = '2.35' SOURCE_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) TARGET_ARCH= os.environ['TARGET_ARCH'] if os.environ.has_key('TARGET_ARCH') else 'x64' os.environ['npm_config_arch'] = TARGET_ARCH diff --git a/tools/electronBuilderHack.js b/tools/electronBuilderHack.js index 1829bc033d5..720a2f9d975 100644 --- a/tools/electronBuilderHack.js +++ b/tools/electronBuilderHack.js @@ -28,4 +28,6 @@ if (isDarwin) { ) } -execute(cmds, env, console.log.bind(null, 'done')) +if (cmds.length > 0) { + execute(cmds, env, console.log.bind(null, 'done')) +}