diff --git a/.resources/app/app_bootstrap/Constants.js b/.resources/app/app_bootstrap/Constants.js new file mode 100644 index 0000000..a02c6e8 --- /dev/null +++ b/.resources/app/app_bootstrap/Constants.js @@ -0,0 +1,37 @@ +"use strict"; + +var _appSettings = require("./appSettings"); +// bootstrap constants +// after startup, these constants will be merged into core module constants +// since they are used in both locations (see app/Constants.js) + +const { + releaseChannel +} = require('./buildInfo'); +const settings = (0, _appSettings.getSettings)(); +function capitalizeFirstLetter(s) { + return s.charAt(0).toUpperCase() + s.slice(1); +} +const appNameSuffix = releaseChannel === 'stable' ? '' : capitalizeFirstLetter(releaseChannel); +const APP_COMPANY = 'Discord Inc'; +const APP_DESCRIPTION = 'Discord - https://discord.com'; +const APP_NAME = 'Discord' + appNameSuffix; +const APP_NAME_FOR_HUMANS = 'Discord' + (appNameSuffix !== '' ? ' ' + appNameSuffix : ''); +const APP_ID_BASE = 'com.squirrel'; +const APP_ID = `${APP_ID_BASE}.${APP_NAME}.${APP_NAME}`; +const APP_PROTOCOL = 'Discord'; +const API_ENDPOINT = settings.get('API_ENDPOINT') || 'https://discord.com/api'; +const UPDATE_ENDPOINT = settings.get('UPDATE_ENDPOINT') || API_ENDPOINT; +const NEW_UPDATE_ENDPOINT = settings.get('NEW_UPDATE_ENDPOINT') || 'https://updates.discord.com/'; +const bootstrapConstants = { + APP_COMPANY, + APP_DESCRIPTION, + APP_NAME, + APP_NAME_FOR_HUMANS, + APP_ID, + APP_PROTOCOL, + API_ENDPOINT, + NEW_UPDATE_ENDPOINT, + UPDATE_ENDPOINT +}; +module.exports = bootstrapConstants; \ No newline at end of file diff --git a/.resources/app/app_bootstrap/GPUSettings.js b/.resources/app/app_bootstrap/GPUSettings.js new file mode 100644 index 0000000..f208526 --- /dev/null +++ b/.resources/app/app_bootstrap/GPUSettings.js @@ -0,0 +1,17 @@ +"use strict"; + +// this file is here for two reasons: +// 1. web requires ./GPUSettings file from electron app (bad!), and requires are +// relative to process.main (bootstrap's index.js) +// 2. GPUSettings has been refactored into GPUSettings, and because we want to +// be able to update GPUSettings OTA, we will have the core module provide +// us with the GPUSettings +// so tl;dr this is core module's GPUSettings, providing compat for web + +exports.replace = function (GPUSettings) { + // replacing module.exports directly would have no effect, since requires are cached + // so we mutate the existing object + for (const name of Object.keys(GPUSettings)) { + exports[name] = GPUSettings[name]; + } +}; \ No newline at end of file diff --git a/.resources/app/app_bootstrap/appSettings.js b/.resources/app/app_bootstrap/appSettings.js new file mode 100644 index 0000000..f0fc965 --- /dev/null +++ b/.resources/app/app_bootstrap/appSettings.js @@ -0,0 +1,19 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.getSettings = getSettings; +exports.init = init; +var _Settings = _interopRequireDefault(require("../common/Settings")); +var paths = _interopRequireWildcard(require("../common/paths")); +function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } +function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +let settings; +function init() { + settings = new _Settings.default(paths.getUserData()); +} +function getSettings() { + return settings; +} \ No newline at end of file diff --git a/.resources/app/app_bootstrap/appUpdater.js b/.resources/app/app_bootstrap/appUpdater.js new file mode 100644 index 0000000..1941c1c --- /dev/null +++ b/.resources/app/app_bootstrap/appUpdater.js @@ -0,0 +1,55 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.focusSplash = focusSplash; +exports.update = update; +var _fs = _interopRequireDefault(require("fs")); +var _path = _interopRequireDefault(require("path")); +var moduleUpdater = _interopRequireWildcard(require("../common/moduleUpdater")); +var paths = _interopRequireWildcard(require("../common/paths")); +var _updater = require("../common/updater"); +var _appSettings = require("./appSettings"); +var autoStart = _interopRequireWildcard(require("./autoStart")); +var _buildInfo = _interopRequireDefault(require("./buildInfo")); +var _errorHandler = require("./errorHandler"); +var firstRun = _interopRequireWildcard(require("./firstRun")); +var splashScreen = _interopRequireWildcard(require("./splashScreen")); +var _Constants = require("./Constants"); +function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } +function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +// settings +const USE_PINNED_UPDATE_MANIFEST = 'USE_PINNED_UPDATE_MANIFEST'; +function update(startMinimized, doneCallback, showCallback) { + const settings = (0, _appSettings.getSettings)(); + if ((0, _updater.tryInitUpdater)(_buildInfo.default, _Constants.NEW_UPDATE_ENDPOINT)) { + const updater = (0, _updater.getUpdater)(); + const usePinnedUpdateManifest = settings.get(USE_PINNED_UPDATE_MANIFEST); + updater.on('host-updated', () => { + autoStart.update(() => {}); + }); + updater.on('unhandled-exception', _errorHandler.fatal); + updater.on(_updater.INCONSISTENT_INSTALLER_STATE_ERROR, _errorHandler.fatal); + updater.on('update-error', _errorHandler.handled); + updater.on('starting-new-host', () => { + // dont run stale launch events--the host we're updating to will run its own callbacks + splashScreen.events.removeListener(splashScreen.APP_SHOULD_LAUNCH, doneCallback); + splashScreen.events.removeListener(splashScreen.APP_SHOULD_SHOW, showCallback); + }); + if (usePinnedUpdateManifest) { + const manifestPath = _path.default.join(paths.getUserData(), 'pinned_update.json'); + updater.setPinnedManifestSync(JSON.parse(_fs.default.readFileSync(manifestPath))); + } + firstRun.performFirstRunTasks(updater); + } else { + moduleUpdater.init(_Constants.UPDATE_ENDPOINT, settings, _buildInfo.default); + } + splashScreen.initSplash(startMinimized); + splashScreen.events.once(splashScreen.APP_SHOULD_LAUNCH, doneCallback); + splashScreen.events.once(splashScreen.APP_SHOULD_SHOW, showCallback); +} +function focusSplash() { + splashScreen.focusWindow(); +} \ No newline at end of file diff --git a/.resources/app/app_bootstrap/autoStart/darwin.js b/.resources/app/app_bootstrap/autoStart/darwin.js new file mode 100644 index 0000000..1e2ca29 --- /dev/null +++ b/.resources/app/app_bootstrap/autoStart/darwin.js @@ -0,0 +1,21 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.install = install; +exports.isInstalled = isInstalled; +exports.uninstall = uninstall; +exports.update = update; +function install(callback) { + return callback(); +} +function update(callback) { + return callback(); +} +function isInstalled(callback) { + return callback(false); +} +function uninstall(callback) { + return callback(); +} \ No newline at end of file diff --git a/.resources/app/app_bootstrap/autoStart/index.js b/.resources/app/app_bootstrap/autoStart/index.js new file mode 100644 index 0000000..9264bb8 --- /dev/null +++ b/.resources/app/app_bootstrap/autoStart/index.js @@ -0,0 +1,3 @@ +"use strict"; + +module.exports = require('./' + process.platform); \ No newline at end of file diff --git a/.resources/app/app_bootstrap/autoStart/linux.js b/.resources/app/app_bootstrap/autoStart/linux.js new file mode 100644 index 0000000..8515689 --- /dev/null +++ b/.resources/app/app_bootstrap/autoStart/linux.js @@ -0,0 +1,71 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.install = install; +exports.isInstalled = isInstalled; +exports.uninstall = uninstall; +exports.update = update; +var _fs = _interopRequireDefault(require("fs")); +var _path = _interopRequireDefault(require("path")); +var _electron = require("electron"); +var _buildInfo = _interopRequireDefault(require("../buildInfo")); +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +// TODO: We should use Constant's APP_NAME, but only once +// we set up backwards compat with this. +const appName = _path.default.basename(process.execPath, '.exe'); +const exePath = _electron.app.getPath('exe'); +const exeDir = _path.default.dirname(exePath); +const iconPath = _path.default.join(exeDir, 'discord.png'); +const autostartDir = _path.default.join(_electron.app.getPath('appData'), 'autostart'); +const electronAppName = _electron.app.name ? _electron.app.name : _electron.app.getName(); +const autostartFileName = _path.default.join(autostartDir, electronAppName + '-' + _buildInfo.default.releaseChannel + '.desktop'); +const desktopFile = `[Desktop Entry] +Type=Application +Exec=${exePath} +Hidden=false +NoDisplay=false +Name=${appName} +Icon=${iconPath} +Comment=Text and voice chat for gamers. +X-GNOME-Autostart-enabled=true +`; +function ensureDir() { + try { + _fs.default.mkdirSync(autostartDir); + return true; + } catch (e) { + // catch for when it already exists. + } + return false; +} +function install(callback) { + // TODO: This could fail. We should read its return value + ensureDir(); + try { + return _fs.default.writeFile(autostartFileName, desktopFile, callback); + } catch (e) { + // I guess we don't autostart then + return callback(); + } +} +function update(callback) { + // TODO: We might need to implement this later on + return callback(); +} +function isInstalled(callback) { + try { + _fs.default.stat(autostartFileName, (err, stats) => { + if (err) { + return callback(false); + } + return callback(stats.isFile()); + }); + } catch (e) { + return callback(false); + } +} +function uninstall(callback) { + return _fs.default.unlink(autostartFileName, callback); +} \ No newline at end of file diff --git a/.resources/app/app_bootstrap/autoStart/win32.js b/.resources/app/app_bootstrap/autoStart/win32.js new file mode 100644 index 0000000..252ed9a --- /dev/null +++ b/.resources/app/app_bootstrap/autoStart/win32.js @@ -0,0 +1,55 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.install = install; +exports.isInstalled = isInstalled; +exports.uninstall = uninstall; +exports.update = update; +var _path = _interopRequireDefault(require("path")); +var windowsUtils = _interopRequireWildcard(require("../windowsUtils")); +var _appSettings = require("../appSettings"); +function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } +function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +const settings = (0, _appSettings.getSettings)(); + +// TODO: We should use Constant's APP_NAME, but only once +// we set up backwards compat with this. +const appName = _path.default.basename(process.execPath, '.exe'); +const fullExeName = _path.default.basename(process.execPath); +const updatePath = _path.default.join(_path.default.dirname(process.execPath), '..', 'Update.exe'); +function install(callback) { + const startMinimized = settings.get('START_MINIMIZED', false); + let execPath = `"${updatePath}" --processStart ${fullExeName}`; + if (startMinimized) { + execPath = `${execPath} --process-start-args --start-minimized`; + } + const queue = [['HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run', '/v', appName, '/d', execPath]]; + windowsUtils.addToRegistry(queue, callback); +} +function update(callback) { + isInstalled(installed => { + if (installed) { + install(callback); + } else { + callback(); + } + }); +} +function isInstalled(callback) { + const queryValue = ['HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run', '/v', appName]; + queryValue.unshift('query'); + windowsUtils.spawnReg(queryValue, (error, stdout) => { + const doesOldKeyExist = stdout.indexOf(appName) >= 0; + callback(doesOldKeyExist); + }); +} +function uninstall(callback) { + const queryValue = ['HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run', '/v', appName, '/f']; + queryValue.unshift('delete'); + windowsUtils.spawnReg(queryValue, (error, stdout) => { + callback(); + }); +} \ No newline at end of file diff --git a/.resources/app/app_bootstrap/bootstrap.js b/.resources/app/app_bootstrap/bootstrap.js new file mode 100644 index 0000000..a071f40 --- /dev/null +++ b/.resources/app/app_bootstrap/bootstrap.js @@ -0,0 +1,167 @@ +"use strict"; + +// bootstrap, or what runs before the rest of desktop does +// responsible for handling updates and updating modules before continuing startup + +if (process.platform === 'linux') { + // Some people are reporting audio problems on Linux that are fixed by setting + // an environment variable PULSE_LATENCY_MSEC=30 -- the "real" fix is to see + // what conditions require this and set this then (also to set it directly in + // our webrtc setup code rather than here) but this should fix the bug for now. + if (process.env.PULSE_LATENCY_MSEC === undefined) { + process.env.PULSE_LATENCY_MSEC = 30; + } +} +const { + app, + Menu +} = require('electron'); +const sentry = require('@sentry/node'); +const buildInfo = require('./buildInfo'); +app.setVersion(buildInfo.version); + +// expose releaseChannel to a global, since it's used by splash screen +global.releaseChannel = buildInfo.releaseChannel; +const errorHandler = require('./errorHandler'); +errorHandler.init(); +const crashReporterSetup = require('../common/crashReporterSetup'); +crashReporterSetup.init(buildInfo, sentry); +const paths = require('../common/paths'); +paths.init(buildInfo); +global.moduleDataPath = paths.getModuleDataPath(); +const appSettings = require('./appSettings'); +appSettings.init(); +const Constants = require('./Constants'); +const GPUSettings = require('./GPUSettings'); +function setupHardwareAcceleration() { + const settings = appSettings.getSettings(); + // TODO: this is a copy of gpuSettings.getEnableHardwareAcceleration + if (!settings.get('enableHardwareAcceleration', true)) { + app.disableHardwareAcceleration(); + } +} +setupHardwareAcceleration(); + +// [adill] work around chrome 66 disabling autoplay by default +app.commandLine.appendSwitch('autoplay-policy', 'no-user-gesture-required'); + +// WinRetrieveSuggestionsOnlyOnDemand: Work around electron 13 bug w/ async spellchecking on Windows. +// HardwareMediaKeyHandling,MediaSessionService: Prevent Discord from registering as a media service. +app.commandLine.appendSwitch('disable-features', 'WinRetrieveSuggestionsOnlyOnDemand,HardwareMediaKeyHandling,MediaSessionService'); +function hasArgvFlag(flag) { + return (process.argv || []).slice(1).includes(flag); +} +console.log(`${Constants.APP_NAME} ${app.getVersion()}`); +let pendingAppQuit = false; +if (process.platform === 'win32') { + // this tells Windows (in particular Windows 10) which icon to associate your app with, important for correctly + // pinning app to task bar. + app.setAppUserModelId(Constants.APP_ID); + const { + handleStartupEvent + } = require('./squirrelUpdate'); + // TODO: Isn't using argv[1] fragile? + const squirrelCommand = process.argv[1]; + // TODO: Is protocol case sensitive? + if (handleStartupEvent(Constants.APP_PROTOCOL, app, squirrelCommand)) { + pendingAppQuit = true; + } +} +const appUpdater = require('./appUpdater'); +const moduleUpdater = require('../common/moduleUpdater'); +const updater = require('../common/updater'); +const splashScreen = require('./splashScreen'); +const autoStart = require('./autoStart'); +const requireNative = require('./requireNative'); +let coreModule; +const allowMultipleInstances = hasArgvFlag('--multi-instance'); +const isFirstInstance = allowMultipleInstances ? true : app.requestSingleInstanceLock(); +function extractUrlFromArgs(args) { + const urlArgIndex = args.indexOf('--url'); + if (urlArgIndex < 0) { + return null; + } + const passThroughArgsIndex = args.indexOf('--'); + if (passThroughArgsIndex < 0 || passThroughArgsIndex < urlArgIndex) { + return null; + } + const url = args[passThroughArgsIndex + 1]; + if (url == null) { + return null; + } + return url; +} +let initialUrl = extractUrlFromArgs(process.argv); +if (!allowMultipleInstances) { + app.on('second-instance', (_event, args, _workingDirectory) => { + if (args != null && args.indexOf('--squirrel-uninstall') > -1) { + app.quit(); + return; + } + const url = extractUrlFromArgs(args); + if (coreModule) { + // url can be null, as a user opening the executable again will focus the app from background + coreModule.handleOpenUrl(url); + } else if (url != null) { + initialUrl = url; + } + if (!coreModule) { + appUpdater.focusSplash(); + } + }); +} +app.on('will-finish-launching', () => { + // on macos protocol links are handled entirely through this event + app.on('open-url', (event, url) => { + event.preventDefault(); + if (coreModule) { + coreModule.handleOpenUrl(url); + } else { + initialUrl = url; + } + }); +}); +function startUpdate() { + console.log('Starting updater.'); + const startMinimized = hasArgvFlag('--start-minimized'); + appUpdater.update(startMinimized, () => { + try { + coreModule = requireNative('discord_desktop_core'); + coreModule.startup({ + paths, + splashScreen, + moduleUpdater, + autoStart, + buildInfo, + appSettings, + Constants, + GPUSettings, + updater, + crashReporterSetup + }); + if (initialUrl != null) { + coreModule.handleOpenUrl(initialUrl); + initialUrl = null; + } + } catch (err) { + return errorHandler.fatal(err); + } + }, () => { + coreModule.setMainWindowVisible(!startMinimized); + }); +} +function startApp() { + console.log('Starting app.'); + paths.cleanOldVersions(buildInfo); + const startupMenu = require('./startupMenu'); + Menu.setApplicationMenu(startupMenu); + startUpdate(); +} +if (pendingAppQuit) { + console.log('Startup prevented.'); +} else if (!isFirstInstance && !allowMultipleInstances) { + console.log('Quitting secondary instance.'); + app.quit(); +} else { + app.whenReady().then(() => startApp()); +} \ No newline at end of file diff --git a/.resources/app/app_bootstrap/buildInfo.js b/.resources/app/app_bootstrap/buildInfo.js new file mode 100644 index 0000000..662e074 --- /dev/null +++ b/.resources/app/app_bootstrap/buildInfo.js @@ -0,0 +1,12 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; +var _path = _interopRequireDefault(require("path")); +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +const buildInfo = require(_path.default.join(process.resourcesPath, 'build_info.json')); +var _default = buildInfo; +exports.default = _default; +module.exports = exports.default; \ No newline at end of file diff --git a/.resources/app/app_bootstrap/data/quotes_copy.json b/.resources/app/app_bootstrap/data/quotes_copy.json new file mode 100644 index 0000000..fc33384 --- /dev/null +++ b/.resources/app/app_bootstrap/data/quotes_copy.json @@ -0,0 +1,14 @@ +[ + "Upsorbing the Contents", + "Additive Parsing the Load", + "Commence Monosaturated Goodening", + "Kick Off the Multi-Core Widening", + "Bastening the Game Turkey", + "Abstracting the Rummage Disc", + "Undecerealenizing the Process", + "Postrefragmenting the Widget Layer", + "Satisfying the Constraints", + "Abnoramalzing Some of the Matrices", + "Optimizing the People", + "Proclaigerizing the Network" +] diff --git a/.resources/app/app_bootstrap/errorHandler.js b/.resources/app/app_bootstrap/errorHandler.js new file mode 100644 index 0000000..669057d --- /dev/null +++ b/.resources/app/app_bootstrap/errorHandler.js @@ -0,0 +1,85 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.fatal = fatal; +exports.handled = handled; +exports.init = init; +var Sentry = _interopRequireWildcard(require("@sentry/node")); +var _electron = require("electron"); +var _process = _interopRequireDefault(require("process")); +var _crashReporterSetup = require("../common/crashReporterSetup"); +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } +function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } +const HANDLED_ERROR_INTERVAL = 3; +const HANDLED_ERROR_LIMIT = 10; +let handledErrorCounter = 0; +let totalHandledErrors = 0; +const consoleOutputOnly = _process.default.env.DISCORD_TEST != null; +function isErrorSafeToSuppress(error) { + return /attempting to call a function in a renderer window/i.test(error.message); +} +function captureJSException(error) { + Sentry.captureException(error, scope => { + scope.clear(); + scope.setTag('nativeBuildNumber', _crashReporterSetup.metadata.nativeBuildNumber); + scope.setUser(_crashReporterSetup.metadata.sentry.user); + scope.setExtras({ + environment: _crashReporterSetup.metadata.sentry.environment, + release: _crashReporterSetup.metadata.sentry.release, + nativeBuildNumber: _crashReporterSetup.metadata.nativeBuildNumber + }); + return scope; + }); +} +function init() { + _process.default.on('uncaughtException', error => { + const stack = error.stack ? error.stack : String(error); + const message = `Uncaught exception:\n ${stack}`; + console.warn(message); + captureJSException(error); + if (!isErrorSafeToSuppress(error)) { + if (consoleOutputOnly) { + console.error(`${message} error: ${error}`); + _process.default.exit(-1); + } + _electron.dialog.showErrorBox('A JavaScript error occurred in the main process', message); + } + }); +} + +// show a similar error message to the error handler, except exit out the app +// after the error message has been closed +function fatal(err) { + const options = { + type: 'error', + message: 'A fatal Javascript error occured', + detail: err && err.stack ? err.stack : String(err) + }; + if (consoleOutputOnly) { + console.error(`fatal: ${err}\n${err === null || err === void 0 ? void 0 : err.stack}`); + _process.default.exit(-1); + } + const callback = _ => _electron.app.quit(); + const electronMajor = parseInt(_process.default.versions.electron.split('.')[0]); + if (electronMajor >= 6) { + _electron.dialog.showMessageBox(null, options).then(callback); + } else { + _electron.dialog.showMessageBox(options, callback); + } + captureJSException(err); +} + +// capture a handled error for telemetry purposes, e.g. finding update loops. +function handled(err) { + if (global.releaseChannel !== 'ptb' && global.releaseChannel !== 'canary' && global.releaseChannel !== 'development') { + return; + } + if (totalHandledErrors < HANDLED_ERROR_LIMIT && handledErrorCounter++ % HANDLED_ERROR_INTERVAL == 0) { + console.warn('Reporting non-fatal error', err); + captureJSException(err); + totalHandledErrors++; + } +} \ No newline at end of file diff --git a/.resources/app/app_bootstrap/firstRun/darwin.js b/.resources/app/app_bootstrap/firstRun/darwin.js new file mode 100644 index 0000000..e261191 --- /dev/null +++ b/.resources/app/app_bootstrap/firstRun/darwin.js @@ -0,0 +1,9 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.performFirstRunTasks = performFirstRunTasks; +function performFirstRunTasks(_updater) { + // +} \ No newline at end of file diff --git a/.resources/app/app_bootstrap/firstRun/index.js b/.resources/app/app_bootstrap/firstRun/index.js new file mode 100644 index 0000000..9264bb8 --- /dev/null +++ b/.resources/app/app_bootstrap/firstRun/index.js @@ -0,0 +1,3 @@ +"use strict"; + +module.exports = require('./' + process.platform); \ No newline at end of file diff --git a/.resources/app/app_bootstrap/firstRun/linux.js b/.resources/app/app_bootstrap/firstRun/linux.js new file mode 100644 index 0000000..e261191 --- /dev/null +++ b/.resources/app/app_bootstrap/firstRun/linux.js @@ -0,0 +1,9 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.performFirstRunTasks = performFirstRunTasks; +function performFirstRunTasks(_updater) { + // +} \ No newline at end of file diff --git a/.resources/app/app_bootstrap/firstRun/win32.js b/.resources/app/app_bootstrap/firstRun/win32.js new file mode 100644 index 0000000..b61ee3a --- /dev/null +++ b/.resources/app/app_bootstrap/firstRun/win32.js @@ -0,0 +1,75 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.performFirstRunTasks = performFirstRunTasks; +var _fs = _interopRequireDefault(require("fs")); +var _path = _interopRequireDefault(require("path")); +var paths = _interopRequireWildcard(require("../../common/paths")); +var _errorHandler = require("../errorHandler"); +var _squirrelUpdate = require("../squirrelUpdate"); +var _Constants = require("../Constants"); +function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } +function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +const appFolder = _path.default.resolve(process.execPath, '..'); +const rootFolder = _path.default.resolve(appFolder, '..'); +const exeName = _path.default.basename(process.execPath); +const updateExe = _path.default.join(rootFolder, 'Update.exe'); +function copyIconToRoot() { + const icoSrc = _path.default.join(appFolder, 'app.ico'); + const icoDest = _path.default.join(rootFolder, 'app.ico'); + try { + const ico = _fs.default.readFileSync(icoSrc); + _fs.default.writeFileSync(icoDest, ico); + return icoDest; + } catch (e) { + return icoSrc; + } +} +function updateShortcuts(updater) { + const shortcutFileName = `${_Constants.APP_NAME_FOR_HUMANS}.lnk`; + const shortcutPaths = [_path.default.join(updater.getKnownFolder('desktop'), shortcutFileName), _path.default.join(updater.getKnownFolder('programs'), _Constants.APP_COMPANY, shortcutFileName)]; + const iconPath = copyIconToRoot(); + for (const shortcutPath of shortcutPaths) { + if (!_fs.default.existsSync(shortcutPath)) { + // If the user deleted the shortcut, don't recreate it. + continue; + } + updater.createShortcut({ + /* eslint-disable camelcase */ + target_path: updateExe, + shortcut_path: shortcutPath, + arguments: `--processStart ${exeName}`, + icon_path: iconPath, + icon_index: 0, + description: _Constants.APP_DESCRIPTION, + app_user_model_id: _Constants.APP_ID, + working_directory: appFolder + /* eslint-enable camelcase */ + }); + } +} + +function performFirstRunTasks(updater) { + const firstRunCompletePath = _path.default.join(paths.getUserDataVersioned(), '.first-run'); + if (!_fs.default.existsSync(firstRunCompletePath)) { + let updatedShortcuts = false; + try { + updateShortcuts(updater); + updatedShortcuts = true; + } catch (e) { + (0, _errorHandler.handled)(e); + } + (0, _squirrelUpdate.installProtocol)(_Constants.APP_PROTOCOL, () => { + try { + if (updatedShortcuts) { + _fs.default.writeFileSync(firstRunCompletePath, 'true'); + } + } catch (e) { + (0, _errorHandler.handled)(e); + } + }); + } +} \ No newline at end of file diff --git a/.resources/app/app_bootstrap/hostUpdater.js b/.resources/app/app_bootstrap/hostUpdater.js new file mode 100644 index 0000000..a55e3ce --- /dev/null +++ b/.resources/app/app_bootstrap/hostUpdater.js @@ -0,0 +1,164 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; +var _electron = require("electron"); +var _events = require("events"); +var _request = _interopRequireDefault(require("./request")); +var squirrelUpdate = _interopRequireWildcard(require("./squirrelUpdate")); +function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } +function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +/* eslint-disable no-console */ + +function versionParse(verString) { + return verString.split('.').map(i => parseInt(i)); +} +function versionNewer(verA, verB) { + let i = 0; + while (true) { + const a = verA[i]; + const b = verB[i]; + i++; + if (a === undefined) { + return false; + } else { + if (b === undefined || a > b) { + return true; + } + if (a < b) { + return false; + } + } + } +} +class AutoUpdaterWin32 extends _events.EventEmitter { + constructor() { + super(); + this.updateUrl = null; + this.updateVersion = null; + } + setFeedURL(updateUrl) { + this.updateUrl = updateUrl; + } + quitAndInstall() { + if (squirrelUpdate.updateExistsSync()) { + squirrelUpdate.restart(_electron.app, this.updateVersion ?? _electron.app.getVersion()); + } else { + /* eslint-disable-next-line */ + require('auto-updater').quitAndInstall(); + } + } + downloadAndInstallUpdate(callback) { + squirrelUpdate.spawnUpdateInstall(this.updateUrl, progress => { + this.emit('update-progress', progress); + }).catch(err => callback(err)).then(() => callback()); + } + checkForUpdates() { + if (this.updateUrl == null) { + throw new Error('Update URL is not set'); + } + this.emit('checking-for-update'); + if (!squirrelUpdate.updateExistsSync()) { + this.emit('update-not-available'); + return; + } + squirrelUpdate.spawnUpdate(['--check', this.updateUrl], (error, stdout) => { + if (error != null) { + this.emit('error', error); + return; + } + try { + // Last line of the output is JSON details about the releases + const json = stdout.trim().split('\n').pop(); + const releasesFound = JSON.parse(json).releasesToApply; + if (releasesFound == null || releasesFound.length === 0) { + this.emit('update-not-available'); + return; + } + const update = releasesFound.pop(); + this.emit('update-available'); + this.downloadAndInstallUpdate(error => { + if (error != null) { + this.emit('error', error); + return; + } + this.updateVersion = update.version; + this.emit('update-downloaded', {}, update.release, update.version, new Date(), this.updateUrl, this.quitAndInstall.bind(this)); + }); + } catch (error) { + error.stdout = stdout; + this.emit('error', error); + } + }); + } +} + +// todo +class AutoUpdaterLinux extends _events.EventEmitter { + constructor() { + super(); + this.updateUrl = null; + } + setFeedURL(url) { + this.updateUrl = url; + } + quitAndInstall() { + // Just restart. The splash screen will hit the update manually state and + // prompt the user to download the new package. + _electron.app.relaunch(); + _electron.app.quit(); + } + async checkForUpdates() { + const currVersion = versionParse(_electron.app.getVersion()); + this.emit('checking-for-update'); + try { + const response = await _request.default.get(this.updateUrl); + if (response.statusCode === 204) { + // you are up to date + this.emit('update-not-available'); + return; + } + let latestVerStr = ''; + let latestVersion = []; + try { + const latestMetadata = JSON.parse(response.body); + latestVerStr = latestMetadata.name; + latestVersion = versionParse(latestVerStr); + } catch (_) {} + if (versionNewer(latestVersion, currVersion)) { + console.log('[Updates] You are out of date!'); + // you need to update + this.emit('update-manually', latestVerStr); + } else { + console.log('[Updates] You are living in the future!'); + this.emit('update-not-available'); + } + } catch (err) { + console.error('[Updates] Error fetching ' + this.updateUrl + ': ' + err.message); + this.emit('error', err); + } + } +} +let autoUpdater; + +// TODO +// events: checking-for-update, update-available, update-not-available, update-manually, update-downloaded, error +// also, checkForUpdates, setFeedURL, quitAndInstall +// also, see electron.autoUpdater, and its API +switch (process.platform) { + case 'darwin': + autoUpdater = require('electron').autoUpdater; + break; + case 'win32': + autoUpdater = new AutoUpdaterWin32(); + break; + case 'linux': + autoUpdater = new AutoUpdaterLinux(); + break; +} +var _default = autoUpdater; +exports.default = _default; +module.exports = exports.default; \ No newline at end of file diff --git a/.resources/app/app_bootstrap/images/img_lucky_dice.png b/.resources/app/app_bootstrap/images/img_lucky_dice.png new file mode 100644 index 0000000..909b729 Binary files /dev/null and b/.resources/app/app_bootstrap/images/img_lucky_dice.png differ diff --git a/.resources/app/app_bootstrap/index.js b/.resources/app/app_bootstrap/index.js new file mode 100644 index 0000000..e24cc86 --- /dev/null +++ b/.resources/app/app_bootstrap/index.js @@ -0,0 +1,39 @@ +"use strict"; + +const buildInfo = require('./buildInfo'); +const paths = require('../common/paths'); +paths.init(buildInfo); +const moduleUpdater = require('../common/moduleUpdater'); +const updater = require('../common/updater'); +const requireNative = require('./requireNative'); +function getAppMode() { + if (process.argv && process.argv.includes('--overlay-host')) { + return 'overlay-host'; + } + return 'app'; +} +const mode = getAppMode(); +if (mode === 'app') { + require('./bootstrap'); +} else if (mode === 'overlay-host') { + // Initialize the update system just enough to find installed native modules. + const appSettings = require('./appSettings'); + appSettings.init(); + const { + NEW_UPDATE_ENDPOINT + } = require('./Constants'); + if (buildInfo.newUpdater) { + if (!updater.tryInitUpdater(buildInfo, NEW_UPDATE_ENDPOINT)) { + throw new Error('Failed to initialize modules in overlay host.'); + } + + // Load the module search path but if there's a pending host update, don't + // restart into it. + updater.getUpdater().startCurrentVersionSync({ + allowObsoleteHost: true + }); + } else { + moduleUpdater.initPathsOnly(buildInfo); + } + requireNative('discord_overlay2/standalone_host.js'); +} \ No newline at end of file diff --git a/.resources/app/app_bootstrap/installDevTools.js b/.resources/app/app_bootstrap/installDevTools.js new file mode 100644 index 0000000..6ee379e --- /dev/null +++ b/.resources/app/app_bootstrap/installDevTools.js @@ -0,0 +1,19 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; +// used in devtools to hook in additional dev tools +// require('electron').remote.require('./installDevTools')() + +function installDevTools() { + console.log(`Installing Devtron`); + const devtron = require('devtron'); + devtron.uninstall(); + devtron.install(); + console.log(`Installed Devtron`); +} +var _default = installDevTools; +exports.default = _default; +module.exports = exports.default; \ No newline at end of file diff --git a/.resources/app/app_bootstrap/ipcMain.js b/.resources/app/app_bootstrap/ipcMain.js new file mode 100644 index 0000000..1a10c7d --- /dev/null +++ b/.resources/app/app_bootstrap/ipcMain.js @@ -0,0 +1,13 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; +var _electron = require("electron"); +var _default = { + on: (event, callback) => _electron.ipcMain.on(`DISCORD_${event}`, callback), + removeListener: (event, callback) => _electron.ipcMain.removeListener(`DISCORD_${event}`, callback) +}; +exports.default = _default; +module.exports = exports.default; \ No newline at end of file diff --git a/.resources/app/app_bootstrap/request.js b/.resources/app/app_bootstrap/request.js new file mode 100644 index 0000000..9e17b19 --- /dev/null +++ b/.resources/app/app_bootstrap/request.js @@ -0,0 +1,162 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; +var _electron = require("electron"); +var _querystring = _interopRequireDefault(require("querystring")); +var _request = _interopRequireDefault(require("request")); +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +const DEFAULT_REQUEST_TIMEOUT = 30000; +function makeHTTPResponse({ + method, + url, + headers, + statusCode, + statusMessage +}, body) { + return { + method, + url, + headers, + statusCode, + statusMessage, + body + }; +} +function makeHTTPStatusError(response) { + const err = new Error(`HTTP Error: Status Code ${response.statusCode}`); + err.response = response; + return err; +} +function handleHTTPResponse(resolve, reject, response, stream) { + const totalBytes = parseInt(response.headers['content-length'] || 1, 10); + let receivedBytes = 0; + const chunks = []; + + // don't stream response if it's a failure + if (response.statusCode >= 300) { + stream = null; + } + response.on('data', chunk => { + if (stream != null) { + receivedBytes += chunk.length; + stream.write(chunk); + stream.emit('progress', { + totalBytes, + receivedBytes + }); + return; + } + chunks.push(chunk); + }); + response.on('end', () => { + if (stream != null) { + stream.on('finish', () => resolve(makeHTTPResponse(response, null))); + stream.end(); + return; + } + const res = makeHTTPResponse(response, Buffer.concat(chunks)); + if (res.statusCode >= 300) { + reject(makeHTTPStatusError(res)); + return; + } + resolve(res); + }); +} +function nodeRequest({ + method, + url, + headers, + qs, + timeout, + body, + stream +}) { + return new Promise((resolve, reject) => { + const req = (0, _request.default)({ + method, + url, + qs, + headers, + followAllRedirects: true, + encoding: null, + timeout: timeout != null ? timeout : DEFAULT_REQUEST_TIMEOUT, + body + }); + req.on('response', response => handleHTTPResponse(resolve, reject, response, stream)); + req.on('error', err => reject(err)); + }); +} +async function electronRequest({ + method, + url, + headers, + qs, + timeout, + body, + stream +}) { + await _electron.app.whenReady(); + const { + net, + session + } = require('electron'); + const req = net.request({ + method, + url: `${url}${qs != null ? `?${_querystring.default.stringify(qs)}` : ''}`, + redirect: 'follow', + session: session.defaultSession + }); + if (headers != null) { + for (const headerKey of Object.keys(headers)) { + req.setHeader(headerKey, headers[headerKey]); + } + } + if (body != null) { + req.write(body, 'utf-8'); + } + return new Promise((resolve, reject) => { + const reqTimeout = setTimeout(() => { + req.abort(); + reject(new Error(`network timeout: ${url}`)); + }, timeout != null ? timeout : DEFAULT_REQUEST_TIMEOUT); + req.on('login', (authInfo, callback) => callback()); + req.on('response', response => { + clearTimeout(reqTimeout); + handleHTTPResponse(resolve, reject, response, stream); + }); + req.on('error', err => { + clearTimeout(reqTimeout); + reject(err); + }); + req.end(); + }); +} +async function requestWithMethod(method, options) { + if (typeof options === 'string') { + options = { + url: options + }; + } + options = { + ...options, + method + }; + try { + return await electronRequest(options); + } catch (err) { + console.log(`Error downloading with electron net: ${err.message}`); + console.log('Falling back to node net library..'); + } + return nodeRequest(options); +} + +// only supports get for now, since retrying is non-idempotent and +// we'd want to grovel the errors to make sure it's safe to retry +var _default = { + get: requestWithMethod.bind(null, 'GET') +}; +exports.default = _default; +module.exports = exports.default; \ No newline at end of file diff --git a/.resources/app/app_bootstrap/requireNative.js b/.resources/app/app_bootstrap/requireNative.js new file mode 100644 index 0000000..c18c0c0 --- /dev/null +++ b/.resources/app/app_bootstrap/requireNative.js @@ -0,0 +1,5 @@ +"use strict"; + +// require(), with paths specialized for requiring only native modules. +module.paths = []; +module.exports = require; \ No newline at end of file diff --git a/.resources/app/app_bootstrap/splash/abddffb32a4a35627c3857a06c751424.png b/.resources/app/app_bootstrap/splash/abddffb32a4a35627c3857a06c751424.png new file mode 100644 index 0000000..909b729 Binary files /dev/null and b/.resources/app/app_bootstrap/splash/abddffb32a4a35627c3857a06c751424.png differ diff --git a/.resources/app/app_bootstrap/splash/ac3f027697c11abd84295888e843f3d2.woff2 b/.resources/app/app_bootstrap/splash/ac3f027697c11abd84295888e843f3d2.woff2 new file mode 100644 index 0000000..20c0fde Binary files /dev/null and b/.resources/app/app_bootstrap/splash/ac3f027697c11abd84295888e843f3d2.woff2 differ diff --git a/.resources/app/app_bootstrap/splash/bf3d19297ef12291559b3edae977480c.woff2 b/.resources/app/app_bootstrap/splash/bf3d19297ef12291559b3edae977480c.woff2 new file mode 100644 index 0000000..0ede5da Binary files /dev/null and b/.resources/app/app_bootstrap/splash/bf3d19297ef12291559b3edae977480c.woff2 differ diff --git a/.resources/app/app_bootstrap/splash/index.html b/.resources/app/app_bootstrap/splash/index.html new file mode 100644 index 0000000..5dec1de --- /dev/null +++ b/.resources/app/app_bootstrap/splash/index.html @@ -0,0 +1,11 @@ + + + + + Discord Updater + + +
+ + + diff --git a/.resources/app/app_bootstrap/splash/index.js b/.resources/app/app_bootstrap/splash/index.js new file mode 100644 index 0000000..a01c575 --- /dev/null +++ b/.resources/app/app_bootstrap/splash/index.js @@ -0,0 +1,44 @@ +!function(e){var t={};function n(r){if(t[r])return t[r].exports;var a=t[r]={i:r,l:!1,exports:{}};return e[r].call(a.exports,a,a.exports,n),a.l=!0,a.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var a in e)n.d(r,a,function(t){return e[t]}.bind(null,a));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=27)}([function(e,t,n){e.exports=n(25)()},function(e,t,n){"use strict";e.exports=n(17)},function(e,t,n){"use strict";!function e(){if("undefined"!=typeof __REACT_DEVTOOLS_GLOBAL_HOOK__&&"function"==typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE){0;try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(e)}catch(e){console.error(e)}}}(),e.exports=n(18)},function(e,t,n){var r; +/*! + Copyright (c) 2018 Jed Watson. + Licensed under the MIT License (MIT), see + http://jedwatson.github.io/classnames +*/!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t=0||Object.prototype.hasOwnProperty.call(e,r)&&(n[r]=e[r]);return n}(this.props,[]);return function(e){c.forEach((function(t){return delete e[t]}))}(a),a.className=this.props.inputClassName,a.id=this.state.inputId,a.style=n,l.default.createElement("div",{className:this.props.className,style:t},this.renderStyles(),l.default.createElement("input",r({},a,{ref:this.inputRef})),l.default.createElement("div",{ref:this.sizerRef,style:s},e),this.props.placeholder?l.default.createElement("div",{ref:this.placeHolderSizerRef,style:s},this.props.placeholder):null)}}]),t}(o.Component);h.propTypes={className:i.default.string,defaultValue:i.default.any,extraWidth:i.default.oneOfType([i.default.number,i.default.string]),id:i.default.string,injectStyles:i.default.bool,inputClassName:i.default.string,inputRef:i.default.func,inputStyle:i.default.object,minWidth:i.default.oneOfType([i.default.number,i.default.string]),onAutosize:i.default.func,onChange:i.default.func,placeholder:i.default.string,placeholderIsMinWidth:i.default.bool,style:i.default.object,value:i.default.any},h.defaultProps={minWidth:1,injectStyles:!0},t.default=h},function(e,t,n){var r=n(9);"string"==typeof r&&(r=[[e.i,r,""]]);var a={hmr:!0,transform:void 0};n(15)(r,a);r.locals&&(e.exports=r.locals)},function(e,t,n){var r=n(10);(t=e.exports=n(5)(!1)).i(n(11),""),t.push([e.i,"@font-face {\n font-family: gg sans;\n font-weight: 400;\n src: url("+r(n(12))+") format('woff2');\n}\n@font-face {\n font-family: gg sans;\n font-weight: 500;\n src: url("+r(n(13))+') format(\'woff2\');\n}\n* {\n box-sizing: border-box;\n -webkit-user-select: none;\n cursor: default;\n}\nbody,\nhtml {\n -webkit-app-region: drag;\n padding: 0;\n margin: 0;\n overflow: hidden;\n width: 300px;\n height: 300px;\n}\n#splash {\n -webkit-app-region: drag;\n background: #282b30;\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n justify-content: center;\n align-items: center;\n z-index: 3000;\n transform: translateZ(0);\n padding-bottom: 10px;\n}\n#splash .splash-inner {\n text-align: center;\n}\n#splash .splash-inner img,\n#splash .splash-inner video {\n size: 200px;\n}\n#splash .splash-inner video {\n visibility: hidden;\n}\n#splash .splash-inner video.loaded {\n visibility: visible;\n}\n#splash .splash-inner .splash-text {\n position: relative;\n top: -30px;\n}\n#splash .splash-inner .splash-text > span {\n color: #8a8e94;\n font-size: 12px;\n font-family: "gg sans", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;\n font-weight: 600;\n display: block;\n}\n#splash .splash-inner .splash-text > span.splash-status {\n color: #fff;\n font-weight: 500;\n font-size: 16px;\n font-variant-numeric: tabular-nums;\n}\n#splash .splash-inner-dl .dice-image {\n position: absolute;\n left: 77px;\n top: 45px;\n width: 146px;\n height: 100px;\n background: url('+r(n(14))+') center center no-repeat;\n background-size: 146px 100px;\n}\n#splash .splash-inner-dl .dl-update-message {\n font-family: "gg sans", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;\n font-style: medium;\n font-size: 18px;\n color: #fff;\n padding-left: 20px;\n padding-right: 20px;\n top: 169px;\n left: 0;\n margin: 0;\n position: absolute;\n text-align: center;\n}\n#splash .splash-inner-dl .dl-version-message {\n font-family: "gg sans", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;\n font-style: medium;\n font-size: 12px;\n color: #8a8e94;\n text-transform: uppercase;\n position: absolute;\n width: 100%;\n bottom: 12px;\n left: 0;\n margin: 0;\n text-align: center;\n}\n#splash .splash-inner-dl .dl-select-frame {\n -webkit-app-region: no-drag;\n font-family: "gg sans", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;\n overflow: hidden;\n position: absolute;\n width: 100%;\n height: 130px;\n top: 220px;\n left: 0;\n margin: 0;\n}\n#splash .splash-inner-dl .dl-select-frame .Select {\n position: absolute;\n left: 0;\n top: 0;\n width: 165px;\n height: 44px;\n margin-left: 20px;\n margin-right: 10px;\n color: #fff;\n}\n#splash .splash-inner-dl .dl-select-frame .Select-control {\n border: 1px solid;\n border-color: rgba(255,255,255,0.3);\n border-radius: 3px;\n background: #282b30;\n height: 44px;\n}\n#splash .splash-inner-dl .dl-select-frame .Select-menu-outer {\n background: #282b30;\n}\n#splash .splash-inner-dl .dl-select-frame .Select-menu {\n max-height: 80px;\n}\n#splash .splash-inner-dl .dl-select-frame .Select-option {\n color: #8a8e94;\n line-height: 15px;\n padding: 5px 10px;\n}\n#splash .splash-inner-dl .dl-select-frame .Select-option.is-focused {\n color: #fff;\n background-color: #4e59e0;\n}\n#splash .splash-inner-dl .dl-select-frame .Select-value {\n color: #fff;\n bottom: 0;\n align-items: center;\n display: flex;\n}\n#splash .splash-inner-dl .dl-select-frame .Select-input {\n outline: none;\n}\n#splash .splash-inner-dl .dl-select-frame .dl-button {\n position: absolute;\n left: 195px;\n top: 0;\n width: 85px;\n height: 44px;\n background-color: #5865f2;\n color: #fff;\n font-size: 14px;\n font-weight: 600;\n border-radius: 3px;\n display: flex;\n justify-content: center;\n align-items: center;\n}\n#splash .splash-inner-dl .dl-select-frame .dl-button:hover {\n background-color: #4e59e0;\n}\n.progress {\n display: flex;\n justify-content: center;\n margin-top: 10px;\n}\n.progress .progress-bar {\n height: 8px;\n border-radius: 4px;\n width: 180px;\n background-color: rgba(255,255,255,0.1);\n}\n.progress .progress-bar .complete {\n border-radius: 4px;\n box-shadow: 0px 2px 4px 0px rgba(0,0,0,0.1), inset 0px 1px 0px 0px rgba(255,255,255,0.1);\n height: 100%;\n background-color: #737f8d;\n}\n.progress-placeholder {\n margin-top: 10px;\n height: 8px;\n}\n',""])},function(e,t){e.exports=function(e){return"string"!=typeof e?e:(/^['"].*['"]$/.test(e)&&(e=e.slice(1,-1)),/["'() \t\n]/.test(e)?'"'+e.replace(/"/g,'\\"').replace(/\n/g,"\\n")+'"':e)}},function(e,t,n){(e.exports=n(5)(!1)).push([e.i,"/**\n * React Select\n * ============\n * Created by Jed Watson and Joss Mackison for KeystoneJS, http://www.keystonejs.com/\n * https://twitter.com/jedwatson https://twitter.com/jossmackison https://twitter.com/keystonejs\n * MIT License: https://github.com/keystonejs/react-select\n*/\n.Select {\n position: relative;\n}\n.Select,\n.Select div,\n.Select input,\n.Select span {\n -webkit-box-sizing: border-box;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n}\n.Select.is-disabled > .Select-control {\n background-color: #f6f6f6;\n}\n.Select.is-disabled .Select-arrow-zone {\n cursor: default;\n pointer-events: none;\n}\n.Select-control {\n background-color: #fff;\n border-color: #d9d9d9 #ccc #b3b3b3;\n border-radius: 4px;\n border: 1px solid #ccc;\n color: #333;\n cursor: default;\n display: table;\n height: 36px;\n outline: none;\n overflow: hidden;\n position: relative;\n width: 100%;\n}\n.Select-control:hover {\n box-shadow: 0 1px 0 rgba(0, 0, 0, 0.06);\n}\n.is-searchable.is-open > .Select-control {\n cursor: text;\n}\n.is-open > .Select-control {\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n background: #fff;\n border-color: #b3b3b3 #ccc #d9d9d9;\n}\n.is-open > .Select-control > .Select-arrow {\n border-color: transparent transparent #999;\n border-width: 0 5px 5px;\n}\n.is-searchable.is-focused:not(.is-open) > .Select-control {\n cursor: text;\n}\n.is-focused:not(.is-open) > .Select-control {\n border-color: #08c #0099e6 #0099e6;\n box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 0 5px -1px rgba(0, 136, 204, 0.5);\n}\n.Select-placeholder {\n bottom: 0;\n color: #aaa;\n left: 0;\n line-height: 34px;\n padding-left: 10px;\n padding-right: 10px;\n position: absolute;\n right: 0;\n top: 0;\n max-width: 100%;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.has-value > .Select-control > .Select-placeholder {\n color: #333;\n}\n.Select-value {\n color: #aaa;\n left: 0;\n padding: 8px 52px 8px 10px;\n position: absolute;\n right: -15px;\n top: 0;\n max-width: 100%;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.has-value > .Select-control > .Select-value {\n color: #333;\n}\n.Select-input {\n height: 34px;\n padding-left: 10px;\n padding-right: 10px;\n vertical-align: middle;\n}\n.Select-input > input {\n background: none transparent;\n border: 0 none;\n box-shadow: none;\n cursor: default;\n display: inline-block;\n font-family: inherit;\n font-size: inherit;\n height: 34px;\n margin: 0;\n outline: none;\n padding: 0;\n -webkit-appearance: none;\n}\n.is-focused .Select-input > input {\n cursor: text;\n}\n.Select-control:not(.is-searchable) > .Select-input {\n outline: none;\n}\n.Select-loading-zone {\n cursor: pointer;\n display: table-cell;\n position: relative;\n text-align: center;\n vertical-align: middle;\n width: 16px;\n}\n.Select-loading {\n -webkit-animation: Select-animation-spin 400ms infinite linear;\n -o-animation: Select-animation-spin 400ms infinite linear;\n animation: Select-animation-spin 400ms infinite linear;\n width: 16px;\n height: 16px;\n box-sizing: border-box;\n border-radius: 50%;\n border: 2px solid #ccc;\n border-right-color: #333;\n display: inline-block;\n position: relative;\n vertical-align: middle;\n}\n.Select-clear-zone {\n -webkit-animation: Select-animation-fadeIn 200ms;\n -o-animation: Select-animation-fadeIn 200ms;\n animation: Select-animation-fadeIn 200ms;\n color: #999;\n cursor: pointer;\n display: table-cell;\n position: relative;\n text-align: center;\n vertical-align: middle;\n width: 17px;\n}\n.Select-clear-zone:hover {\n color: #d0021b;\n}\n.Select-clear {\n display: inline-block;\n font-size: 18px;\n line-height: 1;\n}\n.Select--multi .Select-clear-zone {\n width: 17px;\n}\n.Select-arrow-zone {\n cursor: pointer;\n display: table-cell;\n position: relative;\n text-align: center;\n vertical-align: middle;\n width: 25px;\n padding-right: 5px;\n}\n.Select-arrow {\n border-color: #999 transparent transparent;\n border-style: solid;\n border-width: 5px 5px 2.5px;\n display: inline-block;\n height: 0;\n width: 0;\n}\n.is-open .Select-arrow,\n.Select-arrow-zone:hover > .Select-arrow {\n border-top-color: #666;\n}\n@-webkit-keyframes Select-animation-fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n@keyframes Select-animation-fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n.Select-menu-outer {\n border-bottom-right-radius: 4px;\n border-bottom-left-radius: 4px;\n background-color: #fff;\n border: 1px solid #ccc;\n border-top-color: #e6e6e6;\n box-shadow: 0 1px 0 rgba(0, 0, 0, 0.06);\n box-sizing: border-box;\n margin-top: -1px;\n max-height: 200px;\n position: absolute;\n top: 100%;\n width: 100%;\n z-index: 1000;\n -webkit-overflow-scrolling: touch;\n}\n.Select-menu {\n max-height: 198px;\n overflow-y: auto;\n}\n.Select-option {\n box-sizing: border-box;\n color: #666666;\n cursor: pointer;\n display: block;\n padding: 8px 10px;\n}\n.Select-option:last-child {\n border-bottom-right-radius: 4px;\n border-bottom-left-radius: 4px;\n}\n.Select-option.is-focused {\n background-color: #f2f9fc;\n color: #333;\n}\n.Select-option.is-disabled {\n color: #cccccc;\n cursor: not-allowed;\n}\n.Select-noresults,\n.Select-search-prompt,\n.Select-searching {\n box-sizing: border-box;\n color: #999999;\n cursor: default;\n display: block;\n padding: 8px 10px;\n}\n.Select--multi .Select-input {\n vertical-align: middle;\n margin-left: 10px;\n padding: 0;\n}\n.Select--multi.has-value .Select-input {\n margin-left: 5px;\n}\n.Select-item {\n background-color: #f2f9fc;\n border-radius: 2px;\n border: 1px solid #c9e6f2;\n color: #08c;\n display: inline-block;\n font-size: 0.9em;\n margin-left: 5px;\n margin-top: 5px;\n vertical-align: top;\n}\n.Select-item-icon,\n.Select-item-label {\n display: inline-block;\n vertical-align: middle;\n}\n.Select-item-label {\n border-bottom-right-radius: 2px;\n border-top-right-radius: 2px;\n cursor: default;\n padding: 2px 5px;\n}\n.Select-item-label .Select-item-label__a {\n color: #08c;\n cursor: pointer;\n}\n.Select-item-icon {\n cursor: pointer;\n border-bottom-left-radius: 2px;\n border-top-left-radius: 2px;\n border-right: 1px solid #c9e6f2;\n padding: 1px 5px 3px;\n}\n.Select-item-icon:hover,\n.Select-item-icon:focus {\n background-color: #ddeff7;\n color: #0077b3;\n}\n.Select-item-icon:active {\n background-color: #c9e6f2;\n}\n.Select--multi.is-disabled .Select-item {\n background-color: #f2f2f2;\n border: 1px solid #d9d9d9;\n color: #888;\n}\n.Select--multi.is-disabled .Select-item-icon {\n cursor: not-allowed;\n border-right: 1px solid #d9d9d9;\n}\n.Select--multi.is-disabled .Select-item-icon:hover,\n.Select--multi.is-disabled .Select-item-icon:focus,\n.Select--multi.is-disabled .Select-item-icon:active {\n background-color: #f2f2f2;\n}\n@keyframes Select-animation-spin {\n to {\n transform: rotate(1turn);\n }\n}\n@-webkit-keyframes Select-animation-spin {\n to {\n -webkit-transform: rotate(1turn);\n }\n}\n",""])},function(e,t,n){e.exports=n.p+"ac3f027697c11abd84295888e843f3d2.woff2"},function(e,t,n){e.exports=n.p+"bf3d19297ef12291559b3edae977480c.woff2"},function(e,t,n){e.exports=n.p+"abddffb32a4a35627c3857a06c751424.png"},function(e,t,n){var r,a,o={},l=(r=function(){return window&&document&&document.all&&!window.atob},function(){return void 0===a&&(a=r.apply(this,arguments)),a}),i=function(e){var t={};return function(n){if(void 0===t[n]){var r=e.call(this,n);if(r instanceof window.HTMLIFrameElement)try{r=r.contentDocument.head}catch(e){r=null}t[n]=r}return t[n]}}((function(e){return document.querySelector(e)})),u=null,s=0,c=[],f=n(16);function d(e,t){for(var n=0;n=0&&c.splice(t,1)}function v(e){var t=document.createElement("style");return e.attrs.type="text/css",g(t,e.attrs),h(e,t),t}function g(e,t){Object.keys(t).forEach((function(n){e.setAttribute(n,t[n])}))}function b(e,t){var n,r,a,o;if(t.transform&&e.css){if(!(o=t.transform(e.css)))return function(){};e.css=o}if(t.singleton){var l=s++;n=u||(u=v(t)),r=w.bind(null,n,l,!1),a=w.bind(null,n,l,!0)}else e.sourceMap&&"function"==typeof URL&&"function"==typeof URL.createObjectURL&&"function"==typeof URL.revokeObjectURL&&"function"==typeof Blob&&"function"==typeof btoa?(n=function(e){var t=document.createElement("link");return e.attrs.type="text/css",e.attrs.rel="stylesheet",g(t,e.attrs),h(e,t),t}(t),r=S.bind(null,n,t),a=function(){m(n),n.href&&URL.revokeObjectURL(n.href)}):(n=v(t),r=k.bind(null,n),a=function(){m(n)});return r(e),function(t){if(t){if(t.css===e.css&&t.media===e.media&&t.sourceMap===e.sourceMap)return;r(e=t)}else a()}}e.exports=function(e,t){if("undefined"!=typeof DEBUG&&DEBUG&&"object"!=typeof document)throw new Error("The style-loader cannot be used in a non-browser environment");(t=t||{}).attrs="object"==typeof t.attrs?t.attrs:{},t.singleton||(t.singleton=l()),t.insertInto||(t.insertInto="head"),t.insertAt||(t.insertAt="bottom");var n=p(e,t);return d(n,t),function(e){for(var r=[],a=0;a