From c8b40c29489f4075bf87fa17e7698afac7796222 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 8 Jan 2016 08:45:40 -0800 Subject: [PATCH 001/357] Add uncaught exception backtrace logging --- console/src/main.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/console/src/main.js b/console/src/main.js index e05b16730c..3b18c5961c 100644 --- a/console/src/main.js +++ b/console/src/main.js @@ -27,7 +27,10 @@ const TRAY_ICON = path.join(__dirname, '../resources/' + TRAY_FILENAME); const APP_ICON = path.join(__dirname, '../resources/console.png'); // print out uncaught exceptions in the console -process.on('uncaughtException', console.log.bind(console)); +process.on('uncaughtException', function(err) { + console.error(err); + console.error(err.stack); +}); var shouldQuit = app.makeSingleInstance(function(commandLine, workingDirectory) { // Someone tried to run a second instance, focus the window (if there is one) From d567c215bbf17f2232775ee0dca443cd47d1ef63 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 8 Jan 2016 08:47:16 -0800 Subject: [PATCH 002/357] Update console log paths to be in OS app data directory --- console/src/main.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/console/src/main.js b/console/src/main.js index 3b18c5961c..99ee15dd81 100644 --- a/console/src/main.js +++ b/console/src/main.js @@ -16,12 +16,22 @@ var Process = hfprocess.Process; var ProcessGroup = hfprocess.ProcessGroup; var ProcessGroupStates = hfprocess.ProcessGroupStates; +function getApplicationDataDirectory() { + // Taken from http://stackoverflow.com/questions/19275776/node-js-how-to-get-the-os-platforms-user-data-folder + var rootDirectory = process.env.APPDATA || (process.platform == 'darwin' ? process.env.HOME + 'Library/Preferences' : '/var/local') + return path.join(rootDirectory, '/High Fidelity/Console'); +} + + const ipcMain = electron.ipcMain; const osType = os.type(); var path = require('path'); +var logPath = path.join(getApplicationDataDirectory(), '/logs'); +console.log("Log directory:", logPath); + const TRAY_FILENAME = (osType == "Darwin" ? "console-tray-Template.png" : "console-tray.png"); const TRAY_ICON = path.join(__dirname, '../resources/' + TRAY_FILENAME); const APP_ICON = path.join(__dirname, '../resources/console.png'); @@ -186,8 +196,6 @@ app.on('ready', function() { app.dock.hide() } - var logPath = path.join(app.getAppPath(), 'logs'); - // Create tray icon tray = new Tray(TRAY_ICON); tray.setToolTip('High Fidelity'); From 4851def51cd584c2bc911b83915be113e513f0c6 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 8 Jan 2016 10:35:04 -0800 Subject: [PATCH 003/357] Add status HTTP server to AC Monitor --- assignment-client/src/AssignmentClientApp.cpp | 10 ++- assignment-client/src/AssignmentClientApp.h | 1 + .../src/AssignmentClientMonitor.cpp | 76 ++++++++++++++----- .../src/AssignmentClientMonitor.h | 19 ++++- assignment-client/src/octree/OctreeServer.cpp | 2 +- domain-server/src/DomainServer.cpp | 4 +- ice-server/src/IceServer.cpp | 2 +- .../embedded-webserver/src/HTTPManager.cpp | 5 +- .../embedded-webserver/src/HTTPManager.h | 3 +- .../embedded-webserver/src/HTTPSManager.cpp | 4 +- .../embedded-webserver/src/HTTPSManager.h | 11 +-- 11 files changed, 97 insertions(+), 40 deletions(-) diff --git a/assignment-client/src/AssignmentClientApp.cpp b/assignment-client/src/AssignmentClientApp.cpp index 9d5e8843d0..19a3350d0d 100644 --- a/assignment-client/src/AssignmentClientApp.cpp +++ b/assignment-client/src/AssignmentClientApp.cpp @@ -94,6 +94,9 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : const QCommandLineOption monitorPortOption(ASSIGNMENT_CLIENT_MONITOR_PORT_OPTION, "assignment-client monitor port", "port"); parser.addOption(monitorPortOption); + const QCommandLineOption httpStatusPortOption(ASSIGNMENT_HTTP_STATUS_PORT, "http status server port", "http-status-port"); + parser.addOption(httpStatusPortOption); + const QCommandLineOption logDirectoryOption(ASSIGNMENT_LOG_DIRECTORY, "directory to store logs", "log-directory"); parser.addOption(logDirectoryOption); @@ -135,6 +138,11 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : numForks = minForks; } + quint16 httpStatusPort { 0 }; + if (parser.isSet(httpStatusPortOption)) { + httpStatusPort = parser.value(httpStatusPortOption).toUShort(); + } + QDir logDirectory { "." }; if (parser.isSet(logDirectoryOption)) { logDirectory = parser.value(logDirectoryOption); @@ -212,7 +220,7 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : AssignmentClientMonitor* monitor = new AssignmentClientMonitor(numForks, minForks, maxForks, requestAssignmentType, assignmentPool, listenPort, walletUUID, assignmentServerHostname, - assignmentServerPort, logDirectory); + assignmentServerPort, httpStatusPort, logDirectory); monitor->setParent(this); connect(this, &QCoreApplication::aboutToQuit, monitor, &AssignmentClientMonitor::aboutToQuit); } else { diff --git a/assignment-client/src/AssignmentClientApp.h b/assignment-client/src/AssignmentClientApp.h index b99b442bbb..37d3b9cc1d 100644 --- a/assignment-client/src/AssignmentClientApp.h +++ b/assignment-client/src/AssignmentClientApp.h @@ -25,6 +25,7 @@ const QString ASSIGNMENT_NUM_FORKS_OPTION = "n"; const QString ASSIGNMENT_MIN_FORKS_OPTION = "min"; const QString ASSIGNMENT_MAX_FORKS_OPTION = "max"; const QString ASSIGNMENT_CLIENT_MONITOR_PORT_OPTION = "monitor-port"; +const QString ASSIGNMENT_HTTP_STATUS_PORT = "http-status-port"; const QString ASSIGNMENT_LOG_DIRECTORY = "log-directory"; class AssignmentClientApp : public QCoreApplication { diff --git a/assignment-client/src/AssignmentClientMonitor.cpp b/assignment-client/src/AssignmentClientMonitor.cpp index bb70c8464f..b9c34e9dd7 100644 --- a/assignment-client/src/AssignmentClientMonitor.cpp +++ b/assignment-client/src/AssignmentClientMonitor.cpp @@ -23,6 +23,7 @@ #include "AssignmentClientApp.h" #include "AssignmentClientChildData.h" #include "SharedUtil.h" +#include const QString ASSIGNMENT_CLIENT_MONITOR_TARGET_NAME = "assignment-client-monitor"; const int WAIT_FOR_CHILD_MSECS = 1000; @@ -32,7 +33,8 @@ AssignmentClientMonitor::AssignmentClientMonitor(const unsigned int numAssignmen const unsigned int maxAssignmentClientForks, Assignment::Type requestAssignmentType, QString assignmentPool, quint16 listenPort, QUuid walletUUID, QString assignmentServerHostname, - quint16 assignmentServerPort, QDir logDirectory) : + quint16 assignmentServerPort, quint16 httpStatusServerPort, QDir logDirectory) : + _httpManager(QHostAddress::LocalHost, httpStatusServerPort, "", this), _numAssignmentClientForks(numAssignmentClientForks), _minAssignmentClientForks(minAssignmentClientForks), _maxAssignmentClientForks(maxAssignmentClientForks), @@ -84,24 +86,21 @@ void AssignmentClientMonitor::simultaneousWaitOnChildren(int waitMsecs) { } } -void AssignmentClientMonitor::childProcessFinished() { - QProcess* childProcess = qobject_cast(sender()); - qint64 processID = _childProcesses.key(childProcess); - - if (processID > 0) { - qDebug() << "Child process" << processID << "has finished. Removing from internal map."; - _childProcesses.remove(processID); +void AssignmentClientMonitor::childProcessFinished(qint64 pid) { + if (_childProcesses.remove(pid)) { + qDebug() << "Child process" << pid << "has finished. Removed from internal map."; } } void AssignmentClientMonitor::stopChildProcesses() { + qDebug() << "Stopping child processes"; auto nodeList = DependencyManager::get(); // ask child processes to terminate - foreach(QProcess* childProcess, _childProcesses) { - if (childProcess->processId() > 0) { - qDebug() << "Attempting to terminate child process" << childProcess->processId(); - childProcess->terminate(); + for (auto& ac : _childProcesses) { + if (ac.process->processId() > 0) { + qDebug() << "Attempting to terminate child process" << ac.process->processId(); + ac.process->terminate(); } } @@ -109,10 +108,10 @@ void AssignmentClientMonitor::stopChildProcesses() { if (_childProcesses.size() > 0) { // ask even more firmly - foreach(QProcess* childProcess, _childProcesses) { - if (childProcess->processId() > 0) { - qDebug() << "Attempting to kill child process" << childProcess->processId(); - childProcess->kill(); + for (auto& ac : _childProcesses) { + if (ac.process->processId() > 0) { + qDebug() << "Attempting to kill child process" << ac.process->processId(); + ac.process->kill(); } } @@ -191,24 +190,28 @@ void AssignmentClientMonitor::spawnChildClient() { qDebug() << "Renaming " << stdoutPathTemp << " to " << stdoutPath; if (!_logDirectory.rename(stdoutFilenameTemp, stdoutFilename)) { qDebug() << "Failed to rename " << stdoutFilenameTemp; + stdoutPath = stdoutPathTemp; stdoutFilename = stdoutFilenameTemp; } qDebug() << "Renaming " << stderrPathTemp << " to " << stderrPath; if (!QFile::rename(stderrPathTemp, stderrPath)) { qDebug() << "Failed to rename " << stderrFilenameTemp; + stderrPath = stderrPathTemp; stderrFilename = stderrFilenameTemp; } - qDebug() << "Child stdout being written to: " << stdoutPathTemp; - qDebug() << "Child stderr being written to: " << stderrPathTemp; + qDebug() << "Child stdout being written to: " << stdoutFilename; + qDebug() << "Child stderr being written to: " << stderrFilename; if (assignmentClient->processId() > 0) { + auto pid = assignmentClient->processId(); // make sure we hear that this process has finished when it does - connect(assignmentClient, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(childProcessFinished())); + connect(assignmentClient, static_cast(&QProcess::finished), + this, [this, pid]() { childProcessFinished(pid); }); qDebug() << "Spawned a child client with PID" << assignmentClient->processId(); - _childProcesses.insert(assignmentClient->processId(), assignmentClient); + _childProcesses.insert(assignmentClient->processId(), { assignmentClient, stdoutPath, stderrPath }); } } @@ -296,9 +299,40 @@ void AssignmentClientMonitor::handleChildStatusPacket(QSharedPointerreadPrimitive(&assignmentType); - childData->setChildType((Assignment::Type) assignmentType); + childData->setChildType(Assignment::Type(assignmentType)); // note when this child talked matchingNode->setLastHeardMicrostamp(usecTimestampNow()); } } + +bool AssignmentClientMonitor::handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler) { + if (url.path() == "/status") { + QByteArray response; + + //QJsonDocument status; + QJsonObject status; + QJsonObject servers; + for (auto& ac : _childProcesses) { + QJsonObject server; + + server["pid"] = ac.process->processId(); + server["logStdout"] = ac.logStdoutPath; + server["logStderr"] = ac.logStderrPath; + + servers[QString::number(ac.process->processId())] = server; + + } + + status["servers"] = servers; + + QJsonDocument document { status }; + + connection->respond(HTTPConnection::StatusCode200, document.toJson()); + } else { + connection->respond(HTTPConnection::StatusCode404); + } + + + return true; +} diff --git a/assignment-client/src/AssignmentClientMonitor.h b/assignment-client/src/AssignmentClientMonitor.h index 27ef3e7cab..c7b552d470 100644 --- a/assignment-client/src/AssignmentClientMonitor.h +++ b/assignment-client/src/AssignmentClientMonitor.h @@ -21,24 +21,34 @@ #include #include "AssignmentClientChildData.h" +#include +#include extern const char* NUM_FORKS_PARAMETER; -class AssignmentClientMonitor : public QObject { +struct ACProcess { + QProcess* process; + QString logStdoutPath; + QString logStderrPath; +}; + +class AssignmentClientMonitor : public QObject, public HTTPRequestHandler { Q_OBJECT public: AssignmentClientMonitor(const unsigned int numAssignmentClientForks, const unsigned int minAssignmentClientForks, const unsigned int maxAssignmentClientForks, Assignment::Type requestAssignmentType, QString assignmentPool, quint16 listenPort, QUuid walletUUID, QString assignmentServerHostname, - quint16 assignmentServerPort, QDir logDirectory); + quint16 assignmentServerPort, quint16 httpStatusServerPort, QDir logDirectory); ~AssignmentClientMonitor(); void stopChildProcesses(); private slots: void checkSpares(); - void childProcessFinished(); + void childProcessFinished(qint64 pid); void handleChildStatusPacket(QSharedPointer message); + bool handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler = false) override; + public slots: void aboutToQuit(); @@ -54,13 +64,14 @@ private: const unsigned int _minAssignmentClientForks; const unsigned int _maxAssignmentClientForks; + HTTPManager _httpManager; Assignment::Type _requestAssignmentType; QString _assignmentPool; QUuid _walletUUID; QString _assignmentServerHostname; quint16 _assignmentServerPort; - QMap _childProcesses; + QMap _childProcesses; }; #endif // hifi_AssignmentClientMonitor_h diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 410aa922dc..22bbed2a25 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -283,7 +283,7 @@ void OctreeServer::initHTTPManager(int port) { QString documentRoot = QString("%1/resources/web").arg(QCoreApplication::applicationDirPath()); // setup an httpManager with us as the request handler and the parent - _httpManager = new HTTPManager(port, documentRoot, this, this); + _httpManager = new HTTPManager(QHostAddress::AnyIPv4, port, documentRoot, this, this); } bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler) { diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index e219b47571..614b90cb18 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -46,7 +46,7 @@ const QString ICE_SERVER_DEFAULT_HOSTNAME = "ice.highfidelity.io"; DomainServer::DomainServer(int argc, char* argv[]) : QCoreApplication(argc, argv), _gatekeeper(this), - _httpManager(DOMAIN_SERVER_HTTP_PORT, QString("%1/resources/web/").arg(QCoreApplication::applicationDirPath()), this), + _httpManager(QHostAddress::AnyIPv4, DOMAIN_SERVER_HTTP_PORT, QString("%1/resources/web/").arg(QCoreApplication::applicationDirPath()), this), _httpsManager(NULL), _allAssignments(), _unfulfilledAssignments(), @@ -157,7 +157,7 @@ bool DomainServer::optionallyReadX509KeyAndCertificate() { QSslCertificate sslCertificate(&certFile); QSslKey privateKey(&keyFile, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey, keyPassphraseString.toUtf8()); - _httpsManager = new HTTPSManager(DOMAIN_SERVER_HTTPS_PORT, sslCertificate, privateKey, QString(), this, this); + _httpsManager = new HTTPSManager(QHostAddress::AnyIPv4, DOMAIN_SERVER_HTTPS_PORT, sslCertificate, privateKey, QString(), this, this); qDebug() << "TCP server listening for HTTPS connections on" << DOMAIN_SERVER_HTTPS_PORT; diff --git a/ice-server/src/IceServer.cpp b/ice-server/src/IceServer.cpp index f65ff4a8cf..2baa7a13a7 100644 --- a/ice-server/src/IceServer.cpp +++ b/ice-server/src/IceServer.cpp @@ -27,7 +27,7 @@ IceServer::IceServer(int argc, char* argv[]) : _id(QUuid::createUuid()), _serverSocket(), _activePeers(), - _httpManager(ICE_SERVER_MONITORING_PORT, QString("%1/web/").arg(QCoreApplication::applicationDirPath()), this) + _httpManager(QHostAddress::AnyIPv4, ICE_SERVER_MONITORING_PORT, QString("%1/web/").arg(QCoreApplication::applicationDirPath()), this) { // start the ice-server socket qDebug() << "ice-server socket is listening on" << ICE_SERVER_DEFAULT_PORT; diff --git a/libraries/embedded-webserver/src/HTTPManager.cpp b/libraries/embedded-webserver/src/HTTPManager.cpp index 4c804f2e7b..7cbdf01bbc 100644 --- a/libraries/embedded-webserver/src/HTTPManager.cpp +++ b/libraries/embedded-webserver/src/HTTPManager.cpp @@ -23,8 +23,9 @@ const int SOCKET_ERROR_EXIT_CODE = 2; const int SOCKET_CHECK_INTERVAL_IN_MS = 30000; -HTTPManager::HTTPManager(quint16 port, const QString& documentRoot, HTTPRequestHandler* requestHandler, QObject* parent) : +HTTPManager::HTTPManager(const QHostAddress& listenAddress, quint16 port, const QString& documentRoot, HTTPRequestHandler* requestHandler, QObject* parent) : QTcpServer(parent), + _listenAddress(listenAddress), _documentRoot(documentRoot), _requestHandler(requestHandler), _port(port) @@ -178,7 +179,7 @@ void HTTPManager::isTcpServerListening() { bool HTTPManager::bindSocket() { qCDebug(embeddedwebserver) << "Attempting to bind TCP socket on port " << QString::number(_port); - if (listen(QHostAddress::AnyIPv4, _port)) { + if (listen(_listenAddress, _port)) { qCDebug(embeddedwebserver) << "TCP socket is listening on" << serverAddress() << "and port" << serverPort(); return true; diff --git a/libraries/embedded-webserver/src/HTTPManager.h b/libraries/embedded-webserver/src/HTTPManager.h index 03498fbe8d..90a896ccf5 100644 --- a/libraries/embedded-webserver/src/HTTPManager.h +++ b/libraries/embedded-webserver/src/HTTPManager.h @@ -33,7 +33,7 @@ class HTTPManager : public QTcpServer, public HTTPRequestHandler { Q_OBJECT public: /// Initializes the manager. - HTTPManager(quint16 port, const QString& documentRoot, HTTPRequestHandler* requestHandler = NULL, QObject* parent = 0); + HTTPManager(const QHostAddress& listenAddress, quint16 port, const QString& documentRoot, HTTPRequestHandler* requestHandler = NULL, QObject* parent = 0); bool handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler = false); @@ -49,6 +49,7 @@ protected: virtual void incomingConnection(qintptr socketDescriptor); virtual bool requestHandledByRequestHandler(HTTPConnection* connection, const QUrl& url); + QHostAddress _listenAddress; QString _documentRoot; HTTPRequestHandler* _requestHandler; QTimer* _isListeningTimer; diff --git a/libraries/embedded-webserver/src/HTTPSManager.cpp b/libraries/embedded-webserver/src/HTTPSManager.cpp index a745d7605e..ee61f15457 100644 --- a/libraries/embedded-webserver/src/HTTPSManager.cpp +++ b/libraries/embedded-webserver/src/HTTPSManager.cpp @@ -15,9 +15,9 @@ #include "HTTPSManager.h" -HTTPSManager::HTTPSManager(quint16 port, const QSslCertificate& certificate, const QSslKey& privateKey, +HTTPSManager::HTTPSManager(QHostAddress listenAddress, quint16 port, const QSslCertificate& certificate, const QSslKey& privateKey, const QString& documentRoot, HTTPSRequestHandler* requestHandler, QObject* parent) : - HTTPManager(port, documentRoot, requestHandler, parent), + HTTPManager(listenAddress, port, documentRoot, requestHandler, parent), _certificate(certificate), _privateKey(privateKey), _sslRequestHandler(requestHandler) diff --git a/libraries/embedded-webserver/src/HTTPSManager.h b/libraries/embedded-webserver/src/HTTPSManager.h index 66c0c76d0b..2d3cc9ed62 100644 --- a/libraries/embedded-webserver/src/HTTPSManager.h +++ b/libraries/embedded-webserver/src/HTTPSManager.h @@ -26,7 +26,8 @@ public: class HTTPSManager : public HTTPManager, public HTTPSRequestHandler { Q_OBJECT public: - HTTPSManager(quint16 port, + HTTPSManager(QHostAddress listenAddress, + quint16 port, const QSslCertificate& certificate, const QSslKey& privateKey, const QString& documentRoot, @@ -35,12 +36,12 @@ public: void setCertificate(const QSslCertificate& certificate) { _certificate = certificate; } void setPrivateKey(const QSslKey& privateKey) { _privateKey = privateKey; } - bool handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler = false); - bool handleHTTPSRequest(HTTPSConnection* connection, const QUrl& url, bool skipSubHandler = false); + bool handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler = false) override; + bool handleHTTPSRequest(HTTPSConnection* connection, const QUrl& url, bool skipSubHandler = false) override; protected: - void incomingConnection(qintptr socketDescriptor); - bool requestHandledByRequestHandler(HTTPConnection* connection, const QUrl& url); + void incomingConnection(qintptr socketDescriptor) override; + bool requestHandledByRequestHandler(HTTPConnection* connection, const QUrl& url) override; private: QSslCertificate _certificate; QSslKey _privateKey; From 9539954b435e5b3f2f7af91aae32641b828cad9f Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 8 Jan 2016 11:04:56 -0800 Subject: [PATCH 004/357] Update Process to store log files in provided directory --- console/src/modules/hf-process.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/console/src/modules/hf-process.js b/console/src/modules/hf-process.js index c8b9f8e57a..a8eaf2632e 100755 --- a/console/src/modules/hf-process.js +++ b/console/src/modules/hf-process.js @@ -126,7 +126,7 @@ Process.prototype = extend(Process.prototype, { var logDirectoryCreated = false; try { - fs.mkdirSync('logs'); + fs.mkdirSync(this.logDirectory); logDirectoryCreated = true; } catch (e) { if (e.code == 'EEXIST') { From 51ee7f6ddb24c995d1895593d707d1451f4e5854 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 8 Jan 2016 11:05:59 -0800 Subject: [PATCH 005/357] Update Process to store its log file locations --- console/src/modules/hf-process.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/console/src/modules/hf-process.js b/console/src/modules/hf-process.js index a8eaf2632e..537f2a81ad 100755 --- a/console/src/modules/hf-process.js +++ b/console/src/modules/hf-process.js @@ -107,6 +107,8 @@ function Process(name, command, commandArgs, logDirectory) { this.commandArgs = commandArgs ? commandArgs : []; this.child = null; this.logDirectory = logDirectory; + this.logStdout = null; + this.logStderr = null; this.state = ProcessStates.STOPPED; }; @@ -175,6 +177,8 @@ Process.prototype = extend(Process.prototype, { console.log("Error renaming log file from " + tmpLogStdout + " to " + pidLogStdout, e); } }); + this.logStdout = pidLogStdout; + fs.closeSync(logStdout); } if (logStderr != 'ignore') { @@ -184,6 +188,9 @@ Process.prototype = extend(Process.prototype, { console.log("Error renaming log file from " + tmpLogStdout + " to " + pidLogStdout, e); } }); + this.logStderr = pidLogStderr; + + fs.closeSync(logStderr); } this.child.on('error', this.onChildStartError.bind(this)); From cd049586ea42aa05c5eaffd0d0d932e3c22aa98f Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 8 Jan 2016 11:07:58 -0800 Subject: [PATCH 006/357] Centralize state updates in Process --- console/src/modules/hf-process.js | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/console/src/modules/hf-process.js b/console/src/modules/hf-process.js index 537f2a81ad..1bdade3b1f 100755 --- a/console/src/modules/hf-process.js +++ b/console/src/modules/hf-process.js @@ -167,7 +167,8 @@ Process.prototype = extend(Process.prototype, { } catch (e) { console.log("Got error starting child process for " + this.name, e); this.child = null; - this.state = ProcessStates.STOPPED; + this.updateState(ProcessStates.STOPPED); + return; } if (logStdout != 'ignore') { @@ -195,10 +196,10 @@ Process.prototype = extend(Process.prototype, { this.child.on('error', this.onChildStartError.bind(this)); this.child.on('close', this.onChildClose.bind(this)); - this.state = ProcessStates.STARTED; - console.log("Child process started"); - this.emit('state-update', this); + console.log("Child process started"); + this.updateState(ProcessStates.STARTED); + this.emit('logs-updated'); }, stop: function() { if (this.state != ProcessStates.STARTED) { @@ -212,7 +213,14 @@ Process.prototype = extend(Process.prototype, { } this.state = ProcessStates.STOPPING; - this.emit('state-update', this); + updateState: function(newState) { + if (this.state != newState) { + this.state = newState; + this.emit('state-update', this); + return true; + } + return false; + }, }, // Events From 87794981c612bf85c9ddcce46a0cc5b978bc4acc Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 8 Jan 2016 11:08:34 -0800 Subject: [PATCH 007/357] Update root app data location --- console/src/main.js | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/console/src/main.js b/console/src/main.js index 99ee15dd81..8f6fec47a5 100644 --- a/console/src/main.js +++ b/console/src/main.js @@ -1,24 +1,38 @@ -'use strict' +'use strict'; var electron = require('electron'); var app = electron.app; // Module to control application life. var BrowserWindow = electron.BrowserWindow; + var Menu = require('menu'); var Tray = require('tray'); var shell = require('shell'); var os = require('os'); var childProcess = require('child_process'); var path = require('path'); +var fs = require('fs'); +var Tail = require('always-tail'); +var http = require('http'); +var path = require('path'); var hfprocess = require('./modules/hf-process.js'); var Process = hfprocess.Process; +var ACMonitorProcess = hfprocess.ACMonitorProcess; +var ProcessStates = hfprocess.ProcessStates; var ProcessGroup = hfprocess.ProcessGroup; var ProcessGroupStates = hfprocess.ProcessGroupStates; function getApplicationDataDirectory() { - // Taken from http://stackoverflow.com/questions/19275776/node-js-how-to-get-the-os-platforms-user-data-folder - var rootDirectory = process.env.APPDATA || (process.platform == 'darwin' ? process.env.HOME + 'Library/Preferences' : '/var/local') + var osType = os.type(); + var rootDirectory; + if (osType == 'Windows_NT') { + rootDirectory = process.env.APPDATA; + } else if (osType == 'Darwin') { + rootDirecotry = process.env.HOME + 'Library/Application Support'; + } else { + rootDirectory = '/usr/local/share'; + } return path.join(rootDirectory, '/High Fidelity/Console'); } From e70906a9c6ffb899e716375bce468ab12acc89ac Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 8 Jan 2016 11:09:48 -0800 Subject: [PATCH 008/357] Add graceful shutdown of home server --- console/src/main.js | 83 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 80 insertions(+), 3 deletions(-) diff --git a/console/src/main.js b/console/src/main.js index 8f6fec47a5..f03f0a1d9b 100644 --- a/console/src/main.js +++ b/console/src/main.js @@ -41,7 +41,25 @@ const ipcMain = electron.ipcMain; const osType = os.type(); -var path = require('path'); +var isShuttingDown = false; +function shutdown() { + if (!isShuttingDown) { + isShuttingDown = true; + logWindow.close(); + homeServer.stop(); + + var timeoutID = setTimeout(app.quit, 5000); + homeServer.on('state-update', function(processGroup) { + if (processGroup.state == ProcessGroupStates.STOPPED) { + clearTimeout(timeoutID); + app.quit(); + } + }); + + updateTrayMenu(null); + } +} + var logPath = path.join(getApplicationDataDirectory(), '/logs'); console.log("Log directory:", logPath); @@ -157,9 +175,64 @@ function buildMenuArray(serverState) { accelerator: 'Command+Q', click: function() { app.quit(); } } - ]; +function buildMenuArray(serverState) { + var menuArray = null; + if (isShuttingDown) { + menuArray = [ + { + label: "Shutting down...", + enabled: false + } + ]; + } else { + menuArray = [ + { + label: 'Go Home', + click: function() { startInterface('hifi://localhost'); }, + enabled: false + }, + { + type: 'separator' + }, + { + label: "Server - Stopped", + enabled: false + }, + { + label: "Start", + click: function() { homeServer.restart(); } + }, + { + label: "Stop", + visible: false, + click: function() { homeServer.stop(); } + }, + { + label: "Settings", + click: function() { shell.openExternal('http://localhost:40100/settings'); }, + enabled: false + }, + { + label: "View Logs", + click: function() { logWindow.open(); } + }, + { + label: "Open Log Directory", + click: function() { openFileBrowser(logPath); } + }, + { + type: 'separator' + }, + { + label: 'Quit', + accelerator: 'Command+Q', + click: function() { shutdown(); } + } + ]; + + updateMenuArray(menuArray, serverState); + } - updateMenuArray(menuArray, serverState); return menuArray; } @@ -189,6 +262,7 @@ function updateMenuArray(menuArray, serverState) { } else if (serverState == ProcessGroupStates.STOPPING) { serverLabelItem.label = "Server - Stopping"; restartItem.label = "Restart"; + restartItem.enabled = false; } } @@ -196,6 +270,9 @@ function updateTrayMenu(serverState) { if (tray) { var menuArray = buildMenuArray(serverState); tray.setContextMenu(Menu.buildFromTemplate(menuArray)); + if (isShuttingDown) { + tray.setToolTip('High Fidelity - Shutting Down'); + } } } From 98e1c42183b61d313978b455c6bc9400353be671 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 8 Jan 2016 11:10:14 -0800 Subject: [PATCH 009/357] Fix openFileBrowser not working with paths with spaces --- console/src/main.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/console/src/main.js b/console/src/main.js index f03f0a1d9b..5d49725c7f 100644 --- a/console/src/main.js +++ b/console/src/main.js @@ -94,6 +94,7 @@ var acPath = null; var debug = argv.debug; + if (argv.localDebugBuilds || argv.localReleaseBuilds) { interfacePath = pathFinder.discoveredPath("Interface", argv.localReleaseBuilds); dsPath = pathFinder.discoveredPath("domain-server", argv.localReleaseBuilds); @@ -104,8 +105,11 @@ if (argv.localDebugBuilds || argv.localReleaseBuilds) { // TODO: show an error for the binaries that couldn't be found function openFileBrowser(path) { + // Add quotes around path + path = '"' + path + '"'; if (osType == "Windows_NT") { - childProcess.exec('start ' + path); + console.log('start "" ' + path); + childProcess.exec('start "" ' + path); } else if (osType == "Darwin") { childProcess.exec('open ' + path); } else if (osType == "Linux") { From 0a8841539395835730be4f6a805ef82fe9344ba0 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 8 Jan 2016 11:10:37 -0800 Subject: [PATCH 010/357] Update console to not shut down when all windows are closed --- console/src/main.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/console/src/main.js b/console/src/main.js index 5d49725c7f..8862bb3ee3 100644 --- a/console/src/main.js +++ b/console/src/main.js @@ -117,6 +117,9 @@ function openFileBrowser(path) { } } +app.on('window-all-closed', function() { +}); + function startInterface(url) { var argArray = []; From 72f53209428b0dec767a736d55b4aa4c5b6d7d18 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 8 Jan 2016 11:12:16 -0800 Subject: [PATCH 011/357] Update console to pass http status port to AC Monitor --- console/src/main.js | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/console/src/main.js b/console/src/main.js index 8862bb3ee3..5ff9925a37 100644 --- a/console/src/main.js +++ b/console/src/main.js @@ -134,7 +134,9 @@ function startInterface(url) { } var tray = null; -var homeServer = null; +global.homeServer = null; +global.domainServer = null; +global.acMonitor = null; const GO_HOME_INDEX = 0; const SERVER_LABEL_INDEX = 2; @@ -283,7 +285,7 @@ function updateTrayMenu(serverState) { } } -var hiddenWindow = null; +const httpStatusPort = 60332; // This method will be called when Electron has finished // initialization and is ready to create browser windows. @@ -301,10 +303,12 @@ app.on('ready', function() { updateTrayMenu(ProcessGroupStates.STOPPED); if (interfacePath && dsPath && acPath) { - homeServer = new ProcessGroup('home', [ - new Process('domain-server', dsPath), - new Process('ac-monitor', acPath, ['-n6', '--log-directory', logPath]) - ]); + domainServer = new Process('domain-server', dsPath, [], logPath); + acMonitor = new ACMonitorProcess('ac-monitor', acPath, ['-n4', + '--log-directory', logPath, + '--http-status-port', httpStatusPort], httpStatusPort, logPath); + homeServer = new ProcessGroup('home', [domainServer, acMonitor]); + logWindow = new LogWindow(acMonitor, domainServer); // make sure we stop child processes on app quit app.on('quit', function(){ @@ -316,7 +320,6 @@ app.on('ready', function() { }; // handle process updates - // homeServer.on('process-update', sendProcessUpdate); homeServer.on('state-update', function(processGroup) { updateTrayMenu(processGroup.state); }); // start the home server From 8113c46df5da3d7144c6bd7f564e50d542b81ccd Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 8 Jan 2016 11:13:03 -0800 Subject: [PATCH 012/357] Add log window --- console/src/log.html | 28 +++++ console/src/log.js | 265 +++++++++++++++++++++++++++++++++++++++++++ console/src/main.js | 75 ++++++------ 3 files changed, 329 insertions(+), 39 deletions(-) create mode 100644 console/src/log.html create mode 100644 console/src/log.js diff --git a/console/src/log.html b/console/src/log.html new file mode 100644 index 0000000000..83fa3f4ef7 --- /dev/null +++ b/console/src/log.html @@ -0,0 +1,28 @@ + + + + Log + + + + + + + +
    + + +
+ +
+
+
+
+
+
+
+
+ + diff --git a/console/src/log.js b/console/src/log.js new file mode 100644 index 0000000000..c42b616756 --- /dev/null +++ b/console/src/log.js @@ -0,0 +1,265 @@ +var remote = require('electron').remote; +var os = require('os'); +var Tail = require('always-tail'); + +function cleanPath(path) { + if (os.type() == "Windows_NT") { + // Fix path on Windows + while (path.indexOf('\\') >= 0) { + path = path.replace('\\', '/', 'g'); + } + } + return path; +} + +ready = function() { + window.$ = require('./vendor/jquery/jquery-2.1.4.min.js'); + + console.log(remote.debug); + + var domainServer = remote.getGlobal('domainServer'); + var acMonitor = remote.getGlobal('acMonitor'); + + var logFiles = { + 'ds': { + }, + 'ac': { + } + }; + + function updateLogFiles() { + var dsLogs = domainServer.getLogs(); + var acLogs = acMonitor.getLogs(); + + // Update ds logs + var dsLogFilePaths = []; + for (var pid in dsLogs) { + dsLogFilePaths.push(dsLogs[pid].stdout); + dsLogFilePaths.push(dsLogs[pid].stderr); + } + console.log(dsLogFilePaths); + console.log(dsLogs); + var dsFilePaths = Object.keys(logFiles.ds); + for (const filePath of dsFilePaths) { + if (dsLogFilePaths.indexOf(filePath) == -1) { + // This file is no longer being used, let's stop watching it + // and remove it from our list. + logFiles.ds[filePath].unwatch(); + delete logFiles[filePath]; + } + } + dsLogFilePaths.forEach(function(filePath) { + if (logFiles.ds[filePath] === undefined) { + var cleanFilePath = cleanPath(filePath); + + var logTail = new Tail(cleanFilePath, '\n', { start: 0, interval: 500 }); + + logTail.on('line', function(msg) { + console.log('msg', msg, 'ds'); + appendLogMessage(0, msg, 'ds'); + }); + + logTail.on('error', function(error) { + console.log("ERROR:", error); + }); + + logTail.watch(); + + logFiles.ds[filePath] = logTail; + console.log("Watching", cleanFilePath); + } + }); + + // Update ac logs + var acLogFilePaths = []; + for (var pid in acLogs) { + acLogFilePaths.push(acLogs[pid].stdout); + acLogFilePaths.push(acLogs[pid].stderr); + } + console.log(acLogFilePaths); + console.log(acLogs); + var acFilePaths = Object.keys(logFiles.ac); + for (filePath of acFilePaths) { + if (acLogFilePaths.indexOf(filePath) == -1) { + // This file is no longer being used, let's stop watching it + // and remove it from our list. + logFiles.ac[filePath].unwatch(); + delete logFiles[filePath]; + } + } + acLogFilePaths.forEach(function(filePath) { + if (logFiles.ac[filePath] === undefined) { + var cleanFilePath = cleanPath(filePath); + + var fs = require('fs'); + + var stats = fs.statSync(cleanFilePath); + var size = stats.size; + var start = Math.max(0, size - (2500 * 50)); + console.log(cleanFilePath, size, start, maxLogLines); + + var logTail = new Tail(cleanFilePath, '\n', { start: start, interval: 500 }); + + logTail.on('line', function(msg) { + console.log('msg', msg, 'ac'); + appendLogMessage(0, msg, 'ac'); + }); + + logTail.on('error', function(error) { + console.log("ERROR:", error); + }); + + logTail.watch(); + + logFiles.ac[filePath] = logTail; + console.log("Watching", cleanFilePath); + } + }); + + console.log(dsLogs, acLogs); + } + + window.onbeforeunload = function(e) { + domainServer.removeListener('logs-updated', updateLogFiles); + acMonitor.removeListener('logs-updated', updateLogFiles); + }; + + domainServer.on('logs-updated', updateLogFiles); + acMonitor.on('logs-updated', updateLogFiles); + + updateLogFiles(); + + const maxLogLines = 2500; + const ipcRenderer = require('electron').ipcRenderer; + + var currentTab = 'domain-server'; + var tabStates = { + 'domain-server': { + atBottom: true, + size: 0 + }, + 'assignment-client': { + atBottom: true, + size: 0 + } + }; + function setCurrentTab(tabId) { + if (currentTab == tabId) { + return; + } + + var padding = 15; + $currentTab = $('#' + currentTab); + tabStates[currentTab].atBottom = $currentTab[0].scrollTop >= ($currentTab[0].scrollHeight - $currentTab.height() - (2 * padding)); + + currentTab = tabId; + $('ul.tabs li').removeClass('current'); + $('.tab-pane').removeClass('current'); + + $('li[data-tab=' + tabId + ']').addClass('current'); + var $pidLog = $("#" + tabId); + $pidLog.addClass('current'); + + if (tabStates[tabId].atBottom) { + $pidLog.scrollTop($pidLog[0].scrollHeight); + } + } + + $('ul.tabs li').click(function(){ + setCurrentTab($(this).attr('data-tab')); + }); + + setCurrentTab('domain-server'); + setCurrentTab('assignment-client'); + + var filter = ""; + + var times = {}; + var t = null; + function start() { + t = Date.now(); + } + function stop(name) { + if (!(name in times)) times[name] = 0; + times[name] += (Date.now() - t); + } + + function printTimes() { + for (var k in times) { + console.log(k, times[k] / 1000, 's'); + } + } + + // Register for log events + // Process added + + function shouldDisplayLogMessage(message) { + return !filter || message.toLowerCase().indexOf(filter) >= 0; + } + + function appendLogMessage(pid, msg, name) { + console.log(pid, msg, name); + start(); + var id = "pid-" + pid; + id = name == "ds" ? "domain-server" : "assignment-client"; + var $pidLog = $('#' + id); + stop('acquire'); + + start(); + // var $logLines = $pidLog.children(); + // var removed = false; + var size = ++tabStates[id].size; + stop('get size'); + start(); + if (size > maxLogLines) { + // $logLines.first().remove(); + $pidLog.find('div.log-line:first').remove(); + removed = true; + } + stop('remove first'); + + start(); + var wasAtBottom = false; + if (currentTab == id) { + var padding = 15; + wasAtBottom = $pidLog[0].scrollTop >= ($pidLog[0].scrollHeight - $pidLog.height() - (2 * padding)); + } + stop('scrollCheck'); + + start(); + var $logLine = $('
').text(msg); + stop('create'); + if (!shouldDisplayLogMessage(msg)) { + $logLine.hide(); + } + start(); + $pidLog.append($logLine); + stop('append'); + + start(); + if (wasAtBottom) { + $pidLog.scrollTop($pidLog[0].scrollHeight); + } + stop('scroll'); + + } + + // handle filtering of table rows on input change + $('#search-input').on('input', function() { + filter = $(this).val().toLowerCase(); + if (filter == "") { + $('.log-line').show(); + } else { + $('.log-line').each(function(){ + // decide to hide or show the row if it matches the filter + if (filter && $(this).text().toLowerCase().indexOf(filter) == -1) { + $(this).hide(); + } else { + $(this).show(); + } + }); + } + }); + + setInterval(printTimes, 10000); +}; diff --git a/console/src/main.js b/console/src/main.js index 5ff9925a37..39ce84f953 100644 --- a/console/src/main.js +++ b/console/src/main.js @@ -144,46 +144,41 @@ const RESTART_INDEX = 3; const STOP_INDEX = 4; const SETTINGS_INDEX = 5; -function buildMenuArray(serverState) { - var menuArray = [ - { - label: 'Go Home', - click: function() { startInterface('hifi://localhost'); }, - enabled: false - }, - { - type: 'separator' - }, - { - label: "Server - Stopped", - enabled: false - }, - { - label: "Start", - click: function() { homeServer.restart(); } - }, - { - label: "Stop", - visible: false, - click: function() { homeServer.stop(); } - }, - { - label: "Settings", - click: function() { shell.openExternal('http://localhost:40100/settings'); }, - enabled: false - }, - { - label: "View Logs", - click: function() { openFileBrowser(logPath); } - }, - { - type: 'separator' - }, - { - label: 'Quit', - accelerator: 'Command+Q', - click: function() { app.quit(); } +var LogWindow = function(ac, ds) { + this.ac = ac; + this.ds = ds; + this.window = null; + this.acMonitor = null; + this.dsMonitor = null; +} +LogWindow.prototype = { + open: function() { + if (this.window) { + this.window.show(); + this.window.restore(); + return; } + // Create the browser window. + this.window = new BrowserWindow({ width: 700, height: 500, icon: APP_ICON }); + this.window.loadURL('file://' + __dirname + '/log.html'); + + if (!debug) { + logWindow.setMenu(null); + } + + this.window.on('closed', function() { + this.window = null; + }.bind(this)); + }, + close: function() { + if (this.window) { + this.window.close(); + } + } +}; + +var logWindow = null; + function buildMenuArray(serverState) { var menuArray = null; if (isShuttingDown) { @@ -312,6 +307,8 @@ app.on('ready', function() { // make sure we stop child processes on app quit app.on('quit', function(){ + console.log('App quitting'); + logWindow.close(); homeServer.stop(); }); From e0acaacc65d750f285bf052a08b70731de135a45 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 8 Jan 2016 11:13:19 -0800 Subject: [PATCH 013/357] Add missing ; to line --- console/src/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/console/src/main.js b/console/src/main.js index 39ce84f953..e9463def83 100644 --- a/console/src/main.js +++ b/console/src/main.js @@ -288,7 +288,7 @@ app.on('ready', function() { if (app.dock) { // hide the dock icon on OS X - app.dock.hide() + app.dock.hide(); } // Create tray icon From 9c4e0d5b19df39d28119896a1802a9b6aed68345 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 8 Jan 2016 11:14:15 -0800 Subject: [PATCH 014/357] Add ac monitor status monitoring --- console/src/modules/hf-process.js | 88 +++++++++++++++++++++++++++++-- 1 file changed, 85 insertions(+), 3 deletions(-) diff --git a/console/src/modules/hf-process.js b/console/src/modules/hf-process.js index 1bdade3b1f..0f4104d2c8 100755 --- a/console/src/modules/hf-process.js +++ b/console/src/modules/hf-process.js @@ -1,5 +1,6 @@ 'use strict' +var request = require('request'); var extend = require('extend'); var util = require('util'); var events = require('events'); @@ -19,6 +20,8 @@ const ProcessStates = { STOPPING: 'stopping' }; + + function ProcessGroup(name, processes) { events.EventEmitter.call(this); @@ -230,13 +233,92 @@ Process.prototype = extend(Process.prototype, { this.emit('state-update', this); }, onChildClose: function(code) { - console.log("Child process closed with code ", code); - this.state = ProcessStates.STOPPED; - this.emit('state-update', this); + console.log("Child process closed with code ", code, this.name); + if (this.stoppingTimeoutID) { + clearTimeout(this.stoppingTimeoutID); + this.stoppingTimeoutID = null; + } + this.updateState(ProcessStates.STOPPED); + } +}); + +// ACMonitorProcess is an extension of Process that keeps track of the AC Montior's +// children status and log locations. +const CHECK_AC_STATUS_INTERVAL = 5000; +function ACMonitorProcess(name, path, args, httpStatusPort, logPath) { + Process.call(this, name, path, args, logPath); + + this.httpStatusPort = httpStatusPort; + + this.requestTimeoutID = null; + this.pendingRequest = null; + this.childServers = {}; +}; +util.inherits(ACMonitorProcess, Process); +ACMonitorProcess.prototype = extend(ACMonitorProcess.prototype, { + updateState: function(newState) { + if (ACMonitorProcess.super_.prototype.updateState.call(this, newState)) { + if (this.state == ProcessStates.STARTED) { + this._updateACMonitorStatus(); + } else { + if (this.requestTimeoutID) { + clearTimeout(this.requestTimeoutID); + this.requestTimeoutID = null; + } + if (this.pendingRequest) { + this.pendingRequest.destroy(); + this.pendingRequest = null; + } + } + } + }, + getLogs: function() { + var logs = {}; + logs[this.child.pid] = { + stdout: this.logStdout == 'ignore' ? null : this.logStdout, + stderr: this.logStderr == 'ignore' ? null : this.logStderr + }; + for (var pid in this.childServers) { + logs[pid] = { + stdout: this.childServers[pid].logStdout, + stderr: this.childServers[pid].logStderr + } + } + console.log(logs); + return logs; + }, + _updateACMonitorStatus: function() { + if (this.state != ProcessStates.STARTED) { + return; + } + + // If there is a pending request, return + if (this.pendingRequest) { + return; + } + + console.log("Checking AC Monitor status"); + var options = { + url: "http://localhost:" + this.httpStatusPort + "/status", + json: true + }; + this.pendingRequest = request(options, function(error, response, body) { + if (error) { + console.error('ERROR Getting AC Monitor status', error); + } else { + this.childServers = body.servers; + } + console.log(body); + + this.emit('logs-updated'); + + this.requestTimeoutID = setTimeout(this._updateACMonitorStatus.bind(this), CHECK_AC_STATUS_INTERVAL); + }.bind(this)); } }); module.exports.Process = Process; +module.exports.ACMonitorProcess = ACMonitorProcess; module.exports.ProcessGroup = ProcessGroup; module.exports.ProcessGroupStates = ProcessGroupStates; module.exports.ProcessStates = ProcessStates; From ab516f654354cf81d87ac8c6276f02f9998ee034 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 8 Jan 2016 11:15:54 -0800 Subject: [PATCH 015/357] Add forceful shutdown of processes if no response after 2.5s --- console/src/modules/hf-process.js | 33 +++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/console/src/modules/hf-process.js b/console/src/modules/hf-process.js index 0f4104d2c8..60a24bb804 100755 --- a/console/src/modules/hf-process.js +++ b/console/src/modules/hf-process.js @@ -204,18 +204,39 @@ Process.prototype = extend(Process.prototype, { this.updateState(ProcessStates.STARTED); this.emit('logs-updated'); }, - stop: function() { - if (this.state != ProcessStates.STARTED) { - console.warn("Can't stop process that is not started."); + stop: function(force) { + if (this.state == ProcessStates.STOPPED) { + console.warn("Can't stop process that is not started or stopping."); return; } if (os.type() == "Windows_NT") { - childProcess.spawn("taskkill", ["/pid", this.child.pid, '/f', '/t']); + var command = "taskkill /pid " + this.child.pid; + if (force) { + command += " /f /t"; + } + childProcess.exec(command, {}, function(error) { + if (error) { + console.error('Error executing taskkill:', error); + } + }); } else { - this.child.kill(); + var signal = force ? 'SIGKILL' : null; + this.child.kill(signal); } - this.state = ProcessStates.STOPPING; + console.log("Stopping child process:", this.child.pid, this.name); + + if (!force) { + this.stoppingTimeoutID = setTimeout(function() { + if (this.state == ProcessStates.STOPPING) { + console.log("Force killling", this.name, this.child.pid); + this.stop(true); + } + }.bind(this), 2500); + } + + this.updateState(ProcessStates.STOPPING); + }, updateState: function(newState) { if (this.state != newState) { this.state = newState; From 8a4855c4119edda5aa98091c699b5d7ddf33b639 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 8 Jan 2016 11:16:11 -0800 Subject: [PATCH 016/357] Add getLogs to Process --- console/src/modules/hf-process.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/console/src/modules/hf-process.js b/console/src/modules/hf-process.js index 60a24bb804..817f25d341 100755 --- a/console/src/modules/hf-process.js +++ b/console/src/modules/hf-process.js @@ -245,13 +245,19 @@ Process.prototype = extend(Process.prototype, { } return false; }, + getLogs: function() { + var logs = {}; + logs[this.child.pid] = { + stdout: this.logStdout == 'ignore' ? null : this.logStdout, + stderr: this.logStderr == 'ignore' ? null : this.logStderr + }; + return logs; }, // Events onChildStartError: function(error) { console.log("Child process error ", error); - this.state = ProcessStates.STOPPED; - this.emit('state-update', this); + this.updateState(ProcessStates.STOPPED); }, onChildClose: function(code) { console.log("Child process closed with code ", code, this.name); From ef7d60687b12159c0f08b1681b45419db1cd0605 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 8 Jan 2016 14:54:48 -0800 Subject: [PATCH 017/357] Add prompt dialog before shutting down --- console/src/main.js | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/console/src/main.js b/console/src/main.js index e9463def83..9cf43dc758 100644 --- a/console/src/main.js +++ b/console/src/main.js @@ -4,7 +4,7 @@ var electron = require('electron'); var app = electron.app; // Module to control application life. var BrowserWindow = electron.BrowserWindow; - +var dialog = electron.dialog; var Menu = require('menu'); var Tray = require('tray'); var shell = require('shell'); @@ -44,19 +44,26 @@ const osType = os.type(); var isShuttingDown = false; function shutdown() { if (!isShuttingDown) { - isShuttingDown = true; - logWindow.close(); - homeServer.stop(); - - var timeoutID = setTimeout(app.quit, 5000); - homeServer.on('state-update', function(processGroup) { - if (processGroup.state == ProcessGroupStates.STOPPED) { - clearTimeout(timeoutID); - app.quit(); - } + var idx = dialog.showMessageBox({ + type: 'question', + buttons: ['Yes', 'No'], + message: 'Are you sure you want to quit?' }); + if (idx == 0) { + isShuttingDown = true; + logWindow.close(); + homeServer.stop(); - updateTrayMenu(null); + var timeoutID = setTimeout(app.quit, 5000); + homeServer.on('state-update', function(processGroup) { + if (processGroup.state == ProcessGroupStates.STOPPED) { + clearTimeout(timeoutID); + app.quit(); + } + }); + + updateTrayMenu(null); + } } } From 337721727321d710a13ec6656b8c0c9a2860b3ef Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 8 Jan 2016 14:57:03 -0800 Subject: [PATCH 018/357] Add title to quit dialog --- console/src/main.js | 1 + 1 file changed, 1 insertion(+) diff --git a/console/src/main.js b/console/src/main.js index 9cf43dc758..a44214d38e 100644 --- a/console/src/main.js +++ b/console/src/main.js @@ -47,6 +47,7 @@ function shutdown() { var idx = dialog.showMessageBox({ type: 'question', buttons: ['Yes', 'No'], + title: 'High Fidelity', message: 'Are you sure you want to quit?' }); if (idx == 0) { From 6d42ce63fcf533149b919e0e23853453ea8c38b1 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 11 Jan 2016 14:06:53 -0800 Subject: [PATCH 019/357] Add splash screen --- console/src/splash.css | 127 ++++++++++++++++++++++++++++++++++++++++ console/src/splash.html | 76 ++++++++++++++++++++++++ console/src/splash.js | 11 ++++ 3 files changed, 214 insertions(+) create mode 100644 console/src/splash.css create mode 100644 console/src/splash.html create mode 100644 console/src/splash.js diff --git a/console/src/splash.css b/console/src/splash.css new file mode 100644 index 0000000000..1bebf3672f --- /dev/null +++ b/console/src/splash.css @@ -0,0 +1,127 @@ +@font-face { + font-family: 'Proxima Nova'; + src: url('vendor/ProximaNova/ProximaNova-Regular.otf'); +} + +body { + height: 100%; + width: 100%; + margin: 0; + padding: 0; + color: #414141; +} +* { + font-family: "Proxima Nova", "Open Sans", Arial, Helvetica, sans-serif; + font-size: 1.022em; + line-height: 130%; +} + + +a:link, a:visited, a:hover, a:active { + color: #2D88A4; + } + +a:hover { + color: #00B4EF; +} + +h1, h2 { + color: black; + margin: 0; + padding: 0; +} +h1 { + font-size: 2.0em; +} +h2 { + font-size: 1.0em; + font-weight: bold; +} + +p { +} + +.header-title { + padding-top: 80px; +} +.content { + margin: 0 110px; +} +.column { + display: inline-block; + float: left; +} + +.column.left { + padding-top: 20px; + width: 415px; + padding-right: 120px; +} +.column.center { + padding-top: 20px; + width: 540px; +} +.column.right { + float: right; + padding-top: 40px; + padding-left: 60px; + + position: absolute; + right: -30px; +} +.column.right img { +} + +.top { + height: 156px; + border-bottom: 2px solid #F5F6F6; +} +.middle { + width: 1364px; /* 1584 - (110 * 2) */ + position: absolute; + top: 156px; + bottom: 98px; +} +.bottom{ + width: 100%; + position: absolute; + height: 98px; + background-color: #F5F6F6; + + bottom: 0; + + /* padding-top: 34px; */ +} + +.footer { + padding-top: 34px; +} + + +.header-title { +} + +.header-right { + /* float: right; */ + position: absolute; + top: 70px; + right: 114px; +} + +input[type="checkbox"] { + display: inline-block; + /* display:none; */ + /* width:19px; */ + /* height:19px; */ +} +/* input[type=checkbox] label:before { */ +/* border-radius: 3px; */ +/* } */ +/* input[type=checkbox]:checked { */ +/* content: "\2713"; */ +/* text-shadow: 1px 1px 1px rgba(0, 0, 0, .2); */ +/* font-size: 15px; */ +/* color: #f3f3f3; */ +/* text-align: center; */ +/* line-height: 15px; */ +/* } */ \ No newline at end of file diff --git a/console/src/splash.html b/console/src/splash.html new file mode 100644 index 0000000000..376af224f5 --- /dev/null +++ b/console/src/splash.html @@ -0,0 +1,76 @@ + + + + High Fidelity + + + + +
+
+

Install complete

+
+
+ +
+
+
+
+

+

What now?

+ Console is your personal domain server in High Fidelity. + It allows your local machine to manage 4000 cubic kilometers of space, + ready for you to build, explore, and share however you like. To start + you off, we've put a few things in your space to play around with and + to learn the ropes. +

+ +

+ To learn more about uploading your own models and scripts, and how to add + items from the Market, check out 'The Basics'. +

+
+
+

+

How do I use it?

+ Console is your personal domain server in High Fidelity. + It allows your local machine to manage your server by clicking on the + High Fidelity icon in your ... In the menu that opens, you can: +

+ +

+

    +
  • go to your 'Home,' automatically launching High Fidelity
  • +
  • administer basic function like starting and stopping your server
  • +
  • access your server's settings and logs
  • +
+

+ +

+ For more information on managing your server, visit our documentation +

+
+
+ +
+
+
+ +
+ + diff --git a/console/src/splash.js b/console/src/splash.js new file mode 100644 index 0000000000..3d9bd81bde --- /dev/null +++ b/console/src/splash.js @@ -0,0 +1,11 @@ +var remote = require('electron').remote; + +ready = function() { + window.$ = require('./vendor/jquery/jquery-2.1.4.min.js'); + + var userConfig = remote.getGlobal('userConfig'); + $('#suppress-splash').change(function() { + console.log("updating"); + userConfig.set('doNotShowSplash', $(this).is(':checked')); + }); +} From d1cf68b4e83c3fc2a9508bf53939ef98076f8ec0 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 11 Jan 2016 14:07:02 -0800 Subject: [PATCH 020/357] Add Proxima Nova From 0ccf3d41a042688ab10c289b71f4cf2c181aa99a Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 11 Jan 2016 14:58:59 -0800 Subject: [PATCH 021/357] Add config.js --- console/src/modules/config.js | 47 +++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 console/src/modules/config.js diff --git a/console/src/modules/config.js b/console/src/modules/config.js new file mode 100644 index 0000000000..663a34e66b --- /dev/null +++ b/console/src/modules/config.js @@ -0,0 +1,47 @@ +var fs = require('fs'); +var extend = require('extend'); + +function Config() { + this.data = {}; +} +Config.prototype = { + load: function(filePath) { + // open file + var rawData = null; + try { + rawData = fs.readFileSync(filePath); + } catch(e) { + console.log("Config file not found"); + } + var configData = {}; + + // read file and json parse + try { + if (rawData) { + configData = JSON.parse(rawData); + } else { + configData = {}; + } + } catch(e) { + console.error("Error parsing config file", filePath) + } + + this.data = {}; + extend(true, this.data, configData); + }, + save: function(filePath) { + fs.writeFileSync(filePath, JSON.stringify(this.data)); + }, + get: function(key, defaultValue) { + if (this.data.hasOwnProperty(key)) { + return this.data[key]; + } + return defaultValue; + }, + set: function(key, value) { + console.log("Setting", key, "to", value); + this.data[key] = value; + } +}; + +exports.Config = Config; From 09369599fcd7cb090a997721e67f51bb8da2a77b Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 11 Jan 2016 15:01:09 -0800 Subject: [PATCH 022/357] Add user config to app --- console/src/main.js | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/console/src/main.js b/console/src/main.js index a44214d38e..882ef65191 100644 --- a/console/src/main.js +++ b/console/src/main.js @@ -16,6 +16,8 @@ var Tail = require('always-tail'); var http = require('http'); var path = require('path'); +var Config = require('./modules/config').Config; + var hfprocess = require('./modules/hf-process.js'); var Process = hfprocess.Process; var ACMonitorProcess = hfprocess.ACMonitorProcess; @@ -72,6 +74,10 @@ function shutdown() { var logPath = path.join(getApplicationDataDirectory(), '/logs'); console.log("Log directory:", logPath); +const configPath = path.join(getApplicationDataDirectory(), 'config.json'); +var userConfig = new Config(); +userConfig.load(configPath); + const TRAY_FILENAME = (osType == "Darwin" ? "console-tray-Template.png" : "console-tray.png"); const TRAY_ICON = path.join(__dirname, '../resources/' + TRAY_FILENAME); const APP_ICON = path.join(__dirname, '../resources/console.png'); @@ -145,6 +151,7 @@ var tray = null; global.homeServer = null; global.domainServer = null; global.acMonitor = null; +global.userConfig = userConfig; const GO_HOME_INDEX = 0; const SERVER_LABEL_INDEX = 2; @@ -290,6 +297,31 @@ function updateTrayMenu(serverState) { const httpStatusPort = 60332; +function maybeShowSplash() { + var suppressSplash = userConfig.get('doNotShowSplash', false); + console.log("Suppress?", suppressSplash) + + if (!suppressSplash) { + var window = new BrowserWindow({ + icon: APP_ICON, + width: 1600, + height: 587, + center: true, + frame: true, + useContentSize: true, + resizable: false + }); + window.loadURL('file://' + __dirname + '/splash.html'); + window.setMenu(null); + window.show(); + + window.webContents.on('new-window', function(e, url) { + e.preventDefault(); + require('shell').openExternal(url); + }); + } +} + // This method will be called when Electron has finished // initialization and is ready to create browser windows. app.on('ready', function() { @@ -304,6 +336,7 @@ app.on('ready', function() { tray.setToolTip('High Fidelity'); updateTrayMenu(ProcessGroupStates.STOPPED); + maybeShowSplash(); if (interfacePath && dsPath && acPath) { domainServer = new Process('domain-server', dsPath, [], logPath); @@ -316,6 +349,7 @@ app.on('ready', function() { // make sure we stop child processes on app quit app.on('quit', function(){ console.log('App quitting'); + userConfig.save(configPath); logWindow.close(); homeServer.stop(); }); From b7315790be35eff9640e169f078d400ae1bd1a27 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 11 Jan 2016 15:02:38 -0800 Subject: [PATCH 023/357] Replace custom app data resolution code with app.getPath --- console/src/main.js | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/console/src/main.js b/console/src/main.js index 882ef65191..c4142d44a8 100644 --- a/console/src/main.js +++ b/console/src/main.js @@ -26,15 +26,7 @@ var ProcessGroup = hfprocess.ProcessGroup; var ProcessGroupStates = hfprocess.ProcessGroupStates; function getApplicationDataDirectory() { - var osType = os.type(); - var rootDirectory; - if (osType == 'Windows_NT') { - rootDirectory = process.env.APPDATA; - } else if (osType == 'Darwin') { - rootDirecotry = process.env.HOME + 'Library/Application Support'; - } else { - rootDirectory = '/usr/local/share'; - } + var rootDirectory = app.getPath('appData'); return path.join(rootDirectory, '/High Fidelity/Console'); } From 88f6a4bed947cec68ddb3675bf69092c6900fa68 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 11 Jan 2016 15:03:00 -0800 Subject: [PATCH 024/357] Add period to end of welcome text --- console/src/splash.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/console/src/splash.html b/console/src/splash.html index 376af224f5..b74652b5a3 100644 --- a/console/src/splash.html +++ b/console/src/splash.html @@ -47,7 +47,7 @@

- For more information on managing your server, visit our documentation + For more information on managing your server, visit our documentation.

From f0142391ee0429954da353c97bdf875be7e15e84 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 11 Jan 2016 15:22:20 -0800 Subject: [PATCH 025/357] Remove extraneous log message and comments --- console/src/main.js | 1 - console/src/modules/config.js | 2 -- 2 files changed, 3 deletions(-) diff --git a/console/src/main.js b/console/src/main.js index c4142d44a8..c45f6e91c0 100644 --- a/console/src/main.js +++ b/console/src/main.js @@ -291,7 +291,6 @@ const httpStatusPort = 60332; function maybeShowSplash() { var suppressSplash = userConfig.get('doNotShowSplash', false); - console.log("Suppress?", suppressSplash) if (!suppressSplash) { var window = new BrowserWindow({ diff --git a/console/src/modules/config.js b/console/src/modules/config.js index 663a34e66b..df44dcfafe 100644 --- a/console/src/modules/config.js +++ b/console/src/modules/config.js @@ -6,7 +6,6 @@ function Config() { } Config.prototype = { load: function(filePath) { - // open file var rawData = null; try { rawData = fs.readFileSync(filePath); @@ -15,7 +14,6 @@ Config.prototype = { } var configData = {}; - // read file and json parse try { if (rawData) { configData = JSON.parse(rawData); From 5b723fd08abe521c0ac2dbb38508902ef567e723 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 11 Jan 2016 16:12:48 -0800 Subject: [PATCH 026/357] Add tail to package.json --- console/package.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/console/package.json b/console/package.json index eee91de831..86e04be6f3 100644 --- a/console/package.json +++ b/console/package.json @@ -26,6 +26,8 @@ }, "dependencies": { "extend": "^3.0.0", - "yargs": "^3.30.0" + "yargs": "^3.30.0", + "request": "2.67.0", + "tail": "0.4.0" } } From a6dc3f9b411a58f46a616e2e6cc8acc8f256532d Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 11 Jan 2016 16:12:58 -0800 Subject: [PATCH 027/357] Adjust start position for log window --- console/src/log.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/console/src/log.js b/console/src/log.js index c42b616756..0c2c9ec7bf 100644 --- a/console/src/log.js +++ b/console/src/log.js @@ -95,7 +95,7 @@ ready = function() { var stats = fs.statSync(cleanFilePath); var size = stats.size; - var start = Math.max(0, size - (2500 * 50)); + var start = Math.max(0, size - (25000)); console.log(cleanFilePath, size, start, maxLogLines); var logTail = new Tail(cleanFilePath, '\n', { start: start, interval: 500 }); From c1e114c576337287a4ebff928d7e8a8bcb656ad6 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 13 Jan 2016 16:06:44 -0800 Subject: [PATCH 028/357] Add start of default content installation --- console/src/downloader.css | 19 +++++++++ console/src/downloader.html | 25 ++++++++++++ console/src/downloader.js | 37 +++++++++++++++++ console/src/main.js | 81 +++++++++++++++++++++++++++++++++++++ 4 files changed, 162 insertions(+) create mode 100644 console/src/downloader.css create mode 100644 console/src/downloader.html create mode 100644 console/src/downloader.js diff --git a/console/src/downloader.css b/console/src/downloader.css new file mode 100644 index 0000000000..f0316f349f --- /dev/null +++ b/console/src/downloader.css @@ -0,0 +1,19 @@ +@font-face { + font-family: 'Proxima Nova'; + src: url('vendor/ProximaNova/ProximaNova-Regular.otf'); +} + +* { + font-family: "Proxima Nova", "Open Sans", Arial, Helvetica, sans-serif; + font-size: 1.022em; + line-height: 130%; +} + +body { + margin: 0; + padding: 0; +} + +progress { + margin: 0 auto; +} \ No newline at end of file diff --git a/console/src/downloader.html b/console/src/downloader.html new file mode 100644 index 0000000000..5db3b64385 --- /dev/null +++ b/console/src/downloader.html @@ -0,0 +1,25 @@ + + + + High Fidelity + + + + +
+ +
+
+ Installing! +
+
+ Error :( +
+ +
+
+ Complete + +
+ + diff --git a/console/src/downloader.js b/console/src/downloader.js new file mode 100644 index 0000000000..14f8482415 --- /dev/null +++ b/console/src/downloader.js @@ -0,0 +1,37 @@ +function ready() { + console.log("Ready"); + + const electron = require('electron'); + window.$ = require('./vendor/jquery/jquery-2.1.4.min.js'); + + $(".state").hide(); + + var currentState = null; + + function updateState(state, args) { + console.log(state, args); + + if (state == 'downloading') { + console.log("Updating progress bar"); + $('#download-progress').attr('value', args.progress * 100); + } else if (state == 'installing') { + } else if (state == 'complete') { + } else if (state == 'error') { + $('#error-message').innerHTML = args.message; + } + + if (currentState != state) { + if (currentState) { + $('#state-' + currentState).hide(); + } + $('#state-' + state).show(); + currentState = state; + } + } + + electron.ipcRenderer.on('update', function(event, message) { + updateState(message.state, message.args); + }); + + updateState('downloading', { progress: 0 }); +} diff --git a/console/src/main.js b/console/src/main.js index c45f6e91c0..bf054e4e2e 100644 --- a/console/src/main.js +++ b/console/src/main.js @@ -15,6 +15,10 @@ var fs = require('fs'); var Tail = require('always-tail'); var http = require('http'); var path = require('path'); +var unzip = require('unzip'); + +var request = require('request'); +var progress = require('request-progress'); var Config = require('./modules/config').Config; @@ -289,6 +293,77 @@ function updateTrayMenu(serverState) { const httpStatusPort = 60332; +function maybeInstallDefaultContentSet() { + var hasRun = userConfig.get('hasRun', false); + + if (false && hasRun) { + return; + } + + // Show popup + var window = new BrowserWindow({ + icon: APP_ICON, + width: 400, + height: 160, + center: true, + frame: true, + useContentSize: true, + resizable: false + }); + window.loadURL('file://' + __dirname + '/downloader.html'); + // window.setMenu(null); + window.show(); + + function sendStateUpdate(state, args) { + console.log(state, args); + window.webContents.send('update', { state: state, args: args }); + } + + var unzipper = unzip.Extract({ path: 'download2', verbose: true }); + unzipper.on('close', function() { + console.log("Done", arguments); + sendStateUpdate('complete'); + }) + unzipper.on('error', function (err) { + console.log("ERROR"); + sendStateUpdate('error', { + message: "Error installing resources." + }); + }); + // responseMessage.pipe(unzipper); + // responseData.pipe(process.stdout); + // console.log("UNZIPPING"); + + // Start downloading content set + progress(request.get({ + url: "http://localhost:8000/contentSet.zip", + // url: "http://builds.highfidelity.com/interface-win64-3908.xe" + }, function(error, responseMessage, responseData) { + if (error || responseMessage.statusCode != 200) { + var message = ''; + if (error) { + message = "Error contacting resource server."; + } else { + message = "Error downloading resources from server."; + } + sendStateUpdate('error', { + message: message + }); + } else { + sendStateUpdate('installing'); + } + }), { throttle: 250 }).on('progress', function(state) { + // Update progress popup + console.log("progress", state); + sendStateUpdate('downloading', { progress: state.percentage }); + }).pipe(unzipper); + + + + + userConfig.set('hasRun', true); +} + function maybeShowSplash() { var suppressSplash = userConfig.get('doNotShowSplash', false); @@ -313,6 +388,10 @@ function maybeShowSplash() { } } +function detectExistingStackManagerResources() { + return false; +} + // This method will be called when Electron has finished // initialization and is ready to create browser windows. app.on('ready', function() { @@ -327,6 +406,8 @@ app.on('ready', function() { tray.setToolTip('High Fidelity'); updateTrayMenu(ProcessGroupStates.STOPPED); + + maybeInstallDefaultContentSet(); maybeShowSplash(); if (interfacePath && dsPath && acPath) { From fe4c161cb6db9a8b413ed692d905bbf35bc8103e Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 14 Jan 2016 12:44:52 -0800 Subject: [PATCH 029/357] Fix sending URL to second interface instance --- interface/src/main.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/interface/src/main.cpp b/interface/src/main.cpp index 43835524ce..90ac6223fc 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -78,8 +78,11 @@ int main(int argc, const char* argv[]) { if (parser.isSet(urlOption)) { QUrl url = QUrl(parser.value(urlOption)); if (url.isValid() && url.scheme() == HIFI_URL_SCHEME) { + qDebug() << "Writing URL to local socket"; socket.write(url.toString().toUtf8()); - socket.waitForBytesWritten(5000); + if (!socket.waitForBytesWritten(5000)) { + qDebug() << "Error writing URL to local socket"; + } } } @@ -95,12 +98,6 @@ int main(int argc, const char* argv[]) { #endif } - // Setup local server - QLocalServer server; - - // We failed to connect to a local server, so we remove any existing servers. - server.removeServer(applicationName); - server.listen(applicationName); QElapsedTimer startupTime; startupTime.start(); @@ -125,6 +122,13 @@ int main(int argc, const char* argv[]) { QSettings::setDefaultFormat(QSettings::IniFormat); Application app(argc, const_cast(argv), startupTime); + // Setup local server + QLocalServer server { &app }; + + // We failed to connect to a local server, so we remove any existing servers. + server.removeServer(applicationName); + server.listen(applicationName); + QObject::connect(&server, &QLocalServer::newConnection, &app, &Application::handleLocalServerConnection); QTranslator translator; From 12fc446d2c4a158acbe043bdcafc2823f4c0b4c8 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 14 Jan 2016 12:48:12 -0800 Subject: [PATCH 030/357] Add splash screen images --- console/src/images/console-hf-logo-2x.png | Bin 0 -> 12108 bytes console/src/images/console-menubar-osx.png | Bin 0 -> 136860 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 console/src/images/console-hf-logo-2x.png create mode 100644 console/src/images/console-menubar-osx.png diff --git a/console/src/images/console-hf-logo-2x.png b/console/src/images/console-hf-logo-2x.png new file mode 100644 index 0000000000000000000000000000000000000000..4c0afd67779133af27925d7c0db7cf98306606b0 GIT binary patch literal 12108 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 (JwiPr~E!2J1ad~KLts@Z%C*S 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⋘M!Q&oBE?UITL>F3y^S@Jo(feDQt! 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 Date: Thu, 14 Jan 2016 12:55:32 -0800 Subject: [PATCH 031/357] Add ServerPathUtils --- libraries/shared/src/ServerPathUtils.cpp | 16 ++++++++++++++++ libraries/shared/src/ServerPathUtils.h | 22 ++++++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 libraries/shared/src/ServerPathUtils.cpp create mode 100644 libraries/shared/src/ServerPathUtils.h diff --git a/libraries/shared/src/ServerPathUtils.cpp b/libraries/shared/src/ServerPathUtils.cpp new file mode 100644 index 0000000000..d253265103 --- /dev/null +++ b/libraries/shared/src/ServerPathUtils.cpp @@ -0,0 +1,16 @@ +#include "ServerPathUtils.h" + +#include +#include + +QString ServerPathUtils::getDataDirectory() { + auto directory = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); + if (directory.isEmpty()) { + directory = '.'; + } + return directory; +} + +QString ServerPathUtils::getDataFilePath(QString filename) { + return QDir(getDataDirectory()).absoluteFilePath(filename); +} diff --git a/libraries/shared/src/ServerPathUtils.h b/libraries/shared/src/ServerPathUtils.h new file mode 100644 index 0000000000..28a9a71f0d --- /dev/null +++ b/libraries/shared/src/ServerPathUtils.h @@ -0,0 +1,22 @@ +// +// ServerPathUtils.h +// libraries/shared/src +// +// Created by Ryan Huffman on 01/12/16. +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_ServerPathUtils_h +#define hifi_ServerPathUtils_h + +#include + +namespace ServerPathUtils { + QString getDataDirectory(); + QString getDataFilePath(QString filename); +} + +#endif // hifi_ServerPathUtils_h \ No newline at end of file From fc42254be117045ee3092aa87fb3dc9c32790b0c Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 14 Jan 2016 12:57:29 -0800 Subject: [PATCH 032/357] Add migration of old Asset server data --- assignment-client/src/assets/AssetServer.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 2f9e7ee1e6..e7a39deab4 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -24,6 +24,7 @@ #include "NodeType.h" #include "SendAssetTask.h" #include "UploadAssetTask.h" +#include const QString ASSET_SERVER_LOGGING_TARGET_NAME = "asset-server"; @@ -49,8 +50,19 @@ void AssetServer::run() { auto nodeList = DependencyManager::get(); nodeList->addNodeTypeToInterestSet(NodeType::Agent); - _resourcesDirectory = QDir(QCoreApplication::applicationDirPath()).filePath("resources/assets"); + const QString RESOURCES_PATH = "resources/assets"; + + _resourcesDirectory = QDir(ServerPathUtils::getDataDirectory()).filePath(RESOURCES_PATH); if (!_resourcesDirectory.exists()) { + qDebug() << "Asset resources directory not found, searching for existing asset resources"; + QString oldDataDirectory = QCoreApplication::applicationDirPath(); + auto oldResourcesDirectory = QDir(oldDataDirectory).filePath(RESOURCES_PATH); + + if (QDir(oldResourcesDirectory).exists()) { + qDebug() << "Existing assets found in " << oldResourcesDirectory << ", copying to " << _resourcesDirectory; + QFile::copy(oldResourcesDirectory, _resourcesDirectory.absolutePath()); + } + qDebug() << "Creating resources directory"; _resourcesDirectory.mkpath("."); } From a9afa53fb77f4cf1b76cec460c716aa6f7b4aca2 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 14 Jan 2016 12:57:48 -0800 Subject: [PATCH 033/357] Add migration of old octree server data --- assignment-client/src/octree/OctreeServer.cpp | 31 +++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 22bbed2a25..387161b464 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -27,6 +27,9 @@ #include "OctreeQueryNode.h" #include "OctreeServerConsts.h" +#include +#include +#include int OctreeServer::_clientCount = 0; const int MOVING_AVERAGE_SAMPLE_COUNTS = 1000000; @@ -280,7 +283,7 @@ OctreeServer::~OctreeServer() { void OctreeServer::initHTTPManager(int port) { // setup the embedded web server - QString documentRoot = QString("%1/resources/web").arg(QCoreApplication::applicationDirPath()); + QString documentRoot = QString("%1/resources/web").arg(ServerPathUtils::getDataDirectory()); // setup an httpManager with us as the request handler and the parent _httpManager = new HTTPManager(QHostAddress::AnyIPv4, port, documentRoot, this, this); @@ -1031,6 +1034,7 @@ void OctreeServer::readConfiguration() { if (!readOptionString(QString("persistFilename"), settingsSectionObject, persistFilename)) { persistFilename = getMyDefaultPersistFilename(); } + strcpy(_persistFilename, qPrintable(persistFilename)); qDebug("persistFilename=%s", _persistFilename); @@ -1096,7 +1100,7 @@ void OctreeServer::run() { _tree->setIsServer(true); qDebug() << "Waiting for connection to domain to request settings from domain-server."; - + // wait until we have the domain-server settings, otherwise we bail DomainHandler& domainHandler = DependencyManager::get()->getDomainHandler(); connect(&domainHandler, &DomainHandler::settingsReceived, this, &OctreeServer::domainSettingsRequestComplete); @@ -1139,9 +1143,30 @@ void OctreeServer::domainSettingsRequestComplete() { // if we want Persistence, set up the local file and persist thread if (_wantPersist) { + // If persist filename does not exist, let's see if there is one beside the application binary + // If there is, let's copy it over to our target persist directory + QString oldResourcesDirectory = QCoreApplication::applicationDirPath(); + auto oldPersistPath = QDir(oldResourcesDirectory).absoluteFilePath(_persistFilename); + auto persistPath = ServerPathUtils::getDataFilePath(_persistFilename); + if (oldPersistPath != persistPath && !QFile::exists(persistPath)) { + qDebug() << "Persist file does not exist, checking for existence of persist file next to application"; + if (QFile::exists(oldPersistPath)) { + qDebug() << "Old persist file found, copying from " << oldPersistPath << " to " << persistPath; + + QDir persistFileDirectory = QDir(persistPath).filePath(".."); + + if (!persistFileDirectory.exists()) { + qDebug() << "Creating data directory " << persistFileDirectory.path(); + persistFileDirectory.mkpath("."); + } + QFile::copy(oldPersistPath, persistPath); + } else { + qDebug() << "No existing persist file found"; + } + } // now set up PersistThread - _persistThread = new OctreePersistThread(_tree, _persistFilename, _persistInterval, + _persistThread = new OctreePersistThread(_tree, persistPath, _persistInterval, _wantBackup, _settings, _debugTimestampNow, _persistAsFileType); _persistThread->initialize(true); } From 5ee5ee4caba076187c56d1fbb19f07c61a39c535 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 14 Jan 2016 13:00:12 -0800 Subject: [PATCH 034/357] Update package.json dependencies --- console/package.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/console/package.json b/console/package.json index 86e04be6f3..71a2443984 100644 --- a/console/package.json +++ b/console/package.json @@ -28,6 +28,8 @@ "extend": "^3.0.0", "yargs": "^3.30.0", "request": "2.67.0", - "tail": "0.4.0" + "request-progress": "1.0.2", + "always-tail": "0.2.0", + "unzip": "0.1.11" } } From e021039539a258f36d0596bfe4fdfc8a62aba129 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 14 Jan 2016 13:00:54 -0800 Subject: [PATCH 035/357] Add migration of Stack Manager data --- console/src/main.js | 41 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/console/src/main.js b/console/src/main.js index bf054e4e2e..0cb5a2d891 100644 --- a/console/src/main.js +++ b/console/src/main.js @@ -29,11 +29,26 @@ var ProcessStates = hfprocess.ProcessStates; var ProcessGroup = hfprocess.ProcessGroup; var ProcessGroupStates = hfprocess.ProcessGroupStates; -function getApplicationDataDirectory() { + +function getRootHifiDataDirectory() { var rootDirectory = app.getPath('appData'); - return path.join(rootDirectory, '/High Fidelity/Console'); + return path.join(rootDirectory, '/High Fidelity'); } +function getStackManagerDataDirectory() { + return path.join(getRootHifiDataDirectory(), "../../Local/High Fidelity"); +} + +function getAssignmentClientResourcesDirectory() { + return path.join(getRootHifiDataDirectory(), '/assignment-client/resources'); +} + +function getApplicationDataDirectory() { + return path.join(getRootHifiDataDirectory(), '/Console'); +} + + +console.log("Root directory is: ", getRootHifiDataDirectory()); const ipcMain = electron.ipcMain; @@ -300,6 +315,19 @@ function maybeInstallDefaultContentSet() { return; } + // Check for existing Stack Manager data + const stackManagerDataPath = getStackManagerDataDirectory(); + console.log("Checking for existence of " + stackManagerDataPath); + var userHasExistingServerData = true; + try { + fs.accessSync(stackManagerDataPath); + } catch (e) { + console.log(e); + userHasExistingServerData = false; + } + + console.log("Existing data?", userHasExistingServerData); + // Show popup var window = new BrowserWindow({ icon: APP_ICON, @@ -319,7 +347,10 @@ function maybeInstallDefaultContentSet() { window.webContents.send('update', { state: state, args: args }); } - var unzipper = unzip.Extract({ path: 'download2', verbose: true }); + var unzipper = unzip.Extract({ + path: getAssignmentClientResourcesDirectory(), + verbose: true + }); unzipper.on('close', function() { console.log("Done", arguments); sendStateUpdate('complete'); @@ -336,8 +367,8 @@ function maybeInstallDefaultContentSet() { // Start downloading content set progress(request.get({ - url: "http://localhost:8000/contentSet.zip", - // url: "http://builds.highfidelity.com/interface-win64-3908.xe" + // url: "http://localhost:8000/contentSet.zip", + url: "http://builds.highfidelity.com/interface-win64-3914.exe" }, function(error, responseMessage, responseData) { if (error || responseMessage.statusCode != 200) { var message = ''; From 820d00a719222292a07f20a0ec38a693e262c9c2 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 14 Jan 2016 13:01:24 -0800 Subject: [PATCH 036/357] Cleanup css and splash.html --- console/src/splash.css | 73 ++++++++++++++++++++++++++++------------- console/src/splash.html | 6 ++-- 2 files changed, 54 insertions(+), 25 deletions(-) diff --git a/console/src/splash.css b/console/src/splash.css index 1bebf3672f..d3d9aac91e 100644 --- a/console/src/splash.css +++ b/console/src/splash.css @@ -1,6 +1,6 @@ @font-face { - font-family: 'Proxima Nova'; - src: url('vendor/ProximaNova/ProximaNova-Regular.otf'); + font-family: 'Proxima Nova'; + src: url('vendor/ProximaNova/ProximaNova-Regular.otf'); } body { @@ -10,43 +10,50 @@ body { padding: 0; color: #414141; } + * { - font-family: "Proxima Nova", "Open Sans", Arial, Helvetica, sans-serif; - font-size: 1.022em; - line-height: 130%; + font-family: "Proxima Nova", "Open Sans", Arial, Helvetica, sans-serif; + font-size: 1.022em; + line-height: 130%; } - -a:link, a:visited, a:hover, a:active { - color: #2D88A4; - } +a:link, +a:visited, +a:hover, +a:active { + color: #2D88A4; +} a:hover { color: #00B4EF; } -h1, h2 { +h1, +h2 { color: black; margin: 0; padding: 0; } + h1 { font-size: 2.0em; } + h2 { font-size: 1.0em; font-weight: bold; } -p { -} +p {} .header-title { padding-top: 80px; } + .content { margin: 0 110px; } + .column { display: inline-block; float: left; @@ -57,39 +64,41 @@ p { width: 415px; padding-right: 120px; } + .column.center { padding-top: 20px; width: 540px; } + .column.right { float: right; padding-top: 40px; padding-left: 60px; - position: absolute; right: -30px; } -.column.right img { -} + +.column.right img {} .top { height: 156px; border-bottom: 2px solid #F5F6F6; } + .middle { - width: 1364px; /* 1584 - (110 * 2) */ + width: 1364px; + /* 1584 - (110 * 2) */ position: absolute; top: 156px; bottom: 98px; } -.bottom{ + +.bottom { width: 100%; position: absolute; height: 98px; background-color: #F5F6F6; - bottom: 0; - /* padding-top: 34px; */ } @@ -97,9 +106,7 @@ p { padding-top: 34px; } - -.header-title { -} +.header-title {} .header-right { /* float: right; */ @@ -114,14 +121,36 @@ input[type="checkbox"] { /* width:19px; */ /* height:19px; */ } + + /* input[type=checkbox] label:before { */ + + /* border-radius: 3px; */ + + /* } */ + + /* input[type=checkbox]:checked { */ + + /* content: "\2713"; */ + + /* text-shadow: 1px 1px 1px rgba(0, 0, 0, .2); */ + + /* font-size: 15px; */ + + /* color: #f3f3f3; */ + + /* text-align: center; */ + + /* line-height: 15px; */ + + /* } */ \ No newline at end of file diff --git a/console/src/splash.html b/console/src/splash.html index b74652b5a3..df60990d64 100644 --- a/console/src/splash.html +++ b/console/src/splash.html @@ -11,7 +11,7 @@

Install complete

- +
@@ -55,9 +55,9 @@ var osType = require('os').type(); menuBarImageURL = ''; if (osType = 'Windows_NT') { - menuBarImageURL = "images/menubar-osx.png"; + menuBarImageURL = "images/console-menubar-osx.png"; } else { - menuBarImageURL = "images/menubar-osx.png"; + menuBarImageURL = "images/console-menubar-osx.png"; } document.write(''); From 253719882d9b8324784be86948d8bb439702f44c Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 15 Jan 2016 08:50:51 -0800 Subject: [PATCH 037/357] Update wlecome screen copy and styling --- console/src/splash.css | 67 +++++++++++------------------------------ console/src/splash.html | 22 +++++--------- 2 files changed, 25 insertions(+), 64 deletions(-) diff --git a/console/src/splash.css b/console/src/splash.css index d3d9aac91e..d4b0eb214a 100644 --- a/console/src/splash.css +++ b/console/src/splash.css @@ -9,6 +9,8 @@ body { margin: 0; padding: 0; color: #414141; + -webkit-touch-callout: none; + -webkit-user-select: none; } * { @@ -21,27 +23,29 @@ a:link, a:visited, a:hover, a:active { + font-weight: bold; color: #2D88A4; } a:hover { + font-weight: bold; color: #00B4EF; } -h1, -h2 { - color: black; +h1 { + font-weight: normal; + color: #6D7472; + font-size: 2.0em; margin: 0; padding: 0; } -h1 { - font-size: 2.0em; -} - h2 { + color: #6D7472; font-size: 1.0em; font-weight: bold; + margin: 0; + padding: 0; } p {} @@ -57,22 +61,21 @@ p {} .column { display: inline-block; float: left; + padding-top: 26px; } .column.left { - padding-top: 20px; width: 415px; padding-right: 120px; } .column.center { - padding-top: 20px; width: 540px; } .column.right { float: right; - padding-top: 40px; + padding-top: 67px; padding-left: 60px; position: absolute; right: -30px; @@ -81,7 +84,7 @@ p {} .column.right img {} .top { - height: 156px; + height: 168px; border-bottom: 2px solid #F5F6F6; } @@ -89,7 +92,7 @@ p {} width: 1364px; /* 1584 - (110 * 2) */ position: absolute; - top: 156px; + top: 168px; bottom: 98px; } @@ -111,46 +114,10 @@ p {} .header-right { /* float: right; */ position: absolute; - top: 70px; + top: 63px; right: 114px; } input[type="checkbox"] { display: inline-block; - /* display:none; */ - /* width:19px; */ - /* height:19px; */ -} - - -/* input[type=checkbox] label:before { */ - - -/* border-radius: 3px; */ - - -/* } */ - - -/* input[type=checkbox]:checked { */ - - -/* content: "\2713"; */ - - -/* text-shadow: 1px 1px 1px rgba(0, 0, 0, .2); */ - - -/* font-size: 15px; */ - - -/* color: #f3f3f3; */ - - -/* text-align: center; */ - - -/* line-height: 15px; */ - - -/* } */ \ No newline at end of file +} \ No newline at end of file diff --git a/console/src/splash.html b/console/src/splash.html index df60990d64..6dd00a1208 100644 --- a/console/src/splash.html +++ b/console/src/splash.html @@ -18,16 +18,11 @@

What now?

- Console is your personal domain server in High Fidelity. - It allows your local machine to manage 4000 cubic kilometers of space, - ready for you to build, explore, and share however you like. To start - you off, we've put a few things in your space to play around with and - to learn the ropes. + The Server Console is your personal domain server in High Fidelity. It allows your local machine to manage 4000 cubic kilometers of space, ready for you to build, explore, and share however you like. To start you off, we've put a few things in your space to play around with and to learn the ropes.

- To learn more about uploading your own models and scripts, and how to add - items from the Market, check out 'The Basics'. + To find out more about uploading your own models and scripts, and how to add items from the Market, check out 'The Basics'.

@@ -47,7 +42,7 @@

- For more information on managing your server, visit our documentation. + For more information on managing your server, visit our documentation.

@@ -55,9 +50,9 @@ var osType = require('os').type(); menuBarImageURL = ''; if (osType = 'Windows_NT') { - menuBarImageURL = "images/console-menubar-osx.png"; + menuBarImageURL = "images/console-menubar-osx.png"; } else { - menuBarImageURL = "images/console-menubar-osx.png"; + menuBarImageURL = "images/console-menubar-osx.png"; } document.write(''); @@ -65,12 +60,11 @@
+
From 57f2722c6b5a57c4df8b6453c963061402dac995 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 15 Jan 2016 08:51:21 -0800 Subject: [PATCH 038/357] Update downloader style and add auto-close --- console/src/downloader.css | 96 ++++++++++++++++++++++++++++++++++++- console/src/downloader.html | 28 +++++++---- console/src/downloader.js | 12 +++-- 3 files changed, 123 insertions(+), 13 deletions(-) diff --git a/console/src/downloader.css b/console/src/downloader.css index f0316f349f..22b217d0a5 100644 --- a/console/src/downloader.css +++ b/console/src/downloader.css @@ -5,15 +5,107 @@ * { font-family: "Proxima Nova", "Open Sans", Arial, Helvetica, sans-serif; - font-size: 1.022em; line-height: 130%; } body { margin: 0; padding: 0; + color: #808785; + margin: 0 auto; + text-align: center; + font-size: 14pt; + -webkit-touch-callout: none; + -webkit-user-select: none; +} + +#error-message { + background-color: #F7F8F8; + color: #EB4C5F; + padding: 20px; + margin: 20px 120px 0 120px; + -webkit-touch-callout: text; + -webkit-user-select: text; } progress { - margin: 0 auto; + height: 1px; + width: 300px; + -webkit-appearance: none; +} + +progress[value]::-webkit-progress-bar { + background-color: #DADADA; + /* border-radius: 2px; */ +} + +progress[value]::-webkit-progress-value { + background-color: #21B7D4; + /* border-radius: 2px; */ +} + +.state { + padding-top: 100px; +} + +h1 { + font-size: 29pt; + font-weight: normal; +} + +#cancel-area { + margin-top: 100px; +} + +a:link, +a:visited, +a:hover, +a:active { + color: #B4B4B4; +} + +a:hover { + color: #2D88A4; +} + +.one { + opacity: 0; + animation: dot 2.3s infinite; + animation-delay: 0.0s; +} + +.two { + opacity: 0; + animation: dot 2.3s infinite; + animation-delay: 0.2s; +} + +.three { + opacity: 0; + animation: dot 2.3s infinite; + animation-delay: 0.3s; +} + +@-webkit-keyframes dot { + 0% { + opacity: 0; + } + 50% { + opacity: 1; + } + 100% { + opacity: 0; + } +} + +@keyframes dot { + 0% { + opacity: 0; + } + 50% { + opacity: 1; + } + 100% { + opacity: 0; + } } \ No newline at end of file diff --git a/console/src/downloader.html b/console/src/downloader.html index 5db3b64385..1b5602455c 100644 --- a/console/src/downloader.html +++ b/console/src/downloader.html @@ -7,19 +7,31 @@
+ +

Downloading...

+
+ Cancel +
+
- Installing! -
-
- Error :( -
- + +

Installing...

+ Just a moment +
+
- Complete - +

Success!

+ You're all set.
+ +
+ +

Houston...

+ An unfortunate error has occurred: +
+
diff --git a/console/src/downloader.js b/console/src/downloader.js index 14f8482415..d40da51c73 100644 --- a/console/src/downloader.js +++ b/console/src/downloader.js @@ -2,6 +2,7 @@ function ready() { console.log("Ready"); const electron = require('electron'); + const remote = require('remote'); window.$ = require('./vendor/jquery/jquery-2.1.4.min.js'); $(".state").hide(); @@ -10,14 +11,15 @@ function ready() { function updateState(state, args) { console.log(state, args); - if (state == 'downloading') { - console.log("Updating progress bar"); $('#download-progress').attr('value', args.progress * 100); } else if (state == 'installing') { } else if (state == 'complete') { + setTimeout(function() { + remote.getCurrentWindow().close(); + }, 2000); } else if (state == 'error') { - $('#error-message').innerHTML = args.message; + $('#error-message').html(args.message); } if (currentState != state) { @@ -33,5 +35,9 @@ function ready() { updateState(message.state, message.args); }); + // updateState('error', { message: "This is an error message", progress: 0.5 }); + // updateState('complete', { progress: 0 }); + updateState('downloading', { progress: 0 }); + electron.ipcRenderer.send('ready'); } From 3a78fbaca56ac6fbbd554d01e91ef2a77ca4de8c Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 15 Jan 2016 08:52:30 -0800 Subject: [PATCH 039/357] Update download contentSet process --- console/src/main.js | 168 ++++++++++++++++++++++++-------------------- 1 file changed, 91 insertions(+), 77 deletions(-) diff --git a/console/src/main.js b/console/src/main.js index 0cb5a2d891..c793716e94 100644 --- a/console/src/main.js +++ b/console/src/main.js @@ -65,8 +65,12 @@ function shutdown() { }); if (idx == 0) { isShuttingDown = true; - logWindow.close(); - homeServer.stop(); + if (logWindow) { + logWindow.close(); + } + if (homeServer) { + homeServer.stop(); + } var timeoutID = setTimeout(app.quit, 5000); homeServer.on('state-update', function(processGroup) { @@ -308,7 +312,7 @@ function updateTrayMenu(serverState) { const httpStatusPort = 60332; -function maybeInstallDefaultContentSet() { +function maybeInstallDefaultContentSet(onComplete) { var hasRun = userConfig.get('hasRun', false); if (false && hasRun) { @@ -331,68 +335,77 @@ function maybeInstallDefaultContentSet() { // Show popup var window = new BrowserWindow({ icon: APP_ICON, - width: 400, - height: 160, + width: 640, + height: 480, center: true, frame: true, useContentSize: true, resizable: false }); window.loadURL('file://' + __dirname + '/downloader.html'); - // window.setMenu(null); + window.setMenu(null); window.show(); - function sendStateUpdate(state, args) { - console.log(state, args); - window.webContents.send('update', { state: state, args: args }); - } + window.on('closed', onComplete); - var unzipper = unzip.Extract({ - path: getAssignmentClientResourcesDirectory(), - verbose: true - }); - unzipper.on('close', function() { - console.log("Done", arguments); - sendStateUpdate('complete'); - }) - unzipper.on('error', function (err) { - console.log("ERROR"); - sendStateUpdate('error', { - message: "Error installing resources." - }); - }); - // responseMessage.pipe(unzipper); - // responseData.pipe(process.stdout); - // console.log("UNZIPPING"); - - // Start downloading content set - progress(request.get({ - // url: "http://localhost:8000/contentSet.zip", - url: "http://builds.highfidelity.com/interface-win64-3914.exe" - }, function(error, responseMessage, responseData) { - if (error || responseMessage.statusCode != 200) { - var message = ''; - if (error) { - message = "Error contacting resource server."; - } else { - message = "Error downloading resources from server."; - } - sendStateUpdate('error', { - message: message - }); - } else { - sendStateUpdate('installing'); + electron.ipcMain.on('ready', function() { + console.log("got ready"); + function sendStateUpdate(state, args) { + console.log(state, window, args); + window.webContents.send('update', { state: state, args: args }); } - }), { throttle: 250 }).on('progress', function(state) { - // Update progress popup - console.log("progress", state); - sendStateUpdate('downloading', { progress: state.percentage }); - }).pipe(unzipper); + + var aborted = false; + + // Start downloading content set + var req = progress(request.get({ + // url: "http://localhost:8000/contentSet.zip", + url: "http://builds.highfidelity.com/interface-win64-3914.exe" + }, function(error, responseMessage, responseData) { + if (aborted) { + return; + } else if (error || responseMessage.statusCode != 200) { + var message = ''; + if (error) { + message = "Error contacting resource server."; + } else { + message = "Error downloading resources from server."; + } + sendStateUpdate('error', { + message: message + }); + } else { + sendStateUpdate('installing'); + } + }), { throttle: 250 }).on('progress', function(state) { + if (!aborted) { + // Update progress popup + console.log("progress", state); + sendStateUpdate('downloading', { progress: state.percentage }); + } + }); + var unzipper = unzip.Extract({ + path: getAssignmentClientResourcesDirectory(), + verbose: true + }); + unzipper.on('close', function() { + console.log("Done", arguments); + sendStateUpdate('complete'); + }); + unzipper.on('error', function (err) { + console.log("aborting"); + aborted = true; + req.abort(); + console.log("ERROR"); + sendStateUpdate('error', { + message: "Error installing resources." + }); + }); + req.pipe(unzipper); - - - userConfig.set('hasRun', true); + userConfig.set('hasRun', true); + }); } function maybeShowSplash() { @@ -438,33 +451,34 @@ app.on('ready', function() { updateTrayMenu(ProcessGroupStates.STOPPED); - maybeInstallDefaultContentSet(); - maybeShowSplash(); + maybeInstallDefaultContentSet(function() { + maybeShowSplash(); - if (interfacePath && dsPath && acPath) { - domainServer = new Process('domain-server', dsPath, [], logPath); - acMonitor = new ACMonitorProcess('ac-monitor', acPath, ['-n4', - '--log-directory', logPath, - '--http-status-port', httpStatusPort], httpStatusPort, logPath); - homeServer = new ProcessGroup('home', [domainServer, acMonitor]); - logWindow = new LogWindow(acMonitor, domainServer); + if (interfacePath && dsPath && acPath) { + domainServer = new Process('domain-server', dsPath, [], logPath); + acMonitor = new ACMonitorProcess('ac-monitor', acPath, ['-n4', + '--log-directory', logPath, + '--http-status-port', httpStatusPort], httpStatusPort, logPath); + homeServer = new ProcessGroup('home', [domainServer, acMonitor]); + logWindow = new LogWindow(acMonitor, domainServer); - // make sure we stop child processes on app quit - app.on('quit', function(){ - console.log('App quitting'); - userConfig.save(configPath); - logWindow.close(); - homeServer.stop(); - }); + // make sure we stop child processes on app quit + app.on('quit', function(){ + console.log('App quitting'); + userConfig.save(configPath); + logWindow.close(); + homeServer.stop(); + }); - var processes = { - home: homeServer - }; + var processes = { + home: homeServer + }; - // handle process updates - homeServer.on('state-update', function(processGroup) { updateTrayMenu(processGroup.state); }); + // handle process updates + homeServer.on('state-update', function(processGroup) { updateTrayMenu(processGroup.state); }); - // start the home server - homeServer.start(); - } + // start the home server + homeServer.start(); + } + }); }); From 05d4394ada0fea77d49056c2ae7c38d7e584bed2 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 15 Jan 2016 10:07:38 -0800 Subject: [PATCH 040/357] Update content set URL --- console/src/main.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/console/src/main.js b/console/src/main.js index c793716e94..d605119ef2 100644 --- a/console/src/main.js +++ b/console/src/main.js @@ -359,8 +359,7 @@ function maybeInstallDefaultContentSet(onComplete) { // Start downloading content set var req = progress(request.get({ - // url: "http://localhost:8000/contentSet.zip", - url: "http://builds.highfidelity.com/interface-win64-3914.exe" + url: "https://s3.amazonaws.com/hifi-public/homeset/updated.zip" }, function(error, responseMessage, responseData) { if (aborted) { return; From a7429d6331545a82cc3eb9bc2048c0af566bd360 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 15 Jan 2016 10:07:49 -0800 Subject: [PATCH 041/357] Remove periods in splash screen --- console/src/splash.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/console/src/splash.html b/console/src/splash.html index 6dd00a1208..e50be32473 100644 --- a/console/src/splash.html +++ b/console/src/splash.html @@ -22,7 +22,7 @@

- To find out more about uploading your own models and scripts, and how to add items from the Market, check out 'The Basics'. + To find out more about uploading your own models and scripts, and how to add items from the Market, check out 'The Basics'

@@ -42,7 +42,7 @@

- For more information on managing your server, visit our documentation. + For more information on managing your server, visit our documentation

From a5eb54b1b7eaf7ac3d5612956a74bdbeb12f2704 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 15 Jan 2016 10:36:09 -0800 Subject: [PATCH 042/357] Move DomainServer script location to app data directory --- domain-server/src/DomainServer.cpp | 3 ++- libraries/networking/src/Assignment.cpp | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 614b90cb18..28e9fd696d 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include "DomainServerNodeData.h" #include "NodeConnectionData.h" @@ -1068,7 +1069,7 @@ QJsonObject DomainServer::jsonObjectForNode(const SharedNodePointer& node) { const char ASSIGNMENT_SCRIPT_HOST_LOCATION[] = "resources/web/assignment"; QString pathForAssignmentScript(const QUuid& assignmentUUID) { - QString newPath(ASSIGNMENT_SCRIPT_HOST_LOCATION); + QString newPath { ServerPathUtils::getDataDirectory() + "/" + QString(ASSIGNMENT_SCRIPT_HOST_LOCATION) }; newPath += "/scripts/"; // append the UUID for this script as the new filename, remove the curly braces newPath += uuidStringWithoutCurlyBraces(assignmentUUID); diff --git a/libraries/networking/src/Assignment.cpp b/libraries/networking/src/Assignment.cpp index e6163c776b..cf40400aa8 100644 --- a/libraries/networking/src/Assignment.cpp +++ b/libraries/networking/src/Assignment.cpp @@ -12,11 +12,13 @@ #include "udt/PacketHeaders.h" #include "SharedUtil.h" #include "UUID.h" +#include "ServerPathUtils.h" #include #include #include "Assignment.h" +#include Assignment::Type Assignment::typeForNodeType(NodeType_t nodeType) { switch (nodeType) { From daa17eadac140b600916635f92e1b1e442c31a17 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 15 Jan 2016 11:47:10 -0800 Subject: [PATCH 043/357] Update main.js to use const for require --- console/src/main.js | 50 ++++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/console/src/main.js b/console/src/main.js index a3fbd9a62d..c0db5c32f3 100644 --- a/console/src/main.js +++ b/console/src/main.js @@ -1,35 +1,33 @@ 'use strict'; -var electron = require('electron'); -var app = electron.app; // Module to control application life. -var BrowserWindow = electron.BrowserWindow; +const electron = require('electron'); +const app = electron.app; // Module to control application life. +const BrowserWindow = electron.BrowserWindow; -var dialog = electron.dialog; -var Menu = require('menu'); -var Tray = require('tray'); -var shell = require('shell'); -var os = require('os'); -var childProcess = require('child_process'); -var path = require('path'); -var fs = require('fs'); -var Tail = require('always-tail'); -var http = require('http'); -var path = require('path'); -var unzip = require('unzip'); +const dialog = electron.dialog; +const Menu = require('menu'); +const Tray = require('tray'); +const shell = require('shell'); +const os = require('os'); +const childProcess = require('child_process'); +const path = require('path'); +const fs = require('fs'); +const Tail = require('always-tail'); +const http = require('http'); +const path = require('path'); +const unzip = require('unzip'); -var request = require('request'); -var progress = require('request-progress'); +const request = require('request'); +const progress = require('request-progress'); -var Config = require('./modules/config').Config; +const Config = require('./modules/config').Config; -const dialog = require('electron').dialog; - -var hfprocess = require('./modules/hf-process.js'); -var Process = hfprocess.Process; -var ACMonitorProcess = hfprocess.ACMonitorProcess; -var ProcessStates = hfprocess.ProcessStates; -var ProcessGroup = hfprocess.ProcessGroup; -var ProcessGroupStates = hfprocess.ProcessGroupStates; +const hfprocess = require('./modules/hf-process.js'); +const Process = hfprocess.Process; +const ACMonitorProcess = hfprocess.ACMonitorProcess; +const ProcessStates = hfprocess.ProcessStates; +const ProcessGroup = hfprocess.ProcessGroup; +const ProcessGroupStates = hfprocess.ProcessGroupStates; function getRootHifiDataDirectory() { From d36efad6febd728798bc0679df1a15bf56a8ecbc Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 15 Jan 2016 14:52:42 -0800 Subject: [PATCH 044/357] Fix log.js style --- console/src/log.css | 67 ++++++++++++++++++++++++++++++++++++++++++++ console/src/log.html | 2 +- console/src/log.js | 38 ++----------------------- 3 files changed, 71 insertions(+), 36 deletions(-) create mode 100644 console/src/log.css diff --git a/console/src/log.css b/console/src/log.css new file mode 100644 index 0000000000..de3c8c3d49 --- /dev/null +++ b/console/src/log.css @@ -0,0 +1,67 @@ +@font-face { + font-family: 'Proxima Nova'; + src: url('vendor/ProximaNova/ProximaNova-Regular.otf'); +} + +body { + font-family: "Proxima Nova", "Open Sans", Arial, Helvetica, sans-serif; + line-height: 1.6; + margin: 0; + padding: 0; +} + +ul.tabs { + margin: 0; + padding: 0px; + list-style: none; +} + +ul.tabs li { + background: none; + color: #222; + display: inline-block; + padding: 10px 15px; + cursor: pointer; +} + +ul.tabs li.current { + background-color: #ededed; + color: #222; +} + +.tab-pane { + display: none; + background-color: #ededed; + width: 100%; + overflow: auto; + margin: 0; + padding: 0; + left: 0; +} + +.tab-pane.current { + display: inherit; +} + +.tab-content { + overflow: auto; + padding: 10px; + background-color: #ededed; +} + +.top { + height: 45px; +} + +.bottom { + position: absolute; + left: 0; + top: 45px; + bottom: 0; + right: 0; +} + +.search { + float: right; + margin: 10px; +} \ No newline at end of file diff --git a/console/src/log.html b/console/src/log.html index 83fa3f4ef7..168e42fe88 100644 --- a/console/src/log.html +++ b/console/src/log.html @@ -16,7 +16,7 @@ -
+
diff --git a/console/src/log.js b/console/src/log.js index 0c2c9ec7bf..6bfb584ce7 100644 --- a/console/src/log.js +++ b/console/src/log.js @@ -127,7 +127,6 @@ ready = function() { domainServer.on('logs-updated', updateLogFiles); acMonitor.on('logs-updated', updateLogFiles); - updateLogFiles(); const maxLogLines = 2500; const ipcRenderer = require('electron').ipcRenderer; @@ -174,22 +173,6 @@ ready = function() { var filter = ""; - var times = {}; - var t = null; - function start() { - t = Date.now(); - } - function stop(name) { - if (!(name in times)) times[name] = 0; - times[name] += (Date.now() - t); - } - - function printTimes() { - for (var k in times) { - console.log(k, times[k] / 1000, 's'); - } - } - // Register for log events // Process added @@ -199,48 +182,33 @@ ready = function() { function appendLogMessage(pid, msg, name) { console.log(pid, msg, name); - start(); var id = "pid-" + pid; id = name == "ds" ? "domain-server" : "assignment-client"; var $pidLog = $('#' + id); - stop('acquire'); - start(); - // var $logLines = $pidLog.children(); - // var removed = false; var size = ++tabStates[id].size; - stop('get size'); - start(); if (size > maxLogLines) { // $logLines.first().remove(); $pidLog.find('div.log-line:first').remove(); removed = true; } - stop('remove first'); - start(); var wasAtBottom = false; if (currentTab == id) { var padding = 15; wasAtBottom = $pidLog[0].scrollTop >= ($pidLog[0].scrollHeight - $pidLog.height() - (2 * padding)); } - stop('scrollCheck'); - start(); var $logLine = $('
').text(msg); - stop('create'); if (!shouldDisplayLogMessage(msg)) { $logLine.hide(); } - start(); - $pidLog.append($logLine); - stop('append'); - start(); + $pidLog.append($logLine); + if (wasAtBottom) { $pidLog.scrollTop($pidLog[0].scrollHeight); } - stop('scroll'); } @@ -261,5 +229,5 @@ ready = function() { } }); - setInterval(printTimes, 10000); + updateLogFiles(); }; From 12c9278d44a63d868e54b1f568fc05f59623c6d2 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 15 Jan 2016 15:05:24 -0800 Subject: [PATCH 045/357] Add SM info to splash --- console/src/splash.css | 13 ++++++- console/src/splash.html | 82 ++++++++++++++++++++++------------------- 2 files changed, 57 insertions(+), 38 deletions(-) diff --git a/console/src/splash.css b/console/src/splash.css index d4b0eb214a..9c39c1717a 100644 --- a/console/src/splash.css +++ b/console/src/splash.css @@ -11,6 +11,7 @@ body { color: #414141; -webkit-touch-callout: none; -webkit-user-select: none; + cursor: default; } * { @@ -74,8 +75,9 @@ p {} } .column.right { + z-index: -1; float: right; - padding-top: 67px; + padding-top: 16px; padding-left: 60px; position: absolute; right: -30px; @@ -105,6 +107,15 @@ p {} /* padding-top: 34px; */ } +#main-content { + height: 350px; + border-bottom: 2px solid #F5F6F6; +} + +#existing-resources-area { + padding-top: 20px; +} + .footer { padding-top: 34px; } diff --git a/console/src/splash.html b/console/src/splash.html index e50be32473..567c09f88e 100644 --- a/console/src/splash.html +++ b/console/src/splash.html @@ -15,47 +15,55 @@
-
-

-

What now?

- The Server Console is your personal domain server in High Fidelity. It allows your local machine to manage 4000 cubic kilometers of space, ready for you to build, explore, and share however you like. To start you off, we've put a few things in your space to play around with and to learn the ropes. -

+
+
+

+

What now?

+ The Server Console is your personal domain server in High Fidelity. It allows your local machine to manage 4000 cubic kilometers of space, ready for you to build, explore, and share however you like. To start you off, we've put a few things in your space to play around with and to learn the ropes. +

-

- To find out more about uploading your own models and scripts, and how to add items from the Market, check out 'The Basics' -

+

+ To find out more about uploading your own models and scripts, and how to add items from the Market, check out 'The Basics' +

+
+
+

+

How do I use it?

+ Console is your personal domain server in High Fidelity. + It allows your local machine to manage your server by clicking on the + High Fidelity icon in your ... In the menu that opens, you can: +

+ +

+

    +
  • go to your 'Home,' automatically launching High Fidelity
  • +
  • administer basic function like starting and stopping your server
  • +
  • access your server's settings and logs
  • +
+

+ +

+ For more information on managing your server, visit our documentation +

+
+
+ +
-
+

-

How do I use it?

- Console is your personal domain server in High Fidelity. - It allows your local machine to manage your server by clicking on the - High Fidelity icon in your ... In the menu that opens, you can: +

Your existing Stack Manager content is safe.

+ Server Console comes with demo content but does not overwrite your data. To import content you previously managed with Stack Manager, see our guide to migrating content.

- -

-

    -
  • go to your 'Home,' automatically launching High Fidelity
  • -
  • administer basic function like starting and stopping your server
  • -
  • access your server's settings and logs
  • -
-

- -

- For more information on managing your server, visit our documentation -

-
-
-
From 40a9efb2486000a61c286810dc0d984283953174 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 15 Jan 2016 15:13:51 -0800 Subject: [PATCH 046/357] Fix cursor on downloader --- console/src/downloader.css | 5 +++++ console/src/downloader.html | 10 ++-------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/console/src/downloader.css b/console/src/downloader.css index 22b217d0a5..47e867eb83 100644 --- a/console/src/downloader.css +++ b/console/src/downloader.css @@ -17,6 +17,7 @@ body { font-size: 14pt; -webkit-touch-callout: none; -webkit-user-select: none; + cursor: default; } #error-message { @@ -24,8 +25,12 @@ body { color: #EB4C5F; padding: 20px; margin: 20px 120px 0 120px; +} + +.selectable { -webkit-touch-callout: text; -webkit-user-select: text; + cursor: text; } progress { diff --git a/console/src/downloader.html b/console/src/downloader.html index 1b5602455c..e40554a6e3 100644 --- a/console/src/downloader.html +++ b/console/src/downloader.html @@ -7,19 +7,13 @@
-

Downloading...

-
- Cancel -
-
-
+

Installing...

Just a moment -
@@ -31,7 +25,7 @@

Houston...

An unfortunate error has occurred: -
+
From 9ee65396b4d1639e01d6bd0a77b2089cd327fbbc Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 15 Jan 2016 15:14:59 -0800 Subject: [PATCH 047/357] Add suppression of download if data exists --- console/src/main.js | 47 +++++++++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/console/src/main.js b/console/src/main.js index c0db5c32f3..35cedb66ee 100644 --- a/console/src/main.js +++ b/console/src/main.js @@ -14,7 +14,6 @@ const path = require('path'); const fs = require('fs'); const Tail = require('always-tail'); const http = require('http'); -const path = require('path'); const unzip = require('unzip'); const request = require('request'); @@ -29,14 +28,23 @@ const ProcessStates = hfprocess.ProcessStates; const ProcessGroup = hfprocess.ProcessGroup; const ProcessGroupStates = hfprocess.ProcessGroupStates; +const osType = os.type(); + +const APP_ICON = path.join(__dirname, '../resources/console.png'); function getRootHifiDataDirectory() { - var rootDirectory = app.getPath('appData'); - return path.join(rootDirectory, '/High Fidelity'); + if (osType == 'Windows_NT') { + var homePath = process.env.HOMEPATH; + return path.join(homePath, 'AppData/Roaming/High Fidelity'); + } else if (osType == 'Darwin') { + return '~/Library/Application Support/High Fidelity'; + } else { + return '/usr/local/share/High Fidelity'; + } } function getStackManagerDataDirectory() { - return path.join(getRootHifiDataDirectory(), "../../Local/High Fidelity"); + // return path.join(getRootHifiDataDirectory(), '../../Local/High Fidelity'); } function getAssignmentClientResourcesDirectory() { @@ -47,12 +55,10 @@ function getApplicationDataDirectory() { return path.join(getRootHifiDataDirectory(), '/Console'); } - -console.log("Root directory is: ", getRootHifiDataDirectory()); +console.log("Root hifi directory is: ", getRootHifiDataDirectory()); const ipcMain = electron.ipcMain; -const osType = os.type(); var isShuttingDown = false; function shutdown() { @@ -168,7 +174,6 @@ function openFileBrowser(path) { // Add quotes around path path = '"' + path + '"'; if (osType == "Windows_NT") { - console.log('start "" ' + path); childProcess.exec('start "" ' + path); } else if (osType == "Darwin") { childProcess.exec('open ' + path); @@ -355,22 +360,27 @@ const httpStatusPort = 60332; function maybeInstallDefaultContentSet(onComplete) { var hasRun = userConfig.get('hasRun', false); - if (false && hasRun) { + if (hasRun) { + onComplete(); return; } - // Check for existing Stack Manager data - const stackManagerDataPath = getStackManagerDataDirectory(); - console.log("Checking for existence of " + stackManagerDataPath); + // Check for existing AC data + const acResourceDirectory = getAssignmentClientResourcesDirectory(); + console.log("Checking for existence of " + acResourceDirectory); var userHasExistingServerData = true; try { - fs.accessSync(stackManagerDataPath); + fs.accessSync(acResourceDirectory); } catch (e) { console.log(e); userHasExistingServerData = false; } - console.log("Existing data?", userHasExistingServerData); + if (userHasExistingServerData) { + console.log("User has existing data, suppressing downloader"); + onComplete(); + return; + } // Show popup var window = new BrowserWindow({ @@ -391,7 +401,7 @@ function maybeInstallDefaultContentSet(onComplete) { electron.ipcMain.on('ready', function() { console.log("got ready"); function sendStateUpdate(state, args) { - console.log(state, window, args); + // console.log(state, window, args); window.webContents.send('update', { state: state, args: args }); } @@ -419,12 +429,11 @@ function maybeInstallDefaultContentSet(onComplete) { }), { throttle: 250 }).on('progress', function(state) { if (!aborted) { // Update progress popup - console.log("progress", state); sendStateUpdate('downloading', { progress: state.percentage }); } }); var unzipper = unzip.Extract({ - path: getAssignmentClientResourcesDirectory(), + path: acResourceDirectory, verbose: true }); unzipper.on('close', function() { @@ -454,14 +463,14 @@ function maybeShowSplash() { var window = new BrowserWindow({ icon: APP_ICON, width: 1600, - height: 587, + height: 737, center: true, frame: true, useContentSize: true, resizable: false }); window.loadURL('file://' + __dirname + '/splash.html'); - window.setMenu(null); + // window.setMenu(null); window.show(); window.webContents.on('new-window', function(e, url) { From 1cab0248fe6e56cb8f57f63cf0e78023fc3dde23 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 15 Jan 2016 15:39:08 -0800 Subject: [PATCH 048/357] Add windows splash image --- console/src/images/console-menubar-osx-2x.png | Bin 0 -> 85194 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 console/src/images/console-menubar-osx-2x.png diff --git a/console/src/images/console-menubar-osx-2x.png b/console/src/images/console-menubar-osx-2x.png new file mode 100644 index 0000000000000000000000000000000000000000..e8b3c11e294fe050ff321ce201c21cd2e1b22302 GIT binary patch literal 85194 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 z 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 mAOMaNL~#HB;8gHW0R{k<+=xwfcAM+~0000 Date: Fri, 15 Jan 2016 15:39:08 -0800 Subject: [PATCH 049/357] Add splash screen windows image --- .../src/images/console-menubar-windows-2x.png | Bin 0 -> 53679 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 console/src/images/console-menubar-windows-2x.png diff --git a/console/src/images/console-menubar-windows-2x.png b/console/src/images/console-menubar-windows-2x.png new file mode 100644 index 0000000000000000000000000000000000000000..5057da17d46eb9a9b75e13567c9b092ec5daeb01 GIT binary patch literal 53679 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¥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 literal 0 HcmV?d00001 From 4f6595ed08de893f98c700d1edef3557db1ddaab Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 5 Jan 2016 11:43:49 -0800 Subject: [PATCH 050/357] fix makefiles build on OS X --- cmake/externals/faceshift/CMakeLists.txt | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/cmake/externals/faceshift/CMakeLists.txt b/cmake/externals/faceshift/CMakeLists.txt index b18b861912..14e6851c77 100644 --- a/cmake/externals/faceshift/CMakeLists.txt +++ b/cmake/externals/faceshift/CMakeLists.txt @@ -21,10 +21,25 @@ ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR) string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER) set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${INSTALL_DIR}/include CACHE FILEPATH "Path to Faceshift include directory") +set(LIBRARY_DEBUG_PATH "lib/Debug") +set(LIBRARY_RELEASE_PATH "lib/Release") + if (WIN32) - set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/lib/Debug/faceshift.lib CACHE FILEPATH "Faceshift libraries") - set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/lib/Release/faceshift.lib CACHE FILEPATH "Faceshift libraries") + set(LIBRARY_PREFIX "") + set(LIBRARY_EXT "lib") elseif (APPLE) - set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/lib/Debug/libfaceshift.a CACHE FILEPATH "Faceshift libraries") - set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/lib/Release/libfaceshift.a CACHE FILEPATH "Faceshift libraries") + set(LIBRARY_EXT "a") + + if (CMAKE_GENERATOR STREQUAL "Unix Makefiles") + set(LIBRARY_PREFIX "lib") + set(LIBRARY_DEBUG_PATH "build") + set(LIBRARY_RELEASE_PATH "build") + else () + set(LIBRARY_PREFIX "") + endif () endif() + +set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG + ${INSTALL_DIR}/${LIBRARY_DEBUG_PATH}/${LIBRARY_PREFIX}faceshift.${LIBRARY_EXT} CACHE FILEPATH "Faceshift libraries") +set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE +${INSTALL_DIR}/${LIBRARY_RELEASE_PATH}/${LIBRARY_PREFIX}faceshift.${LIBRARY_EXT} CACHE FILEPATH "Faceshift libraries") From e6ccce6a38e762a65a9ed34e031064f3d9ed352b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 5 Jan 2016 11:57:39 -0800 Subject: [PATCH 051/357] fix placement of _logDirectory member variable --- .../src/AssignmentClientMonitor.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/assignment-client/src/AssignmentClientMonitor.cpp b/assignment-client/src/AssignmentClientMonitor.cpp index b9c34e9dd7..bcb0def396 100644 --- a/assignment-client/src/AssignmentClientMonitor.cpp +++ b/assignment-client/src/AssignmentClientMonitor.cpp @@ -34,6 +34,7 @@ AssignmentClientMonitor::AssignmentClientMonitor(const unsigned int numAssignmen Assignment::Type requestAssignmentType, QString assignmentPool, quint16 listenPort, QUuid walletUUID, QString assignmentServerHostname, quint16 assignmentServerPort, quint16 httpStatusServerPort, QDir logDirectory) : + _logDirectory(logDirectory), _httpManager(QHostAddress::LocalHost, httpStatusServerPort, "", this), _numAssignmentClientForks(numAssignmentClientForks), _minAssignmentClientForks(minAssignmentClientForks), @@ -42,8 +43,8 @@ AssignmentClientMonitor::AssignmentClientMonitor(const unsigned int numAssignmen _assignmentPool(assignmentPool), _walletUUID(walletUUID), _assignmentServerHostname(assignmentServerHostname), - _assignmentServerPort(assignmentServerPort), - _logDirectory(logDirectory) + _assignmentServerPort(assignmentServerPort) + { qDebug() << "_requestAssignmentType =" << _requestAssignmentType; @@ -200,7 +201,7 @@ void AssignmentClientMonitor::spawnChildClient() { stderrPath = stderrPathTemp; stderrFilename = stderrFilenameTemp; } - + qDebug() << "Child stdout being written to: " << stdoutFilename; qDebug() << "Child stderr being written to: " << stderrFilename; @@ -209,10 +210,10 @@ void AssignmentClientMonitor::spawnChildClient() { // make sure we hear that this process has finished when it does connect(assignmentClient, static_cast(&QProcess::finished), this, [this, pid]() { childProcessFinished(pid); }); - + qDebug() << "Spawned a child client with PID" << assignmentClient->processId(); _childProcesses.insert(assignmentClient->processId(), { assignmentClient, stdoutPath, stderrPath }); - } + } } void AssignmentClientMonitor::checkSpares() { @@ -268,12 +269,12 @@ void AssignmentClientMonitor::handleChildStatusPacket(QSharedPointer()->addOrUpdateNode (senderID, NodeType::Unassigned, senderSockAddr, senderSockAddr, false, false); - + auto childData = std::unique_ptr { new AssignmentClientChildData(Assignment::Type::AllTypes) }; matchingNode->setLinkedData(std::move(childData)); @@ -298,9 +299,9 @@ void AssignmentClientMonitor::handleChildStatusPacket(QSharedPointerreadPrimitive(&assignmentType); - + childData->setChildType(Assignment::Type(assignmentType)); - + // note when this child talked matchingNode->setLastHeardMicrostamp(usecTimestampNow()); } From 0463e008cf4b88961449c233c3503a315675b6d9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 5 Jan 2016 12:08:56 -0800 Subject: [PATCH 052/357] base cpack configuaration using install commands --- CMakeLists.txt | 3 ++ cmake/macros/GenerateInstallers.cmake | 51 ++++++++++++------- .../PackageLibrariesForDeployment.cmake | 33 ++++-------- cmake/macros/SetupHifiProject.cmake | 6 +-- console/CMakeLists.txt | 4 +- interface/CMakeLists.txt | 12 ++--- 6 files changed, 55 insertions(+), 54 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 59c787ce4a..b272970925 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -211,6 +211,9 @@ endif() set_packaging_parameters() +# setup component categories for installer +set(APP_COMPONENT Runtime) + # add subdirectories for all targets if (NOT ANDROID) add_subdirectory(assignment-client) diff --git a/cmake/macros/GenerateInstallers.cmake b/cmake/macros/GenerateInstallers.cmake index 18e5c190a6..f79c3528bf 100644 --- a/cmake/macros/GenerateInstallers.cmake +++ b/cmake/macros/GenerateInstallers.cmake @@ -10,23 +10,40 @@ # macro(GENERATE_INSTALLERS) - if (DEPLOY_PACKAGE AND WIN32) - file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/package-bundle") - find_program(MAKENSIS_COMMAND makensis PATHS [HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\NSIS]) - if (NOT MAKENSIS_COMMAND) - message(FATAL_ERROR "The Nullsoft Scriptable Install Systems is required for generating packaged installers on Windows (http://nsis.sourceforge.net/)") - endif () - add_custom_target( - build-package ALL - DEPENDS interface assignment-client domain-server stack-manager - COMMAND set INSTALLER_SOURCE_DIR=${CMAKE_BINARY_DIR}/package-bundle - COMMAND set INSTALLER_NAME=${CMAKE_BINARY_DIR}/${INSTALLER_NAME} - COMMAND set INSTALLER_SCRIPTS_DIR=${CMAKE_SOURCE_DIR}/examples - COMMAND set INSTALLER_COMPANY=${INSTALLER_COMPANY} - COMMAND set INSTALLER_DIRECTORY=${INSTALLER_DIRECTORY} - COMMAND CMD /C "\"${MAKENSIS_COMMAND}\" ${CMAKE_SOURCE_DIR}/tools/nsis/release.nsi" - ) + include(CPackComponent) - set_target_properties(build-package PROPERTIES EXCLUDE_FROM_ALL TRUE FOLDER "Installer") + if (APPLE) + install(TARGETS ${CLIENT_TARGET} BUNDLE DESTINATION bin COMPONENT ${APP_COMPONENT}) + else () + install(TARGETS ${CLIENT_TARGET} RUNTIME DESTINATION bin COMPONENT ${APP_COMPONENT}) endif () + + cpack_add_component(${APP_COMPONENT} + DISPLAY_NAME "Applications" + Description "The High Fidelity Applications" + GROUP "Runtime" + ) + + cpack_add_component_group(Runtime) + + include(CPack) + # if (DEPLOY_PACKAGE AND WIN32) + # file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/package-bundle") + # find_program(MAKENSIS_COMMAND makensis PATHS [HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\NSIS]) + # if (NOT MAKENSIS_COMMAND) + # message(FATAL_ERROR "The Nullsoft Scriptable Install Systems is required for generating packaged installers on Windows (http://nsis.sourceforge.net/)") + # endif () + # add_custom_target( + # build-package ALL + # DEPENDS interface assignment-client domain-server stack-manager + # COMMAND set INSTALLER_SOURCE_DIR=${CMAKE_BINARY_DIR}/package-bundle + # COMMAND set INSTALLER_NAME=${CMAKE_BINARY_DIR}/${INSTALLER_NAME} + # COMMAND set INSTALLER_SCRIPTS_DIR=${CMAKE_SOURCE_DIR}/examples + # COMMAND set INSTALLER_COMPANY=${INSTALLER_COMPANY} + # COMMAND set INSTALLER_DIRECTORY=${INSTALLER_DIRECTORY} + # COMMAND CMD /C "\"${MAKENSIS_COMMAND}\" ${CMAKE_SOURCE_DIR}/tools/nsis/release.nsi" + # ) + # + # set_target_properties(build-package PROPERTIES EXCLUDE_FROM_ALL TRUE FOLDER "Installer") + # endif () endmacro() diff --git a/cmake/macros/PackageLibrariesForDeployment.cmake b/cmake/macros/PackageLibrariesForDeployment.cmake index 17b5d5f49d..44d609c064 100644 --- a/cmake/macros/PackageLibrariesForDeployment.cmake +++ b/cmake/macros/PackageLibrariesForDeployment.cmake @@ -1,25 +1,25 @@ -# +# # PackageLibrariesForDeployment.cmake # cmake/macros -# +# # Copyright 2015 High Fidelity, Inc. # Created by Stephen Birarda on February 17, 2014 # # Distributed under the Apache License, Version 2.0. # See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -# +# macro(PACKAGE_LIBRARIES_FOR_DEPLOYMENT) - + if (WIN32) configure_file( - ${HIFI_CMAKE_DIR}/templates/FixupBundlePostBuild.cmake.in + ${HIFI_CMAKE_DIR}/templates/FixupBundlePostBuild.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/FixupBundlePostBuild.cmake @ONLY ) - + set(PLUGIN_PATH "plugins") - + # add a post-build command to copy DLLs beside the executable add_custom_command( TARGET ${TARGET_NAME} @@ -29,31 +29,18 @@ macro(PACKAGE_LIBRARIES_FOR_DEPLOYMENT) -DBUNDLE_PLUGIN_DIR=$/${PLUGIN_PATH} -P ${CMAKE_CURRENT_BINARY_DIR}/FixupBundlePostBuild.cmake ) - + find_program(WINDEPLOYQT_COMMAND windeployqt PATHS ${QT_DIR}/bin NO_DEFAULT_PATH) - + if (NOT WINDEPLOYQT_COMMAND) message(FATAL_ERROR "Could not find windeployqt at ${QT_DIR}/bin. windeployqt is required.") endif () - + # add a post-build command to call windeployqt to copy Qt plugins add_custom_command( TARGET ${TARGET_NAME} POST_BUILD COMMAND CMD /C "SET PATH=%PATH%;${QT_DIR}/bin && ${WINDEPLOYQT_COMMAND} ${EXTRA_DEPLOY_OPTIONS} $<$,$,$>:--release> $" ) - elseif (DEFINED BUILD_BUNDLE AND BUILD_BUNDLE AND APPLE) - find_program(MACDEPLOYQT_COMMAND macdeployqt PATHS ${QT_DIR}/bin NO_DEFAULT_PATH) - - if (NOT MACDEPLOYQT_COMMAND) - message(FATAL_ERROR "Could not find macdeployqt at ${QT_DIR}/bin. macdeployqt is required.") - endif () - - # add a post-build command to call macdeployqt to copy Qt plugins - add_custom_command( - TARGET ${TARGET_NAME} - POST_BUILD - COMMAND ${MACDEPLOYQT_COMMAND} ${CMAKE_CURRENT_BINARY_DIR}/\${CONFIGURATION}/${TARGET_NAME}.app -verbose 0 - ) endif () endmacro() diff --git a/cmake/macros/SetupHifiProject.cmake b/cmake/macros/SetupHifiProject.cmake index 212dbe6317..6c150b6c8d 100644 --- a/cmake/macros/SetupHifiProject.cmake +++ b/cmake/macros/SetupHifiProject.cmake @@ -22,11 +22,7 @@ macro(SETUP_HIFI_PROJECT) endif () endforeach() - if (DEFINED BUILD_BUNDLE AND BUILD_BUNDLE AND APPLE) - add_executable(${TARGET_NAME} MACOSX_BUNDLE ${TARGET_SRCS} ${AUTOMTC_SRC} ${AUTOSCRIBE_SHADER_LIB_SRC}) - else () - add_executable(${TARGET_NAME} ${TARGET_SRCS} ${AUTOMTC_SRC} ${AUTOSCRIBE_SHADER_LIB_SRC}) - endif() + add_executable(${TARGET_NAME} ${TARGET_SRCS} ${AUTOMTC_SRC} ${AUTOSCRIBE_SHADER_LIB_SRC}) # include the generated application version header target_include_directories(${TARGET_NAME} PRIVATE "${CMAKE_BINARY_DIR}/includes") diff --git a/console/CMakeLists.txt b/console/CMakeLists.txt index 490f59acc6..120f185c90 100644 --- a/console/CMakeLists.txt +++ b/console/CMakeLists.txt @@ -5,7 +5,7 @@ if (BUILD_TAGGED_BETA) endif() # add a target that will package the console -add_custom_target(${TARGET_NAME} +add_custom_target(${TARGET_NAME} ALL COMMAND npm run packager -- --out ${CMAKE_CURRENT_BINARY_DIR} ${BETA_OPTION} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) @@ -19,6 +19,6 @@ elseif (UNIX) set(PACKAGED_CONSOLE_FOLDER "server-console-linux-x64") endif () -set_target_properties(${TARGET_NAME} PROPERTIES EXCLUDE_FROM_ALL TRUE FOLDER "Installer") +install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/${PACKAGED_CONSOLE_FOLDER}/Server Console.app" DESTINATION bin COMPONENT ${APP_COMPONENT}) consolidate_installer_components() diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index d20e7dd71f..cc2faa2422 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -203,11 +203,8 @@ if (APPLE) target_link_libraries(${TARGET_NAME} ${OpenGL} ${AppKit}) - # install command for OS X bundle - INSTALL(TARGETS ${TARGET_NAME} - BUNDLE DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/install" COMPONENT Runtime - RUNTIME DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/install" COMPONENT Runtime - ) + # setup install of OS X interface bundle + install(TARGETS ${TARGET_NAME} BUNDLE DESTINATION bin COMPONENT ${APP_COMPONENT}) else (APPLE) # copy the resources files beside the executable add_custom_command(TARGET ${TARGET_NAME} POST_BUILD @@ -219,11 +216,12 @@ else (APPLE) $/scripts ) + # setup install of interface target + install(TARGETS ${TARGET_NAME} RUNTIME DESTINATION bin COMPONENT ${APP_COMPONENT}) + # link target to external libraries if (WIN32) target_link_libraries(${TARGET_NAME} wsock32.lib Winmm.lib) - else (WIN32) - # Nothing else required on linux apparently endif() endif (APPLE) From 3a33d8815ef432f6743e7ada1849e3b5d588e615 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 5 Jan 2016 12:25:28 -0800 Subject: [PATCH 053/357] add the AC and DS as packaged console dependencies --- console/CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/console/CMakeLists.txt b/console/CMakeLists.txt index 120f185c90..017870b329 100644 --- a/console/CMakeLists.txt +++ b/console/CMakeLists.txt @@ -10,6 +10,9 @@ add_custom_target(${TARGET_NAME} ALL WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) +# add a dependency from the package target to the server components +add_dependencies(${TARGET_NAME} assignment-client domain-server) + # set the packaged console folder depending on platform, so we can copy it if (APPLE) set(PACKAGED_CONSOLE_FOLDER "Server\\ Console-darwin-x64") From f5bf431cd5fd71c249e3203fbb3fc19dce7ae6eb Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 5 Jan 2016 13:17:38 -0800 Subject: [PATCH 054/357] ignore logs and packages when packaging console --- console/packager.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/console/packager.js b/console/packager.js index 7f52542fe2..f46ac1ceb5 100644 --- a/console/packager.js +++ b/console/packager.js @@ -22,7 +22,8 @@ var options = { prune: true, arch: "x64", platform: platform, - icon: "resources/" + iconName + icon: "resources/" + iconName, + ignore: "logs|(S|s)erver(\s|-)(C|c)onsole-\S+" } const EXEC_NAME = "server-console"; From 550b47f58bae77e9b47589db4e211c81c2f09e53 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 5 Jan 2016 13:17:52 -0800 Subject: [PATCH 055/357] ignore logs and packages when packaging console --- console/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/console/CMakeLists.txt b/console/CMakeLists.txt index 017870b329..c59b0520be 100644 --- a/console/CMakeLists.txt +++ b/console/CMakeLists.txt @@ -22,6 +22,6 @@ elseif (UNIX) set(PACKAGED_CONSOLE_FOLDER "server-console-linux-x64") endif () -install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/${PACKAGED_CONSOLE_FOLDER}/Server Console.app" DESTINATION bin COMPONENT ${APP_COMPONENT}) +install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/${PACKAGED_CONSOLE_FOLDER}/Server Console.app" DESTINATION bin COMPONENT ${SERVER_COMPONENT}) consolidate_installer_components() From 92064fe507fb2ef6d9ff484267d96bccd5c833ae Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 5 Jan 2016 13:18:01 -0800 Subject: [PATCH 056/357] generate a componentized server/client installer --- CMakeLists.txt | 3 ++- cmake/macros/GenerateInstallers.cmake | 15 ++++++++++----- interface/CMakeLists.txt | 4 ++-- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b272970925..0a763cb064 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -212,7 +212,8 @@ endif() set_packaging_parameters() # setup component categories for installer -set(APP_COMPONENT Runtime) +set(CLIENT_COMPONENT client) +set(SERVER_COMPONENT server) # add subdirectories for all targets if (NOT ANDROID) diff --git a/cmake/macros/GenerateInstallers.cmake b/cmake/macros/GenerateInstallers.cmake index f79c3528bf..9b8b4b1b80 100644 --- a/cmake/macros/GenerateInstallers.cmake +++ b/cmake/macros/GenerateInstallers.cmake @@ -12,21 +12,26 @@ macro(GENERATE_INSTALLERS) include(CPackComponent) + set(CPACK_PACKAGE_NAME "High Fidelity") + set(CPACK_PACKAGE_VENDOR "High Fidelity, Inc.") + set(CPACK_PACKAGE_INSTALL_DIRECTORY "High Fidelity") + if (APPLE) install(TARGETS ${CLIENT_TARGET} BUNDLE DESTINATION bin COMPONENT ${APP_COMPONENT}) else () install(TARGETS ${CLIENT_TARGET} RUNTIME DESTINATION bin COMPONENT ${APP_COMPONENT}) endif () - cpack_add_component(${APP_COMPONENT} - DISPLAY_NAME "Applications" - Description "The High Fidelity Applications" - GROUP "Runtime" + cpack_add_component(${CLIENT_COMPONENT} + DISPLAY_NAME "High Fidelity Client" ) - cpack_add_component_group(Runtime) + cpack_add_component(${SERVER_COMPONENT} + DISPLAY_NAME "High Fidelity Server" + ) include(CPack) + # if (DEPLOY_PACKAGE AND WIN32) # file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/package-bundle") # find_program(MAKENSIS_COMMAND makensis PATHS [HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\NSIS]) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index cc2faa2422..3c8e9879b2 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -204,7 +204,7 @@ if (APPLE) target_link_libraries(${TARGET_NAME} ${OpenGL} ${AppKit}) # setup install of OS X interface bundle - install(TARGETS ${TARGET_NAME} BUNDLE DESTINATION bin COMPONENT ${APP_COMPONENT}) + install(TARGETS ${TARGET_NAME} BUNDLE DESTINATION bin COMPONENT ${CLIENT_COMPONENT}) else (APPLE) # copy the resources files beside the executable add_custom_command(TARGET ${TARGET_NAME} POST_BUILD @@ -217,7 +217,7 @@ else (APPLE) ) # setup install of interface target - install(TARGETS ${TARGET_NAME} RUNTIME DESTINATION bin COMPONENT ${APP_COMPONENT}) + install(TARGETS ${TARGET_NAME} RUNTIME DESTINATION bin COMPONENT ${CLIENT_COMPONENT}) # link target to external libraries if (WIN32) From 39c3ae79f90ffec56ddad981911db8cc119a4e74 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 5 Jan 2016 13:33:21 -0800 Subject: [PATCH 057/357] fix the ignore for server console packaging --- console/packager.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/console/packager.js b/console/packager.js index f46ac1ceb5..c71c4fe407 100644 --- a/console/packager.js +++ b/console/packager.js @@ -23,7 +23,7 @@ var options = { arch: "x64", platform: platform, icon: "resources/" + iconName, - ignore: "logs|(S|s)erver(\s|-)(C|c)onsole-\S+" + ignore: "logs|(S|s)erver(\\s|-)(C|c)onsole-\\S+" } const EXEC_NAME = "server-console"; From e421624e992a9fd97d4f0204799dc04b40b46d93 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 5 Jan 2016 13:34:00 -0800 Subject: [PATCH 058/357] put AC and DS binaries beside server-console --- assignment-client/CMakeLists.txt | 2 ++ cmake/macros/InstallBesideConsole.cmake | 21 +++++++++++++++++++++ console/CMakeLists.txt | 1 + domain-server/CMakeLists.txt | 2 ++ 4 files changed, 26 insertions(+) create mode 100644 cmake/macros/InstallBesideConsole.cmake diff --git a/assignment-client/CMakeLists.txt b/assignment-client/CMakeLists.txt index a473a7427c..b2e890fe9e 100644 --- a/assignment-client/CMakeLists.txt +++ b/assignment-client/CMakeLists.txt @@ -9,5 +9,7 @@ link_hifi_libraries( controllers physics ) +install_beside_console() + package_libraries_for_deployment() consolidate_installer_components() diff --git a/cmake/macros/InstallBesideConsole.cmake b/cmake/macros/InstallBesideConsole.cmake new file mode 100644 index 0000000000..08515feffb --- /dev/null +++ b/cmake/macros/InstallBesideConsole.cmake @@ -0,0 +1,21 @@ +# +# InstallBesideConsole.cmake +# cmake/macros +# +# Copyright 2016 High Fidelity, Inc. +# Created by Stephen Birarda on January 5th, 2016 +# +# Distributed under the Apache License, Version 2.0. +# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +# + +macro(install_beside_console) + # install this component beside the installed server-console executable + if (APPLE) + set(COMPONENT_DESTINATION "bin/Server Console.app/Contents/MacOS/") + else () + set(COMPONENT_DESTINATION bin) + endif () + + install(TARGETS ${TARGET_NAME} RUNTIME DESTINATION ${COMPONENT_DESTINATION} COMPONENT ${SERVER_COMPONENT}) +endmacro() diff --git a/console/CMakeLists.txt b/console/CMakeLists.txt index c59b0520be..df4d9b6610 100644 --- a/console/CMakeLists.txt +++ b/console/CMakeLists.txt @@ -22,6 +22,7 @@ elseif (UNIX) set(PACKAGED_CONSOLE_FOLDER "server-console-linux-x64") endif () +# install the packaged Server Console install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/${PACKAGED_CONSOLE_FOLDER}/Server Console.app" DESTINATION bin COMPONENT ${SERVER_COMPONENT}) consolidate_installer_components() diff --git a/domain-server/CMakeLists.txt b/domain-server/CMakeLists.txt index 6bcda2de4a..9437656f9b 100644 --- a/domain-server/CMakeLists.txt +++ b/domain-server/CMakeLists.txt @@ -36,5 +36,7 @@ if (UNIX) target_link_libraries(${TARGET_NAME} ${CMAKE_DL_LIBS}) endif (UNIX) +install_beside_console() + package_libraries_for_deployment() consolidate_installer_components() From 6eb96c27e5fabe2a1855114e87e1d69005c7dc33 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 5 Jan 2016 17:21:08 -0800 Subject: [PATCH 059/357] use standard PlugIns path, fix for makefiles build --- cmake/macros/SetupHifiPlugin.cmake | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cmake/macros/SetupHifiPlugin.cmake b/cmake/macros/SetupHifiPlugin.cmake index b9fc4490d7..d8b8c80f9b 100644 --- a/cmake/macros/SetupHifiPlugin.cmake +++ b/cmake/macros/SetupHifiPlugin.cmake @@ -12,12 +12,12 @@ macro(SETUP_HIFI_PLUGIN) set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Plugins") if (APPLE) - set(PLUGIN_PATH "interface.app/Contents/MacOS/plugins") + set(PLUGIN_PATH "interface.app/Contents/PlugIns") else() set(PLUGIN_PATH "plugins") endif() - IF(${CMAKE_SYSTEM_NAME} MATCHES "Linux") + if (CMAKE_SYSTEM_NAME MATCHES "Linux" OR CMAKE_GENERATOR STREQUAL "Unix Makefiles") set(PLUGIN_FULL_PATH "${CMAKE_BINARY_DIR}/interface/${PLUGIN_PATH}/") else() set(PLUGIN_FULL_PATH "${CMAKE_BINARY_DIR}/interface/$/${PLUGIN_PATH}/") @@ -35,5 +35,4 @@ macro(SETUP_HIFI_PLUGIN) "$" ${PLUGIN_FULL_PATH} ) - endmacro() From 386d3a950f1e5917326662ddc9836932633457ed Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 5 Jan 2016 17:21:30 -0800 Subject: [PATCH 060/357] default to beta/dev build for server console --- console/CMakeLists.txt | 14 +++++++++----- console/packager.js | 3 ++- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/console/CMakeLists.txt b/console/CMakeLists.txt index df4d9b6610..43933af410 100644 --- a/console/CMakeLists.txt +++ b/console/CMakeLists.txt @@ -1,12 +1,12 @@ set(TARGET_NAME package-console) -if (BUILD_TAGGED_BETA) - set(BETA_OPTION "--beta") +if (PRODUCTION_BUILD) + set(PRODUCTION_OPTION "--production") endif() # add a target that will package the console add_custom_target(${TARGET_NAME} ALL - COMMAND npm run packager -- --out ${CMAKE_CURRENT_BINARY_DIR} ${BETA_OPTION} + COMMAND npm run packager -- --out ${CMAKE_CURRENT_BINARY_DIR} ${PRODUCTION_OPTION} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) @@ -22,7 +22,11 @@ elseif (UNIX) set(PACKAGED_CONSOLE_FOLDER "server-console-linux-x64") endif () -# install the packaged Server Console -install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/${PACKAGED_CONSOLE_FOLDER}/Server Console.app" DESTINATION bin COMPONENT ${SERVER_COMPONENT}) +# install the packaged Server Console +install( + PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/${PACKAGED_CONSOLE_FOLDER}/Server Console.app" + DESTINATION "Applications/High Fidelity" + COMPONENT ${SERVER_COMPONENT} +) consolidate_installer_components() diff --git a/console/packager.js b/console/packager.js index c71c4fe407..2489436857 100644 --- a/console/packager.js +++ b/console/packager.js @@ -11,7 +11,7 @@ if (osType == "Darwin" || osType == "Linux") { var argv = require('yargs').argv; // check which icon we should use, beta or regular -var iconName = argv.beta ? "console-beta" : "console" +var iconName = argv.production ? "console" : "console-beta"; // setup the common options for the packager var options = { @@ -32,6 +32,7 @@ const FULL_NAME = "High Fidelity Server Console"; // setup per OS options if (osType == "Darwin") { + options["app-bundle-id"] = "com.highfidelity.server-console" + (argv.production ? "" : "-dev") options["name"] = SHORT_NAME } else if (osType == "Windows_NT") { options["version-string"] = { From d491a7f0e5b7de586ac5df604ff46952c465a18b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 5 Jan 2016 17:22:07 -0800 Subject: [PATCH 061/357] work around OS X package installer relocation --- cmake/macros/GenerateInstallers.cmake | 15 +++++++++------ cmake/macros/InstallBesideConsole.cmake | 4 ++-- cmake/macros/SetPackagingParameters.cmake | 11 ++++++----- interface/CMakeLists.txt | 23 +++++++++++++++-------- 4 files changed, 32 insertions(+), 21 deletions(-) diff --git a/cmake/macros/GenerateInstallers.cmake b/cmake/macros/GenerateInstallers.cmake index 9b8b4b1b80..3645f1bc7f 100644 --- a/cmake/macros/GenerateInstallers.cmake +++ b/cmake/macros/GenerateInstallers.cmake @@ -12,14 +12,12 @@ macro(GENERATE_INSTALLERS) include(CPackComponent) - set(CPACK_PACKAGE_NAME "High Fidelity") - set(CPACK_PACKAGE_VENDOR "High Fidelity, Inc.") - set(CPACK_PACKAGE_INSTALL_DIRECTORY "High Fidelity") + set(CPACK_PACKAGE_NAME "HighFidelity") + set(CPACK_PACKAGE_VENDOR "HighFidelity") if (APPLE) - install(TARGETS ${CLIENT_TARGET} BUNDLE DESTINATION bin COMPONENT ${APP_COMPONENT}) - else () - install(TARGETS ${CLIENT_TARGET} RUNTIME DESTINATION bin COMPONENT ${APP_COMPONENT}) + set(CPACK_PACKAGE_INSTALL_DIRECTORY "/") + set(CPACK_PACKAGING_INSTALL_PREFIX /) endif () cpack_add_component(${CLIENT_COMPONENT} @@ -30,6 +28,11 @@ macro(GENERATE_INSTALLERS) DISPLAY_NAME "High Fidelity Server" ) + if (APPLE) + # we don't want the OS X package to install anywhere but the main volume, so disable relocation + set(CPACK_PACKAGE_RELOCATABLE FALSE) + endif () + include(CPack) # if (DEPLOY_PACKAGE AND WIN32) diff --git a/cmake/macros/InstallBesideConsole.cmake b/cmake/macros/InstallBesideConsole.cmake index 08515feffb..58885681f8 100644 --- a/cmake/macros/InstallBesideConsole.cmake +++ b/cmake/macros/InstallBesideConsole.cmake @@ -12,9 +12,9 @@ macro(install_beside_console) # install this component beside the installed server-console executable if (APPLE) - set(COMPONENT_DESTINATION "bin/Server Console.app/Contents/MacOS/") + set(COMPONENT_DESTINATION "Applications/High Fidelity/Server Console.app/Contents/MacOS/") else () - set(COMPONENT_DESTINATION bin) + set(COMPONENT_DESTINATION .) endif () install(TARGETS ${TARGET_NAME} RUNTIME DESTINATION ${COMPONENT_DESTINATION} COMPONENT ${SERVER_COMPONENT}) diff --git a/cmake/macros/SetPackagingParameters.cmake b/cmake/macros/SetPackagingParameters.cmake index 7f071f4c87..0a1ff9485c 100644 --- a/cmake/macros/SetPackagingParameters.cmake +++ b/cmake/macros/SetPackagingParameters.cmake @@ -14,17 +14,18 @@ macro(SET_PACKAGING_PARAMETERS) if (DEFINED ENV{JOB_ID}) - set(DEPLOY_PACKAGE 1) + set(DEPLOY_PACKAGE TRUE) set(BUILD_SEQ $ENV{JOB_ID}) - set(BUILD_TAGGED_BETA FALSE) + set(PRODUCTION_BUILD TRUE) + set(BETA_BUILD FALSE) set(INSTALLER_COMPANY "High Fidelity") set(INSTALLER_DIRECTORY "${INSTALLER_COMPANY}") set(INSTALLER_NAME "interface-win64-${BUILD_SEQ}.exe") set(INTERFACE_ICON "interface.ico") set(CONSOLE_ICON "console.ico") elseif (DEFINED ENV{ghprbPullId}) - set(DEPLOY_PACKAGE 1) - set(BUILD_TAGGED_BETA TRUE) + set(DEPLOY_PACKAGE TRUE) + set(BETA_BUILD TRUE) set(BUILD_SEQ "PR-$ENV{ghprbPullId}") set(INSTALLER_COMPANY "High Fidelity - PR") set(INSTALLER_DIRECTORY "${INSTALLER_COMPANY}\\${BUILD_SEQ}") @@ -33,7 +34,7 @@ macro(SET_PACKAGING_PARAMETERS) set(CONSOLE_ICON "console-beta.ico") else () set(BUILD_SEQ "dev") - set(BUILD_TAGGED_BETA TRUE) + set(BETA_BUILD TRUE) set(INSTALLER_COMPANY "High Fidelity - Dev") set(INSTALLER_DIRECTORY "${INSTALLER_COMPANY}") set(INSTALLER_NAME "dev-interface-win64.exe") diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 3c8e9879b2..784c34a302 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -62,15 +62,18 @@ set(INTERFACE_SRCS ${INTERFACE_SRCS} "${QT_UI_HEADERS}" "${QT_RESOURCES}") # qt5_create_translation_custom(${QM} ${INTERFACE_SRCS} ${QT_UI_FILES} ${TS}) if (APPLE) - # configure CMake to use a custom Info.plist - SET_TARGET_PROPERTIES( ${this_target} PROPERTIES MACOSX_BUNDLE_INFO_PLIST MacOSXBundleInfo.plist.in ) + set(MACOSX_BUNDLE_BUNDLE_NAME "High Fidelity") - set(MACOSX_BUNDLE_BUNDLE_NAME Interface) - set(MACOSX_BUNDLE_GUI_IDENTIFIER io.highfidelity.Interface) + # configure CMake to use a custom Info.plist and to produce a .app with the correct name + set_target_properties(${this_target} PROPERTIES + MACOSX_BUNDLE_INFO_PLIST MacOSXBundleInfo.plist.in + ) - if (UPPER_CMAKE_BUILD_TYPE MATCHES RELEASE OR UPPER_CMAKE_BUILD_TYPE MATCHES RELWITHDEBINFO) + if (PRODUCTION_BUILD) + set(MACOSX_BUNDLE_GUI_IDENTIFIER com.highfidelity.interface) set(ICON_FILENAME "interface.icns") else () + set(MACOSX_BUNDLE_GUI_IDENTIFIER com.highfidelity.interface-dev) set(ICON_FILENAME "interface-beta.icns") endif () @@ -190,7 +193,7 @@ target_link_libraries( # Issue causes build failure unless we add this directory. # See https://bugreports.qt.io/browse/QTBUG-43351 if (WIN32) - add_paths_to_fixup_libs(${Qt5_DIR}/../../../plugins/qtwebengine) + add_paths_to_fixup_libs(${Qt5_DIR}/../../../plugins/qtwebengine) endif() # assume we are using a Qt build without bearer management @@ -204,7 +207,11 @@ if (APPLE) target_link_libraries(${TARGET_NAME} ${OpenGL} ${AppKit}) # setup install of OS X interface bundle - install(TARGETS ${TARGET_NAME} BUNDLE DESTINATION bin COMPONENT ${CLIENT_COMPONENT}) + install(TARGETS ${TARGET_NAME} + BUNDLE DESTINATION "Applications/High Fidelity" + COMPONENT ${CLIENT_COMPONENT} + RENAME ${MACOSX_BUNDLE_BUNDLE_NAME} + ) else (APPLE) # copy the resources files beside the executable add_custom_command(TARGET ${TARGET_NAME} POST_BUILD @@ -217,7 +224,7 @@ else (APPLE) ) # setup install of interface target - install(TARGETS ${TARGET_NAME} RUNTIME DESTINATION bin COMPONENT ${CLIENT_COMPONENT}) + install(TARGETS ${TARGET_NAME} RUNTIME DESTINATION . COMPONENT ${CLIENT_COMPONENT}) # link target to external libraries if (WIN32) From f87d8885f4554da265c73114e127698f77c09335 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 5 Jan 2016 18:05:55 -0800 Subject: [PATCH 062/357] rename interface bundle for production and pr build --- cmake/macros/SetPackagingParameters.cmake | 5 ++- .../templates/RenameInterfaceBundle.cmake.in | 16 ++++++++++ interface/CMakeLists.txt | 32 +++++++++++++++---- 3 files changed, 44 insertions(+), 9 deletions(-) create mode 100644 cmake/templates/RenameInterfaceBundle.cmake.in diff --git a/cmake/macros/SetPackagingParameters.cmake b/cmake/macros/SetPackagingParameters.cmake index 0a1ff9485c..37e7d3bf3c 100644 --- a/cmake/macros/SetPackagingParameters.cmake +++ b/cmake/macros/SetPackagingParameters.cmake @@ -17,7 +17,6 @@ macro(SET_PACKAGING_PARAMETERS) set(DEPLOY_PACKAGE TRUE) set(BUILD_SEQ $ENV{JOB_ID}) set(PRODUCTION_BUILD TRUE) - set(BETA_BUILD FALSE) set(INSTALLER_COMPANY "High Fidelity") set(INSTALLER_DIRECTORY "${INSTALLER_COMPANY}") set(INSTALLER_NAME "interface-win64-${BUILD_SEQ}.exe") @@ -25,7 +24,7 @@ macro(SET_PACKAGING_PARAMETERS) set(CONSOLE_ICON "console.ico") elseif (DEFINED ENV{ghprbPullId}) set(DEPLOY_PACKAGE TRUE) - set(BETA_BUILD TRUE) + set(PR_BUILD TRUE) set(BUILD_SEQ "PR-$ENV{ghprbPullId}") set(INSTALLER_COMPANY "High Fidelity - PR") set(INSTALLER_DIRECTORY "${INSTALLER_COMPANY}\\${BUILD_SEQ}") @@ -34,7 +33,7 @@ macro(SET_PACKAGING_PARAMETERS) set(CONSOLE_ICON "console-beta.ico") else () set(BUILD_SEQ "dev") - set(BETA_BUILD TRUE) + set(DEV_BUILD TRUE) set(INSTALLER_COMPANY "High Fidelity - Dev") set(INSTALLER_DIRECTORY "${INSTALLER_COMPANY}") set(INSTALLER_NAME "dev-interface-win64.exe") diff --git a/cmake/templates/RenameInterfaceBundle.cmake.in b/cmake/templates/RenameInterfaceBundle.cmake.in new file mode 100644 index 0000000000..a579c6efe1 --- /dev/null +++ b/cmake/templates/RenameInterfaceBundle.cmake.in @@ -0,0 +1,16 @@ +# +# RenameInterfaceBundle.cmake.in +# cmake/templates +# +# Copyright 2016 High Fidelity, Inc. +# Created by Stephen Birarda on January 5, 2016 +# +# Distributed under the Apache License, Version 2.0. +# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +# + +set(SOURCE_BUNDLE "@CMAKE_INSTALL_PREFIX@/Applications/High Fidelity/interface.app") +set(DESTINATION_BUNDLE "@CMAKE_INSTALL_PREFIX@/Applications/High Fidelity/@INTERFACE_BUNDLE_NAME@.app") +message(STATUS "Renaming ${SOURCE_BUNDLE} to ${DESTINATION_BUNDLE}") + +file(RENAME ${SOURCE_BUNDLE} ${DESTINATION_BUNDLE}) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 784c34a302..91b306dad3 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -64,16 +64,19 @@ set(INTERFACE_SRCS ${INTERFACE_SRCS} "${QT_UI_HEADERS}" "${QT_RESOURCES}") if (APPLE) set(MACOSX_BUNDLE_BUNDLE_NAME "High Fidelity") - # configure CMake to use a custom Info.plist and to produce a .app with the correct name - set_target_properties(${this_target} PROPERTIES - MACOSX_BUNDLE_INFO_PLIST MacOSXBundleInfo.plist.in - ) + # configure CMake to use a custom Info.plist + set_target_properties(${this_target} PROPERTIES MACOSX_BUNDLE_INFO_PLIST MacOSXBundleInfo.plist.in) if (PRODUCTION_BUILD) set(MACOSX_BUNDLE_GUI_IDENTIFIER com.highfidelity.interface) set(ICON_FILENAME "interface.icns") else () - set(MACOSX_BUNDLE_GUI_IDENTIFIER com.highfidelity.interface-dev) + if (DEV_BUILD) + set(MACOSX_BUNDLE_GUI_IDENTIFIER com.highfidelity.interface-dev) + elseif (PR_BUILD) + set(MACOSX_BUNDLE_GUI_IDENTIFIER com.highfidelity.interface-pr) + endif () + set(ICON_FILENAME "interface-beta.icns") endif () @@ -210,8 +213,25 @@ if (APPLE) install(TARGETS ${TARGET_NAME} BUNDLE DESTINATION "Applications/High Fidelity" COMPONENT ${CLIENT_COMPONENT} - RENAME ${MACOSX_BUNDLE_BUNDLE_NAME} ) + + if (PRODUCTION_BUILD OR PR_BUILD) + # for a production or PR build, setup rename of produced bundle + # for production builds it becomes "High Fidelity" and PR builds are "High Fidelity" with the PR number + if (PRODUCTION_BUILD) + set(INTERFACE_BUNDLE_NAME "High Fidelity") + elseif (PR_BUILD) + set(INTERFACE_BUNDLE_NAME "High Fidelity ${BUILD_SEQ}") + endif () + + configure_file( + ${HIFI_CMAKE_DIR}/templates/RenameInterfaceBundle.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/RenameInterfaceBundle.cmake + @ONLY + ) + + set_target_properties(${TARGET_NAME} PROPERTIES POST_INSTALL_SCRIPT "${CMAKE_CURRENT_BINARY_DIR}/RenameInterfaceBundle.cmake") + endif () else (APPLE) # copy the resources files beside the executable add_custom_command(TARGET ${TARGET_NAME} POST_BUILD From e3ef18ae6eb8ac93e53188a87d4cf83e302bb855 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 5 Jan 2016 18:32:08 -0800 Subject: [PATCH 063/357] customize Interface output name for PR/dev/prod --- cmake/macros/SetupHifiPlugin.cmake | 3 +- .../templates/RenameInterfaceBundle.cmake.in | 16 ---------- interface/CMakeLists.txt | 32 ++++++++----------- 3 files changed, 16 insertions(+), 35 deletions(-) delete mode 100644 cmake/templates/RenameInterfaceBundle.cmake.in diff --git a/cmake/macros/SetupHifiPlugin.cmake b/cmake/macros/SetupHifiPlugin.cmake index d8b8c80f9b..2f31ee5d4e 100644 --- a/cmake/macros/SetupHifiPlugin.cmake +++ b/cmake/macros/SetupHifiPlugin.cmake @@ -12,7 +12,8 @@ macro(SETUP_HIFI_PLUGIN) set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Plugins") if (APPLE) - set(PLUGIN_PATH "interface.app/Contents/PlugIns") + get_property(_INTERFACE_BUNDLE_NAME GLOBAL PROPERTY INTERFACE_BUNDLE_NAME) + set(PLUGIN_PATH "${_INTERFACE_BUNDLE_NAME}.app/Contents/PlugIns") else() set(PLUGIN_PATH "plugins") endif() diff --git a/cmake/templates/RenameInterfaceBundle.cmake.in b/cmake/templates/RenameInterfaceBundle.cmake.in deleted file mode 100644 index a579c6efe1..0000000000 --- a/cmake/templates/RenameInterfaceBundle.cmake.in +++ /dev/null @@ -1,16 +0,0 @@ -# -# RenameInterfaceBundle.cmake.in -# cmake/templates -# -# Copyright 2016 High Fidelity, Inc. -# Created by Stephen Birarda on January 5, 2016 -# -# Distributed under the Apache License, Version 2.0. -# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -# - -set(SOURCE_BUNDLE "@CMAKE_INSTALL_PREFIX@/Applications/High Fidelity/interface.app") -set(DESTINATION_BUNDLE "@CMAKE_INSTALL_PREFIX@/Applications/High Fidelity/@INTERFACE_BUNDLE_NAME@.app") -message(STATUS "Renaming ${SOURCE_BUNDLE} to ${DESTINATION_BUNDLE}") - -file(RENAME ${SOURCE_BUNDLE} ${DESTINATION_BUNDLE}) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 91b306dad3..c0fb3c95a2 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -100,6 +100,20 @@ endif() # create the executable, make it a bundle on OS X if (APPLE) add_executable(${TARGET_NAME} MACOSX_BUNDLE ${INTERFACE_SRCS} ${QM}) + + # change the target name to the right thing depending on the type of build this is + # set a global INTERFACE_BUNDLE_NAME property so that we can have plugins copied to the right place + if (PRODUCTION_BUILD) + set(_INTERFACE_BUNDLE_NAME "High Fidelity") + elseif (PR_BUILD) + set(_INTERFACE_BUNDLE_NAME "High Fidelity ${BUILD_SEQ}") + elseif (DEV_BUILD) + set(_INTERFACE_BUNDLE_NAME "Interface") + endif() + + set_property(GLOBAL PROPERTY INTERFACE_BUNDLE_NAME ${_INTERFACE_BUNDLE_NAME}) + + set_target_properties(${TARGET_NAME} PROPERTIES OUTPUT_NAME ${_INTERFACE_BUNDLE_NAME}) elseif(WIN32) add_executable(${TARGET_NAME} WIN32 ${INTERFACE_SRCS} ${QM}) else() @@ -214,24 +228,6 @@ if (APPLE) BUNDLE DESTINATION "Applications/High Fidelity" COMPONENT ${CLIENT_COMPONENT} ) - - if (PRODUCTION_BUILD OR PR_BUILD) - # for a production or PR build, setup rename of produced bundle - # for production builds it becomes "High Fidelity" and PR builds are "High Fidelity" with the PR number - if (PRODUCTION_BUILD) - set(INTERFACE_BUNDLE_NAME "High Fidelity") - elseif (PR_BUILD) - set(INTERFACE_BUNDLE_NAME "High Fidelity ${BUILD_SEQ}") - endif () - - configure_file( - ${HIFI_CMAKE_DIR}/templates/RenameInterfaceBundle.cmake.in - ${CMAKE_CURRENT_BINARY_DIR}/RenameInterfaceBundle.cmake - @ONLY - ) - - set_target_properties(${TARGET_NAME} PROPERTIES POST_INSTALL_SCRIPT "${CMAKE_CURRENT_BINARY_DIR}/RenameInterfaceBundle.cmake") - endif () else (APPLE) # copy the resources files beside the executable add_custom_command(TARGET ${TARGET_NAME} POST_BUILD From cbc0c4e31da46e157f1ea8b9b0a1741b62c875de Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 6 Jan 2016 10:39:55 -0800 Subject: [PATCH 064/357] rename console packaging target --- .../SymlinkOrCopyDirectoryBesideTarget.cmake | 20 +++++++++---------- console/CMakeLists.txt | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/cmake/macros/SymlinkOrCopyDirectoryBesideTarget.cmake b/cmake/macros/SymlinkOrCopyDirectoryBesideTarget.cmake index fe6f5b671e..37a7a9caa0 100644 --- a/cmake/macros/SymlinkOrCopyDirectoryBesideTarget.cmake +++ b/cmake/macros/SymlinkOrCopyDirectoryBesideTarget.cmake @@ -1,5 +1,5 @@ # -# CopyDirectoryBesideTarget.cmake +# CopyDirectoryBesideTarget.cmake # cmake/macros # # Created by Stephen Birarda on 04/30/15. @@ -10,22 +10,22 @@ # macro(SYMLINK_OR_COPY_DIRECTORY_BESIDE_TARGET _SHOULD_SYMLINK _DIRECTORY _DESTINATION) - + # remove the current directory add_custom_command( TARGET ${TARGET_NAME} POST_BUILD COMMAND "${CMAKE_COMMAND}" -E remove_directory $/${_DESTINATION} ) - + if (${_SHOULD_SYMLINK}) - + # first create the destination add_custom_command( TARGET ${TARGET_NAME} POST_BUILD COMMAND "${CMAKE_COMMAND}" -E make_directory $/${_DESTINATION} ) - + # the caller wants a symlink, so just add a command to symlink all contents of _DIRECTORY # in the destination - we can't simply create a symlink for _DESTINATION # because the remove_directory call above would delete the original files @@ -35,20 +35,20 @@ macro(SYMLINK_OR_COPY_DIRECTORY_BESIDE_TARGET _SHOULD_SYMLINK _DIRECTORY _DESTIN foreach(_ITEM ${_DIR_ITEMS}) # get the filename for this item get_filename_component(_ITEM_FILENAME ${_ITEM} NAME) - + # add the command to symlink this item add_custom_command( TARGET ${TARGET_NAME} POST_BUILD COMMAND "${CMAKE_COMMAND}" -E create_symlink ${_ITEM} $/${_DESTINATION}/${_ITEM_FILENAME} - ) - endforeach() + ) + endforeach() else () # copy the directory add_custom_command( - TARGET ${TARGET_NAME} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_directory ${_DIRECTORY} + TARGET ${TARGET_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory ${_DIRECTORY} $/${_DESTINATION} ) endif () diff --git a/console/CMakeLists.txt b/console/CMakeLists.txt index 43933af410..6f813489a1 100644 --- a/console/CMakeLists.txt +++ b/console/CMakeLists.txt @@ -1,4 +1,4 @@ -set(TARGET_NAME package-console) +set(TARGET_NAME packaged-console) if (PRODUCTION_BUILD) set(PRODUCTION_OPTION "--production") From 6c5c3a856b5b94d33d0c2155c87a818a554cc53d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 6 Jan 2016 11:57:39 -0800 Subject: [PATCH 065/357] fix for search paths for distributed server-console --- console/package.json | 4 +-- console/src/main.js | 9 +++--- console/src/modules/path-finder.js | 44 ++++++++++++++++++++++++------ 3 files changed, 41 insertions(+), 16 deletions(-) diff --git a/console/package.json b/console/package.json index 32cbfb58eb..a2c59703ea 100644 --- a/console/package.json +++ b/console/package.json @@ -18,8 +18,8 @@ }, "main": "src/main.js", "scripts": { - "start": "electron . --local-debug-builds --debug", - "local-release": "electron . --local-release-builds --debug", + "start": "electron . --binary-type local-debug --debug", + "local-release": "electron . --binary-type local-release --debug", "packager": "node packager.js" }, "dependencies": { diff --git a/console/src/main.js b/console/src/main.js index 35cedb66ee..7a94062090 100644 --- a/console/src/main.js +++ b/console/src/main.js @@ -128,12 +128,11 @@ var acPath = null; var debug = argv.debug; +var binaryType = argv.binaryType; -if (argv.localDebugBuilds || argv.localReleaseBuilds) { - interfacePath = pathFinder.discoveredPath("Interface", argv.localReleaseBuilds); - dsPath = pathFinder.discoveredPath("domain-server", argv.localReleaseBuilds); - acPath = pathFinder.discoveredPath("assignment-client", argv.localReleaseBuilds); -} +interfacePath = pathFinder.discoveredPath("Interface", binaryType); +dsPath = pathFinder.discoveredPath("domain-server", binaryType); +acPath = pathFinder.discoveredPath("assignment-client", binaryType); function binaryMissingMessage(displayName, executableName, required) { var message = "The " + displayName + " executable was not found.\n"; diff --git a/console/src/modules/path-finder.js b/console/src/modules/path-finder.js index 690389f5f2..c26f3b445f 100644 --- a/console/src/modules/path-finder.js +++ b/console/src/modules/path-finder.js @@ -1,6 +1,6 @@ var fs = require('fs'); -exports.searchPaths = function(name, preferRelease) { +exports.searchPaths = function(name, binaryType) { function platformExtension(name) { if (name == "Interface") { if (process.platform == "darwin") { @@ -16,15 +16,41 @@ exports.searchPaths = function(name, preferRelease) { } var extension = platformExtension(name); - var basePath = "../build/" + name + "/"; + var devBasePath = "../build/" + name + "/"; - return [ - basePath + name + extension, - basePath + (preferRelease ? "Release/" : "Debug/") + name + extension - ]; + var paths = []; + + if (binaryType == "local-release" || binaryType == "local-debug") { + // check in the developer build tree for binaries + paths = [ + devBasePath + name + extension, + devBasePath + (binaryType == "local-release" ? "Release/" : "Debug/") + name + extension + ] + } else { + // check directly beside the binary + paths = [ + __dirname + "/" + name + extension, + ]; + + // check if we're inside an app bundle on OS X + if (process.platform == "darwin") { + var contentPath = ".app/Contents/"; + var contentEndIndex = __dirname.indexOf(contentPath); + + if (contentEndIndex != -1) { + // this is an app bundle, check in Contents/MacOS for the binaries + var appPath = __dirname.substring(0, contentEndIndex); + appPath += ".app/Contents/MacOS/"; + + paths.push(appPath + name + extension); + } + } + } + + return paths; } -exports.discoveredPath = function (name, preferRelease) { +exports.discoveredPath = function (name, binaryType) { function binaryFromPaths(name, paths) { for (var i = 0; i < paths.length; i++) { var path = paths[i]; @@ -37,7 +63,7 @@ exports.discoveredPath = function (name, preferRelease) { return path; } } catch (e) { - console.warn("Executable with name " + name + " not found at path " + path); + console.log("Executable with name " + name + " not found at path " + path); } } @@ -45,5 +71,5 @@ exports.discoveredPath = function (name, preferRelease) { } // attempt to find a binary at the usual paths, return null if it doesn't exist - return binaryFromPaths(name, this.searchPaths(name, preferRelease)); + return binaryFromPaths(name, this.searchPaths(name, binaryType)); } From 35394289a4b150186e2934906ff37fac151c5ca9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 6 Jan 2016 11:58:53 -0800 Subject: [PATCH 066/357] add message for another instance already running --- console/src/main.js | 1 + 1 file changed, 1 insertion(+) diff --git a/console/src/main.js b/console/src/main.js index 7a94062090..3d2896a40d 100644 --- a/console/src/main.js +++ b/console/src/main.js @@ -114,6 +114,7 @@ var shouldQuit = app.makeSingleInstance(function(commandLine, workingDirectory) }); if (shouldQuit) { + console.warn("Another instance of the Server Console is already running - this instance will quit."); app.quit(); return; } From b7154cacd2d7c92c38b1eb241901dfc39734a3b2 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 6 Jan 2016 15:26:41 -0800 Subject: [PATCH 067/357] use shell application to avoid fixup on Electron --- cmake/macros/InstallBesideConsole.cmake | 36 +++++++++++++++++++++++-- console/.gitignore | 1 + console/packager.js | 2 +- 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/cmake/macros/InstallBesideConsole.cmake b/cmake/macros/InstallBesideConsole.cmake index 58885681f8..c0a387b22e 100644 --- a/cmake/macros/InstallBesideConsole.cmake +++ b/cmake/macros/InstallBesideConsole.cmake @@ -12,10 +12,42 @@ macro(install_beside_console) # install this component beside the installed server-console executable if (APPLE) - set(COMPONENT_DESTINATION "Applications/High Fidelity/Server Console.app/Contents/MacOS/") + set(SHELL_APP_CONTENTS "Components.app/Contents") + set(COMPONENT_DESTINATION "${SHELL_APP_CONTENTS}/MacOS") + else () set(COMPONENT_DESTINATION .) endif () - install(TARGETS ${TARGET_NAME} RUNTIME DESTINATION ${COMPONENT_DESTINATION} COMPONENT ${SERVER_COMPONENT}) + install( + TARGETS ${TARGET_NAME} + RUNTIME DESTINATION ${COMPONENT_DESTINATION} + COMPONENT ${SERVER_COMPONENT} + ) + + if (APPLE) + # during the install phase, call fixup to drop the shared libraries for these components in the right place + set(EXECUTABLE_NEEDING_FIXUP "\${CMAKE_INSTALL_PREFIX}/${COMPONENT_DESTINATION}/${TARGET_NAME}") + install(CODE " + include(BundleUtilities) + fixup_bundle(\"${EXECUTABLE_NEEDING_FIXUP}\" \"\" \"${FIXUP_LIBS}\") + " COMPONENT ${SERVER_COMPONENT}) + + # once installed copy the contents of the shell Components.app to the console application + set(CONSOLE_INSTALL_PATH "Applications/High Fidelity/Server Console.app") + set(INSTALLED_CONSOLE_CONTENTS "\${CMAKE_INSTALL_PREFIX}/${CONSOLE_INSTALL_PATH}/Contents") + + set(INSTALLED_SHELL_CONTENTS "\${CMAKE_INSTALL_PREFIX}/${SHELL_APP_CONTENTS}") + install(CODE " + message(STATUS \"CHECKING ${INSTALLED_SHELL_CONTENTS}/Frameworks/*\") + file(GLOB FRAMEWORKS \"${INSTALLED_SHELL_CONTENTS}/Frameworks/*\") + message(STATUS \"Copying \${FRAMEWORKS} to ${INSTALLED_CONSOLE_CONTENTS}/Frameworks\") + file(COPY \${FRAMEWORKS} DESTINATION \"${INSTALLED_CONSOLE_CONTENTS}/Frameworks\") + file(GLOB BINARIES \"${INSTALLED_SHELL_CONTENTS}/MacOS/*\") + message(STATUS \"Copying \${BINARIES} to ${INSTALLED_CONSOLE_CONTENTS}/Frameworks\") + file(COPY \${BINARIES} DESTINATION \"${INSTALLED_CONSOLE_CONTENTS}/MacOS\") + " COMPONENT ${SERVER_COMPONENT}) + + endif () + endmacro() diff --git a/console/.gitignore b/console/.gitignore index de75c10412..1624823e80 100644 --- a/console/.gitignore +++ b/console/.gitignore @@ -1,4 +1,5 @@ Server\ Console-*/ server-console-*/ +electron-packager/ npm-debug.log logs/ diff --git a/console/packager.js b/console/packager.js index 2489436857..341ae0c1a7 100644 --- a/console/packager.js +++ b/console/packager.js @@ -23,7 +23,7 @@ var options = { arch: "x64", platform: platform, icon: "resources/" + iconName, - ignore: "logs|(S|s)erver(\\s|-)(C|c)onsole-\\S+" + ignore: "logs|(S|s)erver(\\s|-)(C|c)onsole-\\S+|electron-packager" } const EXEC_NAME = "server-console"; From 71307c12809bc516d70a1cd4877118e8c26abf2d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 6 Jan 2016 15:29:44 -0800 Subject: [PATCH 068/357] remove extra debug from shell application copy --- cmake/macros/InstallBesideConsole.cmake | 1 - 1 file changed, 1 deletion(-) diff --git a/cmake/macros/InstallBesideConsole.cmake b/cmake/macros/InstallBesideConsole.cmake index c0a387b22e..8514a89aa2 100644 --- a/cmake/macros/InstallBesideConsole.cmake +++ b/cmake/macros/InstallBesideConsole.cmake @@ -39,7 +39,6 @@ macro(install_beside_console) set(INSTALLED_SHELL_CONTENTS "\${CMAKE_INSTALL_PREFIX}/${SHELL_APP_CONTENTS}") install(CODE " - message(STATUS \"CHECKING ${INSTALLED_SHELL_CONTENTS}/Frameworks/*\") file(GLOB FRAMEWORKS \"${INSTALLED_SHELL_CONTENTS}/Frameworks/*\") message(STATUS \"Copying \${FRAMEWORKS} to ${INSTALLED_CONSOLE_CONTENTS}/Frameworks\") file(COPY \${FRAMEWORKS} DESTINATION \"${INSTALLED_CONSOLE_CONTENTS}/Frameworks\") From 3906a4fe387cdf4225b673c1c01d4a22a3e42e30 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 6 Jan 2016 15:38:03 -0800 Subject: [PATCH 069/357] drop the resources folder for DS beside executable --- cmake/macros/InstallBesideConsole.cmake | 20 +++++++++++++++++--- cmake/macros/SetPackagingParameters.cmake | 6 ++++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/cmake/macros/InstallBesideConsole.cmake b/cmake/macros/InstallBesideConsole.cmake index 8514a89aa2..f23b037221 100644 --- a/cmake/macros/InstallBesideConsole.cmake +++ b/cmake/macros/InstallBesideConsole.cmake @@ -14,9 +14,8 @@ macro(install_beside_console) if (APPLE) set(SHELL_APP_CONTENTS "Components.app/Contents") set(COMPONENT_DESTINATION "${SHELL_APP_CONTENTS}/MacOS") - else () - set(COMPONENT_DESTINATION .) + set(COMPONENT_DESTINATION ${CONSOLE_INSTALL_PATH}) endif () install( @@ -25,6 +24,21 @@ macro(install_beside_console) COMPONENT ${SERVER_COMPONENT} ) + if (TARGET_NAME STREQUAL domain-server) + if (APPLE) + set(RESOURCES_DESTINATION ${CONSOLE_INSTALL_PATH}/Contents/MacOS) + else () + set(RESOURCES_DESTINATION ${CONSOLE_INSTALL_PATH}) + endif () + + # install the resources folder for the domain-server where its executable will be + install( + DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/resources + DESTINATION ${RESOURCES_DESTINATION} + USE_SOURCE_PERMISSIONS + ) + endif () + if (APPLE) # during the install phase, call fixup to drop the shared libraries for these components in the right place set(EXECUTABLE_NEEDING_FIXUP "\${CMAKE_INSTALL_PREFIX}/${COMPONENT_DESTINATION}/${TARGET_NAME}") @@ -34,7 +48,7 @@ macro(install_beside_console) " COMPONENT ${SERVER_COMPONENT}) # once installed copy the contents of the shell Components.app to the console application - set(CONSOLE_INSTALL_PATH "Applications/High Fidelity/Server Console.app") + set(INSTALLED_CONSOLE_CONTENTS "\${CMAKE_INSTALL_PREFIX}/${CONSOLE_INSTALL_PATH}/Contents") set(INSTALLED_SHELL_CONTENTS "\${CMAKE_INSTALL_PREFIX}/${SHELL_APP_CONTENTS}") diff --git a/cmake/macros/SetPackagingParameters.cmake b/cmake/macros/SetPackagingParameters.cmake index 37e7d3bf3c..f68a69e688 100644 --- a/cmake/macros/SetPackagingParameters.cmake +++ b/cmake/macros/SetPackagingParameters.cmake @@ -13,6 +13,12 @@ macro(SET_PACKAGING_PARAMETERS) + if (APPLE) + set(CONSOLE_INSTALL_PATH "Applications/High Fidelity/Server Console.app") + else () + set(CONSOLE_INSTALL_PATH ".") + endif() + if (DEFINED ENV{JOB_ID}) set(DEPLOY_PACKAGE TRUE) set(BUILD_SEQ $ENV{JOB_ID}) From d9db64dc91623ad106a18b7ddb4d189d5e567732 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 6 Jan 2016 17:10:32 -0800 Subject: [PATCH 070/357] add npm-debug to global gitignore --- .gitignore | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 5a1587abd6..4a1c1c227b 100644 --- a/.gitignore +++ b/.gitignore @@ -36,7 +36,7 @@ interface/external/*/* # Ignore interfaceCache for Linux users interface/interfaceCache/ -# ignore audio-client externals +# ignore audio-client externals libraries/audio-client/external/*/* !libraries/audio-client/external/*/readme.txt @@ -48,4 +48,5 @@ TAGS *.swp # ignore node files for the console -node_modules \ No newline at end of file +node_modules +npm-debug.log From 817d651c47251fb97155391f5ee5497f8efa6428 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 6 Jan 2016 17:10:57 -0800 Subject: [PATCH 071/357] add initial fixup install commands for interface --- CMakeLists.txt | 2 ++ cmake/macros/FixupInterface.cmake | 57 +++++++++++++++++++++++++++++++ interface/CMakeLists.txt | 4 +++ 3 files changed, 63 insertions(+) create mode 100644 cmake/macros/FixupInterface.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 0a763cb064..73626323dd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -115,6 +115,8 @@ else () endif () endif () +set(QT_DIR $ENV{QT_DIR}) + if (WIN32) if (NOT EXISTS ${QT_CMAKE_PREFIX_PATH}) message(FATAL_ERROR "Could not determine QT_CMAKE_PREFIX_PATH.") diff --git a/cmake/macros/FixupInterface.cmake b/cmake/macros/FixupInterface.cmake new file mode 100644 index 0000000000..d3873a55f5 --- /dev/null +++ b/cmake/macros/FixupInterface.cmake @@ -0,0 +1,57 @@ +# +# FixupInterface.cmake +# cmake/macros +# +# Copyright 2016 High Fidelity, Inc. +# Created by Stephen Birarda on January 6th, 2016 +# +# Distributed under the Apache License, Version 2.0. +# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +# + +macro(fixup_interface) + if (APPLE) + + string(REPLACE " " "\\" ESCAPED_BUNDLE_NAME ${_INTERFACE_BUNDLE_NAME}) + set(INTERFACE_INSTALL_PATH "Applications/High\\ Fidelity/${ESCAPED_BUNDLE_NAME}.app") + + # install QtWebProcess from Qt to the application bundle + # since it is missed by macdeployqt + # https://bugreports.qt.io/browse/QTBUG-35211 + set(LIBEXEC_PATH "${INTERFACE_INSTALL_PATH}/Contents/libexec") + install( + PROGRAMS "${QT_DIR}/libexec/QtWebProcess" + DESTINATION ${LIBEXEC_PATH} + COMPONENT ${CLIENT_COMPONENT} + ) + + set(QTWEBPROCESS_PATH "\${CMAKE_INSTALL_PREFIX}/${LIBEXEC_PATH}") + + # we also need a qt.conf in the directory of QtWebProcess + install(CODE " + file(WRITE ${QTWEBPROCESS_PATH}/qt.conf + \"[Paths]\nPlugins = ../PlugIns\nImports = ../Resources/qml\nQml2Imports = ../Resources/qml\" + )" + COMPONENT ${CLIENT_COMPONENT} + ) + + find_program(MACDEPLOYQT_COMMAND macdeployqt PATHS "${QT_DIR}/bin" NO_DEFAULT_PATH) + + if (NOT MACDEPLOYQT_COMMAND AND (PRODUCTION_BUILD OR PR_BUILD)) + message(FATAL_ERROR "Could not find macdeployqt at ${QT_DIR}/bin.\ + It is required to produce an relocatable interface application.\ + Check that the environment variable QT_DIR points to your Qt installation.\ + ") + endif () + + install(CODE " + execute_process(COMMAND ${MACDEPLOYQT_COMMAND}\ + \${CMAKE_INSTALL_PREFIX}/${INTERFACE_INSTALL_PATH}/\ + -verbose=2 -qmldir=${CMAKE_SOURCE_DIR}/interface/resources/qml/\ + -executable=\${CMAKE_INSTALL_PREFIX}/${INTERFACE_INSTALL_PATH}/Contents/libexec/QtWebProcess\ + )" + COMPONENT ${CLIENT_COMPONENT} + ) + + endif () +endmacro() diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index c0fb3c95a2..2fb5d8c33c 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -228,6 +228,7 @@ if (APPLE) BUNDLE DESTINATION "Applications/High Fidelity" COMPONENT ${CLIENT_COMPONENT} ) + else (APPLE) # copy the resources files beside the executable add_custom_command(TARGET ${TARGET_NAME} POST_BUILD @@ -248,6 +249,9 @@ else (APPLE) endif() endif (APPLE) +# call the fixup_interface macro to add required bundling commands for installation +fixup_interface() + if (WIN32) set(EXTRA_DEPLOY_OPTIONS "--qmldir ${PROJECT_SOURCE_DIR}/resources/qml") endif() From 4f00982724d176fe841ccba15dfbaf43f167a8a0 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 6 Jan 2016 18:01:54 -0800 Subject: [PATCH 072/357] remove extraneous add dependency for FIXUP_LIB --- cmake/macros/TargetSixense.cmake | 6 +++--- interface/CMakeLists.txt | 4 ---- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/cmake/macros/TargetSixense.cmake b/cmake/macros/TargetSixense.cmake index b52af9cdd2..6fd9cede1f 100644 --- a/cmake/macros/TargetSixense.cmake +++ b/cmake/macros/TargetSixense.cmake @@ -1,14 +1,14 @@ -# +# # Copyright 2015 High Fidelity, Inc. # Created by Bradley Austin Davis on 2015/10/10 # # Distributed under the Apache License, Version 2.0. # See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -# +# macro(TARGET_SIXENSE) add_dependency_external_projects(sixense) find_package(Sixense REQUIRED) target_include_directories(${TARGET_NAME} PRIVATE ${SIXENSE_INCLUDE_DIRS}) target_link_libraries(${TARGET_NAME} ${SIXENSE_LIBRARIES}) add_definitions(-DHAVE_SIXENSE) -endmacro() \ No newline at end of file +endmacro() diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 2fb5d8c33c..e3dd4529d3 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -122,10 +122,6 @@ endif() target_include_directories(${TARGET_NAME} PRIVATE "${CMAKE_BINARY_DIR}/includes") -# These are external plugins, but we need to do the 'add dependency' here so that their -# binary directories get added to the fixup path -add_dependency_external_projects(sixense) -add_dependency_external_projects(sdl2) if (WIN32) add_dependency_external_projects(OpenVR) endif() From 55886d43f5717b00ae56a8c68de4a9e56933e001 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 7 Jan 2016 11:56:02 -0800 Subject: [PATCH 073/357] add DDE component as downloadable optional --- CMakeLists.txt | 4 --- cmake/macros/FixupInterface.cmake | 13 +++++---- cmake/macros/GenerateInstallers.cmake | 33 +++++++++++++++++++++-- cmake/macros/InstallBesideConsole.cmake | 8 +++--- cmake/macros/SetPackagingParameters.cmake | 27 ++++++++++++++----- cmake/macros/SetupHifiPlugin.cmake | 3 +-- interface/CMakeLists.txt | 27 +++++++++---------- 7 files changed, 77 insertions(+), 38 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 73626323dd..83ab275d28 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -213,10 +213,6 @@ endif() set_packaging_parameters() -# setup component categories for installer -set(CLIENT_COMPONENT client) -set(SERVER_COMPONENT server) - # add subdirectories for all targets if (NOT ANDROID) add_subdirectory(assignment-client) diff --git a/cmake/macros/FixupInterface.cmake b/cmake/macros/FixupInterface.cmake index d3873a55f5..1e2e6cc081 100644 --- a/cmake/macros/FixupInterface.cmake +++ b/cmake/macros/FixupInterface.cmake @@ -12,13 +12,16 @@ macro(fixup_interface) if (APPLE) - string(REPLACE " " "\\" ESCAPED_BUNDLE_NAME ${_INTERFACE_BUNDLE_NAME}) - set(INTERFACE_INSTALL_PATH "Applications/High\\ Fidelity/${ESCAPED_BUNDLE_NAME}.app") + string(REPLACE " " "\\ " ESCAPED_BUNDLE_NAME ${INTERFACE_BUNDLE_NAME}) + string(REPLACE " " "\\ " ESCAPED_INSTALL_PATH ${INTERFACE_INSTALL_DIR}) + set(_INTERFACE_INSTALL_PATH "${ESCAPED_INSTALL_PATH}/${ESCAPED_BUNDLE_NAME}.app") + + message(${_INTERFACE_INSTALL_PATH}) # install QtWebProcess from Qt to the application bundle # since it is missed by macdeployqt # https://bugreports.qt.io/browse/QTBUG-35211 - set(LIBEXEC_PATH "${INTERFACE_INSTALL_PATH}/Contents/libexec") + set(LIBEXEC_PATH "${_INTERFACE_INSTALL_PATH}/Contents/libexec") install( PROGRAMS "${QT_DIR}/libexec/QtWebProcess" DESTINATION ${LIBEXEC_PATH} @@ -46,9 +49,9 @@ macro(fixup_interface) install(CODE " execute_process(COMMAND ${MACDEPLOYQT_COMMAND}\ - \${CMAKE_INSTALL_PREFIX}/${INTERFACE_INSTALL_PATH}/\ + \${CMAKE_INSTALL_PREFIX}/${_INTERFACE_INSTALL_PATH}/\ -verbose=2 -qmldir=${CMAKE_SOURCE_DIR}/interface/resources/qml/\ - -executable=\${CMAKE_INSTALL_PREFIX}/${INTERFACE_INSTALL_PATH}/Contents/libexec/QtWebProcess\ + -executable=\${CMAKE_INSTALL_PREFIX}/${_INTERFACE_INSTALL_PATH}/Contents/libexec/QtWebProcess\ )" COMPONENT ${CLIENT_COMPONENT} ) diff --git a/cmake/macros/GenerateInstallers.cmake b/cmake/macros/GenerateInstallers.cmake index 3645f1bc7f..cbe95f15f9 100644 --- a/cmake/macros/GenerateInstallers.cmake +++ b/cmake/macros/GenerateInstallers.cmake @@ -20,10 +20,39 @@ macro(GENERATE_INSTALLERS) set(CPACK_PACKAGING_INSTALL_PREFIX /) endif () - cpack_add_component(${CLIENT_COMPONENT} - DISPLAY_NAME "High Fidelity Client" + # setup downloads + cpack_configure_downloads( + http://hifi-production.s3.amazonaws.com/optionals/ + ADD_REMOVE ) + set(CLIENT_GROUP client) + + # add a component group for the client + cpack_add_component_group( + ${CLIENT_GROUP} + DISPLAY_NAME "Client" + EXPANDED + ) + + cpack_add_component( + ${CLIENT_COMPONENT} + DISPLAY_NAME "High Fidelity Client" + GROUP ${CLIENT_GROUP} + ) + + if (DDE_APP_PATH) + # add a download component for DDE + cpack_add_component( + ${DDE_COMPONENT} + DISPLAY_NAME "Webcam Body Movement" + DEPENDS ${CLIENT_COMPONENT} + GROUP ${CLIENT_GROUP} + DOWNLOADED + ARCHIVE_FILE "DDE" + ) + endif () + cpack_add_component(${SERVER_COMPONENT} DISPLAY_NAME "High Fidelity Server" ) diff --git a/cmake/macros/InstallBesideConsole.cmake b/cmake/macros/InstallBesideConsole.cmake index f23b037221..54d3272c7a 100644 --- a/cmake/macros/InstallBesideConsole.cmake +++ b/cmake/macros/InstallBesideConsole.cmake @@ -15,7 +15,7 @@ macro(install_beside_console) set(SHELL_APP_CONTENTS "Components.app/Contents") set(COMPONENT_DESTINATION "${SHELL_APP_CONTENTS}/MacOS") else () - set(COMPONENT_DESTINATION ${CONSOLE_INSTALL_PATH}) + set(COMPONENT_DESTINATION ${CONSOLE_INSTALL_DIR}) endif () install( @@ -26,9 +26,9 @@ macro(install_beside_console) if (TARGET_NAME STREQUAL domain-server) if (APPLE) - set(RESOURCES_DESTINATION ${CONSOLE_INSTALL_PATH}/Contents/MacOS) + set(RESOURCES_DESTINATION ${CONSOLE_INSTALL_APP_PATH}/Contents/MacOS) else () - set(RESOURCES_DESTINATION ${CONSOLE_INSTALL_PATH}) + set(RESOURCES_DESTINATION ${CONSOLE_INSTALL_DIR}) endif () # install the resources folder for the domain-server where its executable will be @@ -49,7 +49,7 @@ macro(install_beside_console) # once installed copy the contents of the shell Components.app to the console application - set(INSTALLED_CONSOLE_CONTENTS "\${CMAKE_INSTALL_PREFIX}/${CONSOLE_INSTALL_PATH}/Contents") + set(INSTALLED_CONSOLE_CONTENTS "\${CMAKE_INSTALL_PREFIX}/${CONSOLE_INSTALL_APP_PATH}/Contents") set(INSTALLED_SHELL_CONTENTS "\${CMAKE_INSTALL_PREFIX}/${SHELL_APP_CONTENTS}") install(CODE " diff --git a/cmake/macros/SetPackagingParameters.cmake b/cmake/macros/SetPackagingParameters.cmake index f68a69e688..a5c65b1dc5 100644 --- a/cmake/macros/SetPackagingParameters.cmake +++ b/cmake/macros/SetPackagingParameters.cmake @@ -12,13 +12,6 @@ # and decides how targets should be packaged. macro(SET_PACKAGING_PARAMETERS) - - if (APPLE) - set(CONSOLE_INSTALL_PATH "Applications/High Fidelity/Server Console.app") - else () - set(CONSOLE_INSTALL_PATH ".") - endif() - if (DEFINED ENV{JOB_ID}) set(DEPLOY_PACKAGE TRUE) set(BUILD_SEQ $ENV{JOB_ID}) @@ -26,6 +19,7 @@ macro(SET_PACKAGING_PARAMETERS) set(INSTALLER_COMPANY "High Fidelity") set(INSTALLER_DIRECTORY "${INSTALLER_COMPANY}") set(INSTALLER_NAME "interface-win64-${BUILD_SEQ}.exe") + set(INTERFACE_BUNDLE_NAME "High Fidelity") set(INTERFACE_ICON "interface.ico") set(CONSOLE_ICON "console.ico") elseif (DEFINED ENV{ghprbPullId}) @@ -35,6 +29,7 @@ macro(SET_PACKAGING_PARAMETERS) set(INSTALLER_COMPANY "High Fidelity - PR") set(INSTALLER_DIRECTORY "${INSTALLER_COMPANY}\\${BUILD_SEQ}") set(INSTALLER_NAME "pr-interface-win64-${BUILD_SEQ}.exe") + set(INTERFACE_BUNDLE_NAME "High Fidelity ${BUILD_SEQ}") set(INTERFACE_ICON "interface-beta.ico") set(CONSOLE_ICON "console-beta.ico") else () @@ -43,10 +38,28 @@ macro(SET_PACKAGING_PARAMETERS) set(INSTALLER_COMPANY "High Fidelity - Dev") set(INSTALLER_DIRECTORY "${INSTALLER_COMPANY}") set(INSTALLER_NAME "dev-interface-win64.exe") + set(INTERFACE_BUNDLE_NAME "Interface") set(INTERFACE_ICON "interface-beta.ico") set(CONSOLE_ICON "console-beta.ico") endif () + if (APPLE) + set(CONSOLE_INSTALL_DIR "Applications/High Fidelity") + set(CONSOLE_APPLICATION_NAME "Server Console.app") + set(CONSOLE_INSTALL_APP_PATH "${CONSOLE_INSTALL_DIR}/${CONSOLE_APPLICATION_NAME}") + + set(INTERFACE_INSTALL_DIR "Applications/High Fidelity") + set(INTERFACE_INSTALL_APP_PATH "${INTERFACE_INSTALL_DIR}/${INTERFACE_BUNDLE_NAME}.app") + else () + set(CONSOLE_INSTALL_DIR ".") + set(INTERFACE_INSTALL_DIR ".") + endif() + + # setup component categories for installer + set(DDE_COMPONENT dde) + set(CLIENT_COMPONENT client) + set(SERVER_COMPONENT server) + # create a header file our targets can use to find out the application version file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/includes") configure_file("${MACRO_DIR}/ApplicationVersion.h.in" "${CMAKE_BINARY_DIR}/includes/ApplicationVersion.h") diff --git a/cmake/macros/SetupHifiPlugin.cmake b/cmake/macros/SetupHifiPlugin.cmake index 2f31ee5d4e..e9c8688590 100644 --- a/cmake/macros/SetupHifiPlugin.cmake +++ b/cmake/macros/SetupHifiPlugin.cmake @@ -12,8 +12,7 @@ macro(SETUP_HIFI_PLUGIN) set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Plugins") if (APPLE) - get_property(_INTERFACE_BUNDLE_NAME GLOBAL PROPERTY INTERFACE_BUNDLE_NAME) - set(PLUGIN_PATH "${_INTERFACE_BUNDLE_NAME}.app/Contents/PlugIns") + set(PLUGIN_PATH "${INTERFACE_BUNDLE_NAME}.app/Contents/PlugIns") else() set(PLUGIN_PATH "plugins") endif() diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index e3dd4529d3..fdae3da232 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -101,19 +101,8 @@ endif() if (APPLE) add_executable(${TARGET_NAME} MACOSX_BUNDLE ${INTERFACE_SRCS} ${QM}) - # change the target name to the right thing depending on the type of build this is - # set a global INTERFACE_BUNDLE_NAME property so that we can have plugins copied to the right place - if (PRODUCTION_BUILD) - set(_INTERFACE_BUNDLE_NAME "High Fidelity") - elseif (PR_BUILD) - set(_INTERFACE_BUNDLE_NAME "High Fidelity ${BUILD_SEQ}") - elseif (DEV_BUILD) - set(_INTERFACE_BUNDLE_NAME "Interface") - endif() - - set_property(GLOBAL PROPERTY INTERFACE_BUNDLE_NAME ${_INTERFACE_BUNDLE_NAME}) - - set_target_properties(${TARGET_NAME} PROPERTIES OUTPUT_NAME ${_INTERFACE_BUNDLE_NAME}) + # make sure the output name for the .app bundle is correct + set_target_properties(${TARGET_NAME} PROPERTIES OUTPUT_NAME ${INTERFACE_BUNDLE_NAME}) elseif(WIN32) add_executable(${TARGET_NAME} WIN32 ${INTERFACE_SRCS} ${QM}) else() @@ -221,7 +210,7 @@ if (APPLE) # setup install of OS X interface bundle install(TARGETS ${TARGET_NAME} - BUNDLE DESTINATION "Applications/High Fidelity" + BUNDLE DESTINATION ${INTERFACE_INSTALL_DIR} COMPONENT ${CLIENT_COMPONENT} ) @@ -248,6 +237,16 @@ endif (APPLE) # call the fixup_interface macro to add required bundling commands for installation fixup_interface() +# if present, add an install of the DDE components +# which will be presented as an option during install +if (APPLE AND DDE_APP_PATH) + install( + PROGRAMS ${DDE_APP_PATH} + DESTINATION ${INTERFACE_INSTALL_PATH}/Contents/MacOS + COMPONENT ${DDE_COMPONENT} + ) +endif () + if (WIN32) set(EXTRA_DEPLOY_OPTIONS "--qmldir ${PROJECT_SOURCE_DIR}/resources/qml") endif() From 86facc15d1cdf66f8793a8c28f1e23a13d4472ad Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 7 Jan 2016 11:56:18 -0800 Subject: [PATCH 074/357] remove debug message in fixup_interface macro --- cmake/macros/FixupInterface.cmake | 2 -- 1 file changed, 2 deletions(-) diff --git a/cmake/macros/FixupInterface.cmake b/cmake/macros/FixupInterface.cmake index 1e2e6cc081..3e5ea7a3e2 100644 --- a/cmake/macros/FixupInterface.cmake +++ b/cmake/macros/FixupInterface.cmake @@ -16,8 +16,6 @@ macro(fixup_interface) string(REPLACE " " "\\ " ESCAPED_INSTALL_PATH ${INTERFACE_INSTALL_DIR}) set(_INTERFACE_INSTALL_PATH "${ESCAPED_INSTALL_PATH}/${ESCAPED_BUNDLE_NAME}.app") - message(${_INTERFACE_INSTALL_PATH}) - # install QtWebProcess from Qt to the application bundle # since it is missed by macdeployqt # https://bugreports.qt.io/browse/QTBUG-35211 From dedb7e277847c79104a5b2dd625adc0f9cb7d7c3 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 7 Jan 2016 13:40:57 -0800 Subject: [PATCH 075/357] bury components in a shell application inside the server-console --- cmake/macros/InstallBesideConsole.cmake | 22 ++++------------------ console/src/modules/path-finder.js | 2 +- interface/CMakeLists.txt | 7 ++++--- 3 files changed, 9 insertions(+), 22 deletions(-) diff --git a/cmake/macros/InstallBesideConsole.cmake b/cmake/macros/InstallBesideConsole.cmake index 54d3272c7a..7e03b40ce6 100644 --- a/cmake/macros/InstallBesideConsole.cmake +++ b/cmake/macros/InstallBesideConsole.cmake @@ -12,8 +12,8 @@ macro(install_beside_console) # install this component beside the installed server-console executable if (APPLE) - set(SHELL_APP_CONTENTS "Components.app/Contents") - set(COMPONENT_DESTINATION "${SHELL_APP_CONTENTS}/MacOS") + set(CONSOLE_APP_CONTENTS "${CONSOLE_INSTALL_APP_PATH}/Contents") + set(COMPONENT_DESTINATION "${CONSOLE_APP_CONTENTS}/MacOS/Components.app/Contents/MacOS") else () set(COMPONENT_DESTINATION ${CONSOLE_INSTALL_DIR}) endif () @@ -26,7 +26,7 @@ macro(install_beside_console) if (TARGET_NAME STREQUAL domain-server) if (APPLE) - set(RESOURCES_DESTINATION ${CONSOLE_INSTALL_APP_PATH}/Contents/MacOS) + set(RESOURCES_DESTINATION ${COMPONENT_DESTINATION}) else () set(RESOURCES_DESTINATION ${CONSOLE_INSTALL_DIR}) endif () @@ -36,6 +36,7 @@ macro(install_beside_console) DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/resources DESTINATION ${RESOURCES_DESTINATION} USE_SOURCE_PERMISSIONS + COMPONENT ${SERVER_COMPONENT} ) endif () @@ -46,21 +47,6 @@ macro(install_beside_console) include(BundleUtilities) fixup_bundle(\"${EXECUTABLE_NEEDING_FIXUP}\" \"\" \"${FIXUP_LIBS}\") " COMPONENT ${SERVER_COMPONENT}) - - # once installed copy the contents of the shell Components.app to the console application - - set(INSTALLED_CONSOLE_CONTENTS "\${CMAKE_INSTALL_PREFIX}/${CONSOLE_INSTALL_APP_PATH}/Contents") - - set(INSTALLED_SHELL_CONTENTS "\${CMAKE_INSTALL_PREFIX}/${SHELL_APP_CONTENTS}") - install(CODE " - file(GLOB FRAMEWORKS \"${INSTALLED_SHELL_CONTENTS}/Frameworks/*\") - message(STATUS \"Copying \${FRAMEWORKS} to ${INSTALLED_CONSOLE_CONTENTS}/Frameworks\") - file(COPY \${FRAMEWORKS} DESTINATION \"${INSTALLED_CONSOLE_CONTENTS}/Frameworks\") - file(GLOB BINARIES \"${INSTALLED_SHELL_CONTENTS}/MacOS/*\") - message(STATUS \"Copying \${BINARIES} to ${INSTALLED_CONSOLE_CONTENTS}/Frameworks\") - file(COPY \${BINARIES} DESTINATION \"${INSTALLED_CONSOLE_CONTENTS}/MacOS\") - " COMPONENT ${SERVER_COMPONENT}) - endif () endmacro() diff --git a/console/src/modules/path-finder.js b/console/src/modules/path-finder.js index c26f3b445f..e12037a26d 100644 --- a/console/src/modules/path-finder.js +++ b/console/src/modules/path-finder.js @@ -40,7 +40,7 @@ exports.searchPaths = function(name, binaryType) { if (contentEndIndex != -1) { // this is an app bundle, check in Contents/MacOS for the binaries var appPath = __dirname.substring(0, contentEndIndex); - appPath += ".app/Contents/MacOS/"; + appPath += ".app/Contents/MacOS/Components.app/Contents/MacOS/"; paths.push(appPath + name + extension); } diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index fdae3da232..8e61f3a6de 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -239,10 +239,11 @@ fixup_interface() # if present, add an install of the DDE components # which will be presented as an option during install -if (APPLE AND DDE_APP_PATH) +if (APPLE AND DEFINED ENV{DDE_APP_PATH}) install( - PROGRAMS ${DDE_APP_PATH} - DESTINATION ${INTERFACE_INSTALL_PATH}/Contents/MacOS + DIRECTORY $ENV{DDE_APP_PATH} + DIRECTORY_PERMISSIONS + DESTINATION ${INTERFACE_INSTALL_APP_PATH}/Contents/MacOS COMPONENT ${DDE_COMPONENT} ) endif () From 1a10d2eb72e176ecfc1068bd7f99a94777e67b75 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 7 Jan 2016 14:10:33 -0800 Subject: [PATCH 076/357] switch to a DragNDrop installer for OS X --- cmake/macros/GenerateInstallers.cmake | 15 +++++++-------- cmake/macros/SetPackagingParameters.cmake | 8 ++++---- console/CMakeLists.txt | 2 +- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/cmake/macros/GenerateInstallers.cmake b/cmake/macros/GenerateInstallers.cmake index cbe95f15f9..cea767fec9 100644 --- a/cmake/macros/GenerateInstallers.cmake +++ b/cmake/macros/GenerateInstallers.cmake @@ -18,6 +18,7 @@ macro(GENERATE_INSTALLERS) if (APPLE) set(CPACK_PACKAGE_INSTALL_DIRECTORY "/") set(CPACK_PACKAGING_INSTALL_PREFIX /) + set(CPACK_OSX_PACKAGE_VERSION ${CMAKE_OSX_DEPLOYMENT_TARGET}) endif () # setup downloads @@ -29,25 +30,23 @@ macro(GENERATE_INSTALLERS) set(CLIENT_GROUP client) # add a component group for the client - cpack_add_component_group( - ${CLIENT_GROUP} - DISPLAY_NAME "Client" - EXPANDED - ) + # cpack_add_component_group( + # ${CLIENT_GROUP} + # DISPLAY_NAME "Client" + # EXPANDED + # ) cpack_add_component( ${CLIENT_COMPONENT} DISPLAY_NAME "High Fidelity Client" - GROUP ${CLIENT_GROUP} ) - if (DDE_APP_PATH) + if (WIN32 AND DDE_APP_PATH) # add a download component for DDE cpack_add_component( ${DDE_COMPONENT} DISPLAY_NAME "Webcam Body Movement" DEPENDS ${CLIENT_COMPONENT} - GROUP ${CLIENT_GROUP} DOWNLOADED ARCHIVE_FILE "DDE" ) diff --git a/cmake/macros/SetPackagingParameters.cmake b/cmake/macros/SetPackagingParameters.cmake index a5c65b1dc5..142f7fcc8c 100644 --- a/cmake/macros/SetPackagingParameters.cmake +++ b/cmake/macros/SetPackagingParameters.cmake @@ -44,12 +44,12 @@ macro(SET_PACKAGING_PARAMETERS) endif () if (APPLE) - set(CONSOLE_INSTALL_DIR "Applications/High Fidelity") + set(CONSOLE_INSTALL_DIR ".") set(CONSOLE_APPLICATION_NAME "Server Console.app") - set(CONSOLE_INSTALL_APP_PATH "${CONSOLE_INSTALL_DIR}/${CONSOLE_APPLICATION_NAME}") + set(CONSOLE_INSTALL_APP_PATH "${CONSOLE_APPLICATION_NAME}") - set(INTERFACE_INSTALL_DIR "Applications/High Fidelity") - set(INTERFACE_INSTALL_APP_PATH "${INTERFACE_INSTALL_DIR}/${INTERFACE_BUNDLE_NAME}.app") + set(INTERFACE_INSTALL_DIR ".") + set(INTERFACE_INSTALL_APP_PATH "${INTERFACE_BUNDLE_NAME}.app") else () set(CONSOLE_INSTALL_DIR ".") set(INTERFACE_INSTALL_DIR ".") diff --git a/console/CMakeLists.txt b/console/CMakeLists.txt index 6f813489a1..be02fe5fcf 100644 --- a/console/CMakeLists.txt +++ b/console/CMakeLists.txt @@ -25,7 +25,7 @@ endif () # install the packaged Server Console install( PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/${PACKAGED_CONSOLE_FOLDER}/Server Console.app" - DESTINATION "Applications/High Fidelity" + DESTINATION ${CONSOLE_INSTALL_DIR} COMPONENT ${SERVER_COMPONENT} ) From 718e99405025c5681e7eeb2275970a6ae2e2a98b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 7 Jan 2016 14:23:34 -0800 Subject: [PATCH 077/357] fix for faceshift library name on OS X --- cmake/externals/faceshift/CMakeLists.txt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cmake/externals/faceshift/CMakeLists.txt b/cmake/externals/faceshift/CMakeLists.txt index 14e6851c77..28fbffec34 100644 --- a/cmake/externals/faceshift/CMakeLists.txt +++ b/cmake/externals/faceshift/CMakeLists.txt @@ -29,13 +29,11 @@ if (WIN32) set(LIBRARY_EXT "lib") elseif (APPLE) set(LIBRARY_EXT "a") + set(LIBRARY_PREFIX "lib") if (CMAKE_GENERATOR STREQUAL "Unix Makefiles") - set(LIBRARY_PREFIX "lib") set(LIBRARY_DEBUG_PATH "build") set(LIBRARY_RELEASE_PATH "build") - else () - set(LIBRARY_PREFIX "") endif () endif() From 275fa1c5c74f087a794cbf8f0590beea91736385 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 7 Jan 2016 14:35:30 -0800 Subject: [PATCH 078/357] fix for override warnings with clang on OS X --- interface/src/Application.h | 92 +++++++++---------- interface/src/avatar/AvatarActionHold.h | 2 +- .../src/RenderableEntityItem.h | 6 +- .../src/RenderablePolyLineEntityItem.h | 12 +-- libraries/physics/src/ObjectAction.h | 4 +- .../src/AbstractViewStateInterface.h | 2 +- 6 files changed, 59 insertions(+), 59 deletions(-) diff --git a/interface/src/Application.h b/interface/src/Application.h index 19fe49ffed..edc50954b0 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -91,7 +91,7 @@ class Application; class Application : public QApplication, public AbstractViewStateInterface, public AbstractScriptingServicesInterface, public AbstractUriHandler { Q_OBJECT - + // TODO? Get rid of those friend class OctreePacketProcessor; friend class PluginContainerProxy; @@ -104,7 +104,7 @@ public: Application(int& argc, char** argv, QElapsedTimer& startup_time); ~Application(); - void postLambdaEvent(std::function f); + void postLambdaEvent(std::function f) override; void loadScripts(); QString getPreviousScriptLocation(); @@ -115,8 +115,8 @@ public: void paintGL(); void resizeGL(); - bool event(QEvent* event); - bool eventFilter(QObject* object, QEvent* event); + bool event(QEvent* event) override; + bool eventFilter(QObject* object, QEvent* event) override; glm::uvec2 getCanvasSize() const; glm::uvec2 getUiSize() const; @@ -135,7 +135,7 @@ public: // passes, mirror window passes, etc ViewFrustum* getDisplayViewFrustum(); const ViewFrustum* getDisplayViewFrustum() const; - ViewFrustum* getShadowViewFrustum() { return &_shadowViewFrustum; } + ViewFrustum* getShadowViewFrustum() override { return &_shadowViewFrustum; } const OctreePacketProcessor& getOctreePacketProcessor() const { return _octreeProcessor; } EntityTreeRenderer* getEntities() { return DependencyManager::get().data(); } QUndoStack* getUndoStack() { return &_undoStack; } @@ -157,7 +157,7 @@ public: Overlays& getOverlays() { return _overlays; } bool isForeground() const { return _isForeground; } - + uint32_t getFrameCount() { return _frameCount; } float getFps() const { return _fps; } float getTargetFrameRate(); // frames/second @@ -172,19 +172,19 @@ public: ToolWindow* getToolWindow() { return _toolWindow ; } virtual controller::ScriptingInterface* getControllerScriptingInterface() { return _controllerScriptingInterface; } - virtual void registerScriptEngineWithApplicationServices(ScriptEngine* scriptEngine); + virtual void registerScriptEngineWithApplicationServices(ScriptEngine* scriptEngine) override; QImage renderAvatarBillboard(RenderArgs* renderArgs); - virtual ViewFrustum* getCurrentViewFrustum() { return getDisplayViewFrustum(); } - virtual QThread* getMainThread() { return thread(); } - virtual float getSizeScale() const; - virtual int getBoundaryLevelAdjust() const; - virtual PickRay computePickRay(float x, float y) const; - virtual glm::vec3 getAvatarPosition() const; - virtual void overrideEnvironmentData(const EnvironmentData& newData) { _environment.override(newData); } - virtual void endOverrideEnvironmentData() { _environment.endOverride(); } - virtual qreal getDevicePixelRatio(); + virtual ViewFrustum* getCurrentViewFrustum() override { return getDisplayViewFrustum(); } + virtual QThread* getMainThread() override { return thread(); } + virtual float getSizeScale() const override; + virtual int getBoundaryLevelAdjust() const override; + virtual PickRay computePickRay(float x, float y) const override; + virtual glm::vec3 getAvatarPosition() const override; + virtual void overrideEnvironmentData(const EnvironmentData& newData) override { _environment.override(newData); } + virtual void endOverrideEnvironmentData() override { _environment.endOverride(); } + virtual qreal getDevicePixelRatio() override; void setActiveDisplayPlugin(const QString& pluginName); @@ -226,9 +226,9 @@ public: void setMaxOctreePacketsPerSecond(int maxOctreePPS); int getMaxOctreePacketsPerSecond(); - render::ScenePointer getMain3DScene() { return _main3DScene; } + render::ScenePointer getMain3DScene() override { return _main3DScene; } render::ScenePointer getMain3DScene() const { return _main3DScene; } - render::EnginePointer getRenderEngine() { return _renderEngine; } + render::EnginePointer getRenderEngine() override { return _renderEngine; } gpu::ContextPointer getGPUContext() const { return _gpuContext; } const QRect& getMirrorViewRect() const { return _mirrorViewRect; } @@ -289,7 +289,7 @@ public slots: void resetSensors(bool andReload = false); void setActiveFaceTracker(); - + #ifdef HAVE_IVIEWHMD void setActiveEyeTracker(); void calibrateEyeTracker1Point(); @@ -306,11 +306,11 @@ public slots: void reloadResourceCaches(); void crashApplication(); - + void rotationModeChanged(); - + void runTests(); - + private slots: void clearDomainOctreeDetails(); void idle(uint64_t now); @@ -325,19 +325,19 @@ private slots: void faceTrackerMuteToggled(); void activeChanged(Qt::ApplicationState state); - + void domainSettingsReceived(const QJsonObject& domainSettingsObject); void handleDomainConnectionDeniedPacket(QSharedPointer message); - + void notifyPacketVersionMismatch(); - + void loadSettings(); void saveSettings(); - + void scriptFinished(const QString& scriptName, ScriptEngine* engine); void saveScripts(); void reloadScript(const QString& scriptName, bool isUserLoaded = true); - + bool acceptSnapshot(const QString& urlString); bool askToSetAvatarUrl(const QString& url); bool askToLoadScript(const QString& scriptFilenameOrURL); @@ -356,13 +356,13 @@ private slots: void packetSent(quint64 length); void updateDisplayMode(); void updateInputModes(); - + private: void initDisplay(); void init(); void cleanupBeforeQuit(); - + void emptyLocalCache(); void update(float deltaTime); @@ -382,45 +382,45 @@ private: void renderRearViewMirror(RenderArgs* renderArgs, const QRect& region, bool billboard = false); int sendNackPackets(); - + void takeSnapshot(); - + MyAvatar* getMyAvatar() const; - + void checkSkeleton(); - + void initializeAcceptedFiles(); int getRenderAmbientLight() const; - + void displaySide(RenderArgs* renderArgs, Camera& whichCamera, bool selfAvatarOnly = false, bool billboard = false); - + bool importSVOFromURL(const QString& urlString); - + bool nearbyEntitiesAreReadyForPhysics(); int processOctreeStats(ReceivedMessage& message, SharedNodePointer sendingNode); void trackIncomingOctreePacket(ReceivedMessage& message, SharedNodePointer sendingNode, bool wasStatsPacket); - + void resizeEvent(QResizeEvent* size); - + void keyPressEvent(QKeyEvent* event); void keyReleaseEvent(QKeyEvent* event); - + void focusOutEvent(QFocusEvent* event); void focusInEvent(QFocusEvent* event); - + void mouseMoveEvent(QMouseEvent* event, unsigned int deviceID = 0); void mousePressEvent(QMouseEvent* event, unsigned int deviceID = 0); void mouseDoublePressEvent(QMouseEvent* event, unsigned int deviceID = 0); void mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID = 0); - + void touchBeginEvent(QTouchEvent* event); void touchEndEvent(QTouchEvent* event); void touchUpdateEvent(QTouchEvent* event); - + void wheelEvent(QWheelEvent* event); void dropEvent(QDropEvent* event); void dragEnterEvent(QDragEnterEvent* event); - + bool _dependencyManagerIsSetup; @@ -510,7 +510,7 @@ private: quint64 _lastNackTime; quint64 _lastSendDownstreamAudioStats; - + bool _aboutToQuit; Bookmarks* _bookmarks; @@ -519,9 +519,9 @@ private: QThread _settingsThread; QTimer _settingsTimer; - + GLCanvas* _glWidget{ nullptr }; - + typedef bool (Application::* AcceptURLMethod)(const QString &); static const QHash _acceptedExtensions; diff --git a/interface/src/avatar/AvatarActionHold.h b/interface/src/avatar/AvatarActionHold.h index b97ec59780..7646f87238 100644 --- a/interface/src/avatar/AvatarActionHold.h +++ b/interface/src/avatar/AvatarActionHold.h @@ -30,7 +30,7 @@ public: virtual void updateActionWorker(float deltaTimeStep) override; - QByteArray serialize() const; + QByteArray serialize() const override; virtual void deserialize(QByteArray serializedArguments) override; virtual bool shouldSuppressLocationEdits() override { return _active && !_ownerEntity.expired(); } diff --git a/libraries/entities-renderer/src/RenderableEntityItem.h b/libraries/entities-renderer/src/RenderableEntityItem.h index 212b71759f..d7d8d65e3a 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.h +++ b/libraries/entities-renderer/src/RenderableEntityItem.h @@ -39,7 +39,7 @@ public: }; namespace render { - template <> const ItemKey payloadGetKey(const RenderableEntityItemProxy::Pointer& payload); + template <> const ItemKey payloadGetKey(const RenderableEntityItemProxy::Pointer& payload); template <> const Item::Bound payloadGetBound(const RenderableEntityItemProxy::Pointer& payload); template <> void payloadRender(const RenderableEntityItemProxy::Pointer& payload, RenderArgs* args); } @@ -73,8 +73,8 @@ private: #define SIMPLE_RENDERABLE() \ public: \ - virtual bool addToScene(EntityItemPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges) { return _renderHelper.addToScene(self, scene, pendingChanges); } \ - virtual void removeFromScene(EntityItemPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges) { _renderHelper.removeFromScene(self, scene, pendingChanges); } \ + virtual bool addToScene(EntityItemPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges) override { return _renderHelper.addToScene(self, scene, pendingChanges); } \ + virtual void removeFromScene(EntityItemPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges) override { _renderHelper.removeFromScene(self, scene, pendingChanges); } \ private: \ SimpleRenderableEntityItem _renderHelper; diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h index d320610d83..dfde97c407 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h @@ -27,19 +27,19 @@ public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); static void createPipeline(); RenderablePolyLineEntityItem(const EntityItemID& entityItemID); - - virtual void render(RenderArgs* args); + + virtual void render(RenderArgs* args) override; virtual void update(const quint64& now) override; - virtual bool needsToCallUpdate() const { return true; }; - + virtual bool needsToCallUpdate() const override { return true; }; + SIMPLE_RENDERABLE(); - + NetworkTexturePointer _texture; static gpu::PipelinePointer _pipeline; static gpu::Stream::FormatPointer _format; static int32_t PAINTSTROKE_GPU_SLOT; - + protected: void updateGeometry(); void updateVertices(); diff --git a/libraries/physics/src/ObjectAction.h b/libraries/physics/src/ObjectAction.h index efab75b802..4e3390b386 100644 --- a/libraries/physics/src/ObjectAction.h +++ b/libraries/physics/src/ObjectAction.h @@ -40,8 +40,8 @@ public: virtual void updateActionWorker(float deltaTimeStep) = 0; // these are from btActionInterface - virtual void updateAction(btCollisionWorld* collisionWorld, btScalar deltaTimeStep); - virtual void debugDraw(btIDebugDraw* debugDrawer); + virtual void updateAction(btCollisionWorld* collisionWorld, btScalar deltaTimeStep) override; + virtual void debugDraw(btIDebugDraw* debugDrawer) override; virtual QByteArray serialize() const override = 0; virtual void deserialize(QByteArray serializedArguments) override = 0; diff --git a/libraries/render-utils/src/AbstractViewStateInterface.h b/libraries/render-utils/src/AbstractViewStateInterface.h index 39da33ee8f..eaef77bef7 100644 --- a/libraries/render-utils/src/AbstractViewStateInterface.h +++ b/libraries/render-utils/src/AbstractViewStateInterface.h @@ -40,7 +40,7 @@ public: virtual ViewFrustum* getShadowViewFrustum() = 0; virtual QThread* getMainThread() = 0; - + virtual float getSizeScale() const = 0; virtual int getBoundaryLevelAdjust() const = 0; virtual PickRay computePickRay(float x, float y) const = 0; From acdd0bda2e9e7970c655655239f67572e571345c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 7 Jan 2016 16:43:55 -0800 Subject: [PATCH 079/357] use external project hack on win only --- interface/CMakeLists.txt | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 8e61f3a6de..367a32a174 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -109,13 +109,18 @@ else() add_executable(${TARGET_NAME} ${INTERFACE_SRCS} ${QM}) endif() +<<<<<<< HEAD target_include_directories(${TARGET_NAME} PRIVATE "${CMAKE_BINARY_DIR}/includes") +======= +>>>>>>> ebdd430... use external project hack on win only if (WIN32) - add_dependency_external_projects(OpenVR) -endif() -if(WIN32 OR APPLE) - add_dependency_external_projects(neuron) + # These are external plugins, but we need to do the 'add dependency' here so that their + # binary directories get added to the fixup path + add_dependency_external_projects(sixense) + add_dependency_external_projects(sdl2) + add_dependency_external_projects(OpenVR) + add_dependency_external_projects(neuron) endif() # disable /OPT:REF and /OPT:ICF for the Debug builds @@ -141,7 +146,7 @@ target_glew() target_opengl() if (WIN32 OR APPLE) - target_faceshift() + target_faceshift() endif() # perform standard include and linking for found externals @@ -208,10 +213,17 @@ if (APPLE) target_link_libraries(${TARGET_NAME} ${OpenGL} ${AppKit}) +<<<<<<< HEAD # setup install of OS X interface bundle install(TARGETS ${TARGET_NAME} BUNDLE DESTINATION ${INTERFACE_INSTALL_DIR} COMPONENT ${CLIENT_COMPONENT} +======= + # install command for OS X bundle + INSTALL(TARGETS ${TARGET_NAME} + BUNDLE DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/install" COMPONENT Runtime + RUNTIME DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/install" COMPONENT Runtime +>>>>>>> ebdd430... use external project hack on win only ) else (APPLE) From 3b3140de48a861b83796ce7800bb7440bb72eb13 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 7 Jan 2016 16:45:37 -0800 Subject: [PATCH 080/357] exclude console build from all by default --- console/CMakeLists.txt | 4 +++- interface/CMakeLists.txt | 2 -- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/console/CMakeLists.txt b/console/CMakeLists.txt index be02fe5fcf..e6c83a1a6f 100644 --- a/console/CMakeLists.txt +++ b/console/CMakeLists.txt @@ -29,4 +29,6 @@ install( COMPONENT ${SERVER_COMPONENT} ) -consolidate_installer_components() +if (NOT PR_BUILD AND NOT PRODUCTION_BUILD) + set_target_properties(${PACKAGING_TARGET_NAME} PROPERTIES EXCLUDE_FROM_ALL) +endif () diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 367a32a174..85f502955e 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -62,8 +62,6 @@ set(INTERFACE_SRCS ${INTERFACE_SRCS} "${QT_UI_HEADERS}" "${QT_RESOURCES}") # qt5_create_translation_custom(${QM} ${INTERFACE_SRCS} ${QT_UI_FILES} ${TS}) if (APPLE) - set(MACOSX_BUNDLE_BUNDLE_NAME "High Fidelity") - # configure CMake to use a custom Info.plist set_target_properties(${this_target} PROPERTIES MACOSX_BUNDLE_INFO_PLIST MacOSXBundleInfo.plist.in) From 799577cac17839411b23ccff9c328327345136bd Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 7 Jan 2016 16:48:45 -0800 Subject: [PATCH 081/357] fix exclude from all call on console --- console/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/console/CMakeLists.txt b/console/CMakeLists.txt index e6c83a1a6f..4f8d447fdf 100644 --- a/console/CMakeLists.txt +++ b/console/CMakeLists.txt @@ -30,5 +30,5 @@ install( ) if (NOT PR_BUILD AND NOT PRODUCTION_BUILD) - set_target_properties(${PACKAGING_TARGET_NAME} PROPERTIES EXCLUDE_FROM_ALL) + set_target_properties(${PACKAGING_TARGET_NAME} PROPERTIES EXCLUDE_FROM_ALL TRUE) endif () From 669365bea12fbc9c6d6ce10777f4868dc9ee72ad Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 7 Jan 2016 16:49:40 -0800 Subject: [PATCH 082/357] add exclusion of console from visual studio default --- console/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/console/CMakeLists.txt b/console/CMakeLists.txt index 4f8d447fdf..56ce5bcb9d 100644 --- a/console/CMakeLists.txt +++ b/console/CMakeLists.txt @@ -30,5 +30,5 @@ install( ) if (NOT PR_BUILD AND NOT PRODUCTION_BUILD) - set_target_properties(${PACKAGING_TARGET_NAME} PROPERTIES EXCLUDE_FROM_ALL TRUE) + set_target_properties(${PACKAGING_TARGET_NAME} PROPERTIES EXCLUDE_FROM_ALL TRUE EXCLUDE_FROM_DEFAULT_BUILD TRUE) endif () From 686ebc2f7a0162baa4b76154a781367e2168c305 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 7 Jan 2016 16:55:55 -0800 Subject: [PATCH 083/357] shuffling and renaming of menu options --- console/src/main.js | 63 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 55 insertions(+), 8 deletions(-) diff --git a/console/src/main.js b/console/src/main.js index 3d2896a40d..16ac4c1008 100644 --- a/console/src/main.js +++ b/console/src/main.js @@ -204,11 +204,11 @@ global.domainServer = null; global.acMonitor = null; global.userConfig = userConfig; -const GO_HOME_INDEX = 0; -const SERVER_LABEL_INDEX = 2; -const RESTART_INDEX = 3; -const STOP_INDEX = 4; -const SETTINGS_INDEX = 5; +const GO_HOME_INDEX = 2; +const SERVER_LABEL_INDEX = 0; +const RESTART_INDEX = 4; +const STOP_INDEX = 5; +const SETTINGS_INDEX = 6; var LogWindow = function(ac, ds) { this.ac = ac; @@ -255,6 +255,7 @@ function goHomeClicked() { var logWindow = null; function buildMenuArray(serverState) { +<<<<<<< HEAD var menuArray = null; if (isShuttingDown) { menuArray = [ @@ -311,6 +312,51 @@ function buildMenuArray(serverState) { updateMenuArray(menuArray, serverState); } +======= + var menuArray = [ + { + label: "Server - Stopped", + enabled: false + }, + { + type: 'separator' + }, + { + label: 'Go Home', + click: function() { startInterface('hifi://localhost'); }, + enabled: false + }, + { + type: 'separator' + }, + { + label: "Start Server", + click: function() { homeServer.restart(); } + }, + { + label: "Stop Server", + visible: false, + click: function() { homeServer.stop(); } + }, + { + label: "Settings", + click: function() { shell.openExternal('http://localhost:40100/settings'); }, + enabled: false + }, + { + label: "View Logs", + click: function() { openFileBrowser(logPath); } + }, + { + type: 'separator' + }, + { + label: 'Quit', + accelerator: 'Command+Q', + click: function() { app.quit(); } + } + ]; +>>>>>>> shuffling and renaming of menu options return menuArray; @@ -334,13 +380,14 @@ function updateMenuArray(menuArray, serverState) { if (serverState == ProcessGroupStates.STARTED) { serverLabelItem.label = "Server - Started"; - restartItem.label = "Restart"; + restartItem.label = "Restart Server"; } else if (serverState == ProcessGroupStates.STOPPED) { serverLabelItem.label = "Server - Stopped"; - restartItem.label = "Start"; + restartItem.label = "Start Server"; } else if (serverState == ProcessGroupStates.STOPPING) { serverLabelItem.label = "Server - Stopping"; - restartItem.label = "Restart"; + + restartItem.label = "Restart Server"; restartItem.enabled = false; } } From 6db36a3863b8d935b87a62deded7f3c8925263f3 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 7 Jan 2016 17:05:47 -0800 Subject: [PATCH 084/357] remove accidentally committed conflict --- interface/CMakeLists.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 85f502955e..995dee8f69 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -107,11 +107,8 @@ else() add_executable(${TARGET_NAME} ${INTERFACE_SRCS} ${QM}) endif() -<<<<<<< HEAD target_include_directories(${TARGET_NAME} PRIVATE "${CMAKE_BINARY_DIR}/includes") -======= ->>>>>>> ebdd430... use external project hack on win only if (WIN32) # These are external plugins, but we need to do the 'add dependency' here so that their # binary directories get added to the fixup path From aa9e9836b46534b886ae3c2e05d9b2bed8288ab5 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 7 Jan 2016 17:06:52 -0800 Subject: [PATCH 085/357] repair another committed conflict --- interface/CMakeLists.txt | 7 ------- 1 file changed, 7 deletions(-) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 995dee8f69..10bb83ed1d 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -208,17 +208,10 @@ if (APPLE) target_link_libraries(${TARGET_NAME} ${OpenGL} ${AppKit}) -<<<<<<< HEAD # setup install of OS X interface bundle install(TARGETS ${TARGET_NAME} BUNDLE DESTINATION ${INTERFACE_INSTALL_DIR} COMPONENT ${CLIENT_COMPONENT} -======= - # install command for OS X bundle - INSTALL(TARGETS ${TARGET_NAME} - BUNDLE DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/install" COMPONENT Runtime - RUNTIME DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/install" COMPONENT Runtime ->>>>>>> ebdd430... use external project hack on win only ) else (APPLE) From 092025673b30850b67795e38754faa5eefaba734 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 7 Jan 2016 17:11:38 -0800 Subject: [PATCH 086/357] fix console exclusion from all --- console/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/console/CMakeLists.txt b/console/CMakeLists.txt index 56ce5bcb9d..66aa8b4509 100644 --- a/console/CMakeLists.txt +++ b/console/CMakeLists.txt @@ -30,5 +30,5 @@ install( ) if (NOT PR_BUILD AND NOT PRODUCTION_BUILD) - set_target_properties(${PACKAGING_TARGET_NAME} PROPERTIES EXCLUDE_FROM_ALL TRUE EXCLUDE_FROM_DEFAULT_BUILD TRUE) + set_target_properties(${TARGET_NAME} PROPERTIES EXCLUDE_FROM_ALL TRUE EXCLUDE_FROM_DEFAULT_BUILD TRUE) endif () From 31f5b1d902c842fdfc53c162d87b7c3415070ee6 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 7 Jan 2016 17:15:26 -0800 Subject: [PATCH 087/357] fix for console install on win/linux --- console/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/console/CMakeLists.txt b/console/CMakeLists.txt index 66aa8b4509..985af27f54 100644 --- a/console/CMakeLists.txt +++ b/console/CMakeLists.txt @@ -15,7 +15,7 @@ add_dependencies(${TARGET_NAME} assignment-client domain-server) # set the packaged console folder depending on platform, so we can copy it if (APPLE) - set(PACKAGED_CONSOLE_FOLDER "Server\\ Console-darwin-x64") + set(PACKAGED_CONSOLE_FOLDER "Server\\ Console-darwin-x64/Server Console.app") elseif (WIN32) set(PACKAGED_CONSOLE_FOLDER "server-console-win32-x64") elseif (UNIX) @@ -24,7 +24,7 @@ endif () # install the packaged Server Console install( - PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/${PACKAGED_CONSOLE_FOLDER}/Server Console.app" + DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${PACKAGED_CONSOLE_FOLDER}" DESTINATION ${CONSOLE_INSTALL_DIR} COMPONENT ${SERVER_COMPONENT} ) From 9bc381ce7ba8f4b9215813cf46b17ad98c376796 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 7 Jan 2016 17:25:44 -0800 Subject: [PATCH 088/357] use file install for win/linux console --- console/CMakeLists.txt | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/console/CMakeLists.txt b/console/CMakeLists.txt index 985af27f54..3a28f63f86 100644 --- a/console/CMakeLists.txt +++ b/console/CMakeLists.txt @@ -23,11 +23,19 @@ elseif (UNIX) endif () # install the packaged Server Console -install( - DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${PACKAGED_CONSOLE_FOLDER}" - DESTINATION ${CONSOLE_INSTALL_DIR} - COMPONENT ${SERVER_COMPONENT} -) +if (APPLE) + install( + PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/${PACKAGED_CONSOLE_FOLDER}" + DESTINATION ${CONSOLE_INSTALL_DIR} + COMPONENT ${SERVER_COMPONENT} + ) +else () + install( + DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${PACKAGED_CONSOLE_FOLDER}/" + DESTINATION ${CONSOLE_INSTALL_DIR} + COMPONENT ${SERVER_COMPONENT} + ) +endif() if (NOT PR_BUILD AND NOT PRODUCTION_BUILD) set_target_properties(${TARGET_NAME} PROPERTIES EXCLUDE_FROM_ALL TRUE EXCLUDE_FROM_DEFAULT_BUILD TRUE) From f569ebb0a9d075904b0707f51456b5f9d1a5ab01 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 7 Jan 2016 17:38:11 -0800 Subject: [PATCH 089/357] use process path to check beside console for components --- console/src/modules/path-finder.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/console/src/modules/path-finder.js b/console/src/modules/path-finder.js index e12037a26d..e3dd118537 100644 --- a/console/src/modules/path-finder.js +++ b/console/src/modules/path-finder.js @@ -29,7 +29,7 @@ exports.searchPaths = function(name, binaryType) { } else { // check directly beside the binary paths = [ - __dirname + "/" + name + extension, + process.execPath + "/" + name + extension, ]; // check if we're inside an app bundle on OS X From 39e95837ec32ed8a199b773c809e06190d75e6b2 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 7 Jan 2016 17:44:55 -0800 Subject: [PATCH 090/357] use path join for platform agnostic absolute path --- console/src/modules/path-finder.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/console/src/modules/path-finder.js b/console/src/modules/path-finder.js index e3dd118537..e126af1358 100644 --- a/console/src/modules/path-finder.js +++ b/console/src/modules/path-finder.js @@ -1,4 +1,5 @@ var fs = require('fs'); +var path = require('path'); exports.searchPaths = function(name, binaryType) { function platformExtension(name) { @@ -29,7 +30,7 @@ exports.searchPaths = function(name, binaryType) { } else { // check directly beside the binary paths = [ - process.execPath + "/" + name + extension, + path.join(process.execPath, name + extension) ]; // check if we're inside an app bundle on OS X @@ -53,17 +54,17 @@ exports.searchPaths = function(name, binaryType) { exports.discoveredPath = function (name, binaryType) { function binaryFromPaths(name, paths) { for (var i = 0; i < paths.length; i++) { - var path = paths[i]; + var testPath = paths[i]; try { - var stats = fs.lstatSync(path); + var stats = fs.lstatSync(testPath); if (stats.isFile() || (stats.isDirectory() && extension == ".app")) { - console.log("Found " + name + " at " + path); - return path; + console.log("Found " + name + " at " + testPath); + return testPath; } } catch (e) { - console.log("Executable with name " + name + " not found at path " + path); + console.log("Executable with name " + name + " not found at path " + testPath); } } From 5ccf59dae9f190d5ca9a10e7234850551ada3cbc Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 7 Jan 2016 17:47:23 -0800 Subject: [PATCH 091/357] use dirname of executable path --- console/src/modules/path-finder.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/console/src/modules/path-finder.js b/console/src/modules/path-finder.js index e126af1358..ce4d4e350f 100644 --- a/console/src/modules/path-finder.js +++ b/console/src/modules/path-finder.js @@ -30,7 +30,7 @@ exports.searchPaths = function(name, binaryType) { } else { // check directly beside the binary paths = [ - path.join(process.execPath, name + extension) + path.join(path.dirname(process.execPath), name + extension) ]; // check if we're inside an app bundle on OS X From 1faa78fe72a047c0a9c6db4f8aef26c4690ce4ad Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 7 Jan 2016 18:03:14 -0800 Subject: [PATCH 092/357] install fixed up DS and AC beside console --- assignment-client/CMakeLists.txt | 4 +- cmake/macros/InstallBesideConsole.cmake | 75 ++++++++++++++----------- console/CMakeLists.txt | 4 +- domain-server/CMakeLists.txt | 4 +- interface/CMakeLists.txt | 10 +++- 5 files changed, 54 insertions(+), 43 deletions(-) diff --git a/assignment-client/CMakeLists.txt b/assignment-client/CMakeLists.txt index b2e890fe9e..19f856c6eb 100644 --- a/assignment-client/CMakeLists.txt +++ b/assignment-client/CMakeLists.txt @@ -9,7 +9,5 @@ link_hifi_libraries( controllers physics ) -install_beside_console() - package_libraries_for_deployment() -consolidate_installer_components() +install_beside_console() diff --git a/cmake/macros/InstallBesideConsole.cmake b/cmake/macros/InstallBesideConsole.cmake index 7e03b40ce6..f598424e66 100644 --- a/cmake/macros/InstallBesideConsole.cmake +++ b/cmake/macros/InstallBesideConsole.cmake @@ -10,43 +10,54 @@ # macro(install_beside_console) - # install this component beside the installed server-console executable - if (APPLE) - set(CONSOLE_APP_CONTENTS "${CONSOLE_INSTALL_APP_PATH}/Contents") - set(COMPONENT_DESTINATION "${CONSOLE_APP_CONTENTS}/MacOS/Components.app/Contents/MacOS") - else () - set(COMPONENT_DESTINATION ${CONSOLE_INSTALL_DIR}) - endif () - - install( - TARGETS ${TARGET_NAME} - RUNTIME DESTINATION ${COMPONENT_DESTINATION} - COMPONENT ${SERVER_COMPONENT} - ) - - if (TARGET_NAME STREQUAL domain-server) + if (WIN32 OR APPLE) + # install this component beside the installed server-console executable if (APPLE) - set(RESOURCES_DESTINATION ${COMPONENT_DESTINATION}) + set(CONSOLE_APP_CONTENTS "${CONSOLE_INSTALL_APP_PATH}/Contents") + set(COMPONENT_DESTINATION "${CONSOLE_APP_CONTENTS}/MacOS/Components.app/Contents/MacOS") else () - set(RESOURCES_DESTINATION ${CONSOLE_INSTALL_DIR}) + set(COMPONENT_DESTINATION ${CONSOLE_INSTALL_DIR}) endif () - # install the resources folder for the domain-server where its executable will be - install( - DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/resources - DESTINATION ${RESOURCES_DESTINATION} - USE_SOURCE_PERMISSIONS - COMPONENT ${SERVER_COMPONENT} - ) - endif () + if (APPLE) + install( + TARGETS ${TARGET_NAME} + RUNTIME DESTINATION ${COMPONENT_DESTINATION} + COMPONENT ${SERVER_COMPONENT} + ) + else () + # setup install of executable and things copied by fixup/windeployqt + install( + FILES $ + DESTINATION ${COMPONENT_DESTINATION} + COMPONENT ${SERVER_COMPONENT} + ) + endif () - if (APPLE) - # during the install phase, call fixup to drop the shared libraries for these components in the right place - set(EXECUTABLE_NEEDING_FIXUP "\${CMAKE_INSTALL_PREFIX}/${COMPONENT_DESTINATION}/${TARGET_NAME}") - install(CODE " - include(BundleUtilities) - fixup_bundle(\"${EXECUTABLE_NEEDING_FIXUP}\" \"\" \"${FIXUP_LIBS}\") - " COMPONENT ${SERVER_COMPONENT}) + if (TARGET_NAME STREQUAL domain-server) + if (APPLE) + set(RESOURCES_DESTINATION ${COMPONENT_DESTINATION}) + else () + set(RESOURCES_DESTINATION ${CONSOLE_INSTALL_DIR}) + endif () + + # install the resources folder for the domain-server where its executable will be + install( + DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/resources + DESTINATION ${RESOURCES_DESTINATION} + USE_SOURCE_PERMISSIONS + COMPONENT ${SERVER_COMPONENT} + ) + endif () + + if (APPLE) + # during the install phase, call fixup to drop the shared libraries for these components in the right place + set(EXECUTABLE_NEEDING_FIXUP "\${CMAKE_INSTALL_PREFIX}/${COMPONENT_DESTINATION}/${TARGET_NAME}") + install(CODE " + include(BundleUtilities) + fixup_bundle(\"${EXECUTABLE_NEEDING_FIXUP}\" \"\" \"${FIXUP_LIBS}\") + " COMPONENT ${SERVER_COMPONENT}) + endif () endif () endmacro() diff --git a/console/CMakeLists.txt b/console/CMakeLists.txt index 3a28f63f86..05ab6f0549 100644 --- a/console/CMakeLists.txt +++ b/console/CMakeLists.txt @@ -22,14 +22,14 @@ elseif (UNIX) set(PACKAGED_CONSOLE_FOLDER "server-console-linux-x64") endif () -# install the packaged Server Console +# install the packaged Server Console in our install directory if (APPLE) install( PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/${PACKAGED_CONSOLE_FOLDER}" DESTINATION ${CONSOLE_INSTALL_DIR} COMPONENT ${SERVER_COMPONENT} ) -else () +elseif (WIN32) install( DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${PACKAGED_CONSOLE_FOLDER}/" DESTINATION ${CONSOLE_INSTALL_DIR} diff --git a/domain-server/CMakeLists.txt b/domain-server/CMakeLists.txt index 9437656f9b..342bfbffe4 100644 --- a/domain-server/CMakeLists.txt +++ b/domain-server/CMakeLists.txt @@ -36,7 +36,5 @@ if (UNIX) target_link_libraries(${TARGET_NAME} ${CMAKE_DL_LIBS}) endif (UNIX) -install_beside_console() - package_libraries_for_deployment() -consolidate_installer_components() +install_beside_console() diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 10bb83ed1d..c656f32359 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -225,12 +225,16 @@ else (APPLE) $/scripts ) - # setup install of interface target - install(TARGETS ${TARGET_NAME} RUNTIME DESTINATION . COMPONENT ${CLIENT_COMPONENT}) - # link target to external libraries if (WIN32) target_link_libraries(${TARGET_NAME} wsock32.lib Winmm.lib) + + # setup install of executable and things copied by fixup/windeployqt + install( + FILES $ + DESTINATION ${INTERFACE_INSTALL_DIR} + COMPONENT ${CLIENT_COMPONENT} + ) endif() endif (APPLE) From 8842c66109429b791342a9062de8581ab53e1251 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 7 Jan 2016 18:05:52 -0800 Subject: [PATCH 093/357] include trailing slash in windows file copy --- cmake/macros/InstallBesideConsole.cmake | 2 +- interface/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/macros/InstallBesideConsole.cmake b/cmake/macros/InstallBesideConsole.cmake index f598424e66..12bbc3bcda 100644 --- a/cmake/macros/InstallBesideConsole.cmake +++ b/cmake/macros/InstallBesideConsole.cmake @@ -28,7 +28,7 @@ macro(install_beside_console) else () # setup install of executable and things copied by fixup/windeployqt install( - FILES $ + FILES "$/" DESTINATION ${COMPONENT_DESTINATION} COMPONENT ${SERVER_COMPONENT} ) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index c656f32359..4dcc86f03c 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -231,7 +231,7 @@ else (APPLE) # setup install of executable and things copied by fixup/windeployqt install( - FILES $ + FILES "$/" DESTINATION ${INTERFACE_INSTALL_DIR} COMPONENT ${CLIENT_COMPONENT} ) From fcd9d9b81096e86adcdde89b19a414d8ce8a5f54 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 8 Jan 2016 13:00:01 -0800 Subject: [PATCH 094/357] setup optional dde archive for windows --- cmake/macros/GenerateInstallers.cmake | 2 +- interface/CMakeLists.txt | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/cmake/macros/GenerateInstallers.cmake b/cmake/macros/GenerateInstallers.cmake index cea767fec9..fc95da6be3 100644 --- a/cmake/macros/GenerateInstallers.cmake +++ b/cmake/macros/GenerateInstallers.cmake @@ -41,7 +41,7 @@ macro(GENERATE_INSTALLERS) DISPLAY_NAME "High Fidelity Client" ) - if (WIN32 AND DDE_APP_PATH) + if (WIN32 AND DEFINED ENV{DDE_ARCHIVE_DIR}) # add a download component for DDE cpack_add_component( ${DDE_COMPONENT} diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 4dcc86f03c..802e409d04 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -245,13 +245,20 @@ fixup_interface() # which will be presented as an option during install if (APPLE AND DEFINED ENV{DDE_APP_PATH}) install( - DIRECTORY $ENV{DDE_APP_PATH} - DIRECTORY_PERMISSIONS + DIRECTORY ENV{DDE_APP_PATH} DESTINATION ${INTERFACE_INSTALL_APP_PATH}/Contents/MacOS COMPONENT ${DDE_COMPONENT} ) endif () +if (WIN32 AND DEFINED ENV{DDE_ARCHIVE_DIR}) + install( + DIRECTORY $ENV{DDE_APP_PATH} + DESTINATION ${INTERFACE_INSTALL_DIR}/dde + COMPONENT ${DDE_COMPONENT} + ) +endif () + if (WIN32) set(EXTRA_DEPLOY_OPTIONS "--qmldir ${PROJECT_SOURCE_DIR}/resources/qml") endif() From 8662fd0afb16c361c554120c85dba63d8ff809ce Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 8 Jan 2016 15:03:03 -0800 Subject: [PATCH 095/357] use correct dde install path for win --- interface/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 802e409d04..8596b2ac77 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -253,7 +253,7 @@ endif () if (WIN32 AND DEFINED ENV{DDE_ARCHIVE_DIR}) install( - DIRECTORY $ENV{DDE_APP_PATH} + DIRECTORY $ENV{DDE_ARCHIVE_DIR}/ DESTINATION ${INTERFACE_INSTALL_DIR}/dde COMPONENT ${DDE_COMPONENT} ) From 87e55543cefbe12b8965a1917a5499b658b20d89 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 8 Jan 2016 16:05:42 -0800 Subject: [PATCH 096/357] repairs to component group for client/dde --- cmake/macros/GenerateInstallers.cmake | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/cmake/macros/GenerateInstallers.cmake b/cmake/macros/GenerateInstallers.cmake index fc95da6be3..3c69453b6e 100644 --- a/cmake/macros/GenerateInstallers.cmake +++ b/cmake/macros/GenerateInstallers.cmake @@ -27,18 +27,19 @@ macro(GENERATE_INSTALLERS) ADD_REMOVE ) - set(CLIENT_GROUP client) + set(CLIENT_GROUP client-group) # add a component group for the client - # cpack_add_component_group( - # ${CLIENT_GROUP} - # DISPLAY_NAME "Client" - # EXPANDED - # ) + cpack_add_component_group( + ${CLIENT_GROUP} + DISPLAY_NAME "Client" + EXPANDED + ) cpack_add_component( ${CLIENT_COMPONENT} DISPLAY_NAME "High Fidelity Client" + GROUP ${CLIENT_GROUP} ) if (WIN32 AND DEFINED ENV{DDE_ARCHIVE_DIR}) @@ -48,6 +49,8 @@ macro(GENERATE_INSTALLERS) DISPLAY_NAME "Webcam Body Movement" DEPENDS ${CLIENT_COMPONENT} DOWNLOADED + DISABLE + GROUP ${CLIENT_GROUP} ARCHIVE_FILE "DDE" ) endif () From 63a88815bcc0ccd6790757a672e1c6d4ac46d663 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 8 Jan 2016 16:21:58 -0800 Subject: [PATCH 097/357] add NSIS template for custom installer options --- cmake/macros/GenerateInstallers.cmake | 4 ++++ cmake/macros/SetPackagingParameters.cmake | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/cmake/macros/GenerateInstallers.cmake b/cmake/macros/GenerateInstallers.cmake index 3c69453b6e..df5a413865 100644 --- a/cmake/macros/GenerateInstallers.cmake +++ b/cmake/macros/GenerateInstallers.cmake @@ -15,6 +15,10 @@ macro(GENERATE_INSTALLERS) set(CPACK_PACKAGE_NAME "HighFidelity") set(CPACK_PACKAGE_VENDOR "HighFidelity") + if (WIN32) + set(INTERFACE_STARTMENU_NAME "High Fidelity") + endif () + if (APPLE) set(CPACK_PACKAGE_INSTALL_DIRECTORY "/") set(CPACK_PACKAGING_INSTALL_PREFIX /) diff --git a/cmake/macros/SetPackagingParameters.cmake b/cmake/macros/SetPackagingParameters.cmake index 142f7fcc8c..b76da6ded6 100644 --- a/cmake/macros/SetPackagingParameters.cmake +++ b/cmake/macros/SetPackagingParameters.cmake @@ -43,6 +43,10 @@ macro(SET_PACKAGING_PARAMETERS) set(CONSOLE_ICON "console-beta.ico") endif () + if (WIN32) + set(INTERFACE_EXEC_NAME "interface") + endif () + if (APPLE) set(CONSOLE_INSTALL_DIR ".") set(CONSOLE_APPLICATION_NAME "Server Console.app") From d2f35adc119f0766758a02eb020a335ae9879da3 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 8 Jan 2016 16:23:07 -0800 Subject: [PATCH 098/357] add space back to package name and vendor --- cmake/macros/GenerateInstallers.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/macros/GenerateInstallers.cmake b/cmake/macros/GenerateInstallers.cmake index df5a413865..26b32463eb 100644 --- a/cmake/macros/GenerateInstallers.cmake +++ b/cmake/macros/GenerateInstallers.cmake @@ -12,8 +12,8 @@ macro(GENERATE_INSTALLERS) include(CPackComponent) - set(CPACK_PACKAGE_NAME "HighFidelity") - set(CPACK_PACKAGE_VENDOR "HighFidelity") + set(CPACK_PACKAGE_NAME "High Fidelity") + set(CPACK_PACKAGE_VENDOR "High Fidelity") if (WIN32) set(INTERFACE_STARTMENU_NAME "High Fidelity") From 59b6d8fde885a947090f370a3daeaa6b97f6ea29 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 8 Jan 2016 16:30:22 -0800 Subject: [PATCH 099/357] set CPACK_MODULE_PATH so custom template is used --- CMakeLists.txt | 6 +++--- cmake/macros/GenerateInstallers.cmake | 2 ++ cmake/macros/PackageLibrariesForDeployment.cmake | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 83ab275d28..dfc7c842a9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -180,9 +180,9 @@ else () set(UPPER_CMAKE_BUILD_TYPE DEBUG) endif () -set(HIFI_CMAKE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/cmake") -set(MACRO_DIR "${HIFI_CMAKE_DIR}/macros") -set(EXTERNAL_PROJECT_DIR "${HIFI_CMAKE_DIR}/externals") +set(HF_CMAKE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/cmake") +set(MACRO_DIR "${HF_CMAKE_DIR}/macros") +set(EXTERNAL_PROJECT_DIR "${HF_CMAKE_DIR}/externals") file(GLOB HIFI_CUSTOM_MACROS "cmake/macros/*.cmake") foreach(CUSTOM_MACRO ${HIFI_CUSTOM_MACROS}) diff --git a/cmake/macros/GenerateInstallers.cmake b/cmake/macros/GenerateInstallers.cmake index 26b32463eb..788bab9ff4 100644 --- a/cmake/macros/GenerateInstallers.cmake +++ b/cmake/macros/GenerateInstallers.cmake @@ -12,6 +12,8 @@ macro(GENERATE_INSTALLERS) include(CPackComponent) + set(CPACK_MODULE_PATH ${CPACK_MODULE_PATH} "${HF_CMAKE_DIR}/templates") + set(CPACK_PACKAGE_NAME "High Fidelity") set(CPACK_PACKAGE_VENDOR "High Fidelity") diff --git a/cmake/macros/PackageLibrariesForDeployment.cmake b/cmake/macros/PackageLibrariesForDeployment.cmake index 44d609c064..322afc52e0 100644 --- a/cmake/macros/PackageLibrariesForDeployment.cmake +++ b/cmake/macros/PackageLibrariesForDeployment.cmake @@ -13,7 +13,7 @@ macro(PACKAGE_LIBRARIES_FOR_DEPLOYMENT) if (WIN32) configure_file( - ${HIFI_CMAKE_DIR}/templates/FixupBundlePostBuild.cmake.in + ${HF_CMAKE_DIR}/templates/FixupBundlePostBuild.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/FixupBundlePostBuild.cmake @ONLY ) From 9621773082e021f0d4f263e805c0dad327940d0b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 8 Jan 2016 16:52:03 -0800 Subject: [PATCH 100/357] add back the NSIS.template.in file --- cmake/templates/NSIS.template.in | 983 +++++++++++++++++++++++++++++++ 1 file changed, 983 insertions(+) create mode 100644 cmake/templates/NSIS.template.in diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in new file mode 100644 index 0000000000..1d3d084486 --- /dev/null +++ b/cmake/templates/NSIS.template.in @@ -0,0 +1,983 @@ +; CPack install script designed for a nmake build + +;-------------------------------- +; You must define these values + + !define VERSION "@CPACK_PACKAGE_VERSION@" + !define PATCH "@CPACK_PACKAGE_VERSION_PATCH@" + !define INST_DIR "@CPACK_TEMPORARY_DIRECTORY@" + +;-------------------------------- +;Variables + + Var MUI_TEMP + Var STARTMENU_FOLDER + Var SV_ALLUSERS + Var START_MENU + Var DO_NOT_ADD_TO_PATH + Var ADD_TO_PATH_ALL_USERS + Var ADD_TO_PATH_CURRENT_USER + Var INSTALL_DESKTOP + Var IS_DEFAULT_INSTALLDIR +;-------------------------------- +;Include Modern UI + + !include "MUI.nsh" + + ;Default installation folder + InstallDir "@CPACK_NSIS_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_DIRECTORY@" + +;-------------------------------- +;General + + ;Name and file + Name "@CPACK_NSIS_PACKAGE_NAME@" + OutFile "@CPACK_TOPLEVEL_DIRECTORY@/@CPACK_OUTPUT_FILE_NAME@" + + ;Set compression + SetCompressor @CPACK_NSIS_COMPRESSOR@ + + ;Require administrator access + RequestExecutionLevel admin + +@CPACK_NSIS_DEFINES@ + + !include Sections.nsh + +;--- Component support macros: --- +; The code for the add/remove functionality is from: +; http://nsis.sourceforge.net/Add/Remove_Functionality +; It has been modified slightly and extended to provide +; inter-component dependencies. +Var AR_SecFlags +Var AR_RegFlags +@CPACK_NSIS_SECTION_SELECTED_VARS@ + +; Loads the "selected" flag for the section named SecName into the +; variable VarName. +!macro LoadSectionSelectedIntoVar SecName VarName + SectionGetFlags ${${SecName}} $${VarName} + IntOp $${VarName} $${VarName} & ${SF_SELECTED} ;Turn off all other bits +!macroend + +; Loads the value of a variable... can we get around this? +!macro LoadVar VarName + IntOp $R0 0 + $${VarName} +!macroend + +; Sets the value of a variable +!macro StoreVar VarName IntValue + IntOp $${VarName} 0 + ${IntValue} +!macroend + +!macro InitSection SecName + ; This macro reads component installed flag from the registry and + ;changes checked state of the section on the components page. + ;Input: section index constant name specified in Section command. + + ClearErrors + ;Reading component status from registry + ReadRegDWORD $AR_RegFlags HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\Components\${SecName}" "Installed" + IfErrors "default_${SecName}" + ;Status will stay default if registry value not found + ;(component was never installed) + IntOp $AR_RegFlags $AR_RegFlags & ${SF_SELECTED} ;Turn off all other bits + SectionGetFlags ${${SecName}} $AR_SecFlags ;Reading default section flags + IntOp $AR_SecFlags $AR_SecFlags & 0xFFFE ;Turn lowest (enabled) bit off + IntOp $AR_SecFlags $AR_RegFlags | $AR_SecFlags ;Change lowest bit + + ; Note whether this component was installed before + !insertmacro StoreVar ${SecName}_was_installed $AR_RegFlags + IntOp $R0 $AR_RegFlags & $AR_RegFlags + + ;Writing modified flags + SectionSetFlags ${${SecName}} $AR_SecFlags + + "default_${SecName}:" + !insertmacro LoadSectionSelectedIntoVar ${SecName} ${SecName}_selected +!macroend + +!macro FinishSection SecName + ; This macro reads section flag set by user and removes the section + ;if it is not selected. + ;Then it writes component installed flag to registry + ;Input: section index constant name specified in Section command. + + SectionGetFlags ${${SecName}} $AR_SecFlags ;Reading section flags + ;Checking lowest bit: + IntOp $AR_SecFlags $AR_SecFlags & ${SF_SELECTED} + IntCmp $AR_SecFlags 1 "leave_${SecName}" + ;Section is not selected: + ;Calling Section uninstall macro and writing zero installed flag + !insertmacro "Remove_${${SecName}}" + WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\Components\${SecName}" \ + "Installed" 0 + Goto "exit_${SecName}" + + "leave_${SecName}:" + ;Section is selected: + WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\Components\${SecName}" \ + "Installed" 1 + + "exit_${SecName}:" +!macroend + +!macro RemoveSection_CPack SecName + ; This macro is used to call section's Remove_... macro + ;from the uninstaller. + ;Input: section index constant name specified in Section command. + + !insertmacro "Remove_${${SecName}}" +!macroend + +; Determine whether the selection of SecName changed +!macro MaybeSelectionChanged SecName + !insertmacro LoadVar ${SecName}_selected + SectionGetFlags ${${SecName}} $R1 + IntOp $R1 $R1 & ${SF_SELECTED} ;Turn off all other bits + + ; See if the status has changed: + IntCmp $R0 $R1 "${SecName}_unchanged" + !insertmacro LoadSectionSelectedIntoVar ${SecName} ${SecName}_selected + + IntCmp $R1 ${SF_SELECTED} "${SecName}_was_selected" + !insertmacro "Deselect_required_by_${SecName}" + goto "${SecName}_unchanged" + + "${SecName}_was_selected:" + !insertmacro "Select_${SecName}_depends" + + "${SecName}_unchanged:" +!macroend +;--- End of Add/Remove macros --- + +;-------------------------------- +;Interface Settings + + !define MUI_HEADERIMAGE + !define MUI_ABORTWARNING + +;-------------------------------- +; path functions + +!verbose 3 +!include "WinMessages.NSH" +!verbose 4 + +;---------------------------------------- +; based upon a script of "Written by KiCHiK 2003-01-18 05:57:02" +;---------------------------------------- +!verbose 3 +!include "WinMessages.NSH" +!verbose 4 +;==================================================== +; get_NT_environment +; Returns: the selected environment +; Output : head of the stack +;==================================================== +!macro select_NT_profile UN +Function ${UN}select_NT_profile + StrCmp $ADD_TO_PATH_ALL_USERS "1" 0 environment_single + DetailPrint "Selected environment for all users" + Push "all" + Return + environment_single: + DetailPrint "Selected environment for current user only." + Push "current" + Return +FunctionEnd +!macroend +!insertmacro select_NT_profile "" +!insertmacro select_NT_profile "un." +;---------------------------------------------------- +!define NT_current_env 'HKCU "Environment"' +!define NT_all_env 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' + +!ifndef WriteEnvStr_RegKey + !ifdef ALL_USERS + !define WriteEnvStr_RegKey \ + 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' + !else + !define WriteEnvStr_RegKey 'HKCU "Environment"' + !endif +!endif + +; AddToPath - Adds the given dir to the search path. +; Input - head of the stack +; Note - Win9x systems requires reboot + +Function AddToPath + Exch $0 + Push $1 + Push $2 + Push $3 + + # don't add if the path doesn't exist + IfFileExists "$0\*.*" "" AddToPath_done + + ReadEnvStr $1 PATH + ; if the path is too long for a NSIS variable NSIS will return a 0 + ; length string. If we find that, then warn and skip any path + ; modification as it will trash the existing path. + StrLen $2 $1 + IntCmp $2 0 CheckPathLength_ShowPathWarning CheckPathLength_Done CheckPathLength_Done + CheckPathLength_ShowPathWarning: + Messagebox MB_OK|MB_ICONEXCLAMATION "Warning! PATH too long installer unable to modify PATH!" + Goto AddToPath_done + CheckPathLength_Done: + Push "$1;" + Push "$0;" + Call StrStr + Pop $2 + StrCmp $2 "" "" AddToPath_done + Push "$1;" + Push "$0\;" + Call StrStr + Pop $2 + StrCmp $2 "" "" AddToPath_done + GetFullPathName /SHORT $3 $0 + Push "$1;" + Push "$3;" + Call StrStr + Pop $2 + StrCmp $2 "" "" AddToPath_done + Push "$1;" + Push "$3\;" + Call StrStr + Pop $2 + StrCmp $2 "" "" AddToPath_done + + Call IsNT + Pop $1 + StrCmp $1 1 AddToPath_NT + ; Not on NT + StrCpy $1 $WINDIR 2 + FileOpen $1 "$1\autoexec.bat" a + FileSeek $1 -1 END + FileReadByte $1 $2 + IntCmp $2 26 0 +2 +2 # DOS EOF + FileSeek $1 -1 END # write over EOF + FileWrite $1 "$\r$\nSET PATH=%PATH%;$3$\r$\n" + FileClose $1 + SetRebootFlag true + Goto AddToPath_done + + AddToPath_NT: + StrCmp $ADD_TO_PATH_ALL_USERS "1" ReadAllKey + ReadRegStr $1 ${NT_current_env} "PATH" + Goto DoTrim + ReadAllKey: + ReadRegStr $1 ${NT_all_env} "PATH" + DoTrim: + StrCmp $1 "" AddToPath_NTdoIt + Push $1 + Call Trim + Pop $1 + StrCpy $0 "$1;$0" + AddToPath_NTdoIt: + StrCmp $ADD_TO_PATH_ALL_USERS "1" WriteAllKey + WriteRegExpandStr ${NT_current_env} "PATH" $0 + Goto DoSend + WriteAllKey: + WriteRegExpandStr ${NT_all_env} "PATH" $0 + DoSend: + SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 + + AddToPath_done: + Pop $3 + Pop $2 + Pop $1 + Pop $0 +FunctionEnd + + +; RemoveFromPath - Remove a given dir from the path +; Input: head of the stack + +Function un.RemoveFromPath + Exch $0 + Push $1 + Push $2 + Push $3 + Push $4 + Push $5 + Push $6 + + IntFmt $6 "%c" 26 # DOS EOF + + Call un.IsNT + Pop $1 + StrCmp $1 1 unRemoveFromPath_NT + ; Not on NT + StrCpy $1 $WINDIR 2 + FileOpen $1 "$1\autoexec.bat" r + GetTempFileName $4 + FileOpen $2 $4 w + GetFullPathName /SHORT $0 $0 + StrCpy $0 "SET PATH=%PATH%;$0" + Goto unRemoveFromPath_dosLoop + + unRemoveFromPath_dosLoop: + FileRead $1 $3 + StrCpy $5 $3 1 -1 # read last char + StrCmp $5 $6 0 +2 # if DOS EOF + StrCpy $3 $3 -1 # remove DOS EOF so we can compare + StrCmp $3 "$0$\r$\n" unRemoveFromPath_dosLoopRemoveLine + StrCmp $3 "$0$\n" unRemoveFromPath_dosLoopRemoveLine + StrCmp $3 "$0" unRemoveFromPath_dosLoopRemoveLine + StrCmp $3 "" unRemoveFromPath_dosLoopEnd + FileWrite $2 $3 + Goto unRemoveFromPath_dosLoop + unRemoveFromPath_dosLoopRemoveLine: + SetRebootFlag true + Goto unRemoveFromPath_dosLoop + + unRemoveFromPath_dosLoopEnd: + FileClose $2 + FileClose $1 + StrCpy $1 $WINDIR 2 + Delete "$1\autoexec.bat" + CopyFiles /SILENT $4 "$1\autoexec.bat" + Delete $4 + Goto unRemoveFromPath_done + + unRemoveFromPath_NT: + StrCmp $ADD_TO_PATH_ALL_USERS "1" unReadAllKey + ReadRegStr $1 ${NT_current_env} "PATH" + Goto unDoTrim + unReadAllKey: + ReadRegStr $1 ${NT_all_env} "PATH" + unDoTrim: + StrCpy $5 $1 1 -1 # copy last char + StrCmp $5 ";" +2 # if last char != ; + StrCpy $1 "$1;" # append ; + Push $1 + Push "$0;" + Call un.StrStr ; Find `$0;` in $1 + Pop $2 ; pos of our dir + StrCmp $2 "" unRemoveFromPath_done + ; else, it is in path + # $0 - path to add + # $1 - path var + StrLen $3 "$0;" + StrLen $4 $2 + StrCpy $5 $1 -$4 # $5 is now the part before the path to remove + StrCpy $6 $2 "" $3 # $6 is now the part after the path to remove + StrCpy $3 $5$6 + + StrCpy $5 $3 1 -1 # copy last char + StrCmp $5 ";" 0 +2 # if last char == ; + StrCpy $3 $3 -1 # remove last char + + StrCmp $ADD_TO_PATH_ALL_USERS "1" unWriteAllKey + WriteRegExpandStr ${NT_current_env} "PATH" $3 + Goto unDoSend + unWriteAllKey: + WriteRegExpandStr ${NT_all_env} "PATH" $3 + unDoSend: + SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 + + unRemoveFromPath_done: + Pop $6 + Pop $5 + Pop $4 + Pop $3 + Pop $2 + Pop $1 + Pop $0 +FunctionEnd + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Uninstall sutff +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +########################################### +# Utility Functions # +########################################### + +;==================================================== +; IsNT - Returns 1 if the current system is NT, 0 +; otherwise. +; Output: head of the stack +;==================================================== +; IsNT +; no input +; output, top of the stack = 1 if NT or 0 if not +; +; Usage: +; Call IsNT +; Pop $R0 +; ($R0 at this point is 1 or 0) + +!macro IsNT un +Function ${un}IsNT + Push $0 + ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" CurrentVersion + StrCmp $0 "" 0 IsNT_yes + ; we are not NT. + Pop $0 + Push 0 + Return + + IsNT_yes: + ; NT!!! + Pop $0 + Push 1 +FunctionEnd +!macroend +!insertmacro IsNT "" +!insertmacro IsNT "un." + +; StrStr +; input, top of stack = string to search for +; top of stack-1 = string to search in +; output, top of stack (replaces with the portion of the string remaining) +; modifies no other variables. +; +; Usage: +; Push "this is a long ass string" +; Push "ass" +; Call StrStr +; Pop $R0 +; ($R0 at this point is "ass string") + +!macro StrStr un +Function ${un}StrStr +Exch $R1 ; st=haystack,old$R1, $R1=needle + Exch ; st=old$R1,haystack + Exch $R2 ; st=old$R1,old$R2, $R2=haystack + Push $R3 + Push $R4 + Push $R5 + StrLen $R3 $R1 + StrCpy $R4 0 + ; $R1=needle + ; $R2=haystack + ; $R3=len(needle) + ; $R4=cnt + ; $R5=tmp + loop: + StrCpy $R5 $R2 $R3 $R4 + StrCmp $R5 $R1 done + StrCmp $R5 "" done + IntOp $R4 $R4 + 1 + Goto loop +done: + StrCpy $R1 $R2 "" $R4 + Pop $R5 + Pop $R4 + Pop $R3 + Pop $R2 + Exch $R1 +FunctionEnd +!macroend +!insertmacro StrStr "" +!insertmacro StrStr "un." + +Function Trim ; Added by Pelaca + Exch $R1 + Push $R2 +Loop: + StrCpy $R2 "$R1" 1 -1 + StrCmp "$R2" " " RTrim + StrCmp "$R2" "$\n" RTrim + StrCmp "$R2" "$\r" RTrim + StrCmp "$R2" ";" RTrim + GoTo Done +RTrim: + StrCpy $R1 "$R1" -1 + Goto Loop +Done: + Pop $R2 + Exch $R1 +FunctionEnd + +Function ConditionalAddToRegisty + Pop $0 + Pop $1 + StrCmp "$0" "" ConditionalAddToRegisty_EmptyString + WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" \ + "$1" "$0" + ;MessageBox MB_OK "Set Registry: '$1' to '$0'" + DetailPrint "Set install registry entry: '$1' to '$0'" + ConditionalAddToRegisty_EmptyString: +FunctionEnd + +;-------------------------------- + +!ifdef CPACK_USES_DOWNLOAD +Function DownloadFile + IfFileExists $INSTDIR\* +2 + CreateDirectory $INSTDIR + Pop $0 + + ; Skip if already downloaded + IfFileExists $INSTDIR\$0 0 +2 + Return + + StrCpy $1 "@CPACK_DOWNLOAD_SITE@" + + try_again: + NSISdl::download "$1/$0" "$INSTDIR\$0" + + Pop $1 + StrCmp $1 "success" success + StrCmp $1 "Cancelled" cancel + MessageBox MB_OK "Download failed: $1" + cancel: + Return + success: +FunctionEnd +!endif + +;-------------------------------- +; Installation types +@CPACK_NSIS_INSTALLATION_TYPES@ + +;-------------------------------- +; Component sections +@CPACK_NSIS_COMPONENT_SECTIONS@ + +;-------------------------------- +; Define some macro setting for the gui +@CPACK_NSIS_INSTALLER_MUI_ICON_CODE@ +@CPACK_NSIS_INSTALLER_ICON_CODE@ +@CPACK_NSIS_INSTALLER_MUI_COMPONENTS_DESC@ +@CPACK_NSIS_INSTALLER_MUI_FINISHPAGE_RUN_CODE@ + +;-------------------------------- +;Pages + !insertmacro MUI_PAGE_WELCOME + + !insertmacro MUI_PAGE_LICENSE "@CPACK_RESOURCE_FILE_LICENSE@" + Page custom InstallOptionsPage + !insertmacro MUI_PAGE_DIRECTORY + + ;Start Menu Folder Page Configuration + !define MUI_STARTMENUPAGE_REGISTRY_ROOT "SHCTX" + !define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" + !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder" + !insertmacro MUI_PAGE_STARTMENU Application $STARTMENU_FOLDER + + @CPACK_NSIS_PAGE_COMPONENTS@ + + !insertmacro MUI_PAGE_INSTFILES + !insertmacro MUI_PAGE_FINISH + + !insertmacro MUI_UNPAGE_CONFIRM + !insertmacro MUI_UNPAGE_INSTFILES + +;-------------------------------- +;Languages + + !insertmacro MUI_LANGUAGE "English" ;first language is the default language + !insertmacro MUI_LANGUAGE "Albanian" + !insertmacro MUI_LANGUAGE "Arabic" + !insertmacro MUI_LANGUAGE "Basque" + !insertmacro MUI_LANGUAGE "Belarusian" + !insertmacro MUI_LANGUAGE "Bosnian" + !insertmacro MUI_LANGUAGE "Breton" + !insertmacro MUI_LANGUAGE "Bulgarian" + !insertmacro MUI_LANGUAGE "Croatian" + !insertmacro MUI_LANGUAGE "Czech" + !insertmacro MUI_LANGUAGE "Danish" + !insertmacro MUI_LANGUAGE "Dutch" + !insertmacro MUI_LANGUAGE "Estonian" + !insertmacro MUI_LANGUAGE "Farsi" + !insertmacro MUI_LANGUAGE "Finnish" + !insertmacro MUI_LANGUAGE "French" + !insertmacro MUI_LANGUAGE "German" + !insertmacro MUI_LANGUAGE "Greek" + !insertmacro MUI_LANGUAGE "Hebrew" + !insertmacro MUI_LANGUAGE "Hungarian" + !insertmacro MUI_LANGUAGE "Icelandic" + !insertmacro MUI_LANGUAGE "Indonesian" + !insertmacro MUI_LANGUAGE "Irish" + !insertmacro MUI_LANGUAGE "Italian" + !insertmacro MUI_LANGUAGE "Japanese" + !insertmacro MUI_LANGUAGE "Korean" + !insertmacro MUI_LANGUAGE "Kurdish" + !insertmacro MUI_LANGUAGE "Latvian" + !insertmacro MUI_LANGUAGE "Lithuanian" + !insertmacro MUI_LANGUAGE "Luxembourgish" + !insertmacro MUI_LANGUAGE "Macedonian" + !insertmacro MUI_LANGUAGE "Malay" + !insertmacro MUI_LANGUAGE "Mongolian" + !insertmacro MUI_LANGUAGE "Norwegian" + !insertmacro MUI_LANGUAGE "Polish" + !insertmacro MUI_LANGUAGE "Portuguese" + !insertmacro MUI_LANGUAGE "PortugueseBR" + !insertmacro MUI_LANGUAGE "Romanian" + !insertmacro MUI_LANGUAGE "Russian" + !insertmacro MUI_LANGUAGE "Serbian" + !insertmacro MUI_LANGUAGE "SerbianLatin" + !insertmacro MUI_LANGUAGE "SimpChinese" + !insertmacro MUI_LANGUAGE "Slovak" + !insertmacro MUI_LANGUAGE "Slovenian" + !insertmacro MUI_LANGUAGE "Spanish" + !insertmacro MUI_LANGUAGE "Swedish" + !insertmacro MUI_LANGUAGE "Thai" + !insertmacro MUI_LANGUAGE "TradChinese" + !insertmacro MUI_LANGUAGE "Turkish" + !insertmacro MUI_LANGUAGE "Ukrainian" + !insertmacro MUI_LANGUAGE "Welsh" + + +;-------------------------------- +;Reserve Files + + ;These files should be inserted before other files in the data block + ;Keep these lines before any File command + ;Only for solid compression (by default, solid compression is enabled for BZIP2 and LZMA) + + ReserveFile "NSIS.InstallOptions.ini" + !insertmacro MUI_RESERVEFILE_INSTALLOPTIONS + +;-------------------------------- +;Installer Sections + +Section "-Core installation" + ;Use the entire tree produced by the INSTALL target. Keep the + ;list of directories here in sync with the RMDir commands below. + SetOutPath "$INSTDIR" + @CPACK_NSIS_EXTRA_PREINSTALL_COMMANDS@ + @CPACK_NSIS_FULL_INSTALL@ + + ;Store installation folder + WriteRegStr SHCTX "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "" $INSTDIR + + ;Create uninstaller + WriteUninstaller "$INSTDIR\Uninstall.exe" + Push "DisplayName" + Push "@CPACK_NSIS_DISPLAY_NAME@" + Call ConditionalAddToRegisty + Push "DisplayVersion" + Push "@CPACK_PACKAGE_VERSION@" + Call ConditionalAddToRegisty + Push "Publisher" + Push "@CPACK_PACKAGE_VENDOR@" + Call ConditionalAddToRegisty + Push "UninstallString" + Push "$INSTDIR\Uninstall.exe" + Call ConditionalAddToRegisty + Push "NoRepair" + Push "1" + Call ConditionalAddToRegisty + + !ifdef CPACK_NSIS_ADD_REMOVE + ;Create add/remove functionality + Push "ModifyPath" + Push "$INSTDIR\AddRemove.exe" + Call ConditionalAddToRegisty + !else + Push "NoModify" + Push "1" + Call ConditionalAddToRegisty + !endif + + ; Optional registration + Push "DisplayIcon" + Push "$INSTDIR\@CPACK_NSIS_INSTALLED_ICON_NAME@" + Call ConditionalAddToRegisty + Push "HelpLink" + Push "@CPACK_NSIS_HELP_LINK@" + Call ConditionalAddToRegisty + Push "URLInfoAbout" + Push "@CPACK_NSIS_URL_INFO_ABOUT@" + Call ConditionalAddToRegisty + Push "Contact" + Push "@CPACK_NSIS_CONTACT@" + Call ConditionalAddToRegisty + !insertmacro MUI_INSTALLOPTIONS_READ $INSTALL_DESKTOP "NSIS.InstallOptions.ini" "Field 5" "State" + !insertmacro MUI_STARTMENU_WRITE_BEGIN Application + + ;Create shortcuts + CreateDirectory "$SMPROGRAMS\$STARTMENU_FOLDER" +@CPACK_NSIS_CREATE_ICONS@ +@CPACK_NSIS_CREATE_ICONS_EXTRA@ + + ; Conditional handling for interface shortcut + ${If} ${SectionIsSelected} ${client} + CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\High Fidelity.lnk" "$INSTDIR\interface.exe" + ${EndIf} + + CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" "$INSTDIR\Uninstall.exe" + + ;Read a value from an InstallOptions INI file + !insertmacro MUI_INSTALLOPTIONS_READ $DO_NOT_ADD_TO_PATH "NSIS.InstallOptions.ini" "Field 2" "State" + !insertmacro MUI_INSTALLOPTIONS_READ $ADD_TO_PATH_ALL_USERS "NSIS.InstallOptions.ini" "Field 3" "State" + !insertmacro MUI_INSTALLOPTIONS_READ $ADD_TO_PATH_CURRENT_USER "NSIS.InstallOptions.ini" "Field 4" "State" + + ; Write special uninstall registry entries + Push "StartMenu" + Push "$STARTMENU_FOLDER" + Call ConditionalAddToRegisty + Push "DoNotAddToPath" + Push "$DO_NOT_ADD_TO_PATH" + Call ConditionalAddToRegisty + Push "AddToPathAllUsers" + Push "$ADD_TO_PATH_ALL_USERS" + Call ConditionalAddToRegisty + Push "AddToPathCurrentUser" + Push "$ADD_TO_PATH_CURRENT_USER" + Call ConditionalAddToRegisty + Push "InstallToDesktop" + Push "$INSTALL_DESKTOP" + Call ConditionalAddToRegisty + + !insertmacro MUI_STARTMENU_WRITE_END + +@CPACK_NSIS_EXTRA_INSTALL_COMMANDS@ + +SectionEnd + +Section "-Add to path" + Push $INSTDIR\bin + StrCmp "@CPACK_NSIS_MODIFY_PATH@" "ON" 0 doNotAddToPath + StrCmp $DO_NOT_ADD_TO_PATH "1" doNotAddToPath 0 + Call AddToPath + doNotAddToPath: +SectionEnd + +;-------------------------------- +; Create custom pages +Function InstallOptionsPage + !insertmacro MUI_HEADER_TEXT "Install Options" "Choose options for installing @CPACK_NSIS_PACKAGE_NAME@" + !insertmacro MUI_INSTALLOPTIONS_DISPLAY "NSIS.InstallOptions.ini" + +FunctionEnd + +;-------------------------------- +; determine admin versus local install +Function un.onInit + + ClearErrors + UserInfo::GetName + IfErrors noLM + Pop $0 + UserInfo::GetAccountType + Pop $1 + StrCmp $1 "Admin" 0 +3 + SetShellVarContext all + ;MessageBox MB_OK 'User "$0" is in the Admin group' + Goto done + StrCmp $1 "Power" 0 +3 + SetShellVarContext all + ;MessageBox MB_OK 'User "$0" is in the Power Users group' + Goto done + + noLM: + ;Get installation folder from registry if available + + done: + +FunctionEnd + +;--- Add/Remove callback functions: --- +!macro SectionList MacroName + ;This macro used to perform operation on multiple sections. + ;List all of your components in following manner here. +@CPACK_NSIS_COMPONENT_SECTION_LIST@ +!macroend + +Section -FinishComponents + ;Removes unselected components and writes component status to registry + !insertmacro SectionList "FinishSection" + +!ifdef CPACK_NSIS_ADD_REMOVE + ; Get the name of the installer executable + System::Call 'kernel32::GetModuleFileNameA(i 0, t .R0, i 1024) i r1' + StrCpy $R3 $R0 + + ; Strip off the last 13 characters, to see if we have AddRemove.exe + StrLen $R1 $R0 + IntOp $R1 $R0 - 13 + StrCpy $R2 $R0 13 $R1 + StrCmp $R2 "AddRemove.exe" addremove_installed + + ; We're not running AddRemove.exe, so install it + CopyFiles $R3 $INSTDIR\AddRemove.exe + + addremove_installed: +!endif +SectionEnd +;--- End of Add/Remove callback functions --- + +;-------------------------------- +; Component dependencies +Function .onSelChange + !insertmacro SectionList MaybeSelectionChanged +FunctionEnd + +;-------------------------------- +;Uninstaller Section + +Section "Uninstall" + ReadRegStr $START_MENU SHCTX \ + "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "StartMenu" + ;MessageBox MB_OK "Start menu is in: $START_MENU" + ReadRegStr $DO_NOT_ADD_TO_PATH SHCTX \ + "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "DoNotAddToPath" + ReadRegStr $ADD_TO_PATH_ALL_USERS SHCTX \ + "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "AddToPathAllUsers" + ReadRegStr $ADD_TO_PATH_CURRENT_USER SHCTX \ + "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "AddToPathCurrentUser" + ;MessageBox MB_OK "Add to path: $DO_NOT_ADD_TO_PATH all users: $ADD_TO_PATH_ALL_USERS" + ReadRegStr $INSTALL_DESKTOP SHCTX \ + "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "InstallToDesktop" + ;MessageBox MB_OK "Install to desktop: $INSTALL_DESKTOP " + +@CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS@ + + ;Remove files we installed. + ;Keep the list of directories here in sync with the File commands above. +@CPACK_NSIS_DELETE_FILES@ +@CPACK_NSIS_DELETE_DIRECTORIES@ + +!ifdef CPACK_NSIS_ADD_REMOVE + ;Remove the add/remove program + Delete "$INSTDIR\AddRemove.exe" +!endif + + ;Remove the uninstaller itself. + Delete "$INSTDIR\Uninstall.exe" + DeleteRegKey SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" + + ;Remove the installation directory if it is empty. + RMDir "$INSTDIR" + + ; Remove the registry entries. + DeleteRegKey SHCTX "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" + + ; Removes all optional components + !insertmacro SectionList "RemoveSection_CPack" + + !insertmacro MUI_STARTMENU_GETFOLDER Application $MUI_TEMP + + Delete "$SMPROGRAMS\$MUI_TEMP\Uninstall.lnk" +@CPACK_NSIS_DELETE_ICONS@ +@CPACK_NSIS_DELETE_ICONS_EXTRA@ + + ;Delete empty start menu parent diretories + StrCpy $MUI_TEMP "$SMPROGRAMS\$MUI_TEMP" + + startMenuDeleteLoop: + ClearErrors + RMDir $MUI_TEMP + GetFullPathName $MUI_TEMP "$MUI_TEMP\.." + + IfErrors startMenuDeleteLoopDone + + StrCmp "$MUI_TEMP" "$SMPROGRAMS" startMenuDeleteLoopDone startMenuDeleteLoop + startMenuDeleteLoopDone: + + ; If the user changed the shortcut, then untinstall may not work. This should + ; try to fix it. + StrCpy $MUI_TEMP "$START_MENU" + Delete "$SMPROGRAMS\$MUI_TEMP\Uninstall.lnk" +@CPACK_NSIS_DELETE_ICONS_EXTRA@ + + ;Delete empty start menu parent diretories + StrCpy $MUI_TEMP "$SMPROGRAMS\$MUI_TEMP" + + secondStartMenuDeleteLoop: + ClearErrors + RMDir $MUI_TEMP + GetFullPathName $MUI_TEMP "$MUI_TEMP\.." + + IfErrors secondStartMenuDeleteLoopDone + + StrCmp "$MUI_TEMP" "$SMPROGRAMS" secondStartMenuDeleteLoopDone secondStartMenuDeleteLoop + secondStartMenuDeleteLoopDone: + + DeleteRegKey /ifempty SHCTX "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" + + Push $INSTDIR\bin + StrCmp $DO_NOT_ADD_TO_PATH_ "1" doNotRemoveFromPath 0 + Call un.RemoveFromPath + doNotRemoveFromPath: +SectionEnd + +;-------------------------------- +; determine admin versus local install +; Is install for "AllUsers" or "JustMe"? +; Default to "JustMe" - set to "AllUsers" if admin or on Win9x +; This function is used for the very first "custom page" of the installer. +; This custom page does not show up visibly, but it executes prior to the +; first visible page and sets up $INSTDIR properly... +; Choose different default installation folder based on SV_ALLUSERS... +; "Program Files" for AllUsers, "My Documents" for JustMe... + +Function .onInit + StrCmp "@CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL@" "ON" 0 inst + + ReadRegStr $0 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "UninstallString" + StrCmp $0 "" inst + + MessageBox MB_YESNOCANCEL|MB_ICONEXCLAMATION \ + "@CPACK_NSIS_PACKAGE_NAME@ is already installed. $\n$\nDo you want to uninstall the old version before installing the new one?" \ + IDYES uninst IDNO inst + Abort + +;Run the uninstaller +uninst: + ClearErrors + StrLen $2 "\Uninstall.exe" + StrCpy $3 $0 -$2 # remove "\Uninstall.exe" from UninstallString to get path + ExecWait '$0 _?=$3' ;Do not copy the uninstaller to a temp file + + IfErrors uninst_failed inst +uninst_failed: + MessageBox MB_OK|MB_ICONSTOP "Uninstall failed." + Abort + + +inst: + ; Reads components status for registry + !insertmacro SectionList "InitSection" + + ; check to see if /D has been used to change + ; the install directory by comparing it to the + ; install directory that is expected to be the + ; default + StrCpy $IS_DEFAULT_INSTALLDIR 0 + StrCmp "$INSTDIR" "@CPACK_NSIS_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_DIRECTORY@" 0 +2 + StrCpy $IS_DEFAULT_INSTALLDIR 1 + + StrCpy $SV_ALLUSERS "JustMe" + ; if default install dir then change the default + ; if it is installed for JustMe + StrCmp "$IS_DEFAULT_INSTALLDIR" "1" 0 +2 + StrCpy $INSTDIR "$DOCUMENTS\@CPACK_PACKAGE_INSTALL_DIRECTORY@" + + ClearErrors + UserInfo::GetName + IfErrors noLM + Pop $0 + UserInfo::GetAccountType + Pop $1 + StrCmp $1 "Admin" 0 +4 + SetShellVarContext all + ;MessageBox MB_OK 'User "$0" is in the Admin group' + StrCpy $SV_ALLUSERS "AllUsers" + Goto done + StrCmp $1 "Power" 0 +4 + SetShellVarContext all + ;MessageBox MB_OK 'User "$0" is in the Power Users group' + StrCpy $SV_ALLUSERS "AllUsers" + Goto done + + noLM: + StrCpy $SV_ALLUSERS "AllUsers" + ;Get installation folder from registry if available + + done: + StrCmp $SV_ALLUSERS "AllUsers" 0 +3 + StrCmp "$IS_DEFAULT_INSTALLDIR" "1" 0 +2 + StrCpy $INSTDIR "@CPACK_NSIS_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_DIRECTORY@" + + StrCmp "@CPACK_NSIS_MODIFY_PATH@" "ON" 0 noOptionsPage + !insertmacro MUI_INSTALLOPTIONS_EXTRACT "NSIS.InstallOptions.ini" + + noOptionsPage: +FunctionEnd From a6006af7be5cf7b9bc6d2b230df985aa48e7913e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 8 Jan 2016 17:10:51 -0800 Subject: [PATCH 101/357] use variables in NSIS script for names --- cmake/templates/NSIS.template.in | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 1d3d084486..1c23101537 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -7,6 +7,9 @@ !define PATCH "@CPACK_PACKAGE_VERSION_PATCH@" !define INST_DIR "@CPACK_TEMPORARY_DIRECTORY@" + !define INTERFACE_SHORTCUT_NAME "High Fidelity" + !define INTERFACE_EXEC_NAME "interface.exe" + ;-------------------------------- ;Variables @@ -698,7 +701,7 @@ Section "-Core installation" ; Conditional handling for interface shortcut ${If} ${SectionIsSelected} ${client} - CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\High Fidelity.lnk" "$INSTDIR\interface.exe" + CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\$INTERFACE_SHORTCUT_NAME.lnk" "$INSTDIR\$INTERFACE_EXEC_NAME" ${EndIf} CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" "$INSTDIR\Uninstall.exe" @@ -855,6 +858,7 @@ Section "Uninstall" !insertmacro MUI_STARTMENU_GETFOLDER Application $MUI_TEMP Delete "$SMPROGRAMS\$MUI_TEMP\Uninstall.lnk" + Delete "$SMPROGRAMS\$MUI_TEMP\$INTERFACE_SHORTCUT_NAME.lnk" @CPACK_NSIS_DELETE_ICONS@ @CPACK_NSIS_DELETE_ICONS_EXTRA@ From 9c8a05fad935e8c7ea1481dbaaa31a291efa96dd Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 11 Jan 2016 10:12:38 -0800 Subject: [PATCH 102/357] use string variables for interface shortcut setup --- cmake/templates/NSIS.template.in | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 1c23101537..c2c5ab80e7 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -1,5 +1,11 @@ ; CPack install script designed for a nmake build +;-------------------------------- +; Variables that drive High Fidelity custom behaviour + + StrCpy $INTERFACE_SHORTCUT_NAME "High Fidelity" + StrCpy $INTERFACE_EXEC_NAME "interface.exe" + ;-------------------------------- ; You must define these values @@ -7,9 +13,6 @@ !define PATCH "@CPACK_PACKAGE_VERSION_PATCH@" !define INST_DIR "@CPACK_TEMPORARY_DIRECTORY@" - !define INTERFACE_SHORTCUT_NAME "High Fidelity" - !define INTERFACE_EXEC_NAME "interface.exe" - ;-------------------------------- ;Variables From 70077591dfeffc61198785fc08a60a902ecac308 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 11 Jan 2016 10:17:54 -0800 Subject: [PATCH 103/357] correct intepolation for defines in NSIS --- cmake/templates/NSIS.template.in | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index c2c5ab80e7..483b863cfb 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -3,8 +3,8 @@ ;-------------------------------- ; Variables that drive High Fidelity custom behaviour - StrCpy $INTERFACE_SHORTCUT_NAME "High Fidelity" - StrCpy $INTERFACE_EXEC_NAME "interface.exe" + !define INTERFACE_SHORTCUT_NAME "High Fidelity" + !define INTERFACE_EXEC_NAME "interface.exe" ;-------------------------------- ; You must define these values @@ -704,7 +704,7 @@ Section "-Core installation" ; Conditional handling for interface shortcut ${If} ${SectionIsSelected} ${client} - CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\$INTERFACE_SHORTCUT_NAME.lnk" "$INSTDIR\$INTERFACE_EXEC_NAME" + CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\${INTERFACE_SHORTCUT_NAME}.lnk" "$INSTDIR\${INTERFACE_EXEC_NAME}" ${EndIf} CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" "$INSTDIR\Uninstall.exe" @@ -861,7 +861,7 @@ Section "Uninstall" !insertmacro MUI_STARTMENU_GETFOLDER Application $MUI_TEMP Delete "$SMPROGRAMS\$MUI_TEMP\Uninstall.lnk" - Delete "$SMPROGRAMS\$MUI_TEMP\$INTERFACE_SHORTCUT_NAME.lnk" + Delete "$SMPROGRAMS\$MUI_TEMP\${INTERFACE_SHORTCUT_NAME}.lnk" @CPACK_NSIS_DELETE_ICONS@ @CPACK_NSIS_DELETE_ICONS_EXTRA@ From 6f7663fbae5f2b3d1d72e0b7e5d7d02313a7d3ee Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 11 Jan 2016 10:25:38 -0800 Subject: [PATCH 104/357] add conditional handling for server-console shortcut --- cmake/templates/NSIS.template.in | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 483b863cfb..c047b69e65 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -5,6 +5,8 @@ !define INTERFACE_SHORTCUT_NAME "High Fidelity" !define INTERFACE_EXEC_NAME "interface.exe" + !define CONSOLE_SHORTCUT_NAME "Server Console" + !define CONSOLE_EXEC_NAME "server-console.exe" ;-------------------------------- ; You must define these values @@ -707,6 +709,11 @@ Section "-Core installation" CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\${INTERFACE_SHORTCUT_NAME}.lnk" "$INSTDIR\${INTERFACE_EXEC_NAME}" ${EndIf} + ; Conditional handling for server console shortcut + ${If} ${SectionIsSelected} ${server} + CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\${CONSOLE_SHORTCUT_NAME}.lnk" "$INSTDIR\${CONSOLE_EXEC_NAME}" + ${EndIf} + CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" "$INSTDIR\Uninstall.exe" ;Read a value from an InstallOptions INI file @@ -862,6 +869,7 @@ Section "Uninstall" Delete "$SMPROGRAMS\$MUI_TEMP\Uninstall.lnk" Delete "$SMPROGRAMS\$MUI_TEMP\${INTERFACE_SHORTCUT_NAME}.lnk" + Delete "$SMPROGRAMS\$MUI_TEMP\${CONSOLE_SHORTCUT_NAME}.lnk" @CPACK_NSIS_DELETE_ICONS@ @CPACK_NSIS_DELETE_ICONS_EXTRA@ From f8f0b99a46c9f535da01e2bc94f224b0e3061ad2 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 11 Jan 2016 11:05:56 -0800 Subject: [PATCH 105/357] add icon to interface exec, icons in start menu --- cmake/macros/SetPackagingParameters.cmake | 9 ++++++--- cmake/templates/Icon.rc.in | 1 + cmake/templates/NSIS.template.in | 10 ++++++++-- interface/CMakeLists.txt | 19 ++++++++++++------- 4 files changed, 27 insertions(+), 12 deletions(-) create mode 100644 cmake/templates/Icon.rc.in diff --git a/cmake/macros/SetPackagingParameters.cmake b/cmake/macros/SetPackagingParameters.cmake index b76da6ded6..a73daa4504 100644 --- a/cmake/macros/SetPackagingParameters.cmake +++ b/cmake/macros/SetPackagingParameters.cmake @@ -20,7 +20,7 @@ macro(SET_PACKAGING_PARAMETERS) set(INSTALLER_DIRECTORY "${INSTALLER_COMPANY}") set(INSTALLER_NAME "interface-win64-${BUILD_SEQ}.exe") set(INTERFACE_BUNDLE_NAME "High Fidelity") - set(INTERFACE_ICON "interface.ico") + set(INTERFACE_ICON_PREFIX "interface") set(CONSOLE_ICON "console.ico") elseif (DEFINED ENV{ghprbPullId}) set(DEPLOY_PACKAGE TRUE) @@ -30,7 +30,7 @@ macro(SET_PACKAGING_PARAMETERS) set(INSTALLER_DIRECTORY "${INSTALLER_COMPANY}\\${BUILD_SEQ}") set(INSTALLER_NAME "pr-interface-win64-${BUILD_SEQ}.exe") set(INTERFACE_BUNDLE_NAME "High Fidelity ${BUILD_SEQ}") - set(INTERFACE_ICON "interface-beta.ico") + set(INTERFACE_ICON_PREFIX "interface-beta") set(CONSOLE_ICON "console-beta.ico") else () set(BUILD_SEQ "dev") @@ -39,12 +39,13 @@ macro(SET_PACKAGING_PARAMETERS) set(INSTALLER_DIRECTORY "${INSTALLER_COMPANY}") set(INSTALLER_NAME "dev-interface-win64.exe") set(INTERFACE_BUNDLE_NAME "Interface") - set(INTERFACE_ICON "interface-beta.ico") + set(INTERFACE_ICON_PREFIX "interface-beta") set(CONSOLE_ICON "console-beta.ico") endif () if (WIN32) set(INTERFACE_EXEC_NAME "interface") + set(INTERFACE_ICON_FILENAME "${INTERFACE_ICON_NAME}.ico") endif () if (APPLE) @@ -54,6 +55,8 @@ macro(SET_PACKAGING_PARAMETERS) set(INTERFACE_INSTALL_DIR ".") set(INTERFACE_INSTALL_APP_PATH "${INTERFACE_BUNDLE_NAME}.app") + + set(INTERFACE_ICON_FILENAME "${INTERFACE_ICON_NAME}.icns") else () set(CONSOLE_INSTALL_DIR ".") set(INTERFACE_INSTALL_DIR ".") diff --git a/cmake/templates/Icon.rc.in b/cmake/templates/Icon.rc.in new file mode 100644 index 0000000000..0a487c96ae --- /dev/null +++ b/cmake/templates/Icon.rc.in @@ -0,0 +1 @@ +IDI_ICON1 ICON DISCARDABLE "@ICON_FILENAME@" diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index c047b69e65..a6c4e0a95d 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -5,8 +5,10 @@ !define INTERFACE_SHORTCUT_NAME "High Fidelity" !define INTERFACE_EXEC_NAME "interface.exe" + !define INTERFACE_ICON_NAME "interface.ico" !define CONSOLE_SHORTCUT_NAME "Server Console" !define CONSOLE_EXEC_NAME "server-console.exe" + !define CONSOLE_ICON_INDEX "1" ;-------------------------------- ; You must define these values @@ -706,12 +708,16 @@ Section "-Core installation" ; Conditional handling for interface shortcut ${If} ${SectionIsSelected} ${client} - CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\${INTERFACE_SHORTCUT_NAME}.lnk" "$INSTDIR\${INTERFACE_EXEC_NAME}" + CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\${INTERFACE_SHORTCUT_NAME}.lnk" \ + "$INSTDIR\${INTERFACE_EXEC_NAME}" \ + "$INSTDIR\${INTERFACE_EXEC_NAME}" ${INTERFACE_ICON_INDEX} ${EndIf} ; Conditional handling for server console shortcut ${If} ${SectionIsSelected} ${server} - CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\${CONSOLE_SHORTCUT_NAME}.lnk" "$INSTDIR\${CONSOLE_EXEC_NAME}" + CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\${CONSOLE_SHORTCUT_NAME}.lnk" \ + "$INSTDIR\${CONSOLE_EXEC_NAME}" \ + "$INSTDIR\${CONSOLE_EXEC_NAME}" ${CONSOLE_ICON_INDEX}\ ${EndIf} CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" "$INSTDIR\Uninstall.exe" diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 8596b2ac77..aaf2891067 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -67,22 +67,19 @@ if (APPLE) if (PRODUCTION_BUILD) set(MACOSX_BUNDLE_GUI_IDENTIFIER com.highfidelity.interface) - set(ICON_FILENAME "interface.icns") else () if (DEV_BUILD) set(MACOSX_BUNDLE_GUI_IDENTIFIER com.highfidelity.interface-dev) elseif (PR_BUILD) set(MACOSX_BUNDLE_GUI_IDENTIFIER com.highfidelity.interface-pr) endif () - - set(ICON_FILENAME "interface-beta.icns") endif () # set how the icon shows up in the Info.plist file - SET(MACOSX_BUNDLE_ICON_FILE "${ICON_FILENAME}") + set(MACOSX_BUNDLE_ICON_FILE "${INTERfACE_ICON_FILENAME}") # set where in the bundle to put the resources file - SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_SOURCE_DIR}/icon/${ICON_FILENAME} PROPERTIES MACOSX_PACKAGE_LOCATION Resources) + set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/icon/${INTERFACE_ICON_FILENAME} PROPERTIES MACOSX_PACKAGE_LOCATION Resources) set(DISCOVERED_RESOURCES "") @@ -92,7 +89,7 @@ if (APPLE) # append the discovered resources to our list of interface sources list(APPEND INTERFACE_SRCS ${DISCOVERED_RESOURCES}) - set(INTERFACE_SRCS ${INTERFACE_SRCS} "${CMAKE_CURRENT_SOURCE_DIR}/icon/${ICON_FILENAME}") + set(INTERFACE_SRCS ${INTERFACE_SRCS} "${CMAKE_CURRENT_SOURCE_DIR}/icon/${INTERFACE_ICON_FILENAME}") endif() # create the executable, make it a bundle on OS X @@ -102,7 +99,15 @@ if (APPLE) # make sure the output name for the .app bundle is correct set_target_properties(${TARGET_NAME} PROPERTIES OUTPUT_NAME ${INTERFACE_BUNDLE_NAME}) elseif(WIN32) - add_executable(${TARGET_NAME} WIN32 ${INTERFACE_SRCS} ${QM}) + # configure an rc file for the chosen icon + set(CONFIGURE_ICON_FILENAME ${INTERFACE_ICON_FILENAME}) + set(CONFIGURE_ICON_RC_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Icon.rc") + configure_file("${CMAKE_CURRENT_SOURCE_DIR}/templates/Icon.rc.in" ${CONFIGURE_ICON_RC_OUTPUT}) + + # add an executable that also has the icon itself and the configured rc file as resources + add_executable(${TARGET_NAME} WIN32 + ${INTERFACE_SRCS} ${QM} ${CONFIGURE_ICON_RC_OUTPUT} "${CMAKE_CURRENT_SOURCE_DIR}/icon/${INTERFACE_ICON_FILENAME}" + ) else() add_executable(${TARGET_NAME} ${INTERFACE_SRCS} ${QM}) endif() From 301124ba3c97949a2fdf4385fa3c167b68ca1d77 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 11 Jan 2016 11:08:24 -0800 Subject: [PATCH 106/357] fix reference to rc template and icon prefix --- cmake/macros/SetPackagingParameters.cmake | 4 ++-- cmake/templates/Icon.rc.in | 2 +- interface/CMakeLists.txt | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cmake/macros/SetPackagingParameters.cmake b/cmake/macros/SetPackagingParameters.cmake index a73daa4504..194fe6b694 100644 --- a/cmake/macros/SetPackagingParameters.cmake +++ b/cmake/macros/SetPackagingParameters.cmake @@ -45,7 +45,7 @@ macro(SET_PACKAGING_PARAMETERS) if (WIN32) set(INTERFACE_EXEC_NAME "interface") - set(INTERFACE_ICON_FILENAME "${INTERFACE_ICON_NAME}.ico") + set(INTERFACE_ICON_FILENAME "${INTERFACE_ICON_PREFIX}.ico") endif () if (APPLE) @@ -56,7 +56,7 @@ macro(SET_PACKAGING_PARAMETERS) set(INTERFACE_INSTALL_DIR ".") set(INTERFACE_INSTALL_APP_PATH "${INTERFACE_BUNDLE_NAME}.app") - set(INTERFACE_ICON_FILENAME "${INTERFACE_ICON_NAME}.icns") + set(INTERFACE_ICON_FILENAME "${INTERFACE_ICON_PREFIX}.icns") else () set(CONSOLE_INSTALL_DIR ".") set(INTERFACE_INSTALL_DIR ".") diff --git a/cmake/templates/Icon.rc.in b/cmake/templates/Icon.rc.in index 0a487c96ae..c7642347ac 100644 --- a/cmake/templates/Icon.rc.in +++ b/cmake/templates/Icon.rc.in @@ -1 +1 @@ -IDI_ICON1 ICON DISCARDABLE "@ICON_FILENAME@" +IDI_ICON1 ICON DISCARDABLE "@CONFIGURE_ICON_FILENAME@" diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index aaf2891067..b34f0d263c 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -102,7 +102,7 @@ elseif(WIN32) # configure an rc file for the chosen icon set(CONFIGURE_ICON_FILENAME ${INTERFACE_ICON_FILENAME}) set(CONFIGURE_ICON_RC_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Icon.rc") - configure_file("${CMAKE_CURRENT_SOURCE_DIR}/templates/Icon.rc.in" ${CONFIGURE_ICON_RC_OUTPUT}) + configure_file("${HF_CMAKE_DIR}/templates/Icon.rc.in" ${CONFIGURE_ICON_RC_OUTPUT}) # add an executable that also has the icon itself and the configured rc file as resources add_executable(${TARGET_NAME} WIN32 From ae67da4bcb668b61db02aa6807b2d890ad4306f1 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 11 Jan 2016 11:21:38 -0800 Subject: [PATCH 107/357] use absolute path to interface icon --- cmake/templates/Icon.rc.in | 2 +- interface/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/templates/Icon.rc.in b/cmake/templates/Icon.rc.in index c7642347ac..d5f6ca74d6 100644 --- a/cmake/templates/Icon.rc.in +++ b/cmake/templates/Icon.rc.in @@ -1 +1 @@ -IDI_ICON1 ICON DISCARDABLE "@CONFIGURE_ICON_FILENAME@" +IDI_ICON1 ICON DISCARDABLE "@CONFIGURE_ICON_PATH@" diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index b34f0d263c..bc459c0e7e 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -100,7 +100,7 @@ if (APPLE) set_target_properties(${TARGET_NAME} PROPERTIES OUTPUT_NAME ${INTERFACE_BUNDLE_NAME}) elseif(WIN32) # configure an rc file for the chosen icon - set(CONFIGURE_ICON_FILENAME ${INTERFACE_ICON_FILENAME}) + set(CONFIGURE_ICON_PATH "${CMAKE_CURRENT_SOURCE_DIR}/icon/${INTERFACE_ICON_FILENAME}") set(CONFIGURE_ICON_RC_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Icon.rc") configure_file("${HF_CMAKE_DIR}/templates/Icon.rc.in" ${CONFIGURE_ICON_RC_OUTPUT}) From 6a503f3db01899aa80765243b5d51673823895e2 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 11 Jan 2016 11:22:14 -0800 Subject: [PATCH 108/357] remove icon as source to interface executable --- interface/CMakeLists.txt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index bc459c0e7e..33b7777042 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -105,9 +105,7 @@ elseif(WIN32) configure_file("${HF_CMAKE_DIR}/templates/Icon.rc.in" ${CONFIGURE_ICON_RC_OUTPUT}) # add an executable that also has the icon itself and the configured rc file as resources - add_executable(${TARGET_NAME} WIN32 - ${INTERFACE_SRCS} ${QM} ${CONFIGURE_ICON_RC_OUTPUT} "${CMAKE_CURRENT_SOURCE_DIR}/icon/${INTERFACE_ICON_FILENAME}" - ) + add_executable(${TARGET_NAME} WIN32 ${INTERFACE_SRCS} ${QM} ${CONFIGURE_ICON_RC_OUTPUT}) else() add_executable(${TARGET_NAME} ${INTERFACE_SRCS} ${QM}) endif() From 25d9a1869a96086c73eaf176ed32f6fc9b955ae9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 11 Jan 2016 11:41:15 -0800 Subject: [PATCH 109/357] handle skipped parameters in CreateShortcut call --- cmake/templates/NSIS.template.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index a6c4e0a95d..2c7b23f8f2 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -710,6 +710,7 @@ Section "-Core installation" ${If} ${SectionIsSelected} ${client} CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\${INTERFACE_SHORTCUT_NAME}.lnk" \ "$INSTDIR\${INTERFACE_EXEC_NAME}" \ + "" \ "$INSTDIR\${INTERFACE_EXEC_NAME}" ${INTERFACE_ICON_INDEX} ${EndIf} @@ -717,6 +718,7 @@ Section "-Core installation" ${If} ${SectionIsSelected} ${server} CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\${CONSOLE_SHORTCUT_NAME}.lnk" \ "$INSTDIR\${CONSOLE_EXEC_NAME}" \ + "" \ "$INSTDIR\${CONSOLE_EXEC_NAME}" ${CONSOLE_ICON_INDEX}\ ${EndIf} From 7f1c66f529655a0c74f6ae65c773b7d457d77448 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 11 Jan 2016 11:42:08 -0800 Subject: [PATCH 110/357] replace interface icon name with icon index --- cmake/templates/NSIS.template.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 2c7b23f8f2..50484ca9f1 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -5,7 +5,7 @@ !define INTERFACE_SHORTCUT_NAME "High Fidelity" !define INTERFACE_EXEC_NAME "interface.exe" - !define INTERFACE_ICON_NAME "interface.ico" + !define INTERFACE_ICON_INDEX "0" !define CONSOLE_SHORTCUT_NAME "Server Console" !define CONSOLE_EXEC_NAME "server-console.exe" !define CONSOLE_ICON_INDEX "1" From b8966de85e452bd43e5b8f6a68432a389311fe66 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 11 Jan 2016 12:25:08 -0800 Subject: [PATCH 111/357] simplified shortcut creation for nsis installer --- cmake/templates/NSIS.template.in | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 50484ca9f1..7d1e8ae379 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -5,10 +5,8 @@ !define INTERFACE_SHORTCUT_NAME "High Fidelity" !define INTERFACE_EXEC_NAME "interface.exe" - !define INTERFACE_ICON_INDEX "0" !define CONSOLE_SHORTCUT_NAME "Server Console" !define CONSOLE_EXEC_NAME "server-console.exe" - !define CONSOLE_ICON_INDEX "1" ;-------------------------------- ; You must define these values @@ -709,17 +707,13 @@ Section "-Core installation" ; Conditional handling for interface shortcut ${If} ${SectionIsSelected} ${client} CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\${INTERFACE_SHORTCUT_NAME}.lnk" \ - "$INSTDIR\${INTERFACE_EXEC_NAME}" \ - "" \ - "$INSTDIR\${INTERFACE_EXEC_NAME}" ${INTERFACE_ICON_INDEX} + "$INSTDIR\${INTERFACE_EXEC_NAME}" ${EndIf} ; Conditional handling for server console shortcut ${If} ${SectionIsSelected} ${server} CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\${CONSOLE_SHORTCUT_NAME}.lnk" \ - "$INSTDIR\${CONSOLE_EXEC_NAME}" \ - "" \ - "$INSTDIR\${CONSOLE_EXEC_NAME}" ${CONSOLE_ICON_INDEX}\ + "$INSTDIR\${CONSOLE_EXEC_NAME}" ${EndIf} CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" "$INSTDIR\Uninstall.exe" From 7739749220603c9079a50940cc5f7423b28101cd Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 11 Jan 2016 13:28:26 -0800 Subject: [PATCH 112/357] add URL handler registration for Interface --- cmake/templates/NSIS.template.in | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 7d1e8ae379..e99d3b6441 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -704,10 +704,16 @@ Section "-Core installation" @CPACK_NSIS_CREATE_ICONS@ @CPACK_NSIS_CREATE_ICONS_EXTRA@ - ; Conditional handling for interface shortcut + ; Conditional handling for Interface specific options ${If} ${SectionIsSelected} ${client} CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\${INTERFACE_SHORTCUT_NAME}.lnk" \ "$INSTDIR\${INTERFACE_EXEC_NAME}" + + ; hifi:// protocol handler registry entries + WriteRegStr HKCR 'hifi' '' 'URL:Alert Protocol' + WriteRegStr HKCR 'hifi' 'URL Protocol' '' + WriteRegStr HKCR 'hifi\DefaultIcon' '' '$INSTDIR\${INTERFACE_EXEC_NAME},1' + WriteRegStr HKCR 'hifi\shell\open\command' '' '$INSTDIR\${INTERFACE_EXEC_NAME} --url "%1"' ${EndIf} ; Conditional handling for server console shortcut From f844573566604a38ee5b133a3e4c006dcb9e6c4e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 11 Jan 2016 13:38:35 -0800 Subject: [PATCH 113/357] name hifi:// links the High Fidelity Protocol --- cmake/templates/NSIS.template.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index e99d3b6441..dd25947339 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -710,7 +710,7 @@ Section "-Core installation" "$INSTDIR\${INTERFACE_EXEC_NAME}" ; hifi:// protocol handler registry entries - WriteRegStr HKCR 'hifi' '' 'URL:Alert Protocol' + WriteRegStr HKCR 'hifi' '' 'URL:High Fidelity Protocol' WriteRegStr HKCR 'hifi' 'URL Protocol' '' WriteRegStr HKCR 'hifi\DefaultIcon' '' '$INSTDIR\${INTERFACE_EXEC_NAME},1' WriteRegStr HKCR 'hifi\shell\open\command' '' '$INSTDIR\${INTERFACE_EXEC_NAME} --url "%1"' From 0cdc78bdbeed8a45a75e266a7c9323a123d86033 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 11 Jan 2016 13:42:48 -0800 Subject: [PATCH 114/357] remove High Fidelity protocol during uninstall --- cmake/templates/NSIS.template.in | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index dd25947339..9caa4857cf 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -7,6 +7,7 @@ !define INTERFACE_EXEC_NAME "interface.exe" !define CONSOLE_SHORTCUT_NAME "Server Console" !define CONSOLE_EXEC_NAME "server-console.exe" + !define HIGH_FIDELITY_PROTOCOL "hifi" ;-------------------------------- ; You must define these values @@ -710,10 +711,10 @@ Section "-Core installation" "$INSTDIR\${INTERFACE_EXEC_NAME}" ; hifi:// protocol handler registry entries - WriteRegStr HKCR 'hifi' '' 'URL:High Fidelity Protocol' - WriteRegStr HKCR 'hifi' 'URL Protocol' '' - WriteRegStr HKCR 'hifi\DefaultIcon' '' '$INSTDIR\${INTERFACE_EXEC_NAME},1' - WriteRegStr HKCR 'hifi\shell\open\command' '' '$INSTDIR\${INTERFACE_EXEC_NAME} --url "%1"' + WriteRegStr HKCR '${HIGH_FIDELITY_PROTOCOL}' '' 'URL:High Fidelity Protocol' + WriteRegStr HKCR '${HIGH_FIDELITY_PROTOCOL}' 'URL Protocol' '' + WriteRegStr HKCR '${HIGH_FIDELITY_PROTOCOL}\DefaultIcon' '' '$INSTDIR\${INTERFACE_EXEC_NAME},1' + WriteRegStr HKCR '${HIGH_FIDELITY_PROTOCOL}\shell\open\command' '' '$INSTDIR\${INTERFACE_EXEC_NAME} --url "%1"' ${EndIf} ; Conditional handling for server console shortcut @@ -881,6 +882,9 @@ Section "Uninstall" @CPACK_NSIS_DELETE_ICONS@ @CPACK_NSIS_DELETE_ICONS_EXTRA@ + ;Delete High Fidelity protocol handling + DeleteRegKey HKCR '${HIGH_FIDELITY_PROTOCOL}' + ;Delete empty start menu parent diretories StrCpy $MUI_TEMP "$SMPROGRAMS\$MUI_TEMP" From b4002d5f42f6dc2c324517efb28b84b718b2c812 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 11 Jan 2016 14:00:19 -0800 Subject: [PATCH 115/357] conditional reg entries for prod build only --- cmake/templates/NSIS.template.in | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 9caa4857cf..7c0aa47272 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -8,6 +8,7 @@ !define CONSOLE_SHORTCUT_NAME "Server Console" !define CONSOLE_EXEC_NAME "server-console.exe" !define HIGH_FIDELITY_PROTOCOL "hifi" + !define PRODUCTION_BUILD "@PRODUCTION_BUILD@" ;-------------------------------- ; You must define these values @@ -710,11 +711,14 @@ Section "-Core installation" CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\${INTERFACE_SHORTCUT_NAME}.lnk" \ "$INSTDIR\${INTERFACE_EXEC_NAME}" - ; hifi:// protocol handler registry entries - WriteRegStr HKCR '${HIGH_FIDELITY_PROTOCOL}' '' 'URL:High Fidelity Protocol' - WriteRegStr HKCR '${HIGH_FIDELITY_PROTOCOL}' 'URL Protocol' '' - WriteRegStr HKCR '${HIGH_FIDELITY_PROTOCOL}\DefaultIcon' '' '$INSTDIR\${INTERFACE_EXEC_NAME},1' - WriteRegStr HKCR '${HIGH_FIDELITY_PROTOCOL}\shell\open\command' '' '$INSTDIR\${INTERFACE_EXEC_NAME} --url "%1"' + ${If} $PRODUCTION_BUILD == "1" + ; hifi:// protocol handler registry entries + WriteRegStr HKCR '${HIGH_FIDELITY_PROTOCOL}' '' 'URL:High Fidelity Protocol' + WriteRegStr HKCR '${HIGH_FIDELITY_PROTOCOL}' 'URL Protocol' '' + WriteRegStr HKCR '${HIGH_FIDELITY_PROTOCOL}\DefaultIcon' '' '$INSTDIR\${INTERFACE_EXEC_NAME},1' + WriteRegStr HKCR '${HIGH_FIDELITY_PROTOCOL}\shell\open\command' '' '$INSTDIR\${INTERFACE_EXEC_NAME} --url "%1"' + ${EndIf} + ${EndIf} ; Conditional handling for server console shortcut From a2904cdc7baf5e45dc86a1748c2b6cfc23eba4c3 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 11 Jan 2016 15:26:57 -0800 Subject: [PATCH 116/357] use a CPackProperties file for custom installer variables --- cmake/macros/GenerateInstallers.cmake | 27 +++--------------- cmake/macros/SetPackagingParameters.cmake | 21 ++++++++------ cmake/templates/CPackProperties.cmake.in | 17 ++++++++++++ cmake/templates/NSIS.template.in | 34 ++++++++--------------- 4 files changed, 46 insertions(+), 53 deletions(-) create mode 100644 cmake/templates/CPackProperties.cmake.in diff --git a/cmake/macros/GenerateInstallers.cmake b/cmake/macros/GenerateInstallers.cmake index 788bab9ff4..01f766c63c 100644 --- a/cmake/macros/GenerateInstallers.cmake +++ b/cmake/macros/GenerateInstallers.cmake @@ -17,9 +17,10 @@ macro(GENERATE_INSTALLERS) set(CPACK_PACKAGE_NAME "High Fidelity") set(CPACK_PACKAGE_VENDOR "High Fidelity") - if (WIN32) - set(INTERFACE_STARTMENU_NAME "High Fidelity") - endif () + # configure a cpack properties file for custom installation options + set(CPACK_CONFIGURED_PROP_FILE "${CMAKE_CURRENT_BINARY_DIR}/CPackCustomProperties.cmake") + configure_file("${HF_CMAKE_DIR}/templates/CPackProperties.cmake.in" ${CPACK_CONFIGURED_PROP_FILE}) + set(CPACK_PROPERTIES_FILE ${CPACK_CONFIGURED_PROP_FILE}) if (APPLE) set(CPACK_PACKAGE_INSTALL_DIRECTORY "/") @@ -71,24 +72,4 @@ macro(GENERATE_INSTALLERS) endif () include(CPack) - - # if (DEPLOY_PACKAGE AND WIN32) - # file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/package-bundle") - # find_program(MAKENSIS_COMMAND makensis PATHS [HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\NSIS]) - # if (NOT MAKENSIS_COMMAND) - # message(FATAL_ERROR "The Nullsoft Scriptable Install Systems is required for generating packaged installers on Windows (http://nsis.sourceforge.net/)") - # endif () - # add_custom_target( - # build-package ALL - # DEPENDS interface assignment-client domain-server stack-manager - # COMMAND set INSTALLER_SOURCE_DIR=${CMAKE_BINARY_DIR}/package-bundle - # COMMAND set INSTALLER_NAME=${CMAKE_BINARY_DIR}/${INSTALLER_NAME} - # COMMAND set INSTALLER_SCRIPTS_DIR=${CMAKE_SOURCE_DIR}/examples - # COMMAND set INSTALLER_COMPANY=${INSTALLER_COMPANY} - # COMMAND set INSTALLER_DIRECTORY=${INSTALLER_DIRECTORY} - # COMMAND CMD /C "\"${MAKENSIS_COMMAND}\" ${CMAKE_SOURCE_DIR}/tools/nsis/release.nsi" - # ) - # - # set_target_properties(build-package PROPERTIES EXCLUDE_FROM_ALL TRUE FOLDER "Installer") - # endif () endmacro() diff --git a/cmake/macros/SetPackagingParameters.cmake b/cmake/macros/SetPackagingParameters.cmake index 194fe6b694..ebe9da00d4 100644 --- a/cmake/macros/SetPackagingParameters.cmake +++ b/cmake/macros/SetPackagingParameters.cmake @@ -19,6 +19,7 @@ macro(SET_PACKAGING_PARAMETERS) set(INSTALLER_COMPANY "High Fidelity") set(INSTALLER_DIRECTORY "${INSTALLER_COMPANY}") set(INSTALLER_NAME "interface-win64-${BUILD_SEQ}.exe") + set(HIGH_FIDELITY_PROTOCOL "hifi") set(INTERFACE_BUNDLE_NAME "High Fidelity") set(INTERFACE_ICON_PREFIX "interface") set(CONSOLE_ICON "console.ico") @@ -43,23 +44,27 @@ macro(SET_PACKAGING_PARAMETERS) set(CONSOLE_ICON "console-beta.ico") endif () + set(CONSOLE_INSTALL_DIR ".") + set(INTERFACE_INSTALL_DIR ".") + if (WIN32) - set(INTERFACE_EXEC_NAME "interface") + set(INTERFACE_EXEC_PREFIX "interface") set(INTERFACE_ICON_FILENAME "${INTERFACE_ICON_PREFIX}.ico") + + set(CONSOLE_EXEC_NAME "server-console.exe") + + # start menu shortcuts + set(INTERFACE_SM_SHORTCUT_NAME "High Fidelity") + set(CONSOLE_SM_SHORTCUT_NAME "Server Console") endif () if (APPLE) - set(CONSOLE_INSTALL_DIR ".") - set(CONSOLE_APPLICATION_NAME "Server Console.app") - set(CONSOLE_INSTALL_APP_PATH "${CONSOLE_APPLICATION_NAME}") + set(CONSOLE_EXEC_NAME "Server Console.app") + set(CONSOLE_INSTALL_APP_PATH "${CONSOLE_EXEC_NAME}") - set(INTERFACE_INSTALL_DIR ".") set(INTERFACE_INSTALL_APP_PATH "${INTERFACE_BUNDLE_NAME}.app") set(INTERFACE_ICON_FILENAME "${INTERFACE_ICON_PREFIX}.icns") - else () - set(CONSOLE_INSTALL_DIR ".") - set(INTERFACE_INSTALL_DIR ".") endif() # setup component categories for installer diff --git a/cmake/templates/CPackProperties.cmake.in b/cmake/templates/CPackProperties.cmake.in new file mode 100644 index 0000000000..510c004441 --- /dev/null +++ b/cmake/templates/CPackProperties.cmake.in @@ -0,0 +1,17 @@ +# +# CPackProperties.cmake.in +# cmake/templates +# +# Copyright 2016 High Fidelity, Inc. +# Created by Stephen Birarda on January 11, 2016 +# +# Distributed under the Apache License, Version 2.0. +# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +# + +set(INTERFACE_SHORTCUT_NAME "@INTERFACE_SM_SHORTCUT_NAME@") +set(INTERFACE_WIN_EXEC_NAME "@INTERFACE_EXEC_PREFIX@.exe") +set(CONSOLE_SHORTCUT_NAME "@CONSOLE_SM_SHORTCUT_NAME@") +set(CONSOLE_WIN_EXEC_NAME "@CONSOLE_EXEC_NAME@") +set(HIGH_FIDELITY_PROTOCOL "@HIGH_FIDELITY_PROTOCOL@") +set(PRODUCTION_BUILD "@PRODUCTION_BUILD@") diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 7c0aa47272..295a929ad3 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -1,15 +1,5 @@ ; CPack install script designed for a nmake build -;-------------------------------- -; Variables that drive High Fidelity custom behaviour - - !define INTERFACE_SHORTCUT_NAME "High Fidelity" - !define INTERFACE_EXEC_NAME "interface.exe" - !define CONSOLE_SHORTCUT_NAME "Server Console" - !define CONSOLE_EXEC_NAME "server-console.exe" - !define HIGH_FIDELITY_PROTOCOL "hifi" - !define PRODUCTION_BUILD "@PRODUCTION_BUILD@" - ;-------------------------------- ; You must define these values @@ -708,23 +698,23 @@ Section "-Core installation" ; Conditional handling for Interface specific options ${If} ${SectionIsSelected} ${client} - CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\${INTERFACE_SHORTCUT_NAME}.lnk" \ - "$INSTDIR\${INTERFACE_EXEC_NAME}" + CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\@INTERFACE_SHORTCUT_NAME@.lnk" \ + "$INSTDIR\@INTERFACE_WIN_EXEC_NAME@" - ${If} $PRODUCTION_BUILD == "1" + ${If} @PRODUCTION_BUILD@ == "1" ; hifi:// protocol handler registry entries - WriteRegStr HKCR '${HIGH_FIDELITY_PROTOCOL}' '' 'URL:High Fidelity Protocol' - WriteRegStr HKCR '${HIGH_FIDELITY_PROTOCOL}' 'URL Protocol' '' - WriteRegStr HKCR '${HIGH_FIDELITY_PROTOCOL}\DefaultIcon' '' '$INSTDIR\${INTERFACE_EXEC_NAME},1' - WriteRegStr HKCR '${HIGH_FIDELITY_PROTOCOL}\shell\open\command' '' '$INSTDIR\${INTERFACE_EXEC_NAME} --url "%1"' + WriteRegStr HKCR '@HIGH_FIDELITY_PROTOCOL@' '' 'URL:High Fidelity Protocol' + WriteRegStr HKCR '@HIGH_FIDELITY_PROTOCOL@' 'URL Protocol' '' + WriteRegStr HKCR '@HIGH_FIDELITY_PROTOCOL@\DefaultIcon' '' '$INSTDIR\@INTERFACE_WIN_EXEC_NAME@,1' + WriteRegStr HKCR '@HIGH_FIDELITY_PROTOCOL@\shell\open\command' '' '$INSTDIR\@INTERFACE_WIN_EXEC_NAME@ --url "%1"' ${EndIf} ${EndIf} ; Conditional handling for server console shortcut ${If} ${SectionIsSelected} ${server} - CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\${CONSOLE_SHORTCUT_NAME}.lnk" \ - "$INSTDIR\${CONSOLE_EXEC_NAME}" + CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\@CONSOLE_SHORTCUT_NAME@.lnk" \ + "$INSTDIR\@CONSOLE_EXEC_NAME@" ${EndIf} CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" "$INSTDIR\Uninstall.exe" @@ -881,13 +871,13 @@ Section "Uninstall" !insertmacro MUI_STARTMENU_GETFOLDER Application $MUI_TEMP Delete "$SMPROGRAMS\$MUI_TEMP\Uninstall.lnk" - Delete "$SMPROGRAMS\$MUI_TEMP\${INTERFACE_SHORTCUT_NAME}.lnk" - Delete "$SMPROGRAMS\$MUI_TEMP\${CONSOLE_SHORTCUT_NAME}.lnk" + Delete "$SMPROGRAMS\$MUI_TEMP\@INTERFACE_SHORTCUT_NAME@.lnk" + Delete "$SMPROGRAMS\$MUI_TEMP\@CONSOLE_SHORTCUT_NAME@.lnk" @CPACK_NSIS_DELETE_ICONS@ @CPACK_NSIS_DELETE_ICONS_EXTRA@ ;Delete High Fidelity protocol handling - DeleteRegKey HKCR '${HIGH_FIDELITY_PROTOCOL}' + DeleteRegKey HKCR '@HIGH_FIDELITY_PROTOCOL@' ;Delete empty start menu parent diretories StrCpy $MUI_TEMP "$SMPROGRAMS\$MUI_TEMP" From 53eb66418a578b8ef3c662ed595f665c2af574ab Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 11 Jan 2016 15:33:12 -0800 Subject: [PATCH 117/357] fix for falsity of build types --- cmake/macros/SetPackagingParameters.cmake | 10 +++++++--- cmake/templates/NSIS.template.in | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/cmake/macros/SetPackagingParameters.cmake b/cmake/macros/SetPackagingParameters.cmake index ebe9da00d4..88257495f6 100644 --- a/cmake/macros/SetPackagingParameters.cmake +++ b/cmake/macros/SetPackagingParameters.cmake @@ -12,10 +12,14 @@ # and decides how targets should be packaged. macro(SET_PACKAGING_PARAMETERS) + set(PR_BUILD 0) + set(PRODUCTION_BUILD 0) + set(DEV_BUILD 0) + if (DEFINED ENV{JOB_ID}) set(DEPLOY_PACKAGE TRUE) set(BUILD_SEQ $ENV{JOB_ID}) - set(PRODUCTION_BUILD TRUE) + set(PRODUCTION_BUILD 1) set(INSTALLER_COMPANY "High Fidelity") set(INSTALLER_DIRECTORY "${INSTALLER_COMPANY}") set(INSTALLER_NAME "interface-win64-${BUILD_SEQ}.exe") @@ -25,7 +29,7 @@ macro(SET_PACKAGING_PARAMETERS) set(CONSOLE_ICON "console.ico") elseif (DEFINED ENV{ghprbPullId}) set(DEPLOY_PACKAGE TRUE) - set(PR_BUILD TRUE) + set(PR_BUILD 1) set(BUILD_SEQ "PR-$ENV{ghprbPullId}") set(INSTALLER_COMPANY "High Fidelity - PR") set(INSTALLER_DIRECTORY "${INSTALLER_COMPANY}\\${BUILD_SEQ}") @@ -35,7 +39,7 @@ macro(SET_PACKAGING_PARAMETERS) set(CONSOLE_ICON "console-beta.ico") else () set(BUILD_SEQ "dev") - set(DEV_BUILD TRUE) + set(DEV_BUILD 1) set(INSTALLER_COMPANY "High Fidelity - Dev") set(INSTALLER_DIRECTORY "${INSTALLER_COMPANY}") set(INSTALLER_NAME "dev-interface-win64.exe") diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 295a929ad3..add9e1afa4 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -701,7 +701,7 @@ Section "-Core installation" CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\@INTERFACE_SHORTCUT_NAME@.lnk" \ "$INSTDIR\@INTERFACE_WIN_EXEC_NAME@" - ${If} @PRODUCTION_BUILD@ == "1" + ${If} "@PRODUCTION_BUILD@" == "1" ; hifi:// protocol handler registry entries WriteRegStr HKCR '@HIGH_FIDELITY_PROTOCOL@' '' 'URL:High Fidelity Protocol' WriteRegStr HKCR '@HIGH_FIDELITY_PROTOCOL@' 'URL Protocol' '' From 929976e781b9693da7b5e1d95ab7de252604f289 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 11 Jan 2016 15:34:07 -0800 Subject: [PATCH 118/357] use new console exec name var from properties --- cmake/templates/NSIS.template.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index add9e1afa4..1ee2ff7816 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -714,7 +714,7 @@ Section "-Core installation" ; Conditional handling for server console shortcut ${If} ${SectionIsSelected} ${server} CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\@CONSOLE_SHORTCUT_NAME@.lnk" \ - "$INSTDIR\@CONSOLE_EXEC_NAME@" + "$INSTDIR\@CONSOLE_WIN_EXEC_NAME@" ${EndIf} CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" "$INSTDIR\Uninstall.exe" From 9f2fbc37bbc3e61e207f1cd2e5f7705775f001b8 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 11 Jan 2016 15:35:53 -0800 Subject: [PATCH 119/357] only remove protocol handler if installed --- cmake/templates/NSIS.template.in | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 1ee2ff7816..24624f54c8 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -876,8 +876,10 @@ Section "Uninstall" @CPACK_NSIS_DELETE_ICONS@ @CPACK_NSIS_DELETE_ICONS_EXTRA@ - ;Delete High Fidelity protocol handling - DeleteRegKey HKCR '@HIGH_FIDELITY_PROTOCOL@' + ;Delete High Fidelity protocol handling, if installed + ${If} "@PRODUCTION_BUILD@" == "1" + DeleteRegKey HKCR '@HIGH_FIDELITY_PROTOCOL@' + ${EndIf} ;Delete empty start menu parent diretories StrCpy $MUI_TEMP "$SMPROGRAMS\$MUI_TEMP" From 798760f175fc08041e6569a137fb9969b3ebe401 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 11 Jan 2016 15:44:00 -0800 Subject: [PATCH 120/357] change cpack names for generated installer --- cmake/macros/GenerateInstallers.cmake | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/cmake/macros/GenerateInstallers.cmake b/cmake/macros/GenerateInstallers.cmake index 01f766c63c..c40fe15d76 100644 --- a/cmake/macros/GenerateInstallers.cmake +++ b/cmake/macros/GenerateInstallers.cmake @@ -14,8 +14,13 @@ macro(GENERATE_INSTALLERS) set(CPACK_MODULE_PATH ${CPACK_MODULE_PATH} "${HF_CMAKE_DIR}/templates") - set(CPACK_PACKAGE_NAME "High Fidelity") - set(CPACK_PACKAGE_VENDOR "High Fidelity") + set(_DISPLAY_NAME "High Fidelity") + + set(CPACK_PACKAGE_NAME _DISPLAY_NAME) + set(CPACK_PACKAGE_VENDOR _DISPLAY_NAME) + set(CPACK_NSIS_DISPLAY_NAME _DISPLAY_NAME) + set(CPACK_NSIS_PACKAGE_NAME _DISPLAY_NAME) + set(CPACK_PACKAGE_INSTALL_DIRECTORY _DISPLAY_NAME) # configure a cpack properties file for custom installation options set(CPACK_CONFIGURED_PROP_FILE "${CMAKE_CURRENT_BINARY_DIR}/CPackCustomProperties.cmake") From cfcda488c45f0d44c815a50af791839604e7c7f8 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 11 Jan 2016 15:45:44 -0800 Subject: [PATCH 121/357] use corect interpolation of display name option --- cmake/macros/GenerateInstallers.cmake | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cmake/macros/GenerateInstallers.cmake b/cmake/macros/GenerateInstallers.cmake index c40fe15d76..17d6a861f7 100644 --- a/cmake/macros/GenerateInstallers.cmake +++ b/cmake/macros/GenerateInstallers.cmake @@ -16,11 +16,11 @@ macro(GENERATE_INSTALLERS) set(_DISPLAY_NAME "High Fidelity") - set(CPACK_PACKAGE_NAME _DISPLAY_NAME) - set(CPACK_PACKAGE_VENDOR _DISPLAY_NAME) - set(CPACK_NSIS_DISPLAY_NAME _DISPLAY_NAME) - set(CPACK_NSIS_PACKAGE_NAME _DISPLAY_NAME) - set(CPACK_PACKAGE_INSTALL_DIRECTORY _DISPLAY_NAME) + set(CPACK_PACKAGE_NAME ${_DISPLAY_NAME}) + set(CPACK_PACKAGE_VENDOR "High Fidelity") + set(CPACK_NSIS_DISPLAY_NAME ${_DISPLAY_NAME}) + set(CPACK_NSIS_PACKAGE_NAME ${_DISPLAY_NAME}) + set(CPACK_PACKAGE_INSTALL_DIRECTORY ${_DISPLAY_NAME}) # configure a cpack properties file for custom installation options set(CPACK_CONFIGURED_PROP_FILE "${CMAKE_CURRENT_BINARY_DIR}/CPackCustomProperties.cmake") From 58cc86bc5b11c3d5314c3214638e43022e89c8da Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 11 Jan 2016 16:58:54 -0800 Subject: [PATCH 122/357] add a file for NSIS post install options --- cmake/macros/GenerateInstallers.cmake | 8 +++++++- cmake/templates/CPackProperties.cmake.in | 1 + cmake/templates/NSIS.PostInstall.ini.in | 10 ++++++++++ cmake/templates/NSIS.template.in | 7 +++++++ 4 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 cmake/templates/NSIS.PostInstall.ini.in diff --git a/cmake/macros/GenerateInstallers.cmake b/cmake/macros/GenerateInstallers.cmake index 17d6a861f7..6c529b6c02 100644 --- a/cmake/macros/GenerateInstallers.cmake +++ b/cmake/macros/GenerateInstallers.cmake @@ -22,7 +22,13 @@ macro(GENERATE_INSTALLERS) set(CPACK_NSIS_PACKAGE_NAME ${_DISPLAY_NAME}) set(CPACK_PACKAGE_INSTALL_DIRECTORY ${_DISPLAY_NAME}) - # configure a cpack properties file for custom installation options + # configure the post install options file for custom installation options + if (WIN32) + set(POST_INSTALL_OPTIONS_PATH "${CMAKE_CURRENT_BINARY_DIR}/NSIS.PostInstallOptions.ini") + configure_file("${HF_CMAKE_DIR}/template/NSIS.PostInstallOptions.ini.in" ${POST_INSTALL_OPTIONS_PATH}) + endif () + + # configure a cpack properties file for custom variables in NSIS template set(CPACK_CONFIGURED_PROP_FILE "${CMAKE_CURRENT_BINARY_DIR}/CPackCustomProperties.cmake") configure_file("${HF_CMAKE_DIR}/templates/CPackProperties.cmake.in" ${CPACK_CONFIGURED_PROP_FILE}) set(CPACK_PROPERTIES_FILE ${CPACK_CONFIGURED_PROP_FILE}) diff --git a/cmake/templates/CPackProperties.cmake.in b/cmake/templates/CPackProperties.cmake.in index 510c004441..00961690c4 100644 --- a/cmake/templates/CPackProperties.cmake.in +++ b/cmake/templates/CPackProperties.cmake.in @@ -15,3 +15,4 @@ set(CONSOLE_SHORTCUT_NAME "@CONSOLE_SM_SHORTCUT_NAME@") set(CONSOLE_WIN_EXEC_NAME "@CONSOLE_EXEC_NAME@") set(HIGH_FIDELITY_PROTOCOL "@HIGH_FIDELITY_PROTOCOL@") set(PRODUCTION_BUILD "@PRODUCTION_BUILD@") +set(POST_INSTALL_OPTIONS_PATH "@POST_INSTALL_OPTIONS_PATH@") diff --git a/cmake/templates/NSIS.PostInstall.ini.in b/cmake/templates/NSIS.PostInstall.ini.in new file mode 100644 index 0000000000..bab6290924 --- /dev/null +++ b/cmake/templates/NSIS.PostInstall.ini.in @@ -0,0 +1,10 @@ +[Settings] +NumFields = 3 + +[Field 1] +Type=checkBox +Text=Create a desktop shortcut for High Fidelity +Left=0 +Right=-1 +Top=0 +Bottom=20 diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 24624f54c8..9b896e6b64 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -562,6 +562,7 @@ FunctionEnd @CPACK_NSIS_PAGE_COMPONENTS@ !insertmacro MUI_PAGE_INSTFILES + Page custom PostInstallOptionsPage !insertmacro MUI_PAGE_FINISH !insertmacro MUI_UNPAGE_CONFIRM @@ -763,6 +764,12 @@ Function InstallOptionsPage FunctionEnd +Function PostInstallOptionsPage + ReserveFile "@POST_INSTALL_OPTIONS_PATH@" + !insertmacro MUI_INSTALLOPTIONS_EXTRACT "@POST_INSTALL_OPTIONS_PATH@" + !insertmacro MUI_INSTALLOPTIONS_DISPLAY "@POST_INSTALL_OPTIONS_PATH@" +FunctionEnd + ;-------------------------------- ; determine admin versus local install Function un.onInit From c9ecf35d82c4b6742d1f484346256009c9410a18 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 11 Jan 2016 17:00:22 -0800 Subject: [PATCH 123/357] rename template file used for post install options --- cmake/macros/GenerateInstallers.cmake | 2 +- .../{NSIS.PostInstall.ini.in => NSIS.PostInstallOptions.ini.in} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename cmake/templates/{NSIS.PostInstall.ini.in => NSIS.PostInstallOptions.ini.in} (100%) diff --git a/cmake/macros/GenerateInstallers.cmake b/cmake/macros/GenerateInstallers.cmake index 6c529b6c02..3c52996d3a 100644 --- a/cmake/macros/GenerateInstallers.cmake +++ b/cmake/macros/GenerateInstallers.cmake @@ -25,7 +25,7 @@ macro(GENERATE_INSTALLERS) # configure the post install options file for custom installation options if (WIN32) set(POST_INSTALL_OPTIONS_PATH "${CMAKE_CURRENT_BINARY_DIR}/NSIS.PostInstallOptions.ini") - configure_file("${HF_CMAKE_DIR}/template/NSIS.PostInstallOptions.ini.in" ${POST_INSTALL_OPTIONS_PATH}) + configure_file("${HF_CMAKE_DIR}/templates/NSIS.PostInstallOptions.ini.in" ${POST_INSTALL_OPTIONS_PATH}) endif () # configure a cpack properties file for custom variables in NSIS template diff --git a/cmake/templates/NSIS.PostInstall.ini.in b/cmake/templates/NSIS.PostInstallOptions.ini.in similarity index 100% rename from cmake/templates/NSIS.PostInstall.ini.in rename to cmake/templates/NSIS.PostInstallOptions.ini.in From dd0f5417595caf1678b69e2ad51a3c78fab5ebc7 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 11 Jan 2016 17:10:16 -0800 Subject: [PATCH 124/357] move call to ReserveFile to right spot --- cmake/templates/NSIS.template.in | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 9b896e6b64..e9825ddfb5 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -632,6 +632,7 @@ FunctionEnd ;Only for solid compression (by default, solid compression is enabled for BZIP2 and LZMA) ReserveFile "NSIS.InstallOptions.ini" + ReserveFile "@POST_INSTALL_OPTIONS_PATH@" !insertmacro MUI_RESERVEFILE_INSTALLOPTIONS ;-------------------------------- @@ -765,7 +766,7 @@ Function InstallOptionsPage FunctionEnd Function PostInstallOptionsPage - ReserveFile "@POST_INSTALL_OPTIONS_PATH@" + !insertmacro MUI_HEADER_TEXT "Post-Install Options" !insertmacro MUI_INSTALLOPTIONS_EXTRACT "@POST_INSTALL_OPTIONS_PATH@" !insertmacro MUI_INSTALLOPTIONS_DISPLAY "@POST_INSTALL_OPTIONS_PATH@" FunctionEnd From 288b044a0f176361620c34dda36b70e4bc39ecfd Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 11 Jan 2016 17:26:40 -0800 Subject: [PATCH 125/357] use nsDialogs for custom post install options --- cmake/macros/GenerateInstallers.cmake | 6 ------ cmake/templates/NSIS.PostInstallOptions.ini.in | 10 ---------- cmake/templates/NSIS.template.in | 17 ++++++++++++++--- 3 files changed, 14 insertions(+), 19 deletions(-) delete mode 100644 cmake/templates/NSIS.PostInstallOptions.ini.in diff --git a/cmake/macros/GenerateInstallers.cmake b/cmake/macros/GenerateInstallers.cmake index 3c52996d3a..360ab2c27b 100644 --- a/cmake/macros/GenerateInstallers.cmake +++ b/cmake/macros/GenerateInstallers.cmake @@ -22,12 +22,6 @@ macro(GENERATE_INSTALLERS) set(CPACK_NSIS_PACKAGE_NAME ${_DISPLAY_NAME}) set(CPACK_PACKAGE_INSTALL_DIRECTORY ${_DISPLAY_NAME}) - # configure the post install options file for custom installation options - if (WIN32) - set(POST_INSTALL_OPTIONS_PATH "${CMAKE_CURRENT_BINARY_DIR}/NSIS.PostInstallOptions.ini") - configure_file("${HF_CMAKE_DIR}/templates/NSIS.PostInstallOptions.ini.in" ${POST_INSTALL_OPTIONS_PATH}) - endif () - # configure a cpack properties file for custom variables in NSIS template set(CPACK_CONFIGURED_PROP_FILE "${CMAKE_CURRENT_BINARY_DIR}/CPackCustomProperties.cmake") configure_file("${HF_CMAKE_DIR}/templates/CPackProperties.cmake.in" ${CPACK_CONFIGURED_PROP_FILE}) diff --git a/cmake/templates/NSIS.PostInstallOptions.ini.in b/cmake/templates/NSIS.PostInstallOptions.ini.in deleted file mode 100644 index bab6290924..0000000000 --- a/cmake/templates/NSIS.PostInstallOptions.ini.in +++ /dev/null @@ -1,10 +0,0 @@ -[Settings] -NumFields = 3 - -[Field 1] -Type=checkBox -Text=Create a desktop shortcut for High Fidelity -Left=0 -Right=-1 -Top=0 -Bottom=20 diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index e9825ddfb5..9761203b65 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -19,6 +19,9 @@ Var ADD_TO_PATH_CURRENT_USER Var INSTALL_DESKTOP Var IS_DEFAULT_INSTALLDIR + + Var POST_INSTALL_DIALOG + Var DESKTOP_CHECKBOX ;-------------------------------- ;Include Modern UI @@ -766,9 +769,17 @@ Function InstallOptionsPage FunctionEnd Function PostInstallOptionsPage - !insertmacro MUI_HEADER_TEXT "Post-Install Options" - !insertmacro MUI_INSTALLOPTIONS_EXTRACT "@POST_INSTALL_OPTIONS_PATH@" - !insertmacro MUI_INSTALLOPTIONS_DISPLAY "@POST_INSTALL_OPTIONS_PATH@" + nsDialogs::Create 1018 + Pop $POST_INSTALL_DIALOG + + ${If} $POST_INSTALL_DIALOG == error + Abort + ${EndIf} + + ${NSD_CreateCheckbox} 0 0 100% 10u "&Create High Fidelity Desktop Shortcut" + Pop $DESKTOP_CHECKBOX + + nsDialogs::Show FunctionEnd ;-------------------------------- From a6c8c62d36c2a67e2af7008216540f74dcc6b92b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 11 Jan 2016 17:33:31 -0800 Subject: [PATCH 126/357] make sure nsDialog file is included --- cmake/templates/NSIS.template.in | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 9761203b65..55e5115254 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -768,6 +768,9 @@ Function InstallOptionsPage FunctionEnd +; Make sure nsDialogs is included before we use it +!include "nsdialogs.nsh" + Function PostInstallOptionsPage nsDialogs::Create 1018 Pop $POST_INSTALL_DIALOG From 269937fe7f756718f79a2c86e4a2469e48c29850 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 11 Jan 2016 18:02:15 -0800 Subject: [PATCH 127/357] add conditional options to post install dialog --- cmake/templates/NSIS.template.in | 42 +++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 55e5115254..36427bf0ab 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -20,8 +20,6 @@ Var INSTALL_DESKTOP Var IS_DEFAULT_INSTALLDIR - Var POST_INSTALL_DIALOG - Var DESKTOP_CHECKBOX ;-------------------------------- ;Include Modern UI @@ -771,6 +769,13 @@ FunctionEnd ; Make sure nsDialogs is included before we use it !include "nsdialogs.nsh" +Var POST_INSTALL_DIALOG +Var DESKTOP_CLIENT_CHECKBOX +Var DESKTOP_SERVER_CHECKBOX +Var SERVER_STARTUP_CHECKBOX +Var LAUNCH_NOW_CHECKBOX +Var CURRENT_OFFSET + Function PostInstallOptionsPage nsDialogs::Create 1018 Pop $POST_INSTALL_DIALOG @@ -779,8 +784,37 @@ Function PostInstallOptionsPage Abort ${EndIf} - ${NSD_CreateCheckbox} 0 0 100% 10u "&Create High Fidelity Desktop Shortcut" - Pop $DESKTOP_CHECKBOX + StrCpy $CURRENT_OFFSET "0" + + ${If} ${SectionIsSelected} ${client} + ${NSD_CreateCheckbox} 0 0 100% 10u "&Create a desktop shortcut for High Fidelity" + Pop $DESKTOP_CLIENT_CHECKBOX + StrCpy $CURRENT_OFFSET "15u" + ${EndIf} + + ${If} ${SectionIsSelected} ${server} + ${NSD_CreateCheckbox} 0 $CURRENT_OFFSET 100% 10u "&Create a desktop shortcut for the High Fidelity Server Console" + Pop $DESKTOP_SERVER_CHECKBOX + ${NSD_SetState} $DESKTOP_SERVER_CHECKBOX ${BST_UNCHECKED} + + ${If} $CURRENT_OFFSET == "0" + StrCpy $CURRENT_OFFSET "15u" + ${Else} + StrCpy $CURRENT_OFFSET "30u" + ${EndIf} + + ${NSD_CreateCheckbox} 0 $CURRENT_OFFSET 100% 10u "&Launch High Fidelity Server Console on startup" + Pop $SERVER_STARTUP_CHECKBOX + + ${If} $CURRENT_OFFSET == "15u" + StrCpy $CURRENT_OFFSET "30u" + ${Else} + StrCpy $CURRENT_OFFSET "45u" + ${EndIf} + ${EndIf} + + ${NSD_CreateCheckbox} 0 $CURRENT_OFFSET 100% 10u "&Launch High Fidelity Now" + Pop $LAUNCH_NOW_CHECKBOX nsDialogs::Show FunctionEnd From f041479f422f06d5c850b53174bbda6095ea904a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 11 Jan 2016 18:09:34 -0800 Subject: [PATCH 128/357] default some checkboxes to checked --- cmake/templates/NSIS.template.in | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 36427bf0ab..51a3c860b1 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -790,12 +790,12 @@ Function PostInstallOptionsPage ${NSD_CreateCheckbox} 0 0 100% 10u "&Create a desktop shortcut for High Fidelity" Pop $DESKTOP_CLIENT_CHECKBOX StrCpy $CURRENT_OFFSET "15u" + ${NSD_SetState} $DESKTOP_CLIENT_CHECKBOX ${BST_CHECKED} ${EndIf} ${If} ${SectionIsSelected} ${server} - ${NSD_CreateCheckbox} 0 $CURRENT_OFFSET 100% 10u "&Create a desktop shortcut for the High Fidelity Server Console" + ${NSD_CreateCheckbox} 0 $CURRENT_OFFSET 100% 10u "&Create a desktop shortcut for High Fidelity Server Console" Pop $DESKTOP_SERVER_CHECKBOX - ${NSD_SetState} $DESKTOP_SERVER_CHECKBOX ${BST_UNCHECKED} ${If} $CURRENT_OFFSET == "0" StrCpy $CURRENT_OFFSET "15u" @@ -805,6 +805,7 @@ Function PostInstallOptionsPage ${NSD_CreateCheckbox} 0 $CURRENT_OFFSET 100% 10u "&Launch High Fidelity Server Console on startup" Pop $SERVER_STARTUP_CHECKBOX + ${NSD_SetState} $SERVER_STARTUP_CHECKBOX ${BST_CHECKED} ${If} $CURRENT_OFFSET == "15u" StrCpy $CURRENT_OFFSET "30u" @@ -815,6 +816,7 @@ Function PostInstallOptionsPage ${NSD_CreateCheckbox} 0 $CURRENT_OFFSET 100% 10u "&Launch High Fidelity Now" Pop $LAUNCH_NOW_CHECKBOX + ${NSD_SetState} $LAUNCH_NOW_CHECKBOX ${BST_CHECKED} nsDialogs::Show FunctionEnd From fd3b665addc0ccdf3b3e146f78b9cdb0573ed2b7 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 12 Jan 2016 11:26:10 -0800 Subject: [PATCH 129/357] make the confirmation page the finish page --- cmake/templates/NSIS.template.in | 1 - 1 file changed, 1 deletion(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 51a3c860b1..ad1c483a46 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -564,7 +564,6 @@ FunctionEnd !insertmacro MUI_PAGE_INSTFILES Page custom PostInstallOptionsPage - !insertmacro MUI_PAGE_FINISH !insertmacro MUI_UNPAGE_CONFIRM !insertmacro MUI_UNPAGE_INSTFILES From ca2b3c323d8e3f36f0d04ede2cb471b3fdfa7630 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 12 Jan 2016 11:42:10 -0800 Subject: [PATCH 130/357] create interface desktop shortcut if required --- cmake/templates/NSIS.template.in | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index ad1c483a46..0a79c97421 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -563,7 +563,7 @@ FunctionEnd @CPACK_NSIS_PAGE_COMPONENTS@ !insertmacro MUI_PAGE_INSTFILES - Page custom PostInstallOptionsPage + Page custom PostInstallOptionsPage HandlePostInstallOptions !insertmacro MUI_UNPAGE_CONFIRM !insertmacro MUI_UNPAGE_INSTFILES @@ -783,6 +783,9 @@ Function PostInstallOptionsPage Abort ${EndIf} + ; Set the text on the dialog button to match finish + SendMessage $POST_INSTALL_DIALOG ${WM_SETTEXT} 0 "STR:$(^CloseBtn)" + StrCpy $CURRENT_OFFSET "0" ${If} ${SectionIsSelected} ${client} @@ -820,6 +823,20 @@ Function PostInstallOptionsPage nsDialogs::Show FunctionEnd +Var DESKTOP_CLIENT_CHECKBOX_STATE + +Function HandlePostInstallOptions + ${If} ${SectionIsSelected} ${client} + ; check if the user asked for a desktop shortcut to High Fidelity + ${NSD_GetState} $DESKTOP_CLIENT_CHECKBOX $DESKTOP_CLIENT_CHECKBOX_STATE + + ${If} $DESKTOP_CLIENT_CHECKBOX_STATE == ${BST_CHECKED} + CreateShortCut "$DESKTOP\@INTERFACE_SHORTCUT_NAME@.lnk" "$INSTDIR\@INTERFACE_WIN_EXEC_NAME@" + ${EndIf} + + ${EndIf} +FunctionEnd + ;-------------------------------- ; determine admin versus local install Function un.onInit From 92d4cc6fc179f3fbda3ee8e30c20f62b107a7a90 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 12 Jan 2016 11:44:54 -0800 Subject: [PATCH 131/357] add a label above post install options --- cmake/templates/NSIS.template.in | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 0a79c97421..a3b5b4bf75 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -786,34 +786,36 @@ Function PostInstallOptionsPage ; Set the text on the dialog button to match finish SendMessage $POST_INSTALL_DIALOG ${WM_SETTEXT} 0 "STR:$(^CloseBtn)" - StrCpy $CURRENT_OFFSET "0" + ${NSD_CreateLabel} 0 0 100% 12u "Setup Options" + + StrCpy $CURRENT_OFFSET "15u" ${If} ${SectionIsSelected} ${client} - ${NSD_CreateCheckbox} 0 0 100% 10u "&Create a desktop shortcut for High Fidelity" + ${NSD_CreateCheckbox} 0 15u 100% 10u "&Create a desktop shortcut for @INTERFACE_SHORTCUT_NAME@" Pop $DESKTOP_CLIENT_CHECKBOX - StrCpy $CURRENT_OFFSET "15u" + StrCpy $CURRENT_OFFSET "30u" ${NSD_SetState} $DESKTOP_CLIENT_CHECKBOX ${BST_CHECKED} ${EndIf} ${If} ${SectionIsSelected} ${server} - ${NSD_CreateCheckbox} 0 $CURRENT_OFFSET 100% 10u "&Create a desktop shortcut for High Fidelity Server Console" + ${NSD_CreateCheckbox} 0 $CURRENT_OFFSET 100% 10u "&Create a desktop shortcut for High Fidelity @CONSOLE_SHORTCUT_NAME@" Pop $DESKTOP_SERVER_CHECKBOX - ${If} $CURRENT_OFFSET == "0" - StrCpy $CURRENT_OFFSET "15u" - ${Else} - StrCpy $CURRENT_OFFSET "30u" - ${EndIf} - - ${NSD_CreateCheckbox} 0 $CURRENT_OFFSET 100% 10u "&Launch High Fidelity Server Console on startup" - Pop $SERVER_STARTUP_CHECKBOX - ${NSD_SetState} $SERVER_STARTUP_CHECKBOX ${BST_CHECKED} - ${If} $CURRENT_OFFSET == "15u" StrCpy $CURRENT_OFFSET "30u" ${Else} StrCpy $CURRENT_OFFSET "45u" ${EndIf} + + ${NSD_CreateCheckbox} 0 $CURRENT_OFFSET 100% 10u "&Launch High Fidelity @CONSOLE_SHORTCUT_NAME@ on startup" + Pop $SERVER_STARTUP_CHECKBOX + ${NSD_SetState} $SERVER_STARTUP_CHECKBOX ${BST_CHECKED} + + ${If} $CURRENT_OFFSET == "30u" + StrCpy $CURRENT_OFFSET "45u" + ${Else} + StrCpy $CURRENT_OFFSET "60u" + ${EndIf} ${EndIf} ${NSD_CreateCheckbox} 0 $CURRENT_OFFSET 100% 10u "&Launch High Fidelity Now" From 26933573c2b664dc2a7a76ad1edec36436a0ebe2 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 12 Jan 2016 11:55:45 -0800 Subject: [PATCH 132/357] handle desktop shortcut for console, startup item --- cmake/templates/CPackProperties.cmake.in | 2 ++ cmake/templates/NSIS.template.in | 35 ++++++++++++++++++------ 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/cmake/templates/CPackProperties.cmake.in b/cmake/templates/CPackProperties.cmake.in index 00961690c4..5e9caa3482 100644 --- a/cmake/templates/CPackProperties.cmake.in +++ b/cmake/templates/CPackProperties.cmake.in @@ -16,3 +16,5 @@ set(CONSOLE_WIN_EXEC_NAME "@CONSOLE_EXEC_NAME@") set(HIGH_FIDELITY_PROTOCOL "@HIGH_FIDELITY_PROTOCOL@") set(PRODUCTION_BUILD "@PRODUCTION_BUILD@") set(POST_INSTALL_OPTIONS_PATH "@POST_INSTALL_OPTIONS_PATH@") +set(CLIENT_COMPONENT_NAME "@CLIENT_COMPONENT@") +set(SERVER_COMPONENT_NAME "@SERVER_COMPONENT@") diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index a3b5b4bf75..f380c36b28 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -699,7 +699,7 @@ Section "-Core installation" @CPACK_NSIS_CREATE_ICONS_EXTRA@ ; Conditional handling for Interface specific options - ${If} ${SectionIsSelected} ${client} + ${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@} CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\@INTERFACE_SHORTCUT_NAME@.lnk" \ "$INSTDIR\@INTERFACE_WIN_EXEC_NAME@" @@ -714,7 +714,7 @@ Section "-Core installation" ${EndIf} ; Conditional handling for server console shortcut - ${If} ${SectionIsSelected} ${server} + ${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@} CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\@CONSOLE_SHORTCUT_NAME@.lnk" \ "$INSTDIR\@CONSOLE_WIN_EXEC_NAME@" ${EndIf} @@ -790,14 +790,14 @@ Function PostInstallOptionsPage StrCpy $CURRENT_OFFSET "15u" - ${If} ${SectionIsSelected} ${client} + ${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@} ${NSD_CreateCheckbox} 0 15u 100% 10u "&Create a desktop shortcut for @INTERFACE_SHORTCUT_NAME@" Pop $DESKTOP_CLIENT_CHECKBOX StrCpy $CURRENT_OFFSET "30u" ${NSD_SetState} $DESKTOP_CLIENT_CHECKBOX ${BST_CHECKED} ${EndIf} - ${If} ${SectionIsSelected} ${server} + ${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@} ${NSD_CreateCheckbox} 0 $CURRENT_OFFSET 100% 10u "&Create a desktop shortcut for High Fidelity @CONSOLE_SHORTCUT_NAME@" Pop $DESKTOP_SERVER_CHECKBOX @@ -825,18 +825,35 @@ Function PostInstallOptionsPage nsDialogs::Show FunctionEnd -Var DESKTOP_CLIENT_CHECKBOX_STATE +Var DESKTOP_CLIENT_STATE +Var DESKTOP_SERVER_STATE Function HandlePostInstallOptions - ${If} ${SectionIsSelected} ${client} + ${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@} ; check if the user asked for a desktop shortcut to High Fidelity - ${NSD_GetState} $DESKTOP_CLIENT_CHECKBOX $DESKTOP_CLIENT_CHECKBOX_STATE + ${NSD_GetState} $DESKTOP_CLIENT_CHECKBOX $DESKTOP_CLIENT_STATE - ${If} $DESKTOP_CLIENT_CHECKBOX_STATE == ${BST_CHECKED} + ${If} $DESKTOP_CLIENT_STATE == ${BST_CHECKED} CreateShortCut "$DESKTOP\@INTERFACE_SHORTCUT_NAME@.lnk" "$INSTDIR\@INTERFACE_WIN_EXEC_NAME@" ${EndIf} ${EndIf} + + ${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@} + ; check if the user asked for a desktop shortcut to Server Console + ${NSD_GetState} $DESKTOP_SERVER_CHECKBOX $DESKTOP_SERVER_STATE + + ${If} $DESKTOP_SERVER_STATE == ${BST_CHECKED} + CreateShortCut "$DESKTOP\@CONSOLE_SHORTCUT_NAME@.lnk" "$INSTDIR\@CONSOLE_WIN_EXEC_NAME@" + ${EndIf} + + ; check if the user asked to have Server Console launched every startup + ${NSD_GetState} $SERVER_STARTUP_CHECKBOX $SERVER_STARTUP_STATE + + ${If} $SERVER_STARTUP_STATE == ${BST_CHECKED} + CreateShortCut "$SMSTARTUP\@CONSOLE_SHORTCUT_NAME@.lnk" "$INSTDIR\@CONSOLE_WIN_EXEC_NAME@" + ${EndIf} + ${EndIf} FunctionEnd ;-------------------------------- @@ -949,6 +966,8 @@ Section "Uninstall" Delete "$SMPROGRAMS\$MUI_TEMP\Uninstall.lnk" Delete "$SMPROGRAMS\$MUI_TEMP\@INTERFACE_SHORTCUT_NAME@.lnk" Delete "$SMPROGRAMS\$MUI_TEMP\@CONSOLE_SHORTCUT_NAME@.lnk" + Delete "$DESKTOP\@INTERFACE_SHORTCUT_NAME@.lnk" + Delete "$DESKTOP\@CONSOLE_SHORTCUT_NAME@.lnk" @CPACK_NSIS_DELETE_ICONS@ @CPACK_NSIS_DELETE_ICONS_EXTRA@ From b1b99479cc575b3bf0440c87e56f609588a06e31 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 12 Jan 2016 11:59:32 -0800 Subject: [PATCH 133/357] add missing SERVER_STARTUP_STATE variable --- cmake/templates/NSIS.template.in | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index f380c36b28..3ad9e8a933 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -827,6 +827,7 @@ FunctionEnd Var DESKTOP_CLIENT_STATE Var DESKTOP_SERVER_STATE +Var SERVER_STARTUP_STATE Function HandlePostInstallOptions ${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@} From 98284862f0dff82eb24c74a5225de8d7b9b5d39c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 12 Jan 2016 12:01:45 -0800 Subject: [PATCH 134/357] explicitly set text for post install dialog button --- cmake/templates/NSIS.template.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 3ad9e8a933..f735905e3b 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -784,7 +784,7 @@ Function PostInstallOptionsPage ${EndIf} ; Set the text on the dialog button to match finish - SendMessage $POST_INSTALL_DIALOG ${WM_SETTEXT} 0 "STR:$(^CloseBtn)" + SendMessage $POST_INSTALL_DIALOG ${WM_SETTEXT} 0 "STR:&Finish" ${NSD_CreateLabel} 0 0 100% 12u "Setup Options" From a5ea0777c20018aa59d35a0530dd5e7c38de1fea Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 12 Jan 2016 12:05:24 -0800 Subject: [PATCH 135/357] make the options label bold --- cmake/templates/NSIS.template.in | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index f735905e3b..fea1e3ff14 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -769,6 +769,7 @@ FunctionEnd !include "nsdialogs.nsh" Var POST_INSTALL_DIALOG +Var OPTIONS_LABEL Var DESKTOP_CLIENT_CHECKBOX Var DESKTOP_SERVER_CHECKBOX Var SERVER_STARTUP_CHECKBOX @@ -786,7 +787,16 @@ Function PostInstallOptionsPage ; Set the text on the dialog button to match finish SendMessage $POST_INSTALL_DIALOG ${WM_SETTEXT} 0 "STR:&Finish" - ${NSD_CreateLabel} 0 0 100% 12u "Setup Options" + ${NSD_CreateLabel} 0 0 100% 14u "Setup Options" + Pop $OPTIONS_LABEL + + ; Set label to bold + CreateFont $R2 "MS Shell Dlg" 14 700 + SendMessage $OPTIONS_LABEL ${WM_SETFONT} $R2 0 + + ; Force label redraw + ShowWindow $OPTIONS_LABEL ${SW_HIDE} + ShowWindow $OPTIONS_LABEL ${SW_SHOW} StrCpy $CURRENT_OFFSET "15u" From 8d8c3426d25648dc77f5a81fd81d065658ab774a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 12 Jan 2016 12:09:51 -0800 Subject: [PATCH 136/357] delete startup shortcut for server console during uninstall --- cmake/templates/NSIS.template.in | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index fea1e3ff14..bcd4469e51 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -979,6 +979,7 @@ Section "Uninstall" Delete "$SMPROGRAMS\$MUI_TEMP\@CONSOLE_SHORTCUT_NAME@.lnk" Delete "$DESKTOP\@INTERFACE_SHORTCUT_NAME@.lnk" Delete "$DESKTOP\@CONSOLE_SHORTCUT_NAME@.lnk" + Delete "$SMSTARTUP\@CONSOLE_SHORTCUT_NAME@.lnk" @CPACK_NSIS_DELETE_ICONS@ @CPACK_NSIS_DELETE_ICONS_EXTRA@ From 399cc5c4d404d7b33ecd75fd20ee3e0c183671e9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 12 Jan 2016 12:15:45 -0800 Subject: [PATCH 137/357] tweak options label font and close button text --- cmake/templates/NSIS.template.in | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index bcd4469e51..e2af21d9c6 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -785,13 +785,13 @@ Function PostInstallOptionsPage ${EndIf} ; Set the text on the dialog button to match finish - SendMessage $POST_INSTALL_DIALOG ${WM_SETTEXT} 0 "STR:&Finish" + SendMessage $POST_INSTALL_DIALOG ${WM_SETTEXT} 1 "STR:$(^CloseBtn)" - ${NSD_CreateLabel} 0 0 100% 14u "Setup Options" + ${NSD_CreateLabel} 0 0 100% 12u "Setup Options" Pop $OPTIONS_LABEL ; Set label to bold - CreateFont $R2 "MS Shell Dlg" 14 700 + CreateFont $R2 "Arial" 12 700 SendMessage $OPTIONS_LABEL ${WM_SETFONT} $R2 0 ; Force label redraw From fe220ca6589b47c19319130af6448f90ffdf0de2 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 12 Jan 2016 12:19:26 -0800 Subject: [PATCH 138/357] attempted fix for finish button text change --- cmake/templates/NSIS.template.in | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index e2af21d9c6..3851422c2b 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -785,7 +785,8 @@ Function PostInstallOptionsPage ${EndIf} ; Set the text on the dialog button to match finish - SendMessage $POST_INSTALL_DIALOG ${WM_SETTEXT} 1 "STR:$(^CloseBtn)" + GetDlgItem $0 $hwndparent 1 + SendMessage $0 ${WM_SETTEXT} 0 "STR:$(^CloseBtn)" ${NSD_CreateLabel} 0 0 100% 12u "Setup Options" Pop $OPTIONS_LABEL From fa711368805a771c53261e8d62f6b9b9866602a6 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 12 Jan 2016 12:21:28 -0800 Subject: [PATCH 139/357] drop post install options label size to 10 --- cmake/templates/NSIS.template.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 3851422c2b..4cd1b4bc04 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -792,7 +792,7 @@ Function PostInstallOptionsPage Pop $OPTIONS_LABEL ; Set label to bold - CreateFont $R2 "Arial" 12 700 + CreateFont $R2 "Arial" 10 700 SendMessage $OPTIONS_LABEL ${WM_SETFONT} $R2 0 ; Force label redraw From f830c9ce252e91e41b0a944f4df0165dd2fdf987 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 12 Jan 2016 12:32:27 -0800 Subject: [PATCH 140/357] launch interface or console post-install if requested --- cmake/templates/NSIS.template.in | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 4cd1b4bc04..eccbaba5e8 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -839,6 +839,7 @@ FunctionEnd Var DESKTOP_CLIENT_STATE Var DESKTOP_SERVER_STATE Var SERVER_STARTUP_STATE +VAR LAUNCH_NOW_STATE Function HandlePostInstallOptions ${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@} @@ -866,6 +867,20 @@ Function HandlePostInstallOptions CreateShortCut "$SMSTARTUP\@CONSOLE_SHORTCUT_NAME@.lnk" "$INSTDIR\@CONSOLE_WIN_EXEC_NAME@" ${EndIf} ${EndIf} + + ; check if we need to launch an application post-install + ${NSD_GetState} $LAUNCH_NOW_CHECKBOX $LAUNCH_NOW_STATE + + ${If} $LAUNCH_NOW_STATE == ${BST_CHECKED} + ; both launches use the explorer trick in case the user has elevated permissions for the installer + ; it won't be possible to use this approach if either application should be launched with a command line param + ${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@} + Exec '"$WINDIR\explorer.exe" "$INSTDIR\@CONSOLE_WIN_EXEC_NAME@"' + ${Else} + Exec '"$WINDIR\explorer.exe" "$INSTDIR\@INTERFACE_WIN_EXEC_NAME@"' + ${EndIf} + ${EndIf} + FunctionEnd ;-------------------------------- From db5935c275303a9d7c5fdea9c9ab56e6b8083ae9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 12 Jan 2016 12:34:40 -0800 Subject: [PATCH 141/357] try to change button text at very end --- cmake/templates/NSIS.template.in | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index eccbaba5e8..4709ec3bed 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -784,10 +784,6 @@ Function PostInstallOptionsPage Abort ${EndIf} - ; Set the text on the dialog button to match finish - GetDlgItem $0 $hwndparent 1 - SendMessage $0 ${WM_SETTEXT} 0 "STR:$(^CloseBtn)" - ${NSD_CreateLabel} 0 0 100% 12u "Setup Options" Pop $OPTIONS_LABEL @@ -834,6 +830,10 @@ Function PostInstallOptionsPage ${NSD_SetState} $LAUNCH_NOW_CHECKBOX ${BST_CHECKED} nsDialogs::Show + + ; Set the text on the dialog button to match finish + GetDlgItem $0 $hwndparent 1 + SendMessage $0 ${WM_SETTEXT} 0 "STR:$(^CloseBtn)" FunctionEnd Var DESKTOP_CLIENT_STATE From 7ce36a69a0f05b68eec452ac6315dbb687eaaa5c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 12 Jan 2016 12:37:55 -0800 Subject: [PATCH 142/357] change close button text before nsDialog create --- cmake/templates/NSIS.template.in | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 4709ec3bed..0af7b7af2c 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -777,6 +777,10 @@ Var LAUNCH_NOW_CHECKBOX Var CURRENT_OFFSET Function PostInstallOptionsPage + ; Set the text on the dialog button to match finish + GetDlgItem $0 $hwndparent 1 + SendMessage $0 ${WM_SETTEXT} 0 "STR:$(^CloseBtn)" + nsDialogs::Create 1018 Pop $POST_INSTALL_DIALOG @@ -830,10 +834,6 @@ Function PostInstallOptionsPage ${NSD_SetState} $LAUNCH_NOW_CHECKBOX ${BST_CHECKED} nsDialogs::Show - - ; Set the text on the dialog button to match finish - GetDlgItem $0 $hwndparent 1 - SendMessage $0 ${WM_SETTEXT} 0 "STR:$(^CloseBtn)" FunctionEnd Var DESKTOP_CLIENT_STATE From 47dbd9d8506d26ba636c974555e4b8ff4a98d95b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 12 Jan 2016 14:16:28 -0800 Subject: [PATCH 143/357] hide back and cancel buttons on finish page --- cmake/templates/NSIS.template.in | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 0af7b7af2c..ff499a7284 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -777,9 +777,15 @@ Var LAUNCH_NOW_CHECKBOX Var CURRENT_OFFSET Function PostInstallOptionsPage - ; Set the text on the dialog button to match finish - GetDlgItem $0 $hwndparent 1 - SendMessage $0 ${WM_SETTEXT} 0 "STR:$(^CloseBtn)" + ; Set the text on the dialog button to match finish, hide the back and cancel buttons + GetDlgItem $R1 $hwndparent 1 + SendMessage $R1 ${WM_SETTEXT} 0 "STR:$(^CloseBtn)" + + GetDlgItem $R2 $hwndparent 2 + ShowWindow $R2 0 + + GetDlgItem $R3 $hwndparent 3 + ShowWindow $R3 0 nsDialogs::Create 1018 Pop $POST_INSTALL_DIALOG From ef0d3b11e9d16f478c81fa7a0b5bf72423e3b114 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 12 Jan 2016 14:31:02 -0800 Subject: [PATCH 144/357] use explicit text for finish button --- cmake/templates/NSIS.template.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index ff499a7284..95d90cfe5c 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -779,7 +779,7 @@ Var CURRENT_OFFSET Function PostInstallOptionsPage ; Set the text on the dialog button to match finish, hide the back and cancel buttons GetDlgItem $R1 $hwndparent 1 - SendMessage $R1 ${WM_SETTEXT} 0 "STR:$(^CloseBtn)" + SendMessage $R1 ${WM_SETTEXT} 0 "STR:&Finish" GetDlgItem $R2 $hwndparent 2 ShowWindow $R2 0 From fec7b77577890c472e3df8899ec70f7cea7e6a77 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 12 Jan 2016 14:43:05 -0800 Subject: [PATCH 145/357] leave the disabled cancel button for spacing --- cmake/templates/NSIS.template.in | 3 --- 1 file changed, 3 deletions(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 95d90cfe5c..c65c5d4dca 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -781,9 +781,6 @@ Function PostInstallOptionsPage GetDlgItem $R1 $hwndparent 1 SendMessage $R1 ${WM_SETTEXT} 0 "STR:&Finish" - GetDlgItem $R2 $hwndparent 2 - ShowWindow $R2 0 - GetDlgItem $R3 $hwndparent 3 ShowWindow $R3 0 From 3a9ac7d4acf76a39225dd5400c52336831ead200 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 12 Jan 2016 15:17:44 -0800 Subject: [PATCH 146/357] remove macro to consolidate installer components --- .../ConsolidateInstallerComponents.cmake | 33 ------------------- interface/CMakeLists.txt | 1 - 2 files changed, 34 deletions(-) delete mode 100644 cmake/macros/ConsolidateInstallerComponents.cmake diff --git a/cmake/macros/ConsolidateInstallerComponents.cmake b/cmake/macros/ConsolidateInstallerComponents.cmake deleted file mode 100644 index ea60fb599a..0000000000 --- a/cmake/macros/ConsolidateInstallerComponents.cmake +++ /dev/null @@ -1,33 +0,0 @@ -macro(CONSOLIDATE_INSTALLER_COMPONENTS) - - if (DEPLOY_PACKAGE AND WIN32) - # Copy icon files for interface and stack manager - if (TARGET_NAME STREQUAL "interface") - set (ICON_FILE_PATH "${PROJECT_SOURCE_DIR}/icon/${INTERFACE_ICON}") - set (ICON_DESTINATION_NAME "interface.ico") - - add_custom_command( - TARGET ${TARGET_NAME} POST_BUILD - COMMAND "${CMAKE_COMMAND}" -E copy ${ICON_FILE_PATH} ${CMAKE_BINARY_DIR}/package-bundle/${ICON_DESTINATION_NAME} - COMMAND "${CMAKE_COMMAND}" -E copy_directory $ ${CMAKE_BINARY_DIR}/package-bundle - ) - elseif (TARGET_NAME STREQUAL "package-console") - set (ICON_FILE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/resources/${CONSOLE_ICON}") - set (ICON_DESTINATION_NAME "console.ico") - - # add a command to copy the folder produced by electron-packager to package-bundle - add_custom_command( - TARGET ${TARGET_NAME} POST_BUILD - COMMAND "${CMAKE_COMMAND}" -E copy ${ICON_FILE_PATH} ${CMAKE_BINARY_DIR}/package-bundle/${ICON_DESTINATION_NAME} - COMMAND "${CMAKE_COMMAND}" -E copy_directory ${CMAKE_CURRENT_BINARY_DIR}/${PACKAGED_CONSOLE_FOLDER} ${CMAKE_BINARY_DIR}/package-bundle - ) - else () - # add a command to copy the fixed up binary and libraries to package-bundle - add_custom_command( - TARGET ${TARGET_NAME} POST_BUILD - COMMAND "${CMAKE_COMMAND}" -E copy_directory $ ${CMAKE_BINARY_DIR}/package-bundle - ) - endif () - endif () - -endmacro() diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 33b7777042..4248aa745d 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -267,4 +267,3 @@ if (WIN32) endif() package_libraries_for_deployment() -consolidate_installer_components() From 9aa5d017d6570ebb7dc77014a78def0c402252fa Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 12 Jan 2016 15:18:01 -0800 Subject: [PATCH 147/357] add optional signing of interface executable --- .../macros/OptionalWinExecutableSigning.cmake | 36 +++++++++++++++++++ interface/CMakeLists.txt | 5 +++ 2 files changed, 41 insertions(+) create mode 100644 cmake/macros/OptionalWinExecutableSigning.cmake diff --git a/cmake/macros/OptionalWinExecutableSigning.cmake b/cmake/macros/OptionalWinExecutableSigning.cmake new file mode 100644 index 0000000000..61eb26b3ed --- /dev/null +++ b/cmake/macros/OptionalWinExecutableSigning.cmake @@ -0,0 +1,36 @@ +# +# OptionalWinExecutableSigning.cmake +# cmake/macros +# +# Copyright 2016 High Fidelity, Inc. +# Created by Stephen Birarda on January 12, 2016 +# +# Distributed under the Apache License, Version 2.0. +# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +# + +macro(optional_win_executable_signing) + if (WIN32 AND (PRODUCTION_BUILD OR PR_BUILD)) + if (DEFINED ENV{HF_PFX_FILE}) + if (DEFINED ENV{HF_PFX_PASSPHRASE}) + # find signtool + find_program(SIGNTOOL_EXEC signtool PATHS "C:/Program Files (x86)/Windows Kits/8.1" PATH_SUFFIXES "bin/x64") + + if (NOT SIGNTOOL_EXEC) + message(FATAL_ERROR "Code signing of executables was requested but signtool.exe could not be found.") + endif () + + # setup the post install command to sign the executable + set(SIGN_COMMAND "${SIGNTOOL_EXEC} sign /f $ENV{HF_PFX_FILE} /p $ENV{HF_PFX_PASSPHRASE} /tr http://tsa.starfieldtech.com\ + /td SHA256 \${CMAKE_INSTALL_PREFIX}/${EXECUTABLE_NAME}" + ) + + install(CODE "execute_process(COMMAND ${SIGN_COMMAND})" COMPONENT ${EXECUTABLE_COMPONENT}) + else () + message(FATAL_ERROR "HF_PFX_PASSPHRASE must be set for executables to be signed.") + endif () + else () + message(WARNING "Producing a production build or PR build but not code signing since HF_PFX_FILE is not set.") + endif () + endif () +endmacro() diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 4248aa745d..aabfc1031c 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -238,6 +238,11 @@ else (APPLE) DESTINATION ${INTERFACE_INSTALL_DIR} COMPONENT ${CLIENT_COMPONENT} ) + + set(EXECUTABLE_NAME "${INTERFACE_EXEC_PREFIX}.exe") + set(EXECUTABLE_COMPONENT ${CLIENT_COMPONENT}) + + optional_win_executable_signing() endif() endif (APPLE) From d14c8cf9ccaccb4c4d4d644f7d7886943e1b5230 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 12 Jan 2016 15:55:14 -0800 Subject: [PATCH 148/357] add signing of DS and AC executable --- cmake/macros/InstallBesideConsole.cmake | 4 ++++ cmake/macros/OptionalWinExecutableSigning.cmake | 2 +- domain-server/CMakeLists.txt | 1 + interface/CMakeLists.txt | 1 - 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/cmake/macros/InstallBesideConsole.cmake b/cmake/macros/InstallBesideConsole.cmake index 12bbc3bcda..f076c856f8 100644 --- a/cmake/macros/InstallBesideConsole.cmake +++ b/cmake/macros/InstallBesideConsole.cmake @@ -32,6 +32,10 @@ macro(install_beside_console) DESTINATION ${COMPONENT_DESTINATION} COMPONENT ${SERVER_COMPONENT} ) + + # on windows for PR and production builds, sign the executable + set(EXECUTABLE_COMPONENT ${SERVER_COMPONENT}) + optional_win_executable_signing() endif () if (TARGET_NAME STREQUAL domain-server) diff --git a/cmake/macros/OptionalWinExecutableSigning.cmake b/cmake/macros/OptionalWinExecutableSigning.cmake index 61eb26b3ed..00b4602834 100644 --- a/cmake/macros/OptionalWinExecutableSigning.cmake +++ b/cmake/macros/OptionalWinExecutableSigning.cmake @@ -22,7 +22,7 @@ macro(optional_win_executable_signing) # setup the post install command to sign the executable set(SIGN_COMMAND "${SIGNTOOL_EXEC} sign /f $ENV{HF_PFX_FILE} /p $ENV{HF_PFX_PASSPHRASE} /tr http://tsa.starfieldtech.com\ - /td SHA256 \${CMAKE_INSTALL_PREFIX}/${EXECUTABLE_NAME}" + /td SHA256 \${CMAKE_INSTALL_PREFIX}/$" ) install(CODE "execute_process(COMMAND ${SIGN_COMMAND})" COMPONENT ${EXECUTABLE_COMPONENT}) diff --git a/domain-server/CMakeLists.txt b/domain-server/CMakeLists.txt index 342bfbffe4..347757ae38 100644 --- a/domain-server/CMakeLists.txt +++ b/domain-server/CMakeLists.txt @@ -37,4 +37,5 @@ if (UNIX) endif (UNIX) package_libraries_for_deployment() + install_beside_console() diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index aabfc1031c..51620fe800 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -239,7 +239,6 @@ else (APPLE) COMPONENT ${CLIENT_COMPONENT} ) - set(EXECUTABLE_NAME "${INTERFACE_EXEC_PREFIX}.exe") set(EXECUTABLE_COMPONENT ${CLIENT_COMPONENT}) optional_win_executable_signing() From 798d234d63f171feb3ed22f46e5b04d7d1165852 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 12 Jan 2016 15:59:08 -0800 Subject: [PATCH 149/357] remove package bundle copying of ssleay dll --- .../macros/OptionalWinExecutableSigning.cmake | 6 ++- cmake/modules/FindOpenSSL.cmake | 39 +++++++------------ console/CMakeLists.txt | 4 ++ 3 files changed, 24 insertions(+), 25 deletions(-) diff --git a/cmake/macros/OptionalWinExecutableSigning.cmake b/cmake/macros/OptionalWinExecutableSigning.cmake index 00b4602834..c8ed0e0d4b 100644 --- a/cmake/macros/OptionalWinExecutableSigning.cmake +++ b/cmake/macros/OptionalWinExecutableSigning.cmake @@ -20,9 +20,13 @@ macro(optional_win_executable_signing) message(FATAL_ERROR "Code signing of executables was requested but signtool.exe could not be found.") endif () + if (NOT EXECUTABLE_NAME) + set(EXECUTABLE_NAME $) + endif () + # setup the post install command to sign the executable set(SIGN_COMMAND "${SIGNTOOL_EXEC} sign /f $ENV{HF_PFX_FILE} /p $ENV{HF_PFX_PASSPHRASE} /tr http://tsa.starfieldtech.com\ - /td SHA256 \${CMAKE_INSTALL_PREFIX}/$" + /td SHA256 \${CMAKE_INSTALL_PREFIX}/${EXECUTABLE_NAME}" ) install(CODE "execute_process(COMMAND ${SIGN_COMMAND})" COMPONENT ${EXECUTABLE_COMPONENT}) diff --git a/cmake/modules/FindOpenSSL.cmake b/cmake/modules/FindOpenSSL.cmake index 3a5394a917..5cc48d2598 100644 --- a/cmake/modules/FindOpenSSL.cmake +++ b/cmake/modules/FindOpenSSL.cmake @@ -8,11 +8,11 @@ # OPENSSL_INCLUDE_DIR - the OpenSSL include directory # OPENSSL_LIBRARIES - The libraries needed to use OpenSSL # OPENSSL_VERSION - This is set to $major.$minor.$revision$path (eg. 0.9.8s) -# +# # Modified on 7/16/2014 by Stephen Birarda # This is an adapted version of the FindOpenSSL.cmake module distributed with Cmake 2.8.12.2 # The original license for that file is displayed below. -# +# #============================================================================= # Copyright 2006-2009 Kitware, Inc. # Copyright 2006 Alexander Neundorf @@ -50,18 +50,18 @@ if (WIN32) ) set(_OPENSSL_ROOT_PATHS "${_programfiles}/OpenSSL" "${_programfiles}/OpenSSL-Win32" "C:/OpenSSL/" "C:/OpenSSL-Win32/") endif() - + unset(_programfiles) set(_OPENSSL_ROOT_HINTS_AND_PATHS HINTS ${_OPENSSL_ROOT_HINTS} PATHS ${_OPENSSL_ROOT_PATHS}) - + else () include("${MACRO_DIR}/HifiLibrarySearchHints.cmake") hifi_library_search_hints("openssl") - + set(_OPENSSL_ROOT_HINTS_AND_PATHS ${OPENSSL_SEARCH_DIRS}) endif () -find_path(OPENSSL_INCLUDE_DIR NAMES openssl/ssl.h HINTS ${_OPENSSL_ROOT_HINTS_AND_PATHS} ${_OPENSSL_INCLUDEDIR} +find_path(OPENSSL_INCLUDE_DIR NAMES openssl/ssl.h HINTS ${_OPENSSL_ROOT_HINTS_AND_PATHS} ${_OPENSSL_INCLUDEDIR} PATH_SUFFIXES include ) @@ -81,15 +81,15 @@ if (WIN32 AND NOT CYGWIN) # We are using the libraries located in the VC subdir instead of the parent directory eventhough : # libeay32MD.lib is identical to ../libeay32.lib, and # ssleay32MD.lib is identical to ../ssleay32.lib - find_library(LIB_EAY_DEBUG NAMES libeay32MDd libeay32d + find_library(LIB_EAY_DEBUG NAMES libeay32MDd libeay32d ${_OPENSSL_ROOT_HINTS_AND_PATHS} PATH_SUFFIXES "lib" "VC" "lib/VC" ) - find_library(LIB_EAY_RELEASE NAMES libeay32MD libeay32 + find_library(LIB_EAY_RELEASE NAMES libeay32MD libeay32 ${_OPENSSL_ROOT_HINTS_AND_PATHS} PATH_SUFFIXES "lib" "VC" "lib/VC" ) - find_library(SSL_EAY_DEBUG NAMES ssleay32MDd ssleay32d + find_library(SSL_EAY_DEBUG NAMES ssleay32MDd ssleay32d ${_OPENSSL_ROOT_HINTS_AND_PATHS} PATH_SUFFIXES "lib" "VC" "lib/VC" ) @@ -109,22 +109,22 @@ if (WIN32 AND NOT CYGWIN) set(OPENSSL_LIBRARIES ${SSL_EAY_LIBRARY} ${LIB_EAY_LIBRARY}) find_path(OPENSSL_DLL_PATH NAMES ssleay32.dll PATH_SUFFIXES "bin" ${_OPENSSL_ROOT_HINTS_AND_PATHS}) - + elseif (MINGW) # same player, for MinGW set(LIB_EAY_NAMES libeay32) set(SSL_EAY_NAMES ssleay32) - + if (CMAKE_CROSSCOMPILING) list(APPEND LIB_EAY_NAMES crypto) list(APPEND SSL_EAY_NAMES ssl) endif () - + find_library(LIB_EAY NAMES ${LIB_EAY_NAMES} ${_OPENSSL_ROOT_HINTS_AND_PATHS} PATH_SUFFIXES "lib" "lib/MinGW" ) - find_library(SSL_EAY NAMES ${SSL_EAY_NAMES} + find_library(SSL_EAY NAMES ${SSL_EAY_NAMES} ${_OPENSSL_ROOT_HINTS_AND_PATHS} PATH_SUFFIXES "lib" "lib/MinGW" ) @@ -147,7 +147,7 @@ else() PATH_SUFFIXES lib ) - find_library(OPENSSL_CRYPTO_LIBRARY NAMES crypto HINTS ${_OPENSSL_ROOT_HINTS_AND_PATHS} ${_OPENSSL_LIBDIR} + find_library(OPENSSL_CRYPTO_LIBRARY NAMES crypto HINTS ${_OPENSSL_ROOT_HINTS_AND_PATHS} ${_OPENSSL_LIBDIR} PATH_SUFFIXES lib ) @@ -196,7 +196,7 @@ if (OPENSSL_INCLUDE_DIR) if(OPENSSL_INCLUDE_DIR AND EXISTS "${OPENSSL_INCLUDE_DIR}/openssl/opensslv.h") file(STRINGS "${OPENSSL_INCLUDE_DIR}/openssl/opensslv.h" openssl_version_str REGEX "^#[ ]?define[\t ]+OPENSSL_VERSION_NUMBER[\t ]+0x([0-9a-fA-F])+.*") - + # The version number is encoded as 0xMNNFFPPS: major minor fix patch status # The status gives if this is a developer or prerelease and is ignored here. # Major, minor, and fix directly translate into the version numbers shown in @@ -252,15 +252,6 @@ endif () if (WIN32) add_paths_to_fixup_libs(${OPENSSL_DLL_PATH}) - # - # For some reason fixup misses the following DLL and only copies libeay32. There's gotta be a better way to handle this - # but for now resorting to the following interm solution - if (DEFINED DEPLOY_PACKAGE AND DEPLOY_PACKAGE) - add_custom_command( - TARGET ${TARGET_NAME} POST_BUILD - COMMAND "${CMAKE_COMMAND}" -E copy ${OPENSSL_DLL_PATH}/ssleay32.dll ${CMAKE_BINARY_DIR}/package-bundle/ - ) - endif () endif () mark_as_advanced(OPENSSL_INCLUDE_DIR OPENSSL_LIBRARIES OPENSSL_SEARCH_DIRS) diff --git a/console/CMakeLists.txt b/console/CMakeLists.txt index 05ab6f0549..85055407be 100644 --- a/console/CMakeLists.txt +++ b/console/CMakeLists.txt @@ -35,6 +35,10 @@ elseif (WIN32) DESTINATION ${CONSOLE_INSTALL_DIR} COMPONENT ${SERVER_COMPONENT} ) + + # sign the copied server console executable after install + set(EXECUTABLE_NAME ${CONSOLE_EXEC_NAME}) + optional_win_executable_signing() endif() if (NOT PR_BUILD AND NOT PRODUCTION_BUILD) From e50e28468c33fc3ec56c712f458b5a83c6c5f731 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 12 Jan 2016 16:03:36 -0800 Subject: [PATCH 150/357] add a status message for executable signing --- cmake/macros/OptionalWinExecutableSigning.cmake | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cmake/macros/OptionalWinExecutableSigning.cmake b/cmake/macros/OptionalWinExecutableSigning.cmake index c8ed0e0d4b..998c57ccd8 100644 --- a/cmake/macros/OptionalWinExecutableSigning.cmake +++ b/cmake/macros/OptionalWinExecutableSigning.cmake @@ -29,7 +29,12 @@ macro(optional_win_executable_signing) /td SHA256 \${CMAKE_INSTALL_PREFIX}/${EXECUTABLE_NAME}" ) - install(CODE "execute_process(COMMAND ${SIGN_COMMAND})" COMPONENT ${EXECUTABLE_COMPONENT}) + install(CODE "\ + message(STATUS \"Signing ${EXECUTABLE_NAME} with signtool.\") + execute_process(COMMAND ${SIGN_COMMAND}) + " + COMPONENT ${EXECUTABLE_COMPONENT} + ) else () message(FATAL_ERROR "HF_PFX_PASSPHRASE must be set for executables to be signed.") endif () From 547d2043e8eb86668b6a468e115a67ef265f6ae8 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 12 Jan 2016 16:12:03 -0800 Subject: [PATCH 151/357] fix for execute_process call with signtool command --- cmake/macros/OptionalWinExecutableSigning.cmake | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/cmake/macros/OptionalWinExecutableSigning.cmake b/cmake/macros/OptionalWinExecutableSigning.cmake index 998c57ccd8..a79a9b0cf9 100644 --- a/cmake/macros/OptionalWinExecutableSigning.cmake +++ b/cmake/macros/OptionalWinExecutableSigning.cmake @@ -25,13 +25,12 @@ macro(optional_win_executable_signing) endif () # setup the post install command to sign the executable - set(SIGN_COMMAND "${SIGNTOOL_EXEC} sign /f $ENV{HF_PFX_FILE} /p $ENV{HF_PFX_PASSPHRASE} /tr http://tsa.starfieldtech.com\ - /td SHA256 \${CMAKE_INSTALL_PREFIX}/${EXECUTABLE_NAME}" - ) install(CODE "\ - message(STATUS \"Signing ${EXECUTABLE_NAME} with signtool.\") - execute_process(COMMAND ${SIGN_COMMAND}) + message(STATUS \"Signing ${TARGET_NAME} with signtool.\") + execute_process(COMMAND ${SIGNTOOL_EXEC} sign /f $ENV{HF_PFX_FILE}\ + /p $ENV{HF_PFX_PASSPHRASE} /tr http://tsa.starfieldtech.com\ + /td SHA256 \${CMAKE_INSTALL_PREFIX}/${EXECUTABLE_NAME}) " COMPONENT ${EXECUTABLE_COMPONENT} ) From e036531796538a2513416629ec5ca93522793dfc Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 12 Jan 2016 16:22:37 -0800 Subject: [PATCH 152/357] attempt to sign executable as a post build step --- cmake/macros/OptionalWinExecutableSigning.cmake | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cmake/macros/OptionalWinExecutableSigning.cmake b/cmake/macros/OptionalWinExecutableSigning.cmake index a79a9b0cf9..4a33a513ba 100644 --- a/cmake/macros/OptionalWinExecutableSigning.cmake +++ b/cmake/macros/OptionalWinExecutableSigning.cmake @@ -24,8 +24,12 @@ macro(optional_win_executable_signing) set(EXECUTABLE_NAME $) endif () - # setup the post install command to sign the executable + add_custom_command( + TARGET ${TARGET_NAME} POST_BUILD + COMMAND ${SIGNTOOL_EXEC} sign /f $ENV{HF_PFX_FILE} /p $ENV{HF_PFX_PASSPHRASE} /tr http://tsa.starfieldtech.com\ /td SHA256 $ + ) + # setup the post install command to sign the executable install(CODE "\ message(STATUS \"Signing ${TARGET_NAME} with signtool.\") execute_process(COMMAND ${SIGNTOOL_EXEC} sign /f $ENV{HF_PFX_FILE}\ From 44e1cdfe00bab5628f90aa3e8ba413f3b3bac78a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 12 Jan 2016 16:31:38 -0800 Subject: [PATCH 153/357] make executable signing a post build step --- cmake/macros/OptionalWinExecutableSigning.cmake | 17 ++++------------- console/CMakeLists.txt | 6 ++++-- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/cmake/macros/OptionalWinExecutableSigning.cmake b/cmake/macros/OptionalWinExecutableSigning.cmake index 4a33a513ba..6248985468 100644 --- a/cmake/macros/OptionalWinExecutableSigning.cmake +++ b/cmake/macros/OptionalWinExecutableSigning.cmake @@ -20,23 +20,14 @@ macro(optional_win_executable_signing) message(FATAL_ERROR "Code signing of executables was requested but signtool.exe could not be found.") endif () - if (NOT EXECUTABLE_NAME) - set(EXECUTABLE_NAME $) + if (NOT EXECUTABLE_PATH) + set(EXECUTABLE_PATH $) endif () + # setup a post build command to sign the executable add_custom_command( TARGET ${TARGET_NAME} POST_BUILD - COMMAND ${SIGNTOOL_EXEC} sign /f $ENV{HF_PFX_FILE} /p $ENV{HF_PFX_PASSPHRASE} /tr http://tsa.starfieldtech.com\ /td SHA256 $ - ) - - # setup the post install command to sign the executable - install(CODE "\ - message(STATUS \"Signing ${TARGET_NAME} with signtool.\") - execute_process(COMMAND ${SIGNTOOL_EXEC} sign /f $ENV{HF_PFX_FILE}\ - /p $ENV{HF_PFX_PASSPHRASE} /tr http://tsa.starfieldtech.com\ - /td SHA256 \${CMAKE_INSTALL_PREFIX}/${EXECUTABLE_NAME}) - " - COMPONENT ${EXECUTABLE_COMPONENT} + COMMAND ${SIGNTOOL_EXEC} sign /f %HF_PFX_FILE% /p %HF_PFX_PASSPHRASE% /tr http://tsa.starfieldtech.com\ /td SHA256 ${EXECUTABLE_PATH} ) else () message(FATAL_ERROR "HF_PFX_PASSPHRASE must be set for executables to be signed.") diff --git a/console/CMakeLists.txt b/console/CMakeLists.txt index 85055407be..055457cff8 100644 --- a/console/CMakeLists.txt +++ b/console/CMakeLists.txt @@ -30,14 +30,16 @@ if (APPLE) COMPONENT ${SERVER_COMPONENT} ) elseif (WIN32) + set(CONSOLE_DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/${PACKAGED_CONSOLE_FOLDER}") + install( - DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${PACKAGED_CONSOLE_FOLDER}/" + DIRECTORY "${CONSOLE_DESTINATION}/" DESTINATION ${CONSOLE_INSTALL_DIR} COMPONENT ${SERVER_COMPONENT} ) # sign the copied server console executable after install - set(EXECUTABLE_NAME ${CONSOLE_EXEC_NAME}) + set(EXECUTABLE_PATH "${CONSOLE_DESTINATION}/${CONSOLE_EXEC_NAME}") optional_win_executable_signing() endif() From 14196ba3701e58b744b6a65672ed54055f687ea2 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 12 Jan 2016 16:43:08 -0800 Subject: [PATCH 154/357] fix for target file name interpolation --- cmake/macros/OptionalWinExecutableSigning.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/macros/OptionalWinExecutableSigning.cmake b/cmake/macros/OptionalWinExecutableSigning.cmake index 6248985468..94ed93db2a 100644 --- a/cmake/macros/OptionalWinExecutableSigning.cmake +++ b/cmake/macros/OptionalWinExecutableSigning.cmake @@ -21,13 +21,13 @@ macro(optional_win_executable_signing) endif () if (NOT EXECUTABLE_PATH) - set(EXECUTABLE_PATH $) + set(EXECUTABLE_PATH "$") endif () # setup a post build command to sign the executable add_custom_command( TARGET ${TARGET_NAME} POST_BUILD - COMMAND ${SIGNTOOL_EXEC} sign /f %HF_PFX_FILE% /p %HF_PFX_PASSPHRASE% /tr http://tsa.starfieldtech.com\ /td SHA256 ${EXECUTABLE_PATH} + COMMAND ${SIGNTOOL_EXEC} sign /f %HF_PFX_FILE% /p %HF_PFX_PASSPHRASE% /tr http://tsa.starfieldtech.com /td SHA256 ${EXECUTABLE_PATH} ) else () message(FATAL_ERROR "HF_PFX_PASSPHRASE must be set for executables to be signed.") From 3b12eef79b2e19eb013777eac88ec386b74be6eb Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 12 Jan 2016 16:45:11 -0800 Subject: [PATCH 155/357] use full path and not simply name for target --- cmake/macros/OptionalWinExecutableSigning.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/macros/OptionalWinExecutableSigning.cmake b/cmake/macros/OptionalWinExecutableSigning.cmake index 94ed93db2a..2ae6ae59fd 100644 --- a/cmake/macros/OptionalWinExecutableSigning.cmake +++ b/cmake/macros/OptionalWinExecutableSigning.cmake @@ -21,7 +21,7 @@ macro(optional_win_executable_signing) endif () if (NOT EXECUTABLE_PATH) - set(EXECUTABLE_PATH "$") + set(EXECUTABLE_PATH "$") endif () # setup a post build command to sign the executable From d6f50b66d6fa72dac194c82dcd859214b01c503a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 12 Jan 2016 17:09:21 -0800 Subject: [PATCH 156/357] add the inner/outer paradigm for signed uninstaller --- cmake/templates/NSIS.template.in | 68 +++++++++++++++++++++++++++----- 1 file changed, 59 insertions(+), 9 deletions(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index c65c5d4dca..68f1776ab8 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -31,15 +31,41 @@ ;-------------------------------- ;General - ;Name and file - Name "@CPACK_NSIS_PACKAGE_NAME@" - OutFile "@CPACK_TOPLEVEL_DIRECTORY@/@CPACK_OUTPUT_FILE_NAME@" + !ifdef INNER + !echo "Inner invocation" ; just to see what's going on + OutFile "$%TEMP%\tempinstaller.exe" ; not really important where this is + SetCompress off ; for speed + !else + !echo "Outer invocation" - ;Set compression - SetCompressor @CPACK_NSIS_COMPRESSOR@ + ; Call makensis again, defining INNER. This writes an installer for us which, when + ; it is invoked, will just write the uninstaller to some location, and then exit. + ; Be sure to substitute the name of this script here. - ;Require administrator access - RequestExecutionLevel admin + !system "$\"${NSISDIR}\makensis$\" /DINNER .nsi" = 0 + + ; So now run that installer we just created as %TEMP%\tempinstaller.exe. Since it + ; calls quit the return value isn't zero. + + !system "$%TEMP%\tempinstaller.exe" = 2 + + ; That will have written an uninstaller binary for us. Now we sign it with your + ; favourite code signing tool. + + !system "signcode $%TEMP%\uninstaller.exe" = 0 + + ; Good. Now we can carry on writing the real installer. + + ;Name and file + Name "@CPACK_NSIS_PACKAGE_NAME@" + OutFile "@CPACK_TOPLEVEL_DIRECTORY@/@CPACK_OUTPUT_FILE_NAME@" + + ;Set compression + SetCompressor @CPACK_NSIS_COMPRESSOR@ + + ;Require administrator access + RequestExecutionLevel admin + !endif @CPACK_NSIS_DEFINES@ @@ -648,8 +674,15 @@ Section "-Core installation" ;Store installation folder WriteRegStr SHCTX "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "" $INSTDIR - ;Create uninstaller - WriteUninstaller "$INSTDIR\Uninstall.exe" + ;Package the signed uninstaller produced by the inner loop + !ifndef INNER + SetOutPath $INSTDIR + + ; this packages the signed uninstaller + + File $%TEMP%\uninstaller.exe + !endif + Push "DisplayName" Push "@CPACK_NSIS_DISPLAY_NAME@" Call ConditionalAddToRegisty @@ -951,6 +984,10 @@ FunctionEnd ;-------------------------------- ;Uninstaller Section +; the normal uninstaller section is only defined for inner (they're not needed in the "outer" +; installer and will just cause warnings because there is no WriteInstaller command) + +!ifdef INNER Section "Uninstall" ReadRegStr $START_MENU SHCTX \ "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "StartMenu" @@ -1046,6 +1083,7 @@ Section "Uninstall" Call un.RemoveFromPath doNotRemoveFromPath: SectionEnd +!endif ;-------------------------------- ; determine admin versus local install @@ -1058,6 +1096,18 @@ SectionEnd ; "Program Files" for AllUsers, "My Documents" for JustMe... Function .onInit + + !ifdef INNER + ; If INNER is defined, then we aren't supposed to do anything except write out + ; the installer. This is better than processing a command line option as it means + ; this entire code path is not present in the final (real) installer. + + WriteUninstaller "$%TEMP%\uninstaller.exe" + + ; just bail out quickly when running the "inner" installer + Quit + !endif + StrCmp "@CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL@" "ON" 0 inst ReadRegStr $0 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "UninstallString" From 3cc8457a985cfb9f1aa903f04749b0f2f230c9d3 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 12 Jan 2016 17:11:11 -0800 Subject: [PATCH 157/357] only call signtool on uninstaller for production build --- cmake/templates/NSIS.template.in | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 68f1776ab8..822d5c3cc0 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -50,9 +50,11 @@ !system "$%TEMP%\tempinstaller.exe" = 2 ; That will have written an uninstaller binary for us. Now we sign it with your - ; favourite code signing tool. + ; favourite code signing tool, if it's a production build. - !system "signcode $%TEMP%\uninstaller.exe" = 0 + ${If} "@PRODUCTION_BUILD@" == "1" + !system "signcode $%TEMP%\uninstaller.exe" = 0 + ${EndIf} ; Good. Now we can carry on writing the real installer. From 6b796a26b011ea65c8d452f95ac654aa0fd39dd3 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 12 Jan 2016 17:13:00 -0800 Subject: [PATCH 158/357] replace name of script for inner invocation --- cmake/templates/NSIS.template.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 822d5c3cc0..92059d3a3e 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -42,7 +42,7 @@ ; it is invoked, will just write the uninstaller to some location, and then exit. ; Be sure to substitute the name of this script here. - !system "$\"${NSISDIR}\makensis$\" /DINNER .nsi" = 0 + !system "$\"${NSISDIR}\makensis$\" /DINNER project.nsi" = 0 ; So now run that installer we just created as %TEMP%\tempinstaller.exe. Since it ; calls quit the return value isn't zero. From cc4f7a9ad8605cf8b1fcde159d9319d490434ffc Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 12 Jan 2016 17:14:58 -0800 Subject: [PATCH 159/357] add message if executable signing enabled --- cmake/macros/OptionalWinExecutableSigning.cmake | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmake/macros/OptionalWinExecutableSigning.cmake b/cmake/macros/OptionalWinExecutableSigning.cmake index 2ae6ae59fd..f0be81c996 100644 --- a/cmake/macros/OptionalWinExecutableSigning.cmake +++ b/cmake/macros/OptionalWinExecutableSigning.cmake @@ -20,6 +20,8 @@ macro(optional_win_executable_signing) message(FATAL_ERROR "Code signing of executables was requested but signtool.exe could not be found.") endif () + message(STATUS "Executable for ${TARGET_NAME} will be signed with SignTool.") + if (NOT EXECUTABLE_PATH) set(EXECUTABLE_PATH "$") endif () From 7f08d77b36281e088afa256fd856ab0b1027bd5e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 12 Jan 2016 17:27:54 -0800 Subject: [PATCH 160/357] move uninstaller signing to onInit --- cmake/templates/NSIS.template.in | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 92059d3a3e..89c5d89a90 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -49,13 +49,6 @@ !system "$%TEMP%\tempinstaller.exe" = 2 - ; That will have written an uninstaller binary for us. Now we sign it with your - ; favourite code signing tool, if it's a production build. - - ${If} "@PRODUCTION_BUILD@" == "1" - !system "signcode $%TEMP%\uninstaller.exe" = 0 - ${EndIf} - ; Good. Now we can carry on writing the real installer. ;Name and file @@ -1110,6 +1103,13 @@ Function .onInit Quit !endif + ; The Inner invocation has written an uninstaller binary for us. + ; We need to sign it if it's a production build. + + ${If} "@PRODUCTION_BUILD@" == "1" + !system "signcode $%TEMP%\uninstaller.exe" = 0 + ${EndIf} + StrCmp "@CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL@" "ON" 0 inst ReadRegStr $0 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "UninstallString" From f8ca9e64a9d4ced73d09cfa7f5f1e280ecb4448e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 12 Jan 2016 17:40:25 -0800 Subject: [PATCH 161/357] pass the signtool executable to nsis --- cmake/macros/OptionalWinExecutableSigning.cmake | 9 +-------- cmake/macros/SetPackagingParameters.cmake | 9 +++++++++ cmake/templates/CPackProperties.cmake.in | 1 + cmake/templates/NSIS.template.in | 15 +++++++-------- 4 files changed, 18 insertions(+), 16 deletions(-) diff --git a/cmake/macros/OptionalWinExecutableSigning.cmake b/cmake/macros/OptionalWinExecutableSigning.cmake index f0be81c996..0ce7f89940 100644 --- a/cmake/macros/OptionalWinExecutableSigning.cmake +++ b/cmake/macros/OptionalWinExecutableSigning.cmake @@ -13,13 +13,6 @@ macro(optional_win_executable_signing) if (WIN32 AND (PRODUCTION_BUILD OR PR_BUILD)) if (DEFINED ENV{HF_PFX_FILE}) if (DEFINED ENV{HF_PFX_PASSPHRASE}) - # find signtool - find_program(SIGNTOOL_EXEC signtool PATHS "C:/Program Files (x86)/Windows Kits/8.1" PATH_SUFFIXES "bin/x64") - - if (NOT SIGNTOOL_EXEC) - message(FATAL_ERROR "Code signing of executables was requested but signtool.exe could not be found.") - endif () - message(STATUS "Executable for ${TARGET_NAME} will be signed with SignTool.") if (NOT EXECUTABLE_PATH) @@ -29,7 +22,7 @@ macro(optional_win_executable_signing) # setup a post build command to sign the executable add_custom_command( TARGET ${TARGET_NAME} POST_BUILD - COMMAND ${SIGNTOOL_EXEC} sign /f %HF_PFX_FILE% /p %HF_PFX_PASSPHRASE% /tr http://tsa.starfieldtech.com /td SHA256 ${EXECUTABLE_PATH} + COMMAND ${SIGNTOOL_EXECUTABLE} sign /f %HF_PFX_FILE% /p %HF_PFX_PASSPHRASE% /tr http://tsa.starfieldtech.com /td SHA256 ${EXECUTABLE_PATH} ) else () message(FATAL_ERROR "HF_PFX_PASSPHRASE must be set for executables to be signed.") diff --git a/cmake/macros/SetPackagingParameters.cmake b/cmake/macros/SetPackagingParameters.cmake index 88257495f6..503c57a619 100644 --- a/cmake/macros/SetPackagingParameters.cmake +++ b/cmake/macros/SetPackagingParameters.cmake @@ -60,6 +60,15 @@ macro(SET_PACKAGING_PARAMETERS) # start menu shortcuts set(INTERFACE_SM_SHORTCUT_NAME "High Fidelity") set(CONSOLE_SM_SHORTCUT_NAME "Server Console") + + # check if we need to find signtool + if (PRODUCTION_BUILD OR PR_BUILD) + find_program(SIGNTOOL_EXECUTABLE signtool PATHS "C:/Program Files (x86)/Windows Kits/8.1" PATH_SUFFIXES "bin/x64") + + if (NOT SIGNTOOL_EXECUTABLE) + message(FATAL_ERROR "Code signing of executables was requested but signtool.exe could not be found.") + endif () + endif () endif () if (APPLE) diff --git a/cmake/templates/CPackProperties.cmake.in b/cmake/templates/CPackProperties.cmake.in index 5e9caa3482..0c645afe4a 100644 --- a/cmake/templates/CPackProperties.cmake.in +++ b/cmake/templates/CPackProperties.cmake.in @@ -18,3 +18,4 @@ set(PRODUCTION_BUILD "@PRODUCTION_BUILD@") set(POST_INSTALL_OPTIONS_PATH "@POST_INSTALL_OPTIONS_PATH@") set(CLIENT_COMPONENT_NAME "@CLIENT_COMPONENT@") set(SERVER_COMPONENT_NAME "@SERVER_COMPONENT@") +set(SIGNTOOL_EXECUTABLE "@SIGNTOOL_EXECUTABLE@") diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 89c5d89a90..8676dabf0f 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -674,7 +674,6 @@ Section "-Core installation" SetOutPath $INSTDIR ; this packages the signed uninstaller - File $%TEMP%\uninstaller.exe !endif @@ -1101,15 +1100,15 @@ Function .onInit ; just bail out quickly when running the "inner" installer Quit + !else + ; The Inner invocation has written an uninstaller binary for us. + ; We need to sign it if it's a production build. + + ${If} "@PRODUCTION_BUILD@" == "1" + !system "@SIGNTOOL_EXECUTABLE@ sign /f %HF_PFX_FILE% /p %HF_PFX_PASSPHRASE% /tr http://tsa.starfieldtech.com /td SHA256 $%TEMP%\uninstaller.exe" = 0 + ${EndIf} !endif - ; The Inner invocation has written an uninstaller binary for us. - ; We need to sign it if it's a production build. - - ${If} "@PRODUCTION_BUILD@" == "1" - !system "signcode $%TEMP%\uninstaller.exe" = 0 - ${EndIf} - StrCmp "@CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL@" "ON" 0 inst ReadRegStr $0 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "UninstallString" From a17ac026cc80985c21e6a770755b48536ca5b109 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 12 Jan 2016 17:50:47 -0800 Subject: [PATCH 162/357] use compile time command for conditional signing --- cmake/templates/NSIS.template.in | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 8676dabf0f..1907113417 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -6,6 +6,7 @@ !define VERSION "@CPACK_PACKAGE_VERSION@" !define PATCH "@CPACK_PACKAGE_VERSION_PATCH@" !define INST_DIR "@CPACK_TEMPORARY_DIRECTORY@" + !define PRODUCTION_BUILD "@PRODUCTION_BUILD@" ;-------------------------------- ;Variables @@ -49,6 +50,12 @@ !system "$%TEMP%\tempinstaller.exe" = 2 + ; The Inner invocation has written an uninstaller binary for us. + ; We need to sign it if it's a production or PR build. + !ifdef PRODUCTION_BUILD + !system "@SIGNTOOL_EXECUTABLE@ sign /f %HF_PFX_FILE% /p %HF_PFX_PASSPHRASE% /tr http://tsa.starfieldtech.com /td SHA256 $%TEMP%\uninstaller.exe" = 0 + !endif + ; Good. Now we can carry on writing the real installer. ;Name and file @@ -1100,13 +1107,6 @@ Function .onInit ; just bail out quickly when running the "inner" installer Quit - !else - ; The Inner invocation has written an uninstaller binary for us. - ; We need to sign it if it's a production build. - - ${If} "@PRODUCTION_BUILD@" == "1" - !system "@SIGNTOOL_EXECUTABLE@ sign /f %HF_PFX_FILE% /p %HF_PFX_PASSPHRASE% /tr http://tsa.starfieldtech.com /td SHA256 $%TEMP%\uninstaller.exe" = 0 - ${EndIf} !endif StrCmp "@CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL@" "ON" 0 inst From 256347f6ef9d902fea34c2be7c048e6db10da23d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 12 Jan 2016 17:52:59 -0800 Subject: [PATCH 163/357] use direct comparison instead of define check --- cmake/templates/NSIS.template.in | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 1907113417..d8c3a59eaf 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -6,7 +6,6 @@ !define VERSION "@CPACK_PACKAGE_VERSION@" !define PATCH "@CPACK_PACKAGE_VERSION_PATCH@" !define INST_DIR "@CPACK_TEMPORARY_DIRECTORY@" - !define PRODUCTION_BUILD "@PRODUCTION_BUILD@" ;-------------------------------- ;Variables @@ -52,7 +51,7 @@ ; The Inner invocation has written an uninstaller binary for us. ; We need to sign it if it's a production or PR build. - !ifdef PRODUCTION_BUILD + !if @PRODUCTION_BUILD@ == 1 !system "@SIGNTOOL_EXECUTABLE@ sign /f %HF_PFX_FILE% /p %HF_PFX_PASSPHRASE% /tr http://tsa.starfieldtech.com /td SHA256 $%TEMP%\uninstaller.exe" = 0 !endif From 0d2b8f183e556c3e0f145c68bc6c21a92583617d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 12 Jan 2016 18:01:03 -0800 Subject: [PATCH 164/357] use fully escaped path for nsis compatibility --- cmake/macros/SetPackagingParameters.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/macros/SetPackagingParameters.cmake b/cmake/macros/SetPackagingParameters.cmake index 503c57a619..bc1d6c9f86 100644 --- a/cmake/macros/SetPackagingParameters.cmake +++ b/cmake/macros/SetPackagingParameters.cmake @@ -63,7 +63,7 @@ macro(SET_PACKAGING_PARAMETERS) # check if we need to find signtool if (PRODUCTION_BUILD OR PR_BUILD) - find_program(SIGNTOOL_EXECUTABLE signtool PATHS "C:/Program Files (x86)/Windows Kits/8.1" PATH_SUFFIXES "bin/x64") + find_program(SIGNTOOL_EXECUTABLE signtool PATHS "C:\\Program\ Files\ (x86)\\Windows\ Kits\\8.1" PATH_SUFFIXES "bin/x64") if (NOT SIGNTOOL_EXECUTABLE) message(FATAL_ERROR "Code signing of executables was requested but signtool.exe could not be found.") From b9ccef6c2c8f478717db4b734b4f02ed19d6fbcf Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 12 Jan 2016 18:04:35 -0800 Subject: [PATCH 165/357] use string replace to escape signtool path --- cmake/macros/SetPackagingParameters.cmake | 6 +++++- cmake/templates/CPackProperties.cmake.in | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/cmake/macros/SetPackagingParameters.cmake b/cmake/macros/SetPackagingParameters.cmake index bc1d6c9f86..a0592e5bb7 100644 --- a/cmake/macros/SetPackagingParameters.cmake +++ b/cmake/macros/SetPackagingParameters.cmake @@ -63,11 +63,15 @@ macro(SET_PACKAGING_PARAMETERS) # check if we need to find signtool if (PRODUCTION_BUILD OR PR_BUILD) - find_program(SIGNTOOL_EXECUTABLE signtool PATHS "C:\\Program\ Files\ (x86)\\Windows\ Kits\\8.1" PATH_SUFFIXES "bin/x64") + find_program(SIGNTOOL_EXECUTABLE signtool PATHS "C:/Program Files (x86)/Windows Kits/8.1" PATH_SUFFIXES "bin/x64") if (NOT SIGNTOOL_EXECUTABLE) message(FATAL_ERROR "Code signing of executables was requested but signtool.exe could not be found.") endif () + + # perform a string replacement on the produced path so it is ready for NSIS + string(REPLACE "/" "\\\\" _SIGNTOOL_EXECUTABLE_BACKSLASH ${SIGNTOOL_EXECUTABLE}) + string(REPLACE " " "\\ " SIGNTOOL_EXECUTABLE_ESCAPED ${_SIGNTOOL_EXECUTABLE_BACKSLASH}) endif () endif () diff --git a/cmake/templates/CPackProperties.cmake.in b/cmake/templates/CPackProperties.cmake.in index 0c645afe4a..1afcc04ffc 100644 --- a/cmake/templates/CPackProperties.cmake.in +++ b/cmake/templates/CPackProperties.cmake.in @@ -18,4 +18,4 @@ set(PRODUCTION_BUILD "@PRODUCTION_BUILD@") set(POST_INSTALL_OPTIONS_PATH "@POST_INSTALL_OPTIONS_PATH@") set(CLIENT_COMPONENT_NAME "@CLIENT_COMPONENT@") set(SERVER_COMPONENT_NAME "@SERVER_COMPONENT@") -set(SIGNTOOL_EXECUTABLE "@SIGNTOOL_EXECUTABLE@") +set(SIGNTOOL_EXECUTABLE "@SIGNTOOL_EXECUTABLE_ESCAPED@") From 89e8cd16d37a35ce38031cafdd916e54c6a09962 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 12 Jan 2016 18:12:15 -0800 Subject: [PATCH 166/357] use quotes in nsis template for signtool path --- cmake/macros/SetPackagingParameters.cmake | 4 ---- cmake/templates/CPackProperties.cmake.in | 2 +- cmake/templates/NSIS.template.in | 2 +- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/cmake/macros/SetPackagingParameters.cmake b/cmake/macros/SetPackagingParameters.cmake index a0592e5bb7..503c57a619 100644 --- a/cmake/macros/SetPackagingParameters.cmake +++ b/cmake/macros/SetPackagingParameters.cmake @@ -68,10 +68,6 @@ macro(SET_PACKAGING_PARAMETERS) if (NOT SIGNTOOL_EXECUTABLE) message(FATAL_ERROR "Code signing of executables was requested but signtool.exe could not be found.") endif () - - # perform a string replacement on the produced path so it is ready for NSIS - string(REPLACE "/" "\\\\" _SIGNTOOL_EXECUTABLE_BACKSLASH ${SIGNTOOL_EXECUTABLE}) - string(REPLACE " " "\\ " SIGNTOOL_EXECUTABLE_ESCAPED ${_SIGNTOOL_EXECUTABLE_BACKSLASH}) endif () endif () diff --git a/cmake/templates/CPackProperties.cmake.in b/cmake/templates/CPackProperties.cmake.in index 1afcc04ffc..0c645afe4a 100644 --- a/cmake/templates/CPackProperties.cmake.in +++ b/cmake/templates/CPackProperties.cmake.in @@ -18,4 +18,4 @@ set(PRODUCTION_BUILD "@PRODUCTION_BUILD@") set(POST_INSTALL_OPTIONS_PATH "@POST_INSTALL_OPTIONS_PATH@") set(CLIENT_COMPONENT_NAME "@CLIENT_COMPONENT@") set(SERVER_COMPONENT_NAME "@SERVER_COMPONENT@") -set(SIGNTOOL_EXECUTABLE "@SIGNTOOL_EXECUTABLE_ESCAPED@") +set(SIGNTOOL_EXECUTABLE "@SIGNTOOL_EXECUTABLE@") diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index d8c3a59eaf..9b8841c586 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -52,7 +52,7 @@ ; The Inner invocation has written an uninstaller binary for us. ; We need to sign it if it's a production or PR build. !if @PRODUCTION_BUILD@ == 1 - !system "@SIGNTOOL_EXECUTABLE@ sign /f %HF_PFX_FILE% /p %HF_PFX_PASSPHRASE% /tr http://tsa.starfieldtech.com /td SHA256 $%TEMP%\uninstaller.exe" = 0 + !system '"@SIGNTOOL_EXECUTABLE@" sign /f %HF_PFX_FILE% /p %HF_PFX_PASSPHRASE% /tr http://tsa.starfieldtech.com /td SHA256 $%TEMP%\uninstaller.exe' = 0 !endif ; Good. Now we can carry on writing the real installer. From 35211049a0075a7259b59e21f3311916545447da Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 12 Jan 2016 18:19:39 -0800 Subject: [PATCH 167/357] fix for env variable referencing for signtool --- cmake/templates/NSIS.template.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 9b8841c586..e081bbf70f 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -52,7 +52,7 @@ ; The Inner invocation has written an uninstaller binary for us. ; We need to sign it if it's a production or PR build. !if @PRODUCTION_BUILD@ == 1 - !system '"@SIGNTOOL_EXECUTABLE@" sign /f %HF_PFX_FILE% /p %HF_PFX_PASSPHRASE% /tr http://tsa.starfieldtech.com /td SHA256 $%TEMP%\uninstaller.exe' = 0 + !system '"@SIGNTOOL_EXECUTABLE@" sign /f $%HF_PFX_FILE% /p $%HF_PFX_PASSPHRASE% /tr http://tsa.starfieldtech.com /td SHA256 $%TEMP%\uninstaller.exe' = 0 !endif ; Good. Now we can carry on writing the real installer. From d8a0b28655c977fd00eade9b1dc48b143b1cb75d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 12 Jan 2016 18:22:58 -0800 Subject: [PATCH 168/357] allow execution of command to use env --- cmake/templates/NSIS.template.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index e081bbf70f..9b8841c586 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -52,7 +52,7 @@ ; The Inner invocation has written an uninstaller binary for us. ; We need to sign it if it's a production or PR build. !if @PRODUCTION_BUILD@ == 1 - !system '"@SIGNTOOL_EXECUTABLE@" sign /f $%HF_PFX_FILE% /p $%HF_PFX_PASSPHRASE% /tr http://tsa.starfieldtech.com /td SHA256 $%TEMP%\uninstaller.exe' = 0 + !system '"@SIGNTOOL_EXECUTABLE@" sign /f %HF_PFX_FILE% /p %HF_PFX_PASSPHRASE% /tr http://tsa.starfieldtech.com /td SHA256 $%TEMP%\uninstaller.exe' = 0 !endif ; Good. Now we can carry on writing the real installer. From fceb91678703a8b10efec52234954bbcff935dcf Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 13 Jan 2016 11:55:06 -0800 Subject: [PATCH 169/357] request admin prior to system call --- cmake/templates/NSIS.template.in | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 9b8841c586..60b99bc7cf 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -49,6 +49,9 @@ !system "$%TEMP%\tempinstaller.exe" = 2 + ;Require administrator access + RequestExecutionLevel admin + ; The Inner invocation has written an uninstaller binary for us. ; We need to sign it if it's a production or PR build. !if @PRODUCTION_BUILD@ == 1 @@ -63,9 +66,6 @@ ;Set compression SetCompressor @CPACK_NSIS_COMPRESSOR@ - - ;Require administrator access - RequestExecutionLevel admin !endif @CPACK_NSIS_DEFINES@ @@ -677,8 +677,6 @@ Section "-Core installation" ;Package the signed uninstaller produced by the inner loop !ifndef INNER - SetOutPath $INSTDIR - ; this packages the signed uninstaller File $%TEMP%\uninstaller.exe !endif From e1ebb5ae5db518306c55e239d151cd3a76058e9c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 13 Jan 2016 11:56:45 -0800 Subject: [PATCH 170/357] use execute in place of system --- cmake/templates/NSIS.template.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 60b99bc7cf..e315d9df55 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -55,7 +55,7 @@ ; The Inner invocation has written an uninstaller binary for us. ; We need to sign it if it's a production or PR build. !if @PRODUCTION_BUILD@ == 1 - !system '"@SIGNTOOL_EXECUTABLE@" sign /f %HF_PFX_FILE% /p %HF_PFX_PASSPHRASE% /tr http://tsa.starfieldtech.com /td SHA256 $%TEMP%\uninstaller.exe' = 0 + !execute '"@SIGNTOOL_EXECUTABLE@" sign /f %HF_PFX_FILE% /p %HF_PFX_PASSPHRASE% /tr http://tsa.starfieldtech.com /td SHA256 $%TEMP%\uninstaller.exe' = 0 !endif ; Good. Now we can carry on writing the real installer. From c0095e57d942a23841d1bef08ea5064cb03f3497 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 13 Jan 2016 12:01:19 -0800 Subject: [PATCH 171/357] run elevated prior to running temp installer --- cmake/templates/NSIS.template.in | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index e315d9df55..3d67f70ea5 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -44,18 +44,18 @@ !system "$\"${NSISDIR}\makensis$\" /DINNER project.nsi" = 0 + ; Require administrator access + RequestExecutionLevel admin + ; So now run that installer we just created as %TEMP%\tempinstaller.exe. Since it ; calls quit the return value isn't zero. !system "$%TEMP%\tempinstaller.exe" = 2 - ;Require administrator access - RequestExecutionLevel admin - ; The Inner invocation has written an uninstaller binary for us. ; We need to sign it if it's a production or PR build. !if @PRODUCTION_BUILD@ == 1 - !execute '"@SIGNTOOL_EXECUTABLE@" sign /f %HF_PFX_FILE% /p %HF_PFX_PASSPHRASE% /tr http://tsa.starfieldtech.com /td SHA256 $%TEMP%\uninstaller.exe' = 0 + !system '"@SIGNTOOL_EXECUTABLE@" sign /f %HF_PFX_FILE% /p %HF_PFX_PASSPHRASE% /tr http://tsa.starfieldtech.com /td SHA256 $%TEMP%\uninstaller.exe' = 0 !endif ; Good. Now we can carry on writing the real installer. From c064a31b77b028fd4cd8a696c960348b57a528a4 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 13 Jan 2016 12:07:14 -0800 Subject: [PATCH 172/357] use ExecWait so it is performed as admin --- cmake/templates/NSIS.template.in | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 3d67f70ea5..777d98c71c 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -55,7 +55,12 @@ ; The Inner invocation has written an uninstaller binary for us. ; We need to sign it if it's a production or PR build. !if @PRODUCTION_BUILD@ == 1 - !system '"@SIGNTOOL_EXECUTABLE@" sign /f %HF_PFX_FILE% /p %HF_PFX_PASSPHRASE% /tr http://tsa.starfieldtech.com /td SHA256 $%TEMP%\uninstaller.exe' = 0 + ExecWait '"@SIGNTOOL_EXECUTABLE@" sign /f %HF_PFX_FILE% /p %HF_PFX_PASSPHRASE% /tr http://tsa.starfieldtech.com /td SHA256 $%TEMP%\uninstaller.exe' $0 + + !if $0 != 0 + DetailPrint "Failed to sign uninstaller. Will not continue generation of installer." + Quit + !endif !endif ; Good. Now we can carry on writing the real installer. From 9972e2b0961d758ff071d2166daadb6d667359af Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 13 Jan 2016 12:16:40 -0800 Subject: [PATCH 173/357] attempt to use RunAsInvoker for inner/outer uninstaller --- cmake/templates/NSIS.template.in | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 777d98c71c..155d10115d 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -38,6 +38,9 @@ !else !echo "Outer invocation" + ; make sure that makensis itself is not run elevated + !system "set __COMPAT_LAYER=RunAsInvoker&makensis ..." + ; Call makensis again, defining INNER. This writes an installer for us which, when ; it is invoked, will just write the uninstaller to some location, and then exit. ; Be sure to substitute the name of this script here. @@ -55,12 +58,7 @@ ; The Inner invocation has written an uninstaller binary for us. ; We need to sign it if it's a production or PR build. !if @PRODUCTION_BUILD@ == 1 - ExecWait '"@SIGNTOOL_EXECUTABLE@" sign /f %HF_PFX_FILE% /p %HF_PFX_PASSPHRASE% /tr http://tsa.starfieldtech.com /td SHA256 $%TEMP%\uninstaller.exe' $0 - - !if $0 != 0 - DetailPrint "Failed to sign uninstaller. Will not continue generation of installer." - Quit - !endif + !system '"@SIGNTOOL_EXECUTABLE@" sign /f %HF_PFX_FILE% /p %HF_PFX_PASSPHRASE% /tr http://tsa.starfieldtech.com /td SHA256 $%TEMP%\uninstaller.exe' = 0 !endif ; Good. Now we can carry on writing the real installer. From ed56dd7303742cae935a16b34788de5e9b21c290 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 13 Jan 2016 12:21:21 -0800 Subject: [PATCH 174/357] call makensis with RunAsInvoker --- cmake/templates/NSIS.template.in | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 155d10115d..f57b91bbd8 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -38,14 +38,11 @@ !else !echo "Outer invocation" - ; make sure that makensis itself is not run elevated - !system "set __COMPAT_LAYER=RunAsInvoker&makensis ..." - ; Call makensis again, defining INNER. This writes an installer for us which, when ; it is invoked, will just write the uninstaller to some location, and then exit. ; Be sure to substitute the name of this script here. - !system "$\"${NSISDIR}\makensis$\" /DINNER project.nsi" = 0 + !system "set __COMPAT_LAYER=RunAsInvoker&$\"${NSISDIR}\makensis$\" /DINNER project.nsi" = 0 ; Require administrator access RequestExecutionLevel admin From 75a8ab56bcf2ceed7e6cae9b7cdeae4e35419ebb Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 13 Jan 2016 12:28:17 -0800 Subject: [PATCH 175/357] attempt to sign in inner invocation --- cmake/templates/NSIS.template.in | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index f57b91bbd8..95b6675113 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -42,7 +42,7 @@ ; it is invoked, will just write the uninstaller to some location, and then exit. ; Be sure to substitute the name of this script here. - !system "set __COMPAT_LAYER=RunAsInvoker&$\"${NSISDIR}\makensis$\" /DINNER project.nsi" = 0 + !system "set __COMPAT_LAYER=RunAsInvoker && $\"${NSISDIR}\makensis$\" /DINNER project.nsi" = 0 ; Require administrator access RequestExecutionLevel admin @@ -52,12 +52,6 @@ !system "$%TEMP%\tempinstaller.exe" = 2 - ; The Inner invocation has written an uninstaller binary for us. - ; We need to sign it if it's a production or PR build. - !if @PRODUCTION_BUILD@ == 1 - !system '"@SIGNTOOL_EXECUTABLE@" sign /f %HF_PFX_FILE% /p %HF_PFX_PASSPHRASE% /tr http://tsa.starfieldtech.com /td SHA256 $%TEMP%\uninstaller.exe' = 0 - !endif - ; Good. Now we can carry on writing the real installer. ;Name and file @@ -1102,6 +1096,12 @@ Function .onInit WriteUninstaller "$%TEMP%\uninstaller.exe" + ; We've written the uninstaller binary. + ; We need to sign it if it's a production or PR build. + !if @PRODUCTION_BUILD@ == 1 + !system '"@SIGNTOOL_EXECUTABLE@" sign /f %HF_PFX_FILE% /p %HF_PFX_PASSPHRASE% /tr http://tsa.starfieldtech.com /td SHA256 $%TEMP%\uninstaller.exe' = 0 + !endif + ; just bail out quickly when running the "inner" installer Quit !endif From 265879cacf219366ebb2f6dd4865b9bb49cc075b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 13 Jan 2016 12:30:07 -0800 Subject: [PATCH 176/357] request admin elevation for uninstaller as well --- cmake/templates/NSIS.template.in | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 95b6675113..1ca9faf57f 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -31,10 +31,14 @@ ;-------------------------------- ;General + ; Require administrator access + RequestExecutionLevel admin + !ifdef INNER !echo "Inner invocation" ; just to see what's going on OutFile "$%TEMP%\tempinstaller.exe" ; not really important where this is SetCompress off ; for speed + !else !echo "Outer invocation" @@ -42,7 +46,7 @@ ; it is invoked, will just write the uninstaller to some location, and then exit. ; Be sure to substitute the name of this script here. - !system "set __COMPAT_LAYER=RunAsInvoker && $\"${NSISDIR}\makensis$\" /DINNER project.nsi" = 0 + !system "$\"${NSISDIR}\makensis$\" /DINNER project.nsi" = 0 ; Require administrator access RequestExecutionLevel admin @@ -52,6 +56,12 @@ !system "$%TEMP%\tempinstaller.exe" = 2 + ; The Inner invocation has written an uninstaller binary for us. + ; We need to sign it if it's a production or PR build. + !if @PRODUCTION_BUILD@ == 1 + !system '"@SIGNTOOL_EXECUTABLE@" sign /f %HF_PFX_FILE% /p %HF_PFX_PASSPHRASE% /tr http://tsa.starfieldtech.com /td SHA256 $%TEMP%\uninstaller.exe' = 0 + !endif + ; Good. Now we can carry on writing the real installer. ;Name and file @@ -1096,12 +1106,6 @@ Function .onInit WriteUninstaller "$%TEMP%\uninstaller.exe" - ; We've written the uninstaller binary. - ; We need to sign it if it's a production or PR build. - !if @PRODUCTION_BUILD@ == 1 - !system '"@SIGNTOOL_EXECUTABLE@" sign /f %HF_PFX_FILE% /p %HF_PFX_PASSPHRASE% /tr http://tsa.starfieldtech.com /td SHA256 $%TEMP%\uninstaller.exe' = 0 - !endif - ; just bail out quickly when running the "inner" installer Quit !endif From 0a0b152f97e7284cc8567b4ffab17bd6f262a9ff Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 13 Jan 2016 13:54:39 -0800 Subject: [PATCH 177/357] attempt to specify user only level for temp installer --- cmake/templates/NSIS.template.in | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 1ca9faf57f..a0d7ac09c4 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -31,17 +31,20 @@ ;-------------------------------- ;General - ; Require administrator access - RequestExecutionLevel admin - !ifdef INNER !echo "Inner invocation" ; just to see what's going on + + ; Require user only for temp installer + RequestExecutionLevel user + OutFile "$%TEMP%\tempinstaller.exe" ; not really important where this is SetCompress off ; for speed - !else !echo "Outer invocation" + ; Require administrator access + RequestExecutionLevel admin + ; Call makensis again, defining INNER. This writes an installer for us which, when ; it is invoked, will just write the uninstaller to some location, and then exit. ; Be sure to substitute the name of this script here. From 6bccdc81b4de0b126de85be1a6fe22f9bfb6a1aa Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 13 Jan 2016 14:16:50 -0800 Subject: [PATCH 178/357] use the UAC plugin to elevate uninstaller --- cmake/templates/NSIS.template.in | 34 ++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index a0d7ac09c4..fcdf5bfa3a 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -30,8 +30,10 @@ ;-------------------------------- ;General - !ifdef INNER + ; leverage the UAC NSIS plugin to promote uninstaller to elevated privileges + !include UAC.nsh + !echo "Inner invocation" ; just to see what's going on ; Require user only for temp installer @@ -62,7 +64,7 @@ ; The Inner invocation has written an uninstaller binary for us. ; We need to sign it if it's a production or PR build. !if @PRODUCTION_BUILD@ == 1 - !system '"@SIGNTOOL_EXECUTABLE@" sign /f %HF_PFX_FILE% /p %HF_PFX_PASSPHRASE% /tr http://tsa.starfieldtech.com /td SHA256 $%TEMP%\uninstaller.exe' = 0 + !system '"@SIGNTOOL_EXECUTABLE@" sign /f %HF_PFX_FILE% /p %HF_PFX_PASSPHRASE% /tr http://tsa.starfieldtech.com /td SHA256 $%TEMP%\Uninstall.exe' = 0 !endif ; Good. Now we can carry on writing the real installer. @@ -685,7 +687,7 @@ Section "-Core installation" ;Package the signed uninstaller produced by the inner loop !ifndef INNER ; this packages the signed uninstaller - File $%TEMP%\uninstaller.exe + File $%TEMP%\Uninstaller.exe !endif Push "DisplayName" @@ -928,6 +930,29 @@ FunctionEnd ; determine admin versus local install Function un.onInit + ; attempt to elevate the uninstaller to admin status + uac_tryagain: + !insertmacro UAC_RunElevated + ${Switch} $0 + ${Case} 0 + ${IfThen} $1 = 1 ${|} Quit ${|} ;we are the outer process, the inner process has done its work, we are done + ${IfThen} $3 <> 0 ${|} ${Break} ${|} ;we are admin, let the show go on + ${If} $1 = 3 ;RunAs completed successfully, but with a non-admin user + MessageBox mb_YesNo|mb_IconExclamation|mb_TopMost|mb_SetForeground "The uninstaller requires admin privileges, try again" /SD IDNO IDYES uac_tryagain IDNO 0 + ${EndIf} + ;fall-through and die + + ${Case} 1223 + MessageBox mb_IconStop|mb_TopMost|mb_SetForeground "The uninstaller requires admin privileges, aborting!" + Quit + ${Case} 1062 + MessageBox mb_IconStop|mb_TopMost|mb_SetForeground "Logon service not running, aborting!" + Quit + ${Default} + MessageBox mb_IconStop|mb_TopMost|mb_SetForeground "Unable to elevate, error $0" + Quit + ${EndSwitch} + ClearErrors UserInfo::GetName IfErrors noLM @@ -994,6 +1019,7 @@ FunctionEnd !ifdef INNER Section "Uninstall" + ReadRegStr $START_MENU SHCTX \ "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "StartMenu" ;MessageBox MB_OK "Start menu is in: $START_MENU" @@ -1107,7 +1133,7 @@ Function .onInit ; the installer. This is better than processing a command line option as it means ; this entire code path is not present in the final (real) installer. - WriteUninstaller "$%TEMP%\uninstaller.exe" + WriteUninstaller "$%TEMP%\Uninstall.exe" ; just bail out quickly when running the "inner" installer Quit From e6b106e1520ebe5b487767f171a246f38e103055 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 13 Jan 2016 14:29:11 -0800 Subject: [PATCH 179/357] move UAC include outside inner defines --- cmake/templates/NSIS.template.in | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index fcdf5bfa3a..c0affd2a6b 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -30,10 +30,10 @@ ;-------------------------------- ;General - !ifdef INNER - ; leverage the UAC NSIS plugin to promote uninstaller to elevated privileges - !include UAC.nsh + ; leverage the UAC NSIS plugin to promote uninstaller to elevated privileges + !include UAC.nsh + !ifdef INNER !echo "Inner invocation" ; just to see what's going on ; Require user only for temp installer From 7f92312d06698714964b8c7f3e3127754d88cdf5 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 13 Jan 2016 14:38:54 -0800 Subject: [PATCH 180/357] reference new elevated uninstaller for file command --- cmake/templates/NSIS.template.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index c0affd2a6b..3cd4531d11 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -687,7 +687,7 @@ Section "-Core installation" ;Package the signed uninstaller produced by the inner loop !ifndef INNER ; this packages the signed uninstaller - File $%TEMP%\Uninstaller.exe + File $%TEMP%\Uninstall.exe !endif Push "DisplayName" From 4e03a06ff9e46706ecbb262bbe470696015ea327 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 13 Jan 2016 15:10:34 -0800 Subject: [PATCH 181/357] set package name prior to uninstaller creation --- cmake/templates/NSIS.template.in | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 3cd4531d11..a1c53c1f16 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -33,6 +33,9 @@ ; leverage the UAC NSIS plugin to promote uninstaller to elevated privileges !include UAC.nsh + ; Set name prior to inner loop so uninstaller has correct values + Name "@CPACK_NSIS_PACKAGE_NAME@" + !ifdef INNER !echo "Inner invocation" ; just to see what's going on @@ -69,8 +72,7 @@ ; Good. Now we can carry on writing the real installer. - ;Name and file - Name "@CPACK_NSIS_PACKAGE_NAME@" + ;Output file OutFile "@CPACK_TOPLEVEL_DIRECTORY@/@CPACK_OUTPUT_FILE_NAME@" ;Set compression From c002332f9ce6ddd066d0db8541a5bdbdf6bef048 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 13 Jan 2016 15:57:14 -0800 Subject: [PATCH 182/357] copy uninstaller to temp directory for correct naming --- cmake/templates/NSIS.template.in | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index a1c53c1f16..4a122615ce 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -932,6 +932,19 @@ FunctionEnd ; determine admin versus local install Function un.onInit + ; In order for the uninstaller to be able to remove itself, we have to do some trickery here. + ; If the $EXEPATH does not contain the $TEMP dir, this instance is not the copied one + ; so we move it to the $TEMP dir and then execute the copied uninstaller. + + ${StrContains} $0 $TEMP $EXEPATH + + ${If} $0 == "notfound" + CopyFiles /SILENT $EXEPATH $TEMP\Uninstall.exe + ExecWait '"$Temp\Uninstall.exe" _?=$INSTDIR' $0 + SetErrorLevel $0 + Quit + ${EndIf} + ; attempt to elevate the uninstaller to admin status uac_tryagain: !insertmacro UAC_RunElevated From 24903ad1611ced2ab47ee00128ebc685ce15f5de Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 13 Jan 2016 15:59:27 -0800 Subject: [PATCH 183/357] add the StrContains macro --- cmake/templates/NSIS.template.in | 48 ++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 4a122615ce..e73fcc0eff 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -928,6 +928,54 @@ Function HandlePostInstallOptions FunctionEnd +; StrContains +; This function does a case sensitive searches for an occurrence of a substring in a string. +; It returns the substring if it is found. +; Otherwise it returns null(""). +; Written by kenglish_hi +; Adapted from StrReplace written by dandaman32 + +Var STR_HAYSTACK +Var STR_NEEDLE +Var STR_CONTAINS_VAR_1 +Var STR_CONTAINS_VAR_2 +Var STR_CONTAINS_VAR_3 +Var STR_CONTAINS_VAR_4 +Var STR_RETURN_VAR + +Function StrContains + Exch $STR_NEEDLE + Exch 1 + Exch $STR_HAYSTACK + ; Uncomment to debug + ;MessageBox MB_OK 'STR_NEEDLE = $STR_NEEDLE STR_HAYSTACK = $STR_HAYSTACK ' + StrCpy $STR_RETURN_VAR "" + StrCpy $STR_CONTAINS_VAR_1 -1 + StrLen $STR_CONTAINS_VAR_2 $STR_NEEDLE + StrLen $STR_CONTAINS_VAR_4 $STR_HAYSTACK + loop: + IntOp $STR_CONTAINS_VAR_1 $STR_CONTAINS_VAR_1 + 1 + StrCpy $STR_CONTAINS_VAR_3 $STR_HAYSTACK $STR_CONTAINS_VAR_2 $STR_CONTAINS_VAR_1 + StrCmp $STR_CONTAINS_VAR_3 $STR_NEEDLE found + StrCmp $STR_CONTAINS_VAR_1 $STR_CONTAINS_VAR_4 done + Goto loop + found: + StrCpy $STR_RETURN_VAR $STR_NEEDLE + Goto done + done: + Pop $STR_NEEDLE ;Prevent "invalid opcode" errors and keep the + Exch $STR_RETURN_VAR +FunctionEnd + +!macro _StrContainsConstructor OUT NEEDLE HAYSTACK + Push `${HAYSTACK}` + Push `${NEEDLE}` + Call StrContains + Pop `${OUT}` +!macroend + +!define StrContains '!insertmacro "_StrContainsConstructor"' + ;-------------------------------- ; determine admin versus local install Function un.onInit From 24ef51c40be538a50876e4fe8d36e1ac1dc7a062 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 13 Jan 2016 16:02:41 -0800 Subject: [PATCH 184/357] use EXEDIR to check if uninstaller is in temp --- cmake/templates/NSIS.template.in | 52 +------------------------------- 1 file changed, 1 insertion(+), 51 deletions(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index e73fcc0eff..16151fd34b 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -928,54 +928,6 @@ Function HandlePostInstallOptions FunctionEnd -; StrContains -; This function does a case sensitive searches for an occurrence of a substring in a string. -; It returns the substring if it is found. -; Otherwise it returns null(""). -; Written by kenglish_hi -; Adapted from StrReplace written by dandaman32 - -Var STR_HAYSTACK -Var STR_NEEDLE -Var STR_CONTAINS_VAR_1 -Var STR_CONTAINS_VAR_2 -Var STR_CONTAINS_VAR_3 -Var STR_CONTAINS_VAR_4 -Var STR_RETURN_VAR - -Function StrContains - Exch $STR_NEEDLE - Exch 1 - Exch $STR_HAYSTACK - ; Uncomment to debug - ;MessageBox MB_OK 'STR_NEEDLE = $STR_NEEDLE STR_HAYSTACK = $STR_HAYSTACK ' - StrCpy $STR_RETURN_VAR "" - StrCpy $STR_CONTAINS_VAR_1 -1 - StrLen $STR_CONTAINS_VAR_2 $STR_NEEDLE - StrLen $STR_CONTAINS_VAR_4 $STR_HAYSTACK - loop: - IntOp $STR_CONTAINS_VAR_1 $STR_CONTAINS_VAR_1 + 1 - StrCpy $STR_CONTAINS_VAR_3 $STR_HAYSTACK $STR_CONTAINS_VAR_2 $STR_CONTAINS_VAR_1 - StrCmp $STR_CONTAINS_VAR_3 $STR_NEEDLE found - StrCmp $STR_CONTAINS_VAR_1 $STR_CONTAINS_VAR_4 done - Goto loop - found: - StrCpy $STR_RETURN_VAR $STR_NEEDLE - Goto done - done: - Pop $STR_NEEDLE ;Prevent "invalid opcode" errors and keep the - Exch $STR_RETURN_VAR -FunctionEnd - -!macro _StrContainsConstructor OUT NEEDLE HAYSTACK - Push `${HAYSTACK}` - Push `${NEEDLE}` - Call StrContains - Pop `${OUT}` -!macroend - -!define StrContains '!insertmacro "_StrContainsConstructor"' - ;-------------------------------- ; determine admin versus local install Function un.onInit @@ -984,9 +936,7 @@ Function un.onInit ; If the $EXEPATH does not contain the $TEMP dir, this instance is not the copied one ; so we move it to the $TEMP dir and then execute the copied uninstaller. - ${StrContains} $0 $TEMP $EXEPATH - - ${If} $0 == "notfound" + ${If} $EXEDIR != $TEMP CopyFiles /SILENT $EXEPATH $TEMP\Uninstall.exe ExecWait '"$Temp\Uninstall.exe" _?=$INSTDIR' $0 SetErrorLevel $0 From 2619c351e8031c8dae6652fce6e0e40859f480f6 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 13 Jan 2016 16:14:05 -0800 Subject: [PATCH 185/357] constantize the uninstaller name --- cmake/templates/NSIS.template.in | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 16151fd34b..39b3e28ecf 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -6,6 +6,7 @@ !define VERSION "@CPACK_PACKAGE_VERSION@" !define PATCH "@CPACK_PACKAGE_VERSION_PATCH@" !define INST_DIR "@CPACK_TEMPORARY_DIRECTORY@" + !define UNINSTALLER_NAME "Uninstall.exe" ;-------------------------------- ;Variables @@ -67,7 +68,7 @@ ; The Inner invocation has written an uninstaller binary for us. ; We need to sign it if it's a production or PR build. !if @PRODUCTION_BUILD@ == 1 - !system '"@SIGNTOOL_EXECUTABLE@" sign /f %HF_PFX_FILE% /p %HF_PFX_PASSPHRASE% /tr http://tsa.starfieldtech.com /td SHA256 $%TEMP%\Uninstall.exe' = 0 + !system '"@SIGNTOOL_EXECUTABLE@" sign /f %HF_PFX_FILE% /p %HF_PFX_PASSPHRASE% /tr http://tsa.starfieldtech.com /td SHA256 $%TEMP%\$UNINSTALLER_NAME' = 0 !endif ; Good. Now we can carry on writing the real installer. @@ -689,7 +690,7 @@ Section "-Core installation" ;Package the signed uninstaller produced by the inner loop !ifndef INNER ; this packages the signed uninstaller - File $%TEMP%\Uninstall.exe + File $%TEMP%\$UNINSTALLER_NAME !endif Push "DisplayName" @@ -702,7 +703,7 @@ Section "-Core installation" Push "@CPACK_PACKAGE_VENDOR@" Call ConditionalAddToRegisty Push "UninstallString" - Push "$INSTDIR\Uninstall.exe" + Push "$INSTDIR\$UNINSTALLER_NAME" Call ConditionalAddToRegisty Push "NoRepair" Push "1" @@ -761,7 +762,7 @@ Section "-Core installation" "$INSTDIR\@CONSOLE_WIN_EXEC_NAME@" ${EndIf} - CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" "$INSTDIR\Uninstall.exe" + CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" "$INSTDIR\$UNINSTALLER_NAME" ;Read a value from an InstallOptions INI file !insertmacro MUI_INSTALLOPTIONS_READ $DO_NOT_ADD_TO_PATH "NSIS.InstallOptions.ini" "Field 2" "State" @@ -937,8 +938,8 @@ Function un.onInit ; so we move it to the $TEMP dir and then execute the copied uninstaller. ${If} $EXEDIR != $TEMP - CopyFiles /SILENT $EXEPATH $TEMP\Uninstall.exe - ExecWait '"$Temp\Uninstall.exe" _?=$INSTDIR' $0 + CopyFiles /SILENT $EXEPATH $TEMP\$UNINSTALLER_NAME + ExecWait '"$Temp\$UNINSTALLER_NAME" _?=$INSTDIR' $0 SetErrorLevel $0 Quit ${EndIf} @@ -1060,7 +1061,7 @@ Section "Uninstall" !endif ;Remove the uninstaller itself. - Delete "$INSTDIR\Uninstall.exe" + Delete "$INSTDIR\$UNINSTALLER_NAME" DeleteRegKey SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" ;Remove the installation directory if it is empty. @@ -1146,7 +1147,7 @@ Function .onInit ; the installer. This is better than processing a command line option as it means ; this entire code path is not present in the final (real) installer. - WriteUninstaller "$%TEMP%\Uninstall.exe" + WriteUninstaller "$%TEMP%\$UNINSTALLER_NAME" ; just bail out quickly when running the "inner" installer Quit From f4817032ec5764842feb19109e7e747d5b5b5f17 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 13 Jan 2016 16:23:48 -0800 Subject: [PATCH 186/357] make uninstaller name a cmake/cpack variable --- cmake/macros/SetPackagingParameters.cmake | 2 ++ cmake/templates/CPackProperties.cmake.in | 1 + cmake/templates/NSIS.template.in | 17 ++++++++--------- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/cmake/macros/SetPackagingParameters.cmake b/cmake/macros/SetPackagingParameters.cmake index 503c57a619..78ba8f1a71 100644 --- a/cmake/macros/SetPackagingParameters.cmake +++ b/cmake/macros/SetPackagingParameters.cmake @@ -69,6 +69,8 @@ macro(SET_PACKAGING_PARAMETERS) message(FATAL_ERROR "Code signing of executables was requested but signtool.exe could not be found.") endif () endif () + + set(GENERATED_UNINSTALLER_EXEC_NAME "Uninstall.exe") endif () if (APPLE) diff --git a/cmake/templates/CPackProperties.cmake.in b/cmake/templates/CPackProperties.cmake.in index 0c645afe4a..0bfa179d5b 100644 --- a/cmake/templates/CPackProperties.cmake.in +++ b/cmake/templates/CPackProperties.cmake.in @@ -19,3 +19,4 @@ set(POST_INSTALL_OPTIONS_PATH "@POST_INSTALL_OPTIONS_PATH@") set(CLIENT_COMPONENT_NAME "@CLIENT_COMPONENT@") set(SERVER_COMPONENT_NAME "@SERVER_COMPONENT@") set(SIGNTOOL_EXECUTABLE "@SIGNTOOL_EXECUTABLE@") +set(UNINSTALLER_NAME "@GENERATED_UNINSTALLER_EXEC_NAME@") diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 39b3e28ecf..035cb1ebe0 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -6,7 +6,6 @@ !define VERSION "@CPACK_PACKAGE_VERSION@" !define PATCH "@CPACK_PACKAGE_VERSION_PATCH@" !define INST_DIR "@CPACK_TEMPORARY_DIRECTORY@" - !define UNINSTALLER_NAME "Uninstall.exe" ;-------------------------------- ;Variables @@ -68,7 +67,7 @@ ; The Inner invocation has written an uninstaller binary for us. ; We need to sign it if it's a production or PR build. !if @PRODUCTION_BUILD@ == 1 - !system '"@SIGNTOOL_EXECUTABLE@" sign /f %HF_PFX_FILE% /p %HF_PFX_PASSPHRASE% /tr http://tsa.starfieldtech.com /td SHA256 $%TEMP%\$UNINSTALLER_NAME' = 0 + !system '"@SIGNTOOL_EXECUTABLE@" sign /f %HF_PFX_FILE% /p %HF_PFX_PASSPHRASE% /tr http://tsa.starfieldtech.com /td SHA256 $%TEMP%\@UNINSTALLER_NAME@' = 0 !endif ; Good. Now we can carry on writing the real installer. @@ -690,7 +689,7 @@ Section "-Core installation" ;Package the signed uninstaller produced by the inner loop !ifndef INNER ; this packages the signed uninstaller - File $%TEMP%\$UNINSTALLER_NAME + File $%TEMP%\@UNINSTALLER_NAME@ !endif Push "DisplayName" @@ -703,7 +702,7 @@ Section "-Core installation" Push "@CPACK_PACKAGE_VENDOR@" Call ConditionalAddToRegisty Push "UninstallString" - Push "$INSTDIR\$UNINSTALLER_NAME" + Push "$INSTDIR\@UNINSTALLER_NAME@" Call ConditionalAddToRegisty Push "NoRepair" Push "1" @@ -762,7 +761,7 @@ Section "-Core installation" "$INSTDIR\@CONSOLE_WIN_EXEC_NAME@" ${EndIf} - CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" "$INSTDIR\$UNINSTALLER_NAME" + CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" "$INSTDIR\@UNINSTALLER_NAME@" ;Read a value from an InstallOptions INI file !insertmacro MUI_INSTALLOPTIONS_READ $DO_NOT_ADD_TO_PATH "NSIS.InstallOptions.ini" "Field 2" "State" @@ -938,8 +937,8 @@ Function un.onInit ; so we move it to the $TEMP dir and then execute the copied uninstaller. ${If} $EXEDIR != $TEMP - CopyFiles /SILENT $EXEPATH $TEMP\$UNINSTALLER_NAME - ExecWait '"$Temp\$UNINSTALLER_NAME" _?=$INSTDIR' $0 + CopyFiles /SILENT $EXEPATH $TEMP\@UNINSTALLER_NAME@ + ExecWait '"$Temp\@UNINSTALLER_NAME@" _?=$INSTDIR' $0 SetErrorLevel $0 Quit ${EndIf} @@ -1061,7 +1060,7 @@ Section "Uninstall" !endif ;Remove the uninstaller itself. - Delete "$INSTDIR\$UNINSTALLER_NAME" + Delete "$INSTDIR\@UNINSTALLER_NAME@" DeleteRegKey SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" ;Remove the installation directory if it is empty. @@ -1147,7 +1146,7 @@ Function .onInit ; the installer. This is better than processing a command line option as it means ; this entire code path is not present in the final (real) installer. - WriteUninstaller "$%TEMP%\$UNINSTALLER_NAME" + WriteUninstaller "$%TEMP%\@UNINSTALLER_NAME@" ; just bail out quickly when running the "inner" installer Quit From a47cf35b325f45ba0970ccaa3e651c70badd2ffb Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 13 Jan 2016 16:38:33 -0800 Subject: [PATCH 187/357] write post install option choices to registry --- cmake/macros/SetPackagingParameters.cmake | 5 +++++ cmake/templates/CPackProperties.cmake.in | 4 ++++ cmake/templates/NSIS.template.in | 10 ++++++++++ 3 files changed, 19 insertions(+) diff --git a/cmake/macros/SetPackagingParameters.cmake b/cmake/macros/SetPackagingParameters.cmake index 78ba8f1a71..3ed10bd860 100644 --- a/cmake/macros/SetPackagingParameters.cmake +++ b/cmake/macros/SetPackagingParameters.cmake @@ -71,6 +71,11 @@ macro(SET_PACKAGING_PARAMETERS) endif () set(GENERATED_UNINSTALLER_EXEC_NAME "Uninstall.exe") + set(POST_INSTALL_OPTIONS_REG_GROUP "PostInstallOptions") + set(CLIENT_DESKTOP_SHORTCUT_REG_KEY "ClientDesktopShortcut") + set(CONSOLE_DESKTOP_SHORTCUT_REG_KEY "ConsoleDesktopShortcut") + set(CONSOLE_STARTUP_REG_KEY "ConsoleStartupShortcut") + set(LAUNCH_NOW_REG_KEY "LaunchAfterInstall") endif () if (APPLE) diff --git a/cmake/templates/CPackProperties.cmake.in b/cmake/templates/CPackProperties.cmake.in index 0bfa179d5b..8baf223c72 100644 --- a/cmake/templates/CPackProperties.cmake.in +++ b/cmake/templates/CPackProperties.cmake.in @@ -20,3 +20,7 @@ set(CLIENT_COMPONENT_NAME "@CLIENT_COMPONENT@") set(SERVER_COMPONENT_NAME "@SERVER_COMPONENT@") set(SIGNTOOL_EXECUTABLE "@SIGNTOOL_EXECUTABLE@") set(UNINSTALLER_NAME "@GENERATED_UNINSTALLER_EXEC_NAME@") +set(CLIENT_DESKTOP_SHORTCUT_REG_KEY "@CLIENT_DESKTOP_SHORTCUT_REG_KEY@") +set(CONSOLE_DESKTOP_SHORTCUT_REG_KEY "@CONSOLE_DESKTOP_SHORTCUT_REG_KEY@") +set(CONSOLE_STARTUP_REG_KEY "@CONSOLE_STARTUP_SHORTCUT_REG_KEY@") +set(LAUNCH_NOW_REG_KEY "@LAUNCH_NOW_REG_KEY@") diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 035cb1ebe0..efd45b1500 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -893,6 +893,8 @@ Function HandlePostInstallOptions ${If} $DESKTOP_CLIENT_STATE == ${BST_CHECKED} CreateShortCut "$DESKTOP\@INTERFACE_SHORTCUT_NAME@.lnk" "$INSTDIR\@INTERFACE_WIN_EXEC_NAME@" + WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Install\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\@POST_INSTALL_OPTIONS_REG_GROUP@" \ + "@CLIENT_DESKTOP_SHORTCUT_REG_KEY@" 1 ${EndIf} ${EndIf} @@ -903,6 +905,8 @@ Function HandlePostInstallOptions ${If} $DESKTOP_SERVER_STATE == ${BST_CHECKED} CreateShortCut "$DESKTOP\@CONSOLE_SHORTCUT_NAME@.lnk" "$INSTDIR\@CONSOLE_WIN_EXEC_NAME@" + WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Install\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\@POST_INSTALL_OPTIONS_REG_GROUP@" \ + "@CONSOLE_DESKTOP_SHORTCUT_REG_KEY@" 1 ${EndIf} ; check if the user asked to have Server Console launched every startup @@ -910,6 +914,9 @@ Function HandlePostInstallOptions ${If} $SERVER_STARTUP_STATE == ${BST_CHECKED} CreateShortCut "$SMSTARTUP\@CONSOLE_SHORTCUT_NAME@.lnk" "$INSTDIR\@CONSOLE_WIN_EXEC_NAME@" + + WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Install\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\@POST_INSTALL_OPTIONS_REG_GROUP@" \ + "@CONSOLE_STARTUP_REG_KEY@" 1 ${EndIf} ${EndIf} @@ -917,6 +924,9 @@ Function HandlePostInstallOptions ${NSD_GetState} $LAUNCH_NOW_CHECKBOX $LAUNCH_NOW_STATE ${If} $LAUNCH_NOW_STATE == ${BST_CHECKED} + WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Install\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\@POST_INSTALL_OPTIONS_REG_GROUP@" \ + "@LAUNCH_NOW_REG_KEY@" 1 + ; both launches use the explorer trick in case the user has elevated permissions for the installer ; it won't be possible to use this approach if either application should be launched with a command line param ${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@} From a0647756b57da05d9abde69c078e457d9fda3652 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 13 Jan 2016 16:44:16 -0800 Subject: [PATCH 188/357] delete the post-install options info from registry on uninstall --- cmake/macros/SetPackagingParameters.cmake | 1 + cmake/templates/CPackProperties.cmake.in | 1 + cmake/templates/NSIS.template.in | 15 +++++++-------- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/cmake/macros/SetPackagingParameters.cmake b/cmake/macros/SetPackagingParameters.cmake index 3ed10bd860..8bf4e2971a 100644 --- a/cmake/macros/SetPackagingParameters.cmake +++ b/cmake/macros/SetPackagingParameters.cmake @@ -71,6 +71,7 @@ macro(SET_PACKAGING_PARAMETERS) endif () set(GENERATED_UNINSTALLER_EXEC_NAME "Uninstall.exe") + set(REGISTRY_HKLM_INSTALL_ROOT "Software\\Microsoft\\Windows\\CurrentVersion\\Install\\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@") set(POST_INSTALL_OPTIONS_REG_GROUP "PostInstallOptions") set(CLIENT_DESKTOP_SHORTCUT_REG_KEY "ClientDesktopShortcut") set(CONSOLE_DESKTOP_SHORTCUT_REG_KEY "ConsoleDesktopShortcut") diff --git a/cmake/templates/CPackProperties.cmake.in b/cmake/templates/CPackProperties.cmake.in index 8baf223c72..87092b83f5 100644 --- a/cmake/templates/CPackProperties.cmake.in +++ b/cmake/templates/CPackProperties.cmake.in @@ -24,3 +24,4 @@ set(CLIENT_DESKTOP_SHORTCUT_REG_KEY "@CLIENT_DESKTOP_SHORTCUT_REG_KEY@") set(CONSOLE_DESKTOP_SHORTCUT_REG_KEY "@CONSOLE_DESKTOP_SHORTCUT_REG_KEY@") set(CONSOLE_STARTUP_REG_KEY "@CONSOLE_STARTUP_SHORTCUT_REG_KEY@") set(LAUNCH_NOW_REG_KEY "@LAUNCH_NOW_REG_KEY@") +set(REGISTRY_HKLM_INSTALL_ROOT "@REGISTRY_HKLM_INSTALL_ROOT@") diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index efd45b1500..86f701d867 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -893,8 +893,7 @@ Function HandlePostInstallOptions ${If} $DESKTOP_CLIENT_STATE == ${BST_CHECKED} CreateShortCut "$DESKTOP\@INTERFACE_SHORTCUT_NAME@.lnk" "$INSTDIR\@INTERFACE_WIN_EXEC_NAME@" - WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Install\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\@POST_INSTALL_OPTIONS_REG_GROUP@" \ - "@CLIENT_DESKTOP_SHORTCUT_REG_KEY@" 1 + WriteRegDWORD HKLM "@REGISTRY_HKLM_INSTALL_ROOT@\@POST_INSTALL_OPTIONS_REG_GROUP@" "@CLIENT_DESKTOP_SHORTCUT_REG_KEY@" 1 ${EndIf} ${EndIf} @@ -905,8 +904,7 @@ Function HandlePostInstallOptions ${If} $DESKTOP_SERVER_STATE == ${BST_CHECKED} CreateShortCut "$DESKTOP\@CONSOLE_SHORTCUT_NAME@.lnk" "$INSTDIR\@CONSOLE_WIN_EXEC_NAME@" - WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Install\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\@POST_INSTALL_OPTIONS_REG_GROUP@" \ - "@CONSOLE_DESKTOP_SHORTCUT_REG_KEY@" 1 + WriteRegDWORD HKLM "@REGISTRY_HKLM_INSTALL_ROOT@" "@CONSOLE_DESKTOP_SHORTCUT_REG_KEY@" 1 ${EndIf} ; check if the user asked to have Server Console launched every startup @@ -915,8 +913,7 @@ Function HandlePostInstallOptions ${If} $SERVER_STARTUP_STATE == ${BST_CHECKED} CreateShortCut "$SMSTARTUP\@CONSOLE_SHORTCUT_NAME@.lnk" "$INSTDIR\@CONSOLE_WIN_EXEC_NAME@" - WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Install\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\@POST_INSTALL_OPTIONS_REG_GROUP@" \ - "@CONSOLE_STARTUP_REG_KEY@" 1 + WriteRegDWORD HKLM "@REGISTRY_HKLM_INSTALL_ROOT@\@POST_INSTALL_OPTIONS_REG_GROUP@" "@CONSOLE_STARTUP_REG_KEY@" 1 ${EndIf} ${EndIf} @@ -924,8 +921,7 @@ Function HandlePostInstallOptions ${NSD_GetState} $LAUNCH_NOW_CHECKBOX $LAUNCH_NOW_STATE ${If} $LAUNCH_NOW_STATE == ${BST_CHECKED} - WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Install\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\@POST_INSTALL_OPTIONS_REG_GROUP@" \ - "@LAUNCH_NOW_REG_KEY@" 1 + WriteRegDWORD HKLM "@REGISTRY_HKLM_INSTALL_ROOT@\@POST_INSTALL_OPTIONS_REG_GROUP@" "@LAUNCH_NOW_REG_KEY@" 1 ; both launches use the explorer trick in case the user has elevated permissions for the installer ; it won't be possible to use this approach if either application should be launched with a command line param @@ -1098,6 +1094,9 @@ Section "Uninstall" DeleteRegKey HKCR '@HIGH_FIDELITY_PROTOCOL@' ${EndIf} + ;Delete post-install option information from registry + DeleteRegKey HKLM '@REGISTRY_HKLM_INSTALL_ROOT@' + ;Delete empty start menu parent diretories StrCpy $MUI_TEMP "$SMPROGRAMS\$MUI_TEMP" From 8e3f18b6280cf9c1d82aafd3f0f1a19ad0f3f1cf Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 13 Jan 2016 16:49:39 -0800 Subject: [PATCH 189/357] require append of @CPACK_PACKAGE_INSTALL_REGISTRY_KEY@ to root --- cmake/macros/SetPackagingParameters.cmake | 2 +- cmake/templates/NSIS.template.in | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cmake/macros/SetPackagingParameters.cmake b/cmake/macros/SetPackagingParameters.cmake index 8bf4e2971a..321f855ec7 100644 --- a/cmake/macros/SetPackagingParameters.cmake +++ b/cmake/macros/SetPackagingParameters.cmake @@ -71,7 +71,7 @@ macro(SET_PACKAGING_PARAMETERS) endif () set(GENERATED_UNINSTALLER_EXEC_NAME "Uninstall.exe") - set(REGISTRY_HKLM_INSTALL_ROOT "Software\\Microsoft\\Windows\\CurrentVersion\\Install\\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@") + set(REGISTRY_HKLM_INSTALL_ROOT "Software\\Microsoft\\Windows\\CurrentVersion\\Install") set(POST_INSTALL_OPTIONS_REG_GROUP "PostInstallOptions") set(CLIENT_DESKTOP_SHORTCUT_REG_KEY "ClientDesktopShortcut") set(CONSOLE_DESKTOP_SHORTCUT_REG_KEY "ConsoleDesktopShortcut") diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 86f701d867..4c2acaf14c 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -893,7 +893,7 @@ Function HandlePostInstallOptions ${If} $DESKTOP_CLIENT_STATE == ${BST_CHECKED} CreateShortCut "$DESKTOP\@INTERFACE_SHORTCUT_NAME@.lnk" "$INSTDIR\@INTERFACE_WIN_EXEC_NAME@" - WriteRegDWORD HKLM "@REGISTRY_HKLM_INSTALL_ROOT@\@POST_INSTALL_OPTIONS_REG_GROUP@" "@CLIENT_DESKTOP_SHORTCUT_REG_KEY@" 1 + WriteRegDWORD HKLM "@REGISTRY_HKLM_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\@POST_INSTALL_OPTIONS_REG_GROUP@" "@CLIENT_DESKTOP_SHORTCUT_REG_KEY@" 1 ${EndIf} ${EndIf} @@ -904,7 +904,7 @@ Function HandlePostInstallOptions ${If} $DESKTOP_SERVER_STATE == ${BST_CHECKED} CreateShortCut "$DESKTOP\@CONSOLE_SHORTCUT_NAME@.lnk" "$INSTDIR\@CONSOLE_WIN_EXEC_NAME@" - WriteRegDWORD HKLM "@REGISTRY_HKLM_INSTALL_ROOT@" "@CONSOLE_DESKTOP_SHORTCUT_REG_KEY@" 1 + WriteRegDWORD HKLM "@REGISTRY_HKLM_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\@POST_INSTALL_OPTIONS_REG_GROUP@" "@CONSOLE_DESKTOP_SHORTCUT_REG_KEY@" 1 ${EndIf} ; check if the user asked to have Server Console launched every startup @@ -913,7 +913,7 @@ Function HandlePostInstallOptions ${If} $SERVER_STARTUP_STATE == ${BST_CHECKED} CreateShortCut "$SMSTARTUP\@CONSOLE_SHORTCUT_NAME@.lnk" "$INSTDIR\@CONSOLE_WIN_EXEC_NAME@" - WriteRegDWORD HKLM "@REGISTRY_HKLM_INSTALL_ROOT@\@POST_INSTALL_OPTIONS_REG_GROUP@" "@CONSOLE_STARTUP_REG_KEY@" 1 + WriteRegDWORD HKLM "@REGISTRY_HKLM_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\@POST_INSTALL_OPTIONS_REG_GROUP@" "@CONSOLE_STARTUP_REG_KEY@" 1 ${EndIf} ${EndIf} @@ -921,7 +921,7 @@ Function HandlePostInstallOptions ${NSD_GetState} $LAUNCH_NOW_CHECKBOX $LAUNCH_NOW_STATE ${If} $LAUNCH_NOW_STATE == ${BST_CHECKED} - WriteRegDWORD HKLM "@REGISTRY_HKLM_INSTALL_ROOT@\@POST_INSTALL_OPTIONS_REG_GROUP@" "@LAUNCH_NOW_REG_KEY@" 1 + WriteRegDWORD HKLM "@REGISTRY_HKLM_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\@POST_INSTALL_OPTIONS_REG_GROUP@" "@LAUNCH_NOW_REG_KEY@" 1 ; both launches use the explorer trick in case the user has elevated permissions for the installer ; it won't be possible to use this approach if either application should be launched with a command line param @@ -1095,7 +1095,7 @@ Section "Uninstall" ${EndIf} ;Delete post-install option information from registry - DeleteRegKey HKLM '@REGISTRY_HKLM_INSTALL_ROOT@' + DeleteRegKey HKLM '@REGISTRY_HKLM_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@' ;Delete empty start menu parent diretories StrCpy $MUI_TEMP "$SMPROGRAMS\$MUI_TEMP" From a1a92cf3a9ed96564de90329c7b16a7314f0f3cf Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 13 Jan 2016 16:59:15 -0800 Subject: [PATCH 190/357] change registry location for post install options --- cmake/macros/SetPackagingParameters.cmake | 2 +- cmake/templates/CPackProperties.cmake.in | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/cmake/macros/SetPackagingParameters.cmake b/cmake/macros/SetPackagingParameters.cmake index 321f855ec7..21075fa0b8 100644 --- a/cmake/macros/SetPackagingParameters.cmake +++ b/cmake/macros/SetPackagingParameters.cmake @@ -71,7 +71,7 @@ macro(SET_PACKAGING_PARAMETERS) endif () set(GENERATED_UNINSTALLER_EXEC_NAME "Uninstall.exe") - set(REGISTRY_HKLM_INSTALL_ROOT "Software\\Microsoft\\Windows\\CurrentVersion\\Install") + set(REGISTRY_HKLM_INSTALL_ROOT "Software") set(POST_INSTALL_OPTIONS_REG_GROUP "PostInstallOptions") set(CLIENT_DESKTOP_SHORTCUT_REG_KEY "ClientDesktopShortcut") set(CONSOLE_DESKTOP_SHORTCUT_REG_KEY "ConsoleDesktopShortcut") diff --git a/cmake/templates/CPackProperties.cmake.in b/cmake/templates/CPackProperties.cmake.in index 87092b83f5..c4d06c64a4 100644 --- a/cmake/templates/CPackProperties.cmake.in +++ b/cmake/templates/CPackProperties.cmake.in @@ -20,8 +20,9 @@ set(CLIENT_COMPONENT_NAME "@CLIENT_COMPONENT@") set(SERVER_COMPONENT_NAME "@SERVER_COMPONENT@") set(SIGNTOOL_EXECUTABLE "@SIGNTOOL_EXECUTABLE@") set(UNINSTALLER_NAME "@GENERATED_UNINSTALLER_EXEC_NAME@") +set(REGISTRY_HKLM_INSTALL_ROOT "@REGISTRY_HKLM_INSTALL_ROOT@") +set(POST_INSTALL_OPTIONS_REG_GROUP "@POST_INSTALL_OPTIONS_REG_GROUP@") set(CLIENT_DESKTOP_SHORTCUT_REG_KEY "@CLIENT_DESKTOP_SHORTCUT_REG_KEY@") set(CONSOLE_DESKTOP_SHORTCUT_REG_KEY "@CONSOLE_DESKTOP_SHORTCUT_REG_KEY@") set(CONSOLE_STARTUP_REG_KEY "@CONSOLE_STARTUP_SHORTCUT_REG_KEY@") set(LAUNCH_NOW_REG_KEY "@LAUNCH_NOW_REG_KEY@") -set(REGISTRY_HKLM_INSTALL_ROOT "@REGISTRY_HKLM_INSTALL_ROOT@") From 3c3ef094bb9df21d20988d3f2c90972f110fd4e3 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 13 Jan 2016 17:21:17 -0800 Subject: [PATCH 191/357] use macro to write post install options --- cmake/templates/CPackProperties.cmake.in | 2 +- cmake/templates/NSIS.template.in | 24 ++++++++++++++++++++---- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/cmake/templates/CPackProperties.cmake.in b/cmake/templates/CPackProperties.cmake.in index c4d06c64a4..6614ba72f1 100644 --- a/cmake/templates/CPackProperties.cmake.in +++ b/cmake/templates/CPackProperties.cmake.in @@ -24,5 +24,5 @@ set(REGISTRY_HKLM_INSTALL_ROOT "@REGISTRY_HKLM_INSTALL_ROOT@") set(POST_INSTALL_OPTIONS_REG_GROUP "@POST_INSTALL_OPTIONS_REG_GROUP@") set(CLIENT_DESKTOP_SHORTCUT_REG_KEY "@CLIENT_DESKTOP_SHORTCUT_REG_KEY@") set(CONSOLE_DESKTOP_SHORTCUT_REG_KEY "@CONSOLE_DESKTOP_SHORTCUT_REG_KEY@") -set(CONSOLE_STARTUP_REG_KEY "@CONSOLE_STARTUP_SHORTCUT_REG_KEY@") +set(CONSOLE_STARTUP_REG_KEY "@CONSOLE_STARTUP_REG_KEY@") set(LAUNCH_NOW_REG_KEY "@LAUNCH_NOW_REG_KEY@") diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 4c2acaf14c..0bd2bfe717 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -850,6 +850,9 @@ Function PostInstallOptionsPage ${NSD_CreateCheckbox} 0 15u 100% 10u "&Create a desktop shortcut for @INTERFACE_SHORTCUT_NAME@" Pop $DESKTOP_CLIENT_CHECKBOX StrCpy $CURRENT_OFFSET "30u" + + ; check if we have a chosen option for this in the registry already + ${NSD_SetState} $DESKTOP_CLIENT_CHECKBOX ${BST_CHECKED} ${EndIf} @@ -881,6 +884,11 @@ Function PostInstallOptionsPage nsDialogs::Show FunctionEnd +!macro WritePostInstallOption OptionName Option + ; writes the value for the given post install option to the registry + WriteRegDWORD HKLM "@REGISTRY_HKLM_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\@POST_INSTALL_OPTIONS_REG_GROUP@" "${OptionName}" ${Option} +!macroend + Var DESKTOP_CLIENT_STATE Var DESKTOP_SERVER_STATE Var SERVER_STARTUP_STATE @@ -893,7 +901,9 @@ Function HandlePostInstallOptions ${If} $DESKTOP_CLIENT_STATE == ${BST_CHECKED} CreateShortCut "$DESKTOP\@INTERFACE_SHORTCUT_NAME@.lnk" "$INSTDIR\@INTERFACE_WIN_EXEC_NAME@" - WriteRegDWORD HKLM "@REGISTRY_HKLM_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\@POST_INSTALL_OPTIONS_REG_GROUP@" "@CLIENT_DESKTOP_SHORTCUT_REG_KEY@" 1 + !insertmacro WritePostInstallOption "@CLIENT_DESKTOP_SHORTCUT_REG_KEY@" 1 + ${Else} + !insertmacro WritePostInstallOption @CLIENT_DESKTOP_SHORTCUT_REG_KEY@ 0 ${EndIf} ${EndIf} @@ -904,7 +914,9 @@ Function HandlePostInstallOptions ${If} $DESKTOP_SERVER_STATE == ${BST_CHECKED} CreateShortCut "$DESKTOP\@CONSOLE_SHORTCUT_NAME@.lnk" "$INSTDIR\@CONSOLE_WIN_EXEC_NAME@" - WriteRegDWORD HKLM "@REGISTRY_HKLM_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\@POST_INSTALL_OPTIONS_REG_GROUP@" "@CONSOLE_DESKTOP_SHORTCUT_REG_KEY@" 1 + !insertmacro WritePostInstallOption @CONSOLE_DESKTOP_SHORTCUT_REG_KEY@ 1 + ${Else} + !insertmacro WritePostInstallOption @CONSOLE_DESKTOP_SHORTCUT_REG_KEY@ 0 ${EndIf} ; check if the user asked to have Server Console launched every startup @@ -913,7 +925,9 @@ Function HandlePostInstallOptions ${If} $SERVER_STARTUP_STATE == ${BST_CHECKED} CreateShortCut "$SMSTARTUP\@CONSOLE_SHORTCUT_NAME@.lnk" "$INSTDIR\@CONSOLE_WIN_EXEC_NAME@" - WriteRegDWORD HKLM "@REGISTRY_HKLM_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\@POST_INSTALL_OPTIONS_REG_GROUP@" "@CONSOLE_STARTUP_REG_KEY@" 1 + !insertmacro WritePostInstallOption @CONSOLE_STARTUP_REG_KEY@ 1 + ${Else} + !insertmacro WritePostInstallOption @CONSOLE_STARTUP_REG_KEY@ 0 ${EndIf} ${EndIf} @@ -921,7 +935,7 @@ Function HandlePostInstallOptions ${NSD_GetState} $LAUNCH_NOW_CHECKBOX $LAUNCH_NOW_STATE ${If} $LAUNCH_NOW_STATE == ${BST_CHECKED} - WriteRegDWORD HKLM "@REGISTRY_HKLM_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\@POST_INSTALL_OPTIONS_REG_GROUP@" "@LAUNCH_NOW_REG_KEY@" 1 + !insertmacro WritePostInstallOption @LAUNCH_NOW_REG_KEY@ 1 ; both launches use the explorer trick in case the user has elevated permissions for the installer ; it won't be possible to use this approach if either application should be launched with a command line param @@ -930,6 +944,8 @@ Function HandlePostInstallOptions ${Else} Exec '"$WINDIR\explorer.exe" "$INSTDIR\@INTERFACE_WIN_EXEC_NAME@"' ${EndIf} + ${Else} + !insertmacro WritePostInstallOption @LAUNCH_NOW_REG_KEY@ 0 ${EndIf} FunctionEnd From 7a6c37aa2f5b76946a04a1bd21b1a9f8d720f414 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 13 Jan 2016 18:00:11 -0800 Subject: [PATCH 192/357] read checkbox states from registry --- cmake/templates/NSIS.template.in | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 0bd2bfe717..44f36c00e6 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -818,6 +818,23 @@ Var SERVER_STARTUP_CHECKBOX Var LAUNCH_NOW_CHECKBOX Var CURRENT_OFFSET +!macro SetPostInstallOption Checkbox OptionName Default + ; reads the value for the given post install option to the registry + ReadRegDWORD $0 HKLM "@REGISTRY_HKLM_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\@POST_INSTALL_OPTIONS_REG_GROUP@" "${OptionName}" + + ${If} $0 == "0" + ; the value in the registry says it should not be checked + ${NSD_SetState} ${Checkbox} ${BST_UNCHECKED} + ${ElseIf} $0 == "1" + ; the value in the registry says it should be checked + ${NSD_SetState} ${Checkbox} ${BST_CHECKED} + ${Else} + ; there was no value in the registry or it's not in the expected format, use default + ${NSD_SetState} ${Checkbox} Default + ${EndIf} + +!macroend + Function PostInstallOptionsPage ; Set the text on the dialog button to match finish, hide the back and cancel buttons GetDlgItem $R1 $hwndparent 1 @@ -851,15 +868,18 @@ Function PostInstallOptionsPage Pop $DESKTOP_CLIENT_CHECKBOX StrCpy $CURRENT_OFFSET "30u" - ; check if we have a chosen option for this in the registry already + ; set the checkbox state depending on what is present in the registry + !insertmacro SetPostInstallOption $DESKTOP_CLIENT_CHECKBOX @CLIENT_DESKTOP_SHORTCUT_REG_KEY@ ${BST_CHECKED} - ${NSD_SetState} $DESKTOP_CLIENT_CHECKBOX ${BST_CHECKED} ${EndIf} ${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@} ${NSD_CreateCheckbox} 0 $CURRENT_OFFSET 100% 10u "&Create a desktop shortcut for High Fidelity @CONSOLE_SHORTCUT_NAME@" Pop $DESKTOP_SERVER_CHECKBOX + ; set the checkbox state depending on what is present in the registry + !insertmacro SetPostInstallOption $DESKTOP_SERVER_CHECKBOX @CONSOLE_DESKTOP_SHORTCUT_REG_KEY@ ${BST_UNCHECKED} + ${If} $CURRENT_OFFSET == "15u" StrCpy $CURRENT_OFFSET "30u" ${Else} @@ -868,7 +888,9 @@ Function PostInstallOptionsPage ${NSD_CreateCheckbox} 0 $CURRENT_OFFSET 100% 10u "&Launch High Fidelity @CONSOLE_SHORTCUT_NAME@ on startup" Pop $SERVER_STARTUP_CHECKBOX - ${NSD_SetState} $SERVER_STARTUP_CHECKBOX ${BST_CHECKED} + + ; set the checkbox state depending on what is present in the registry + !insertmacro SetPostInstallOption $SERVER_STARTUP_CHECKBOX @CONSOLE_STARTUP_REG_KEY@ ${BST_CHECKED} ${If} $CURRENT_OFFSET == "30u" StrCpy $CURRENT_OFFSET "45u" @@ -879,7 +901,9 @@ Function PostInstallOptionsPage ${NSD_CreateCheckbox} 0 $CURRENT_OFFSET 100% 10u "&Launch High Fidelity Now" Pop $LAUNCH_NOW_CHECKBOX - ${NSD_SetState} $LAUNCH_NOW_CHECKBOX ${BST_CHECKED} + + ; set the checkbox state depending on what is present in the registry + !insertmacro SetPostInstallOption $LAUNCH_NOW_CHECKBOX @LAUNCH_NOW_REG_KEY@ ${BST_CHECKED} nsDialogs::Show FunctionEnd From fef0c31fadfce517bd7832281e5221fff90701cb Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 13 Jan 2016 18:14:12 -0800 Subject: [PATCH 193/357] fix handling of not-present post install options --- cmake/templates/NSIS.template.in | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 44f36c00e6..28bfb801e5 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -819,9 +819,15 @@ Var LAUNCH_NOW_CHECKBOX Var CURRENT_OFFSET !macro SetPostInstallOption Checkbox OptionName Default + ; clear errors so we can detect if registry value is not present + ClearErrors + ; reads the value for the given post install option to the registry ReadRegDWORD $0 HKLM "@REGISTRY_HKLM_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\@POST_INSTALL_OPTIONS_REG_GROUP@" "${OptionName}" + ; jump to UseDefault if no value found in the registry + IfErrors UseDefault 0 + ${If} $0 == "0" ; the value in the registry says it should not be checked ${NSD_SetState} ${Checkbox} ${BST_UNCHECKED} @@ -829,10 +835,17 @@ Var CURRENT_OFFSET ; the value in the registry says it should be checked ${NSD_SetState} ${Checkbox} ${BST_CHECKED} ${Else} - ; there was no value in the registry or it's not in the expected format, use default + ; the value in the registry was not in the expected format, use default ${NSD_SetState} ${Checkbox} Default ${EndIf} + Goto End + + UseDefault: + ; there was no value in the registry, use default + ${NSD_SetState} ${Checkbox} Default + + End: !macroend Function PostInstallOptionsPage From 69ceb9fa98768b33aeaf6696a7ea39ee3c9a4624 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 13 Jan 2016 18:23:56 -0800 Subject: [PATCH 194/357] use string comparison for cleaner registry checking --- cmake/templates/NSIS.template.in | 40 +++++++++++--------------------- 1 file changed, 13 insertions(+), 27 deletions(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 28bfb801e5..49570052f5 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -819,33 +819,19 @@ Var LAUNCH_NOW_CHECKBOX Var CURRENT_OFFSET !macro SetPostInstallOption Checkbox OptionName Default - ; clear errors so we can detect if registry value is not present - ClearErrors - ; reads the value for the given post install option to the registry - ReadRegDWORD $0 HKLM "@REGISTRY_HKLM_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\@POST_INSTALL_OPTIONS_REG_GROUP@" "${OptionName}" + ReadRegStr $0 HKLM "@REGISTRY_HKLM_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\@POST_INSTALL_OPTIONS_REG_GROUP@" "${OptionName}" - ; jump to UseDefault if no value found in the registry - IfErrors UseDefault 0 - - ${If} $0 == "0" + ${If} $0 == "NO" ; the value in the registry says it should not be checked ${NSD_SetState} ${Checkbox} ${BST_UNCHECKED} - ${ElseIf} $0 == "1" + ${ElseIf} $0 == "YES" ; the value in the registry says it should be checked ${NSD_SetState} ${Checkbox} ${BST_CHECKED} ${Else} ; the value in the registry was not in the expected format, use default - ${NSD_SetState} ${Checkbox} Default + ${NSD_SetState} ${Checkbox} ${Default} ${EndIf} - - Goto End - - UseDefault: - ; there was no value in the registry, use default - ${NSD_SetState} ${Checkbox} Default - - End: !macroend Function PostInstallOptionsPage @@ -923,7 +909,7 @@ FunctionEnd !macro WritePostInstallOption OptionName Option ; writes the value for the given post install option to the registry - WriteRegDWORD HKLM "@REGISTRY_HKLM_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\@POST_INSTALL_OPTIONS_REG_GROUP@" "${OptionName}" ${Option} + WriteRegStr HKLM "@REGISTRY_HKLM_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\@POST_INSTALL_OPTIONS_REG_GROUP@" "${OptionName}" ${Option} !macroend Var DESKTOP_CLIENT_STATE @@ -938,9 +924,9 @@ Function HandlePostInstallOptions ${If} $DESKTOP_CLIENT_STATE == ${BST_CHECKED} CreateShortCut "$DESKTOP\@INTERFACE_SHORTCUT_NAME@.lnk" "$INSTDIR\@INTERFACE_WIN_EXEC_NAME@" - !insertmacro WritePostInstallOption "@CLIENT_DESKTOP_SHORTCUT_REG_KEY@" 1 + !insertmacro WritePostInstallOption "@CLIENT_DESKTOP_SHORTCUT_REG_KEY@" YES ${Else} - !insertmacro WritePostInstallOption @CLIENT_DESKTOP_SHORTCUT_REG_KEY@ 0 + !insertmacro WritePostInstallOption @CLIENT_DESKTOP_SHORTCUT_REG_KEY@ NO ${EndIf} ${EndIf} @@ -951,9 +937,9 @@ Function HandlePostInstallOptions ${If} $DESKTOP_SERVER_STATE == ${BST_CHECKED} CreateShortCut "$DESKTOP\@CONSOLE_SHORTCUT_NAME@.lnk" "$INSTDIR\@CONSOLE_WIN_EXEC_NAME@" - !insertmacro WritePostInstallOption @CONSOLE_DESKTOP_SHORTCUT_REG_KEY@ 1 + !insertmacro WritePostInstallOption @CONSOLE_DESKTOP_SHORTCUT_REG_KEY@ YES ${Else} - !insertmacro WritePostInstallOption @CONSOLE_DESKTOP_SHORTCUT_REG_KEY@ 0 + !insertmacro WritePostInstallOption @CONSOLE_DESKTOP_SHORTCUT_REG_KEY@ NO ${EndIf} ; check if the user asked to have Server Console launched every startup @@ -962,9 +948,9 @@ Function HandlePostInstallOptions ${If} $SERVER_STARTUP_STATE == ${BST_CHECKED} CreateShortCut "$SMSTARTUP\@CONSOLE_SHORTCUT_NAME@.lnk" "$INSTDIR\@CONSOLE_WIN_EXEC_NAME@" - !insertmacro WritePostInstallOption @CONSOLE_STARTUP_REG_KEY@ 1 + !insertmacro WritePostInstallOption @CONSOLE_STARTUP_REG_KEY@ YES ${Else} - !insertmacro WritePostInstallOption @CONSOLE_STARTUP_REG_KEY@ 0 + !insertmacro WritePostInstallOption @CONSOLE_STARTUP_REG_KEY@ NO ${EndIf} ${EndIf} @@ -972,7 +958,7 @@ Function HandlePostInstallOptions ${NSD_GetState} $LAUNCH_NOW_CHECKBOX $LAUNCH_NOW_STATE ${If} $LAUNCH_NOW_STATE == ${BST_CHECKED} - !insertmacro WritePostInstallOption @LAUNCH_NOW_REG_KEY@ 1 + !insertmacro WritePostInstallOption @LAUNCH_NOW_REG_KEY@ YES ; both launches use the explorer trick in case the user has elevated permissions for the installer ; it won't be possible to use this approach if either application should be launched with a command line param @@ -982,7 +968,7 @@ Function HandlePostInstallOptions Exec '"$WINDIR\explorer.exe" "$INSTDIR\@INTERFACE_WIN_EXEC_NAME@"' ${EndIf} ${Else} - !insertmacro WritePostInstallOption @LAUNCH_NOW_REG_KEY@ 0 + !insertmacro WritePostInstallOption @LAUNCH_NOW_REG_KEY@ NO ${EndIf} FunctionEnd From e9ce0318a24a6254eb2b74b8f7fbba7fccd7ae51 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 13 Jan 2016 18:44:42 -0800 Subject: [PATCH 195/357] add the custom installer license --- cmake/installer/InstallerLicense.txt | 12 ++++++++++++ cmake/macros/GenerateInstallers.cmake | 2 ++ 2 files changed, 14 insertions(+) create mode 100644 cmake/installer/InstallerLicense.txt diff --git a/cmake/installer/InstallerLicense.txt b/cmake/installer/InstallerLicense.txt new file mode 100644 index 0000000000..9f69dbd942 --- /dev/null +++ b/cmake/installer/InstallerLicense.txt @@ -0,0 +1,12 @@ +Copyright (c) 2013-2016, High Fidelity, Inc. +All rights reserved. +licensing@highfidelity.io + +Licensed under the Apache License version 2.0 (the "License"); +You may not use this software except in compliance with the License. +You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0 + +This software includes third-party software. +Please see each individual software license for additional details. + +THIS SOFTWARE IS DISTRIBUTED "AS-IS" WITHOUT ANY WARRANTIES, CONDITIONS AND REPRESENTATIONS WHETHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES AND CONDITIONS OF MERCHANTABILITY, MERCHANTABLE QUALITY, FITNESS FOR A PARTICULAR PURPOSE, PERFORMANCE, DURABILITY, TITLE, NON-INFRINGEMENT, AND THOSE ARISING BY STATUTE OR FROM CUSTOM OR USAGE OF TRADE OR COURSE OF DEALING. diff --git a/cmake/macros/GenerateInstallers.cmake b/cmake/macros/GenerateInstallers.cmake index 360ab2c27b..73f132609f 100644 --- a/cmake/macros/GenerateInstallers.cmake +++ b/cmake/macros/GenerateInstallers.cmake @@ -22,6 +22,8 @@ macro(GENERATE_INSTALLERS) set(CPACK_NSIS_PACKAGE_NAME ${_DISPLAY_NAME}) set(CPACK_PACKAGE_INSTALL_DIRECTORY ${_DISPLAY_NAME}) + set(CPACK_RESOURCE_FILE_LICENSE "${HF_CMAKE_DIR}/installer/InstallerLicense.txt") + # configure a cpack properties file for custom variables in NSIS template set(CPACK_CONFIGURED_PROP_FILE "${CMAKE_CURRENT_BINARY_DIR}/CPackCustomProperties.cmake") configure_file("${HF_CMAKE_DIR}/templates/CPackProperties.cmake.in" ${CPACK_CONFIGURED_PROP_FILE}) From 0b118a8e980e75e876d807bb14e3f425496b09fd Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 14 Jan 2016 10:13:43 -0800 Subject: [PATCH 196/357] replace ApplicationVersion with BuildInfo --- assignment-client/src/AssignmentClientApp.cpp | 6 +++--- cmake/macros/SetPackagingParameters.cmake | 11 ++++------- .../BuildInfo.h.in} | 9 ++++++--- domain-server/src/DomainServer.cpp | 6 +++--- interface/src/Application.cpp | 4 ++-- libraries/networking/src/Assignment.cpp | 4 ++-- 6 files changed, 20 insertions(+), 20 deletions(-) rename cmake/{macros/ApplicationVersion.h.in => templates/BuildInfo.h.in} (52%) diff --git a/assignment-client/src/AssignmentClientApp.cpp b/assignment-client/src/AssignmentClientApp.cpp index 19a3350d0d..8b9b5360c9 100644 --- a/assignment-client/src/AssignmentClientApp.cpp +++ b/assignment-client/src/AssignmentClientApp.cpp @@ -12,7 +12,7 @@ #include #include -#include +#include #include #include #include @@ -44,10 +44,10 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : ShutdownEventListener::getInstance(); # endif - setOrganizationName("High Fidelity"); + setOrganizationName(BuildInfo::MODIFIED_ORGANIZATION); setOrganizationDomain("highfidelity.io"); setApplicationName("assignment-client"); - setApplicationName(BUILD_VERSION); + setApplicationName(BuildInfo::VERSION); // use the verbose message handler in Logging qInstallMessageHandler(LogHandler::verboseMessageHandler); diff --git a/cmake/macros/SetPackagingParameters.cmake b/cmake/macros/SetPackagingParameters.cmake index 21075fa0b8..772dc2fc7c 100644 --- a/cmake/macros/SetPackagingParameters.cmake +++ b/cmake/macros/SetPackagingParameters.cmake @@ -20,8 +20,7 @@ macro(SET_PACKAGING_PARAMETERS) set(DEPLOY_PACKAGE TRUE) set(BUILD_SEQ $ENV{JOB_ID}) set(PRODUCTION_BUILD 1) - set(INSTALLER_COMPANY "High Fidelity") - set(INSTALLER_DIRECTORY "${INSTALLER_COMPANY}") + set(BUILD_ORGANIZATION "High Fidelity") set(INSTALLER_NAME "interface-win64-${BUILD_SEQ}.exe") set(HIGH_FIDELITY_PROTOCOL "hifi") set(INTERFACE_BUNDLE_NAME "High Fidelity") @@ -31,8 +30,7 @@ macro(SET_PACKAGING_PARAMETERS) set(DEPLOY_PACKAGE TRUE) set(PR_BUILD 1) set(BUILD_SEQ "PR-$ENV{ghprbPullId}") - set(INSTALLER_COMPANY "High Fidelity - PR") - set(INSTALLER_DIRECTORY "${INSTALLER_COMPANY}\\${BUILD_SEQ}") + set(BUILD_ORGANIZATION "High Fidelity - PR#$ENV{ghprbPullId}") set(INSTALLER_NAME "pr-interface-win64-${BUILD_SEQ}.exe") set(INTERFACE_BUNDLE_NAME "High Fidelity ${BUILD_SEQ}") set(INTERFACE_ICON_PREFIX "interface-beta") @@ -40,8 +38,7 @@ macro(SET_PACKAGING_PARAMETERS) else () set(BUILD_SEQ "dev") set(DEV_BUILD 1) - set(INSTALLER_COMPANY "High Fidelity - Dev") - set(INSTALLER_DIRECTORY "${INSTALLER_COMPANY}") + set(BUILD_ORGANIZATION "High Fidelity - Dev") set(INSTALLER_NAME "dev-interface-win64.exe") set(INTERFACE_BUNDLE_NAME "Interface") set(INTERFACE_ICON_PREFIX "interface-beta") @@ -95,6 +92,6 @@ macro(SET_PACKAGING_PARAMETERS) # create a header file our targets can use to find out the application version file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/includes") - configure_file("${MACRO_DIR}/ApplicationVersion.h.in" "${CMAKE_BINARY_DIR}/includes/ApplicationVersion.h") + configure_file("${HF_CMAKE_DIR}/templates/BuildInfo.h.in" "${CMAKE_BINARY_DIR}/includes/BuildInfo.h") endmacro(SET_PACKAGING_PARAMETERS) diff --git a/cmake/macros/ApplicationVersion.h.in b/cmake/templates/BuildInfo.h.in similarity index 52% rename from cmake/macros/ApplicationVersion.h.in rename to cmake/templates/BuildInfo.h.in index 736d00726c..a531317354 100644 --- a/cmake/macros/ApplicationVersion.h.in +++ b/cmake/templates/BuildInfo.h.in @@ -1,12 +1,15 @@ // -// ApplicationVersion.h.in +// BuildInfo.h.in // cmake/macros // -// Created by Leonardo Murillo on 8/13/15. +// Created by Stephen Birarda on 1/14/16. // Copyright 2015 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -const QString BUILD_VERSION = "@BUILD_SEQ@"; +namespace BuildInfo { + const QString MODIFIED_ORGANIZATION = "@BUILD_ORGANIZATION@"; + const QString VERSION = "@BUILD_SEQ@"; +} diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 28e9fd696d..70dd55f9c9 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -24,7 +24,7 @@ #include #include -#include +#include #include #include #include @@ -72,10 +72,10 @@ DomainServer::DomainServer(int argc, char* argv[]) : connect(this, &QCoreApplication::aboutToQuit, this, &DomainServer::aboutToQuit); - setOrganizationName("High Fidelity"); + setOrganizationName(BuildInfo::MODIFIED_ORGANIZATION); setOrganizationDomain("highfidelity.io"); setApplicationName("domain-server"); - setApplicationVersion(BUILD_VERSION); + setApplicationVersion(BuildInfo::VERSION); QSettings::setDefaultFormat(QSettings::IniFormat); // make sure we have a fresh AccountManager instance diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 46b4d4172d..d65c72c9f4 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -60,7 +60,7 @@ #include #include #include -#include +#include #include #include #include @@ -306,7 +306,7 @@ bool setupEssentials(int& argc, char** argv) { listenPort = atoi(portStr); } // Set build version - QCoreApplication::setApplicationVersion(BUILD_VERSION); + QCoreApplication::setApplicationVersion(BuildInfo::VERSION); Setting::preInit(); diff --git a/libraries/networking/src/Assignment.cpp b/libraries/networking/src/Assignment.cpp index cf40400aa8..0114bcb708 100644 --- a/libraries/networking/src/Assignment.cpp +++ b/libraries/networking/src/Assignment.cpp @@ -16,7 +16,7 @@ #include -#include +#include #include "Assignment.h" #include @@ -66,7 +66,7 @@ Assignment::Assignment(Assignment::Command command, Assignment::Type type, const // this is a newly created assignment, generate a random UUID _uuid = QUuid::createUuid(); } else if (_command == Assignment::RequestCommand) { - _nodeVersion = BUILD_VERSION; + _nodeVersion = BuildInfo::VERSION; } } From ded210db39c673053eebb576bb6dcf9ff63d3dcc Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 14 Jan 2016 10:16:42 -0800 Subject: [PATCH 197/357] exclude udt-test from ALL_BUILD --- tools/udt-test/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/udt-test/CMakeLists.txt b/tools/udt-test/CMakeLists.txt index f21e3e9aea..a6752ec09e 100644 --- a/tools/udt-test/CMakeLists.txt +++ b/tools/udt-test/CMakeLists.txt @@ -1,5 +1,7 @@ set(TARGET_NAME udt-test) setup_hifi_project() +set_target_properties(${TARGET_NAME} PROPERTIES EXCLUDE_FROM_ALL TRUE EXCLUDE_FROM_DEFAULT_BUILD TRUE) + link_hifi_libraries(networking shared) -package_libraries_for_deployment() \ No newline at end of file +package_libraries_for_deployment() From 24450517fa11dbe5f5e19cc9b67074b713f40444 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 14 Jan 2016 10:25:26 -0800 Subject: [PATCH 198/357] add npm install command to packaged-console target --- console/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/console/CMakeLists.txt b/console/CMakeLists.txt index 055457cff8..1b021e4f47 100644 --- a/console/CMakeLists.txt +++ b/console/CMakeLists.txt @@ -6,6 +6,7 @@ endif() # add a target that will package the console add_custom_target(${TARGET_NAME} ALL + COMMAND npm install COMMAND npm run packager -- --out ${CMAKE_CURRENT_BINARY_DIR} ${PRODUCTION_OPTION} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) From 876d36c2d33b9cf7fdcd32708cafc87a91a047b4 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 14 Jan 2016 11:05:07 -0800 Subject: [PATCH 199/357] install scripts beside interface executable --- interface/CMakeLists.txt | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 51620fe800..7a7449798d 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -217,6 +217,8 @@ if (APPLE) COMPONENT ${CLIENT_COMPONENT} ) + set(SCRIPTS_INSTALL_DIR "${INTERFACE_INSTALL_APP_PATH}/Contents/Resources") + else (APPLE) # copy the resources files beside the executable add_custom_command(TARGET ${TARGET_NAME} POST_BUILD @@ -239,12 +241,23 @@ else (APPLE) COMPONENT ${CLIENT_COMPONENT} ) + set(SCRIPTS_INSTALL_DIR "${INTERFACE_INSTALL_DIR}") + set(EXECUTABLE_COMPONENT ${CLIENT_COMPONENT}) optional_win_executable_signing() endif() endif (APPLE) +if (SCRIPTS_INSTALL_DIR) + # setup install of scripts beside interface executable + install( + DIRECTORY "${CMAKE_SOURCE_DIR}/examples/" + DESTINATION ${SCRIPTS_INSTALL_DIR}/scripts + COMPONENT ${CLIENT_COMPONENT} + ) +endif() + # call the fixup_interface macro to add required bundling commands for installation fixup_interface() From 3e9f124209162d78786c30488da71a7cdde0bd1f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 14 Jan 2016 11:05:46 -0800 Subject: [PATCH 200/357] update packaging parameters for suggested jenkins setup --- cmake/macros/SetPackagingParameters.cmake | 20 ++++++++++---------- cmake/templates/BuildInfo.h.in | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/cmake/macros/SetPackagingParameters.cmake b/cmake/macros/SetPackagingParameters.cmake index 772dc2fc7c..104174c17d 100644 --- a/cmake/macros/SetPackagingParameters.cmake +++ b/cmake/macros/SetPackagingParameters.cmake @@ -16,30 +16,30 @@ macro(SET_PACKAGING_PARAMETERS) set(PRODUCTION_BUILD 0) set(DEV_BUILD 0) - if (DEFINED ENV{JOB_ID}) + set(RELEASE_TYPE ENV{RELEASE_TYPE}) + set(RELEASE_NUMBER ENV{RELEASE_NUMBER}) + + if (RELEASE_TYPE STREQUAL "PRODUCTION") set(DEPLOY_PACKAGE TRUE) - set(BUILD_SEQ $ENV{JOB_ID}) set(PRODUCTION_BUILD 1) set(BUILD_ORGANIZATION "High Fidelity") - set(INSTALLER_NAME "interface-win64-${BUILD_SEQ}.exe") + set(BUILD_VERSION ${RELEASE_NUMBER}) set(HIGH_FIDELITY_PROTOCOL "hifi") set(INTERFACE_BUNDLE_NAME "High Fidelity") set(INTERFACE_ICON_PREFIX "interface") set(CONSOLE_ICON "console.ico") - elseif (DEFINED ENV{ghprbPullId}) + elseif (RELEASE_TYPE STREQUAL "PR") set(DEPLOY_PACKAGE TRUE) set(PR_BUILD 1) - set(BUILD_SEQ "PR-$ENV{ghprbPullId}") - set(BUILD_ORGANIZATION "High Fidelity - PR#$ENV{ghprbPullId}") - set(INSTALLER_NAME "pr-interface-win64-${BUILD_SEQ}.exe") - set(INTERFACE_BUNDLE_NAME "High Fidelity ${BUILD_SEQ}") + set(BUILD_VERSION "PR${RELEASE_NUMBER}") + set(BUILD_ORGANIZATION "High Fidelity - PR#${RELEASE_NUMBER}") + set(INTERFACE_BUNDLE_NAME "High Fidelity PR#${RELEASE_NUMBER}") set(INTERFACE_ICON_PREFIX "interface-beta") set(CONSOLE_ICON "console-beta.ico") else () - set(BUILD_SEQ "dev") set(DEV_BUILD 1) set(BUILD_ORGANIZATION "High Fidelity - Dev") - set(INSTALLER_NAME "dev-interface-win64.exe") + set(BUILD_VERSION "dev") set(INTERFACE_BUNDLE_NAME "Interface") set(INTERFACE_ICON_PREFIX "interface-beta") set(CONSOLE_ICON "console-beta.ico") diff --git a/cmake/templates/BuildInfo.h.in b/cmake/templates/BuildInfo.h.in index a531317354..3a462feb1a 100644 --- a/cmake/templates/BuildInfo.h.in +++ b/cmake/templates/BuildInfo.h.in @@ -11,5 +11,5 @@ namespace BuildInfo { const QString MODIFIED_ORGANIZATION = "@BUILD_ORGANIZATION@"; - const QString VERSION = "@BUILD_SEQ@"; + const QString VERSION = "@BUILD_VERSION@"; } From 926b75782fbb996627d3afe43291b30030635846 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 14 Jan 2016 11:10:59 -0800 Subject: [PATCH 201/357] use build version for cpack package version --- cmake/macros/GenerateInstallers.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/macros/GenerateInstallers.cmake b/cmake/macros/GenerateInstallers.cmake index 73f132609f..8962e0cfef 100644 --- a/cmake/macros/GenerateInstallers.cmake +++ b/cmake/macros/GenerateInstallers.cmake @@ -18,6 +18,7 @@ macro(GENERATE_INSTALLERS) set(CPACK_PACKAGE_NAME ${_DISPLAY_NAME}) set(CPACK_PACKAGE_VENDOR "High Fidelity") + set(CPACK_PACKAGE_VERSION ${BUILD_VERSION}) set(CPACK_NSIS_DISPLAY_NAME ${_DISPLAY_NAME}) set(CPACK_NSIS_PACKAGE_NAME ${_DISPLAY_NAME}) set(CPACK_PACKAGE_INSTALL_DIRECTORY ${_DISPLAY_NAME}) From c83ac2171c2ed7e8d039d6a198f6a6df7d06be1e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 14 Jan 2016 11:34:07 -0800 Subject: [PATCH 202/357] fix for reference to interface filename --- interface/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 7a7449798d..2649462477 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -76,7 +76,7 @@ if (APPLE) endif () # set how the icon shows up in the Info.plist file - set(MACOSX_BUNDLE_ICON_FILE "${INTERfACE_ICON_FILENAME}") + set(MACOSX_BUNDLE_ICON_FILE "${INTERFACE_ICON_FILENAME}") # set where in the bundle to put the resources file set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/icon/${INTERFACE_ICON_FILENAME} PROPERTIES MACOSX_PACKAGE_LOCATION Resources) From ffd79a5df406415090b12a1b6bbb36bac070ebac Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 14 Jan 2016 11:36:52 -0800 Subject: [PATCH 203/357] pretty up the packaged installer name --- cmake/macros/GenerateInstallers.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/macros/GenerateInstallers.cmake b/cmake/macros/GenerateInstallers.cmake index 8962e0cfef..e0fecb1763 100644 --- a/cmake/macros/GenerateInstallers.cmake +++ b/cmake/macros/GenerateInstallers.cmake @@ -19,6 +19,7 @@ macro(GENERATE_INSTALLERS) set(CPACK_PACKAGE_NAME ${_DISPLAY_NAME}) set(CPACK_PACKAGE_VENDOR "High Fidelity") set(CPACK_PACKAGE_VERSION ${BUILD_VERSION}) + set(CPACK_PACKAGE_FILE_NAME "HighFidelity-beta-${BUILD_VERSION}") set(CPACK_NSIS_DISPLAY_NAME ${_DISPLAY_NAME}) set(CPACK_NSIS_PACKAGE_NAME ${_DISPLAY_NAME}) set(CPACK_PACKAGE_INSTALL_DIRECTORY ${_DISPLAY_NAME}) From 0a15f0400c31cca93ec1f522ea441081756baa1e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 14 Jan 2016 11:37:06 -0800 Subject: [PATCH 204/357] fix env variable referencing in SetPackagingParameters --- cmake/macros/SetPackagingParameters.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/macros/SetPackagingParameters.cmake b/cmake/macros/SetPackagingParameters.cmake index 104174c17d..0748a91001 100644 --- a/cmake/macros/SetPackagingParameters.cmake +++ b/cmake/macros/SetPackagingParameters.cmake @@ -16,8 +16,8 @@ macro(SET_PACKAGING_PARAMETERS) set(PRODUCTION_BUILD 0) set(DEV_BUILD 0) - set(RELEASE_TYPE ENV{RELEASE_TYPE}) - set(RELEASE_NUMBER ENV{RELEASE_NUMBER}) + set(RELEASE_TYPE $ENV{RELEASE_TYPE}) + set(RELEASE_NUMBER $ENV{RELEASE_NUMBER}) if (RELEASE_TYPE STREQUAL "PRODUCTION") set(DEPLOY_PACKAGE TRUE) From 7d2684f01ec89d0430283513f6284024be246510 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 14 Jan 2016 11:41:21 -0800 Subject: [PATCH 205/357] use alpha for packaged installer name --- cmake/macros/GenerateInstallers.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/macros/GenerateInstallers.cmake b/cmake/macros/GenerateInstallers.cmake index e0fecb1763..408c4f27f3 100644 --- a/cmake/macros/GenerateInstallers.cmake +++ b/cmake/macros/GenerateInstallers.cmake @@ -19,7 +19,7 @@ macro(GENERATE_INSTALLERS) set(CPACK_PACKAGE_NAME ${_DISPLAY_NAME}) set(CPACK_PACKAGE_VENDOR "High Fidelity") set(CPACK_PACKAGE_VERSION ${BUILD_VERSION}) - set(CPACK_PACKAGE_FILE_NAME "HighFidelity-beta-${BUILD_VERSION}") + set(CPACK_PACKAGE_FILE_NAME "HighFidelity-Alpha-${BUILD_VERSION}") set(CPACK_NSIS_DISPLAY_NAME ${_DISPLAY_NAME}) set(CPACK_NSIS_PACKAGE_NAME ${_DISPLAY_NAME}) set(CPACK_PACKAGE_INSTALL_DIRECTORY ${_DISPLAY_NAME}) From aa9319001ed783c4b07cfecf2465b0adf08de939 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 14 Jan 2016 12:11:04 -0800 Subject: [PATCH 206/357] use BUILD_ORGANIZATION for installer display name --- cmake/macros/GenerateInstallers.cmake | 3 +-- cmake/macros/SetPackagingParameters.cmake | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/cmake/macros/GenerateInstallers.cmake b/cmake/macros/GenerateInstallers.cmake index 408c4f27f3..e4c84ebef2 100644 --- a/cmake/macros/GenerateInstallers.cmake +++ b/cmake/macros/GenerateInstallers.cmake @@ -14,7 +14,7 @@ macro(GENERATE_INSTALLERS) set(CPACK_MODULE_PATH ${CPACK_MODULE_PATH} "${HF_CMAKE_DIR}/templates") - set(_DISPLAY_NAME "High Fidelity") + set(_DISPLAY_NAME ${BUILD_ORGANIZATION}) set(CPACK_PACKAGE_NAME ${_DISPLAY_NAME}) set(CPACK_PACKAGE_VENDOR "High Fidelity") @@ -22,7 +22,6 @@ macro(GENERATE_INSTALLERS) set(CPACK_PACKAGE_FILE_NAME "HighFidelity-Alpha-${BUILD_VERSION}") set(CPACK_NSIS_DISPLAY_NAME ${_DISPLAY_NAME}) set(CPACK_NSIS_PACKAGE_NAME ${_DISPLAY_NAME}) - set(CPACK_PACKAGE_INSTALL_DIRECTORY ${_DISPLAY_NAME}) set(CPACK_RESOURCE_FILE_LICENSE "${HF_CMAKE_DIR}/installer/InstallerLicense.txt") diff --git a/cmake/macros/SetPackagingParameters.cmake b/cmake/macros/SetPackagingParameters.cmake index 0748a91001..5491d6f5d9 100644 --- a/cmake/macros/SetPackagingParameters.cmake +++ b/cmake/macros/SetPackagingParameters.cmake @@ -22,8 +22,8 @@ macro(SET_PACKAGING_PARAMETERS) if (RELEASE_TYPE STREQUAL "PRODUCTION") set(DEPLOY_PACKAGE TRUE) set(PRODUCTION_BUILD 1) - set(BUILD_ORGANIZATION "High Fidelity") set(BUILD_VERSION ${RELEASE_NUMBER}) + set(BUILD_ORGANIZATION "High Fidelity") set(HIGH_FIDELITY_PROTOCOL "hifi") set(INTERFACE_BUNDLE_NAME "High Fidelity") set(INTERFACE_ICON_PREFIX "interface") @@ -38,8 +38,8 @@ macro(SET_PACKAGING_PARAMETERS) set(CONSOLE_ICON "console-beta.ico") else () set(DEV_BUILD 1) - set(BUILD_ORGANIZATION "High Fidelity - Dev") set(BUILD_VERSION "dev") + set(BUILD_ORGANIZATION "High Fidelity - Dev") set(INTERFACE_BUNDLE_NAME "Interface") set(INTERFACE_ICON_PREFIX "interface-beta") set(CONSOLE_ICON "console-beta.ico") From c0c627a226ee082313da760c11c8b67d33e47767 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 14 Jan 2016 12:18:31 -0800 Subject: [PATCH 207/357] explicitly set install directory to match display name --- cmake/macros/GenerateInstallers.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/macros/GenerateInstallers.cmake b/cmake/macros/GenerateInstallers.cmake index e4c84ebef2..06091b6b84 100644 --- a/cmake/macros/GenerateInstallers.cmake +++ b/cmake/macros/GenerateInstallers.cmake @@ -22,6 +22,7 @@ macro(GENERATE_INSTALLERS) set(CPACK_PACKAGE_FILE_NAME "HighFidelity-Alpha-${BUILD_VERSION}") set(CPACK_NSIS_DISPLAY_NAME ${_DISPLAY_NAME}) set(CPACK_NSIS_PACKAGE_NAME ${_DISPLAY_NAME}) + set(CPACK_PACKAGE_INSTALL_DIRECTORY ${_DISPLAY_NAME}) set(CPACK_RESOURCE_FILE_LICENSE "${HF_CMAKE_DIR}/installer/InstallerLicense.txt") From 99ad79d833110ff209c7e924f960d5aa7ad941c3 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 14 Jan 2016 12:38:57 -0800 Subject: [PATCH 208/357] add an icon for nsis installer --- cmake/installer/Installer.ico | Bin 0 -> 31238 bytes cmake/macros/GenerateInstallers.cmake | 1 + 2 files changed, 1 insertion(+) create mode 100644 cmake/installer/Installer.ico diff --git a/cmake/installer/Installer.ico b/cmake/installer/Installer.ico new file mode 100644 index 0000000000000000000000000000000000000000..c4316f5de6d0b2925fbb6cacdbd3d4c8f78422c8 GIT binary patch literal 31238 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 z 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 Q@E{g@A+I;dv-9Ww2X31H^8f$< literal 0 HcmV?d00001 diff --git a/cmake/macros/GenerateInstallers.cmake b/cmake/macros/GenerateInstallers.cmake index 06091b6b84..a8b4cf16eb 100644 --- a/cmake/macros/GenerateInstallers.cmake +++ b/cmake/macros/GenerateInstallers.cmake @@ -23,6 +23,7 @@ macro(GENERATE_INSTALLERS) set(CPACK_NSIS_DISPLAY_NAME ${_DISPLAY_NAME}) set(CPACK_NSIS_PACKAGE_NAME ${_DISPLAY_NAME}) set(CPACK_PACKAGE_INSTALL_DIRECTORY ${_DISPLAY_NAME}) + set(CPACK_NSIS_MUI_ICON "${HF_CMAKE_DIR}/installer/Installer.ico") set(CPACK_RESOURCE_FILE_LICENSE "${HF_CMAKE_DIR}/installer/InstallerLicense.txt") From 81493f9b4e379c18e9679e32ceacfb2d8276c216 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 14 Jan 2016 13:12:26 -0800 Subject: [PATCH 209/357] only sign production build executables --- cmake/macros/OptionalWinExecutableSigning.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/macros/OptionalWinExecutableSigning.cmake b/cmake/macros/OptionalWinExecutableSigning.cmake index 0ce7f89940..6b4534f1ac 100644 --- a/cmake/macros/OptionalWinExecutableSigning.cmake +++ b/cmake/macros/OptionalWinExecutableSigning.cmake @@ -10,7 +10,7 @@ # macro(optional_win_executable_signing) - if (WIN32 AND (PRODUCTION_BUILD OR PR_BUILD)) + if (WIN32 AND PRODUCTION_BUILD) if (DEFINED ENV{HF_PFX_FILE}) if (DEFINED ENV{HF_PFX_PASSPHRASE}) message(STATUS "Executable for ${TARGET_NAME} will be signed with SignTool.") From 0cfc87160a7f7d7b0f50fbb2821fcb435bf16732 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 14 Jan 2016 13:14:41 -0800 Subject: [PATCH 210/357] use different syntax for custom packaged console target --- console/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/console/CMakeLists.txt b/console/CMakeLists.txt index 1b021e4f47..576aaf0747 100644 --- a/console/CMakeLists.txt +++ b/console/CMakeLists.txt @@ -6,7 +6,7 @@ endif() # add a target that will package the console add_custom_target(${TARGET_NAME} ALL - COMMAND npm install + npm install COMMAND npm run packager -- --out ${CMAKE_CURRENT_BINARY_DIR} ${PRODUCTION_OPTION} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) From 264fe3720f00c1ad3ae989be51747639a07be465 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 14 Jan 2016 13:18:50 -0800 Subject: [PATCH 211/357] use separate targets for npm install/packager --- console/CMakeLists.txt | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/console/CMakeLists.txt b/console/CMakeLists.txt index 576aaf0747..86bb1a38b6 100644 --- a/console/CMakeLists.txt +++ b/console/CMakeLists.txt @@ -5,11 +5,18 @@ if (PRODUCTION_BUILD) endif() # add a target that will package the console -add_custom_target(${TARGET_NAME} ALL - npm install - COMMAND npm run packager -- --out ${CMAKE_CURRENT_BINARY_DIR} ${PRODUCTION_OPTION} +add_custom_target(${TARGET_NAME}-npm-install + COMMAND npm install WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) +add_custom_target(${TARGET_NAME} + COMMAND npm run packager -- --out ${CMAKE_CURRENT_BINARY_DIR} ${PRODUCTION_OPTION} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + DEPENDS ${TARGET_NAME}-npm-install +) + +set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Console") +set_target_properties(${TARGET_NAME}-npm-install PROPERTIES FOLDER "Console") # add a dependency from the package target to the server components add_dependencies(${TARGET_NAME} assignment-client domain-server) From 537f8deeec40c1745f355a1004c006eb0d72fc8e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 14 Jan 2016 13:22:59 -0800 Subject: [PATCH 212/357] update to new license in root and installer --- LICENSE | 25 ++++++++++++------------- cmake/installer/InstallerLicense.txt | 12 ------------ cmake/macros/GenerateInstallers.cmake | 2 +- 3 files changed, 13 insertions(+), 26 deletions(-) delete mode 100644 cmake/installer/InstallerLicense.txt diff --git a/LICENSE b/LICENSE index 93c9a953d4..53c5ccf39a 100644 --- a/LICENSE +++ b/LICENSE @@ -1,13 +1,12 @@ -Copyright 2014 High Fidelity, Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. \ No newline at end of file +Copyright (c) 2013-2016, High Fidelity, Inc. +All rights reserved. +licensing@highfidelity.io + +Licensed under the Apache License version 2.0 (the "License"); +You may not use this software except in compliance with the License. +You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0 + +This software includes third-party software. +Please see each individual software license for additional details. + +This software is distributed "as-is" without any warranties, conditions, or representations whether express or implied, including without limitation the implied warranties and conditions of merchantability, merchantable quality, fitness for a particular purpose, performance, durability, title, non-infringement, and those arising from statute or from custom or usage of trade or course of dealing. diff --git a/cmake/installer/InstallerLicense.txt b/cmake/installer/InstallerLicense.txt deleted file mode 100644 index 9f69dbd942..0000000000 --- a/cmake/installer/InstallerLicense.txt +++ /dev/null @@ -1,12 +0,0 @@ -Copyright (c) 2013-2016, High Fidelity, Inc. -All rights reserved. -licensing@highfidelity.io - -Licensed under the Apache License version 2.0 (the "License"); -You may not use this software except in compliance with the License. -You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0 - -This software includes third-party software. -Please see each individual software license for additional details. - -THIS SOFTWARE IS DISTRIBUTED "AS-IS" WITHOUT ANY WARRANTIES, CONDITIONS AND REPRESENTATIONS WHETHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES AND CONDITIONS OF MERCHANTABILITY, MERCHANTABLE QUALITY, FITNESS FOR A PARTICULAR PURPOSE, PERFORMANCE, DURABILITY, TITLE, NON-INFRINGEMENT, AND THOSE ARISING BY STATUTE OR FROM CUSTOM OR USAGE OF TRADE OR COURSE OF DEALING. diff --git a/cmake/macros/GenerateInstallers.cmake b/cmake/macros/GenerateInstallers.cmake index a8b4cf16eb..d5f2f21558 100644 --- a/cmake/macros/GenerateInstallers.cmake +++ b/cmake/macros/GenerateInstallers.cmake @@ -25,7 +25,7 @@ macro(GENERATE_INSTALLERS) set(CPACK_PACKAGE_INSTALL_DIRECTORY ${_DISPLAY_NAME}) set(CPACK_NSIS_MUI_ICON "${HF_CMAKE_DIR}/installer/Installer.ico") - set(CPACK_RESOURCE_FILE_LICENSE "${HF_CMAKE_DIR}/installer/InstallerLicense.txt") + set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSE") # configure a cpack properties file for custom variables in NSIS template set(CPACK_CONFIGURED_PROP_FILE "${CMAKE_CURRENT_BINARY_DIR}/CPackCustomProperties.cmake") From d34c3bdc1c86a3871b2bc4c226447e59810457e0 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 14 Jan 2016 13:32:49 -0800 Subject: [PATCH 213/357] add custom header image for installer --- cmake/installer/installer-header.bmp | Bin 0 -> 102656 bytes cmake/macros/GenerateInstallers.cmake | 3 ++- cmake/templates/CPackProperties.cmake.in | 1 + cmake/templates/NSIS.template.in | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 cmake/installer/installer-header.bmp diff --git a/cmake/installer/installer-header.bmp b/cmake/installer/installer-header.bmp new file mode 100644 index 0000000000000000000000000000000000000000..28101932c7e58afc8a1690813fbfdc0a7301ee08 GIT binary patch literal 102656 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 h7z_r3!C){L3 Date: Thu, 14 Jan 2016 13:59:31 -0800 Subject: [PATCH 214/357] use backslashes for header image path on win --- cmake/macros/FixPathForNSIS.cmake | 16 ++++++++++++++++ cmake/macros/GenerateInstallers.cmake | 8 +++++++- 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 cmake/macros/FixPathForNSIS.cmake diff --git a/cmake/macros/FixPathForNSIS.cmake b/cmake/macros/FixPathForNSIS.cmake new file mode 100644 index 0000000000..22ee538ed7 --- /dev/null +++ b/cmake/macros/FixPathForNSIS.cmake @@ -0,0 +1,16 @@ +# +# FixPathForNSIS.cmake +# +# Created by Sam Gateau on 1/14/16. +# Copyright 2016 High Fidelity, Inc. +# +# Distributed under the Apache License, Version 2.0. +# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +# + +macro(fix_path_for_nsis INITIAL_PATH RESULTING_PATH) + # replace forward slash with backslash + string(REPLACE "/" "\\\\" _BACKSLASHED_PATH ${INITIAL_PATH}) + # set the resulting path variable + set(${RESULTING_PATH} ${_BACKSLASHED_PATH}) +endmacro() diff --git a/cmake/macros/GenerateInstallers.cmake b/cmake/macros/GenerateInstallers.cmake index f3c03ca141..4ca1ff714b 100644 --- a/cmake/macros/GenerateInstallers.cmake +++ b/cmake/macros/GenerateInstallers.cmake @@ -24,7 +24,13 @@ macro(GENERATE_INSTALLERS) set(CPACK_NSIS_PACKAGE_NAME ${_DISPLAY_NAME}) set(CPACK_PACKAGE_INSTALL_DIRECTORY ${_DISPLAY_NAME}) set(CPACK_NSIS_MUI_ICON "${HF_CMAKE_DIR}/installer/installer.ico") - set(INSTALLER_HEADER_IMAGE "${HF_CMAKE_DIR}/installer/installer-header.bmp") + + if (WIN32) + # use macro to put backslashes in header image path since nsis requires them + set(_INSTALLER_HEADER_BAD_PATH "${HF_CMAKE_DIR}/installer/installer-header.bmp") + set(INSTALLER_HEADER_IMAGE "") + fix_path_for_nsis(${_INSTALLER_HEADER_BAD_PATH} INSTALLER_HEADER_IMAGE) + endif() set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSE") From 9ce0f6a0b1b791eb88ea52b526504b708713b70a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 14 Jan 2016 14:19:19 -0800 Subject: [PATCH 215/357] add a header image for uninstaller --- cmake/installer/uninstaller-header.bmp | Bin 0 -> 102656 bytes cmake/macros/GenerateInstallers.cmake | 4 ++++ cmake/templates/CPackProperties.cmake.in | 1 + cmake/templates/NSIS.template.in | 1 + 4 files changed, 6 insertions(+) create mode 100644 cmake/installer/uninstaller-header.bmp diff --git a/cmake/installer/uninstaller-header.bmp b/cmake/installer/uninstaller-header.bmp new file mode 100644 index 0000000000000000000000000000000000000000..d43166ded3e75c995fba9e114846ec803f539a07 GIT binary patch literal 102656 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 Z2m}IwKp+qZ1OkCTAP@)yqP_I$^?$FtU&;Ug literal 0 HcmV?d00001 diff --git a/cmake/macros/GenerateInstallers.cmake b/cmake/macros/GenerateInstallers.cmake index 4ca1ff714b..fb29641cc4 100644 --- a/cmake/macros/GenerateInstallers.cmake +++ b/cmake/macros/GenerateInstallers.cmake @@ -30,6 +30,10 @@ macro(GENERATE_INSTALLERS) set(_INSTALLER_HEADER_BAD_PATH "${HF_CMAKE_DIR}/installer/installer-header.bmp") set(INSTALLER_HEADER_IMAGE "") fix_path_for_nsis(${_INSTALLER_HEADER_BAD_PATH} INSTALLER_HEADER_IMAGE) + + set(_UNINSTALLER_HEADER_BAD_PATH "${HF_CMAKE_DIR}/installer/uninstaller-header.bmp") + set(UNINSTALLER_HEADER_IMAGE "") + fix_path_for_nsis(${_UNINSTALLER_HEADER_BAD_PATH} UNINSTALLER_HEADER_IMAGE) endif() set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSE") diff --git a/cmake/templates/CPackProperties.cmake.in b/cmake/templates/CPackProperties.cmake.in index e7071c707a..e2d0c239a9 100644 --- a/cmake/templates/CPackProperties.cmake.in +++ b/cmake/templates/CPackProperties.cmake.in @@ -27,3 +27,4 @@ set(CONSOLE_DESKTOP_SHORTCUT_REG_KEY "@CONSOLE_DESKTOP_SHORTCUT_REG_KEY@") set(CONSOLE_STARTUP_REG_KEY "@CONSOLE_STARTUP_REG_KEY@") set(LAUNCH_NOW_REG_KEY "@LAUNCH_NOW_REG_KEY@") set(INSTALLER_HEADER_IMAGE "@INSTALLER_HEADER_IMAGE@") +set(UNINSTALLER_HEADER_IMAGE "@UNINSTALLER_HEADER_IMAGE@") diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index d5fc926b72..49db02c928 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -195,6 +195,7 @@ Var AR_RegFlags !define MUI_HEADERIMAGE !define MUI_HEADERIMAGE_BITMAP "@INSTALLER_HEADER_IMAGE@" + !define MUI_HEADERIMAGE_UNBITMAP "@UNINSTALLER_HEADER_IMAGE@" !define MUI_ABORTWARNING ;-------------------------------- From fc65053eb53b5c222dfa3a4e3e6e160efb5fb6ef Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 14 Jan 2016 14:26:29 -0800 Subject: [PATCH 216/357] add an icon for item in add/remove --- cmake/installer/uninstaller.ico | Bin 0 -> 27121 bytes cmake/macros/GenerateInstallers.cmake | 1 + 2 files changed, 1 insertion(+) create mode 100644 cmake/installer/uninstaller.ico diff --git a/cmake/installer/uninstaller.ico b/cmake/installer/uninstaller.ico new file mode 100644 index 0000000000000000000000000000000000000000..8d84d9d094e49570e1e664819169a29156a45d64 GIT binary patch literal 27121 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 MroX{S3xy#62aBKbeE Date: Thu, 14 Jan 2016 14:40:24 -0800 Subject: [PATCH 217/357] install the add/remove icon --- cmake/installer/{uninstaller.ico => add-remove.ico} | Bin cmake/macros/GenerateInstallers.cmake | 12 ++++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) rename cmake/installer/{uninstaller.ico => add-remove.ico} (100%) diff --git a/cmake/installer/uninstaller.ico b/cmake/installer/add-remove.ico similarity index 100% rename from cmake/installer/uninstaller.ico rename to cmake/installer/add-remove.ico diff --git a/cmake/macros/GenerateInstallers.cmake b/cmake/macros/GenerateInstallers.cmake index b09218f844..c44d76da70 100644 --- a/cmake/macros/GenerateInstallers.cmake +++ b/cmake/macros/GenerateInstallers.cmake @@ -23,10 +23,18 @@ macro(GENERATE_INSTALLERS) set(CPACK_NSIS_DISPLAY_NAME ${_DISPLAY_NAME}) set(CPACK_NSIS_PACKAGE_NAME ${_DISPLAY_NAME}) set(CPACK_PACKAGE_INSTALL_DIRECTORY ${_DISPLAY_NAME}) - set(CPACK_NSIS_MUI_ICON "${HF_CMAKE_DIR}/installer/installer.ico") - set(CPACK_NSIS_INSTALLED_ICON_NAME "${HF_CMAKE_DIR}/installer/uninstaller.ico") if (WIN32) + set(CPACK_NSIS_MUI_ICON "${HF_CMAKE_DIR}/installer/installer.ico") + + # install the uninstaller icon and reference it for Add/Remove icon + set(ADD_REMOVE_ICON_NAME "add-remove.ico") + install( + FILES "${HF_CMAKE_DIR}/installer/${ADD_REMOVE_ICON_NAME}" + DESTINATION "." + ) + set(CPACK_NSIS_INSTALLED_ICON_NAME ${ADD_REMOVE_ICON_NAME}) + # use macro to put backslashes in header image path since nsis requires them set(_INSTALLER_HEADER_BAD_PATH "${HF_CMAKE_DIR}/installer/installer-header.bmp") set(INSTALLER_HEADER_IMAGE "") From 95acd2cfc320795e029ef05c80e0b2f0eaebe9f8 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 14 Jan 2016 14:51:28 -0800 Subject: [PATCH 218/357] drop in add remove icon during core install --- cmake/macros/GenerateInstallers.cmake | 5 +---- cmake/templates/CPackProperties.cmake.in | 1 + cmake/templates/NSIS.template.in | 3 +++ 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/cmake/macros/GenerateInstallers.cmake b/cmake/macros/GenerateInstallers.cmake index c44d76da70..82ce52f02c 100644 --- a/cmake/macros/GenerateInstallers.cmake +++ b/cmake/macros/GenerateInstallers.cmake @@ -29,10 +29,7 @@ macro(GENERATE_INSTALLERS) # install the uninstaller icon and reference it for Add/Remove icon set(ADD_REMOVE_ICON_NAME "add-remove.ico") - install( - FILES "${HF_CMAKE_DIR}/installer/${ADD_REMOVE_ICON_NAME}" - DESTINATION "." - ) + set(ADD_REMOVE_ICON_PATH "${HF_CMAKE_DIR}/installer/${ADD_REMOVE_ICON_NAME}") set(CPACK_NSIS_INSTALLED_ICON_NAME ${ADD_REMOVE_ICON_NAME}) # use macro to put backslashes in header image path since nsis requires them diff --git a/cmake/templates/CPackProperties.cmake.in b/cmake/templates/CPackProperties.cmake.in index e2d0c239a9..bf1a4ec033 100644 --- a/cmake/templates/CPackProperties.cmake.in +++ b/cmake/templates/CPackProperties.cmake.in @@ -28,3 +28,4 @@ set(CONSOLE_STARTUP_REG_KEY "@CONSOLE_STARTUP_REG_KEY@") set(LAUNCH_NOW_REG_KEY "@LAUNCH_NOW_REG_KEY@") set(INSTALLER_HEADER_IMAGE "@INSTALLER_HEADER_IMAGE@") set(UNINSTALLER_HEADER_IMAGE "@UNINSTALLER_HEADER_IMAGE@") +set(ADD_REMOVE_ICON_PATH "@ADD_REMOVE_ICON_PATH@") diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 49db02c928..027520cdd9 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -721,6 +721,9 @@ Section "-Core installation" Call ConditionalAddToRegisty !endif + ; Package the add/remove icon file + File "@ADD_REMOVE_ICON_PATH@" + ; Optional registration Push "DisplayIcon" Push "$INSTDIR\@CPACK_NSIS_INSTALLED_ICON_NAME@" From 0533438b8f6e30472b6ad8f56627236a914849a4 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 14 Jan 2016 14:54:12 -0800 Subject: [PATCH 219/357] use backslashes in add remove icon path --- cmake/macros/GenerateInstallers.cmake | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmake/macros/GenerateInstallers.cmake b/cmake/macros/GenerateInstallers.cmake index 82ce52f02c..1357c87261 100644 --- a/cmake/macros/GenerateInstallers.cmake +++ b/cmake/macros/GenerateInstallers.cmake @@ -29,7 +29,8 @@ macro(GENERATE_INSTALLERS) # install the uninstaller icon and reference it for Add/Remove icon set(ADD_REMOVE_ICON_NAME "add-remove.ico") - set(ADD_REMOVE_ICON_PATH "${HF_CMAKE_DIR}/installer/${ADD_REMOVE_ICON_NAME}") + set(ADD_REMOVE_ICON_BAD_PATH "${HF_CMAKE_DIR}/installer/${ADD_REMOVE_ICON_NAME}") + fix_path_for_nsis(${ADD_REMOVE_ICON_BAD_PATH} ADD_REMOVE_ICON_PATH) set(CPACK_NSIS_INSTALLED_ICON_NAME ${ADD_REMOVE_ICON_NAME}) # use macro to put backslashes in header image path since nsis requires them From 124e0fb61fe59baff1b29b9fafd398ad80f492a9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 14 Jan 2016 15:02:20 -0800 Subject: [PATCH 220/357] remove the add/remove icon during uninstall --- cmake/templates/NSIS.template.in | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 027520cdd9..d38d29b1f4 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -1109,6 +1109,9 @@ Section "Uninstall" Delete "$INSTDIR\AddRemove.exe" !endif + ;Remove the Add/Remove icon + Delete "$INSTDIR\@CPACK_NSIS_INSTALLED_ICON_NAME@" + ;Remove the uninstaller itself. Delete "$INSTDIR\@UNINSTALLER_NAME@" DeleteRegKey SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" From 0098fe27dfdf543d465c3438108c194b7a56114d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 14 Jan 2016 15:32:56 -0800 Subject: [PATCH 221/357] don't uninstall a previously installed section from the installer --- cmake/templates/NSIS.template.in | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index d38d29b1f4..c49442ee1f 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -147,10 +147,14 @@ Var AR_RegFlags IntOp $AR_SecFlags $AR_SecFlags & ${SF_SELECTED} IntCmp $AR_SecFlags 1 "leave_${SecName}" ;Section is not selected: - ;Calling Section uninstall macro and writing zero installed flag - !insertmacro "Remove_${${SecName}}" - WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\Components\${SecName}" \ - "Installed" 0 + + ; NOTE: The default CPack template calls Section uninstall macro and writes zero installed flag + ; We do not do that here because it would absolutely cause issues with shared dependencies + + ;!insertmacro "Remove_${${SecName}}" + ;WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\Components\${SecName}" \ + ; "Installed" 0 + Goto "exit_${SecName}" "leave_${SecName}:" From 5730772f6b206a47a53c7117bdfb7d7cc89595dc Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 14 Jan 2016 15:50:08 -0800 Subject: [PATCH 222/357] disable install button with neither component selected --- cmake/templates/NSIS.template.in | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index c49442ee1f..152aaa1d61 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -1076,6 +1076,16 @@ SectionEnd ; Component dependencies Function .onSelChange !insertmacro SectionList MaybeSelectionChanged + + ; if neither component is selected, disable the install button + ${IfNot} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@} + ${AndIfNot} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@} + GetDlgItem $0 $HWNDPARENT 1 + EnableWindow $0 0 + ${Else} + GetDlgItem $0 $HWNDPARENT 1 + EnableWindow $0 1 + ${EndIf} FunctionEnd ;-------------------------------- From 59b4c2545fd7a439dd8ddbdad49a543bc44eb8df Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 14 Jan 2016 16:16:08 -0800 Subject: [PATCH 223/357] remove DDE as component of installer --- cmake/macros/GenerateInstallers.cmake | 29 --------------------------- interface/CMakeLists.txt | 18 ----------------- 2 files changed, 47 deletions(-) diff --git a/cmake/macros/GenerateInstallers.cmake b/cmake/macros/GenerateInstallers.cmake index 1357c87261..c046a8ac1a 100644 --- a/cmake/macros/GenerateInstallers.cmake +++ b/cmake/macros/GenerateInstallers.cmake @@ -56,40 +56,11 @@ macro(GENERATE_INSTALLERS) set(CPACK_OSX_PACKAGE_VERSION ${CMAKE_OSX_DEPLOYMENT_TARGET}) endif () - # setup downloads - cpack_configure_downloads( - http://hifi-production.s3.amazonaws.com/optionals/ - ADD_REMOVE - ) - - set(CLIENT_GROUP client-group) - - # add a component group for the client - cpack_add_component_group( - ${CLIENT_GROUP} - DISPLAY_NAME "Client" - EXPANDED - ) - cpack_add_component( ${CLIENT_COMPONENT} DISPLAY_NAME "High Fidelity Client" - GROUP ${CLIENT_GROUP} ) - if (WIN32 AND DEFINED ENV{DDE_ARCHIVE_DIR}) - # add a download component for DDE - cpack_add_component( - ${DDE_COMPONENT} - DISPLAY_NAME "Webcam Body Movement" - DEPENDS ${CLIENT_COMPONENT} - DOWNLOADED - DISABLE - GROUP ${CLIENT_GROUP} - ARCHIVE_FILE "DDE" - ) - endif () - cpack_add_component(${SERVER_COMPONENT} DISPLAY_NAME "High Fidelity Server" ) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 2649462477..23d9c9c7f8 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -261,24 +261,6 @@ endif() # call the fixup_interface macro to add required bundling commands for installation fixup_interface() -# if present, add an install of the DDE components -# which will be presented as an option during install -if (APPLE AND DEFINED ENV{DDE_APP_PATH}) - install( - DIRECTORY ENV{DDE_APP_PATH} - DESTINATION ${INTERFACE_INSTALL_APP_PATH}/Contents/MacOS - COMPONENT ${DDE_COMPONENT} - ) -endif () - -if (WIN32 AND DEFINED ENV{DDE_ARCHIVE_DIR}) - install( - DIRECTORY $ENV{DDE_ARCHIVE_DIR}/ - DESTINATION ${INTERFACE_INSTALL_DIR}/dde - COMPONENT ${DDE_COMPONENT} - ) -endif () - if (WIN32) set(EXTRA_DEPLOY_OPTIONS "--qmldir ${PROJECT_SOURCE_DIR}/resources/qml") endif() From 34da13c148131a1b058a703cc1dc420f72d8148e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 14 Jan 2016 16:26:58 -0800 Subject: [PATCH 224/357] test of next version of nsis modern ui --- cmake/templates/NSIS.template.in | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 152aaa1d61..3fdda07ee8 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -23,7 +23,7 @@ ;-------------------------------- ;Include Modern UI - !include "MUI.nsh" + !include "MUI2.nsh" ;Default installation folder InstallDir "@CPACK_NSIS_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_DIRECTORY@" @@ -741,7 +741,7 @@ Section "-Core installation" Push "Contact" Push "@CPACK_NSIS_CONTACT@" Call ConditionalAddToRegisty - !insertmacro MUI_INSTALLOPTIONS_READ $INSTALL_DESKTOP "NSIS.InstallOptions.ini" "Field 5" "State" + !insertmacro INSTALLOPTIONS_READ $INSTALL_DESKTOP "NSIS.InstallOptions.ini" "Field 5" "State" !insertmacro MUI_STARTMENU_WRITE_BEGIN Application ;Create shortcuts @@ -773,9 +773,9 @@ Section "-Core installation" CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" "$INSTDIR\@UNINSTALLER_NAME@" ;Read a value from an InstallOptions INI file - !insertmacro MUI_INSTALLOPTIONS_READ $DO_NOT_ADD_TO_PATH "NSIS.InstallOptions.ini" "Field 2" "State" - !insertmacro MUI_INSTALLOPTIONS_READ $ADD_TO_PATH_ALL_USERS "NSIS.InstallOptions.ini" "Field 3" "State" - !insertmacro MUI_INSTALLOPTIONS_READ $ADD_TO_PATH_CURRENT_USER "NSIS.InstallOptions.ini" "Field 4" "State" + !insertmacro INSTALLOPTIONS_READ $DO_NOT_ADD_TO_PATH "NSIS.InstallOptions.ini" "Field 2" "State" + !insertmacro INSTALLOPTIONS_READ $ADD_TO_PATH_ALL_USERS "NSIS.InstallOptions.ini" "Field 3" "State" + !insertmacro INSTALLOPTIONS_READ $ADD_TO_PATH_CURRENT_USER "NSIS.InstallOptions.ini" "Field 4" "State" ; Write special uninstall registry entries Push "StartMenu" @@ -812,7 +812,7 @@ SectionEnd ; Create custom pages Function InstallOptionsPage !insertmacro MUI_HEADER_TEXT "Install Options" "Choose options for installing @CPACK_NSIS_PACKAGE_NAME@" - !insertmacro MUI_INSTALLOPTIONS_DISPLAY "NSIS.InstallOptions.ini" + !insertmacro INSTALLOPTIONS_DISPLAY "NSIS.InstallOptions.ini" FunctionEnd @@ -1290,7 +1290,7 @@ inst: StrCpy $INSTDIR "@CPACK_NSIS_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_DIRECTORY@" StrCmp "@CPACK_NSIS_MODIFY_PATH@" "ON" 0 noOptionsPage - !insertmacro MUI_INSTALLOPTIONS_EXTRACT "NSIS.InstallOptions.ini" + !insertmacro INSTALLOPTIONS_EXTRACT "NSIS.InstallOptions.ini" noOptionsPage: FunctionEnd From ccf459454da5b23cd61c555675929bf16bcbad9f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 14 Jan 2016 16:35:12 -0800 Subject: [PATCH 225/357] fix install options setup for MUI2 --- cmake/templates/NSIS.template.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 3fdda07ee8..d47a691805 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -677,7 +677,7 @@ FunctionEnd ReserveFile "NSIS.InstallOptions.ini" ReserveFile "@POST_INSTALL_OPTIONS_PATH@" - !insertmacro MUI_RESERVEFILE_INSTALLOPTIONS + ReserveFile "${NSISDIR}\Plugins\InstallOptions.dll" ;-------------------------------- ;Installer Sections From e474a6097135ab616d65ee8635351dd977cbe14d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 14 Jan 2016 16:38:57 -0800 Subject: [PATCH 226/357] include InstallOptions for MUI2 --- cmake/templates/NSIS.template.in | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index d47a691805..6c80dcfc01 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -24,6 +24,7 @@ ;Include Modern UI !include "MUI2.nsh" + !include "InstallOptions.nsh" ;Default installation folder InstallDir "@CPACK_NSIS_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_DIRECTORY@" From 41a58f7ef4a15de5aebb621e849a3b7e21b77d43 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 15 Jan 2016 10:07:22 -0800 Subject: [PATCH 227/357] fix interface missing alert text --- console/src/main.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/console/src/main.js b/console/src/main.js index 16ac4c1008..8576e6d907 100644 --- a/console/src/main.js +++ b/console/src/main.js @@ -248,7 +248,7 @@ function goHomeClicked() { startInterface('hifi://localhost'); } else { // show an error to say that we can't go home without an interface instance - dialog.showErrorBox("Client Not Found", binaryMissingMessage("High Fidelity Client", "Interface", false)); + dialog.showErrorBox("Client Not Found", binaryMissingMessage("High Fidelity client", "Interface", false)); } } @@ -323,7 +323,7 @@ function buildMenuArray(serverState) { }, { label: 'Go Home', - click: function() { startInterface('hifi://localhost'); }, + click: goHomeClicked, enabled: false }, { From 3e3831dbdd207ee6a335e8b1fc274312b1e1d5ca Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 15 Jan 2016 10:21:33 -0800 Subject: [PATCH 228/357] assume that production console is an app bundle on OS X --- console/src/modules/path-finder.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/console/src/modules/path-finder.js b/console/src/modules/path-finder.js index ce4d4e350f..da8016eb7c 100644 --- a/console/src/modules/path-finder.js +++ b/console/src/modules/path-finder.js @@ -33,17 +33,21 @@ exports.searchPaths = function(name, binaryType) { path.join(path.dirname(process.execPath), name + extension) ]; - // check if we're inside an app bundle on OS X + // assume we're inside an app bundle on OS X if (process.platform == "darwin") { var contentPath = ".app/Contents/"; var contentEndIndex = __dirname.indexOf(contentPath); if (contentEndIndex != -1) { - // this is an app bundle, check in Contents/MacOS for the binaries - var appPath = __dirname.substring(0, contentEndIndex); - appPath += ".app/Contents/MacOS/Components.app/Contents/MacOS/"; + // this is an app bundle + var appPath = __dirname.substring(0, contentEndIndex) + ".app"; - paths.push(appPath + name + extension); + // check in Contents/MacOS for the binaries + var componentsPath = appPath + "/Contents/MacOS/Components.app/Contents/MacOS/"; + paths.push(componentsPath + name + extension); + + // check beside the app bundle for the binaries + paths.push(path.join(path.dirname(appPath), name + extension)); } } } From c1a9a7f4c1e9dec157ceb2d067a6d0d7d80ccad7 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 15 Jan 2016 10:33:53 -0800 Subject: [PATCH 229/357] add ssleay copy for win AC/DS/Interface --- assignment-client/CMakeLists.txt | 2 + cmake/templates/FixupBundlePostBuild.cmake.in | 63 ++++++++++--------- domain-server/CMakeLists.txt | 1 + interface/CMakeLists.txt | 1 + 4 files changed, 37 insertions(+), 30 deletions(-) diff --git a/assignment-client/CMakeLists.txt b/assignment-client/CMakeLists.txt index 19f856c6eb..9c8f6bdb78 100644 --- a/assignment-client/CMakeLists.txt +++ b/assignment-client/CMakeLists.txt @@ -9,5 +9,7 @@ link_hifi_libraries( controllers physics ) +set(MANUAL_SSLEAY_COPY TRUE) package_libraries_for_deployment() + install_beside_console() diff --git a/cmake/templates/FixupBundlePostBuild.cmake.in b/cmake/templates/FixupBundlePostBuild.cmake.in index 6e3ad9723b..3bdc025e11 100644 --- a/cmake/templates/FixupBundlePostBuild.cmake.in +++ b/cmake/templates/FixupBundlePostBuild.cmake.in @@ -1,56 +1,59 @@ -# +# # FixupBundlePostBuild.cmake.in # cmake/templates -# +# # Copyright 2015 High Fidelity, Inc. # Created by Stephen Birarda on February 13, 2014 # # Distributed under the Apache License, Version 2.0. # See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -# +# include(BundleUtilities) - -# replace copy_resolved_item_into_bundle +# replace copy_resolved_item_into_bundle # # The official version of copy_resolved_item_into_bundle will print out a "warning:" when # the resolved item matches the resolved embedded item. This not not really an issue that # should rise to the level of a "warning" so we replace this message with a "status:" # function(copy_resolved_item_into_bundle resolved_item resolved_embedded_item) - if(WIN32) - # ignore case on Windows - string(TOLOWER "${resolved_item}" resolved_item_compare) - string(TOLOWER "${resolved_embedded_item}" resolved_embedded_item_compare) - else() - set(resolved_item_compare "${resolved_item}") - set(resolved_embedded_item_compare "${resolved_embedded_item}") - endif() + if (WIN32) + # ignore case on Windows + string(TOLOWER "${resolved_item}" resolved_item_compare) + string(TOLOWER "${resolved_embedded_item}" resolved_embedded_item_compare) + else() + set(resolved_item_compare "${resolved_item}") + set(resolved_embedded_item_compare "${resolved_embedded_item}") + endif() - if("${resolved_item_compare}" STREQUAL "${resolved_embedded_item_compare}") - # this is our only change from the original version - message(STATUS "status: resolved_item == resolved_embedded_item - not copying...") - else() - #message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy ${resolved_item} ${resolved_embedded_item}") - execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${resolved_item}" "${resolved_embedded_item}") - if(UNIX AND NOT APPLE) - file(RPATH_REMOVE FILE "${resolved_embedded_item}") - endif() + if ("${resolved_item_compare}" STREQUAL "${resolved_embedded_item_compare}") + # this is our only change from the original version + message(STATUS "status: resolved_item == resolved_embedded_item - not copying...") + else() + #message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy ${resolved_item} ${resolved_embedded_item}") + execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${resolved_item}" "${resolved_embedded_item}") + if(UNIX AND NOT APPLE) + file(RPATH_REMOVE FILE "${resolved_embedded_item}") endif() + endif() endfunction() message(STATUS "FIXUP_LIBS for fixup_bundle called for bundle ${BUNDLE_EXECUTABLE} are @FIXUP_LIBS@") - message(STATUS "Scanning for plugins from ${BUNDLE_PLUGIN_DIR}") if (APPLE) - set(PLUGIN_EXTENSION "dylib") -elseif (WIN32) - set(PLUGIN_EXTENSION "dll") -else() - set(PLUGIN_EXTENSION "so") + set(PLUGIN_EXTENSION "dylib") +elseif (WIN32) + set(PLUGIN_EXTENSION "dll") +else() + set(PLUGIN_EXTENSION "so") endif() -file(GLOB RUNTIME_PLUGINS "${BUNDLE_PLUGIN_DIR}/*.${PLUGIN_EXTENSION}") -fixup_bundle("${BUNDLE_EXECUTABLE}" "${RUNTIME_PLUGINS}" "@FIXUP_LIBS@") +file(GLOB EXTRA_LIBRARIES "${BUNDLE_PLUGIN_DIR}/*.${PLUGIN_EXTENSION}") + +if (MANUAL_SSLEAY_COPY) + file(SET EXTRA_LIBRARIES ${EXTRA_LIBRARIES} "ssleay32.dll") +endif() + +fixup_bundle("${BUNDLE_EXECUTABLE}" "${EXTRA_LIBRARIES}" "@FIXUP_LIBS@") diff --git a/domain-server/CMakeLists.txt b/domain-server/CMakeLists.txt index 347757ae38..cbea7ef34c 100644 --- a/domain-server/CMakeLists.txt +++ b/domain-server/CMakeLists.txt @@ -36,6 +36,7 @@ if (UNIX) target_link_libraries(${TARGET_NAME} ${CMAKE_DL_LIBS}) endif (UNIX) +set(MANUAL_SSLEAY_COPY TRUE) package_libraries_for_deployment() install_beside_console() diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 23d9c9c7f8..fc6bf77033 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -265,4 +265,5 @@ if (WIN32) set(EXTRA_DEPLOY_OPTIONS "--qmldir ${PROJECT_SOURCE_DIR}/resources/qml") endif() +set(MANUAL_SSLEAY_COPY TRUE) package_libraries_for_deployment() From e19b61bcbf8d6548f6bfeafb87bd431d777f53de Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 15 Jan 2016 10:36:11 -0800 Subject: [PATCH 230/357] fixup the only used ssleay library --- cmake/templates/FixupBundlePostBuild.cmake.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/templates/FixupBundlePostBuild.cmake.in b/cmake/templates/FixupBundlePostBuild.cmake.in index 3bdc025e11..e7dcfe757d 100644 --- a/cmake/templates/FixupBundlePostBuild.cmake.in +++ b/cmake/templates/FixupBundlePostBuild.cmake.in @@ -53,7 +53,7 @@ endif() file(GLOB EXTRA_LIBRARIES "${BUNDLE_PLUGIN_DIR}/*.${PLUGIN_EXTENSION}") if (MANUAL_SSLEAY_COPY) - file(SET EXTRA_LIBRARIES ${EXTRA_LIBRARIES} "ssleay32.dll") + file(SET EXTRA_LIBRARIES ${EXTRA_LIBRARIES} ${SSL_EAY_LIBRARY_RELEASE}) endif() fixup_bundle("${BUNDLE_EXECUTABLE}" "${EXTRA_LIBRARIES}" "@FIXUP_LIBS@") From bb9f7856f4e2c70379956facca530126c50c5869 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 15 Jan 2016 10:41:08 -0800 Subject: [PATCH 231/357] use cmake generator expression to fixup correct ssleay --- cmake/templates/FixupBundlePostBuild.cmake.in | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmake/templates/FixupBundlePostBuild.cmake.in b/cmake/templates/FixupBundlePostBuild.cmake.in index e7dcfe757d..75513a033f 100644 --- a/cmake/templates/FixupBundlePostBuild.cmake.in +++ b/cmake/templates/FixupBundlePostBuild.cmake.in @@ -53,7 +53,8 @@ endif() file(GLOB EXTRA_LIBRARIES "${BUNDLE_PLUGIN_DIR}/*.${PLUGIN_EXTENSION}") if (MANUAL_SSLEAY_COPY) - file(SET EXTRA_LIBRARIES ${EXTRA_LIBRARIES} ${SSL_EAY_LIBRARY_RELEASE}) + message(STATUS "Adding $<$:"@SSL_EAY_LIBRARY_DEBUG@"> $<$>:"@SSL_EAY_LIBRARY_RELEASE@"> to fixed up libraries") + list(APPEND EXTRA_LIBRARIES $<$:${SSL_EAY_LIBRARY_DEBUG}> $<$>:${SSL_EAY_LIBRARY_RELEASE}>) endif() fixup_bundle("${BUNDLE_EXECUTABLE}" "${EXTRA_LIBRARIES}" "@FIXUP_LIBS@") From 05e48528bdd515f64d47b3a214653324147b6c41 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 15 Jan 2016 11:01:14 -0800 Subject: [PATCH 232/357] make sure SSL_EAY_LIBRARY_* is set when used --- assignment-client/CMakeLists.txt | 9 +++++++-- cmake/templates/FixupBundlePostBuild.cmake.in | 6 +++--- domain-server/CMakeLists.txt | 8 +++++--- interface/CMakeLists.txt | 9 ++++++--- 4 files changed, 21 insertions(+), 11 deletions(-) diff --git a/assignment-client/CMakeLists.txt b/assignment-client/CMakeLists.txt index 9c8f6bdb78..0c54ad71ac 100644 --- a/assignment-client/CMakeLists.txt +++ b/assignment-client/CMakeLists.txt @@ -9,7 +9,12 @@ link_hifi_libraries( controllers physics ) -set(MANUAL_SSLEAY_COPY TRUE) -package_libraries_for_deployment() +if (WIN32) + # we need SSL_EAY_LIBRARY_* to be set before we call package_libraries_for_deployment() + # so we have to call find_package(OpenSSL) here even though this target doesn't specifically need it + find_package(OpenSSL REQUIRED) + set(MANUAL_SSLEAY_COPY TRUE) + package_libraries_for_deployment() +endif() install_beside_console() diff --git a/cmake/templates/FixupBundlePostBuild.cmake.in b/cmake/templates/FixupBundlePostBuild.cmake.in index 75513a033f..3eeeb8082d 100644 --- a/cmake/templates/FixupBundlePostBuild.cmake.in +++ b/cmake/templates/FixupBundlePostBuild.cmake.in @@ -52,9 +52,9 @@ endif() file(GLOB EXTRA_LIBRARIES "${BUNDLE_PLUGIN_DIR}/*.${PLUGIN_EXTENSION}") -if (MANUAL_SSLEAY_COPY) - message(STATUS "Adding $<$:"@SSL_EAY_LIBRARY_DEBUG@"> $<$>:"@SSL_EAY_LIBRARY_RELEASE@"> to fixed up libraries") - list(APPEND EXTRA_LIBRARIES $<$:${SSL_EAY_LIBRARY_DEBUG}> $<$>:${SSL_EAY_LIBRARY_RELEASE}>) +if (@MANUAL_SSLEAY_COPY@) + message(STATUS "Adding $<$:@SSL_EAY_LIBRARY_DEBUG@> $<$>:@SSL_EAY_LIBRARY_RELEASE@> to fixed up libraries") + list(APPEND EXTRA_LIBRARIES "$<$:@SSL_EAY_LIBRARY_DEBUG@>" "$<$>:@SSL_EAY_LIBRARY_RELEASE@>") endif() fixup_bundle("${BUNDLE_EXECUTABLE}" "${EXTRA_LIBRARIES}" "@FIXUP_LIBS@") diff --git a/domain-server/CMakeLists.txt b/domain-server/CMakeLists.txt index cbea7ef34c..08bd39190a 100644 --- a/domain-server/CMakeLists.txt +++ b/domain-server/CMakeLists.txt @@ -34,9 +34,11 @@ target_link_libraries(${TARGET_NAME} ${OPENSSL_LIBRARIES}) # libcrypto uses dlopen in libdl if (UNIX) target_link_libraries(${TARGET_NAME} ${CMAKE_DL_LIBS}) -endif (UNIX) +endif () -set(MANUAL_SSLEAY_COPY TRUE) -package_libraries_for_deployment() +if (WIN32) + set(MANUAL_SSLEAY_COPY TRUE) + package_libraries_for_deployment() +endif () install_beside_console() diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index fc6bf77033..482adea848 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -263,7 +263,10 @@ fixup_interface() if (WIN32) set(EXTRA_DEPLOY_OPTIONS "--qmldir ${PROJECT_SOURCE_DIR}/resources/qml") -endif() -set(MANUAL_SSLEAY_COPY TRUE) -package_libraries_for_deployment() + # we need SSL_EAY_LIBRARY_* to be set before we call package_libraries_for_deployment() + # so we have to call find_package(OpenSSL) here even though this target doesn't specifically need it + find_package(OpenSSL REQUIRED) + set(MANUAL_SSLEAY_COPY TRUE) + package_libraries_for_deployment() +endif() From 29b5076da4b29e3976385cd3a255100cd16cd497 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 15 Jan 2016 11:13:42 -0800 Subject: [PATCH 233/357] set a variable in template to boolean --- cmake/templates/FixupBundlePostBuild.cmake.in | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmake/templates/FixupBundlePostBuild.cmake.in b/cmake/templates/FixupBundlePostBuild.cmake.in index 3eeeb8082d..fce74db31c 100644 --- a/cmake/templates/FixupBundlePostBuild.cmake.in +++ b/cmake/templates/FixupBundlePostBuild.cmake.in @@ -52,7 +52,8 @@ endif() file(GLOB EXTRA_LIBRARIES "${BUNDLE_PLUGIN_DIR}/*.${PLUGIN_EXTENSION}") -if (@MANUAL_SSLEAY_COPY@) +set(MANUAL_SSLEAY_COPY @MANUAL_SSLEAY_COPY@) +if (MANUAL_SSLEAY_COPY) message(STATUS "Adding $<$:@SSL_EAY_LIBRARY_DEBUG@> $<$>:@SSL_EAY_LIBRARY_RELEASE@> to fixed up libraries") list(APPEND EXTRA_LIBRARIES "$<$:@SSL_EAY_LIBRARY_DEBUG@>" "$<$>:@SSL_EAY_LIBRARY_RELEASE@>") endif() From cf5b6198fde02654e8a97e255720687f26800333 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 15 Jan 2016 11:50:39 -0800 Subject: [PATCH 234/357] use install command to manually place ssleay library --- assignment-client/CMakeLists.txt | 5 +--- cmake/macros/InstallBesideConsole.cmake | 4 +++ cmake/macros/ManuallyInstallSSLEay.cmake | 28 +++++++++++++++++++ .../PackageLibrariesForDeployment.cmake | 1 - cmake/templates/FixupBundlePostBuild.cmake.in | 11 ++------ domain-server/CMakeLists.txt | 2 +- interface/CMakeLists.txt | 8 +++--- 7 files changed, 40 insertions(+), 19 deletions(-) create mode 100644 cmake/macros/ManuallyInstallSSLEay.cmake diff --git a/assignment-client/CMakeLists.txt b/assignment-client/CMakeLists.txt index 0c54ad71ac..3a2106250c 100644 --- a/assignment-client/CMakeLists.txt +++ b/assignment-client/CMakeLists.txt @@ -10,11 +10,8 @@ link_hifi_libraries( ) if (WIN32) - # we need SSL_EAY_LIBRARY_* to be set before we call package_libraries_for_deployment() - # so we have to call find_package(OpenSSL) here even though this target doesn't specifically need it - find_package(OpenSSL REQUIRED) - set(MANUAL_SSLEAY_COPY TRUE) package_libraries_for_deployment() endif() install_beside_console() +manually_install_ssl_eay() diff --git a/cmake/macros/InstallBesideConsole.cmake b/cmake/macros/InstallBesideConsole.cmake index f076c856f8..d34f54ed77 100644 --- a/cmake/macros/InstallBesideConsole.cmake +++ b/cmake/macros/InstallBesideConsole.cmake @@ -64,4 +64,8 @@ macro(install_beside_console) endif () endif () + # set variables used by manual ssleay library copy + set(TARGET_INSTALL_DIR ${COMPONENT_DESTINATION}) + set(TARGET_INSTALL_COMPONENT ${SERVER_COMPONENT}) + endmacro() diff --git a/cmake/macros/ManuallyInstallSSLEay.cmake b/cmake/macros/ManuallyInstallSSLEay.cmake new file mode 100644 index 0000000000..405bf6b1d3 --- /dev/null +++ b/cmake/macros/ManuallyInstallSSLEay.cmake @@ -0,0 +1,28 @@ +# +# ManuallyInstallSSLEay.cmake +# +# Created by Stephen Birarda on 1/15/16. +# Copyright 2014 High Fidelity, Inc. +# +# Distributed under the Apache License, Version 2.0. +# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +# + +macro(manually_install_ssl_eay) + + # on windows we have had issues with targets missing ssleay library + # not convinced we actually need it (I assume it would show up in the dependency tree) + # but to be safe we install it manually beside the current target + if (WIN32) + # we need to find SSL_EAY_LIBRARY_* so we can install it beside this target + # so we have to call find_package(OpenSSL) here even though this target may not specifically need it + find_package(OpenSSL REQUIRED) + + install( + FILES $<$:${SSL_EAY_LIBRARY_DEBUG}> $<$>:${SSL_EAY_LIBRARY_RELEASE}> + DESTINATION ${TARGET_INSTALL_DIR} + COMPONENT ${TARGET_INSTALL_COMPONENT} + ) + endif() + +endmacro() diff --git a/cmake/macros/PackageLibrariesForDeployment.cmake b/cmake/macros/PackageLibrariesForDeployment.cmake index 322afc52e0..050cea9fe1 100644 --- a/cmake/macros/PackageLibrariesForDeployment.cmake +++ b/cmake/macros/PackageLibrariesForDeployment.cmake @@ -10,7 +10,6 @@ # macro(PACKAGE_LIBRARIES_FOR_DEPLOYMENT) - if (WIN32) configure_file( ${HF_CMAKE_DIR}/templates/FixupBundlePostBuild.cmake.in diff --git a/cmake/templates/FixupBundlePostBuild.cmake.in b/cmake/templates/FixupBundlePostBuild.cmake.in index fce74db31c..57d1fd787f 100644 --- a/cmake/templates/FixupBundlePostBuild.cmake.in +++ b/cmake/templates/FixupBundlePostBuild.cmake.in @@ -50,12 +50,5 @@ else() set(PLUGIN_EXTENSION "so") endif() -file(GLOB EXTRA_LIBRARIES "${BUNDLE_PLUGIN_DIR}/*.${PLUGIN_EXTENSION}") - -set(MANUAL_SSLEAY_COPY @MANUAL_SSLEAY_COPY@) -if (MANUAL_SSLEAY_COPY) - message(STATUS "Adding $<$:@SSL_EAY_LIBRARY_DEBUG@> $<$>:@SSL_EAY_LIBRARY_RELEASE@> to fixed up libraries") - list(APPEND EXTRA_LIBRARIES "$<$:@SSL_EAY_LIBRARY_DEBUG@>" "$<$>:@SSL_EAY_LIBRARY_RELEASE@>") -endif() - -fixup_bundle("${BUNDLE_EXECUTABLE}" "${EXTRA_LIBRARIES}" "@FIXUP_LIBS@") +file(GLOB EXTRA_PLUGINS "${BUNDLE_PLUGIN_DIR}/*.${PLUGIN_EXTENSION}") +fixup_bundle("${BUNDLE_EXECUTABLE}" "${EXTRA_PLUGINS}" "@FIXUP_LIBS@") diff --git a/domain-server/CMakeLists.txt b/domain-server/CMakeLists.txt index 08bd39190a..e48657e20e 100644 --- a/domain-server/CMakeLists.txt +++ b/domain-server/CMakeLists.txt @@ -37,8 +37,8 @@ if (UNIX) endif () if (WIN32) - set(MANUAL_SSLEAY_COPY TRUE) package_libraries_for_deployment() endif () install_beside_console() +manually_install_ssl_eay() diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 482adea848..91a0abb3ee 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -264,9 +264,9 @@ fixup_interface() if (WIN32) set(EXTRA_DEPLOY_OPTIONS "--qmldir ${PROJECT_SOURCE_DIR}/resources/qml") - # we need SSL_EAY_LIBRARY_* to be set before we call package_libraries_for_deployment() - # so we have to call find_package(OpenSSL) here even though this target doesn't specifically need it - find_package(OpenSSL REQUIRED) - set(MANUAL_SSLEAY_COPY TRUE) + set(TARGET_INSTALL_DIR ${INTERFACE_INSTALL_DIR}) + set(TARGET_INSTALL_COMPONENT ${CLIENT_COMPONENT}) + manually_install_ssl_eay() + package_libraries_for_deployment() endif() From 0876da7a7d795f8f27725dd8cbd56a0ec1b258cf Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 15 Jan 2016 13:03:18 -0800 Subject: [PATCH 235/357] call manual install of ssleay from console install --- assignment-client/CMakeLists.txt | 1 - cmake/macros/InstallBesideConsole.cmake | 1 + domain-server/CMakeLists.txt | 1 - 3 files changed, 1 insertion(+), 2 deletions(-) diff --git a/assignment-client/CMakeLists.txt b/assignment-client/CMakeLists.txt index 3a2106250c..3c102e1f02 100644 --- a/assignment-client/CMakeLists.txt +++ b/assignment-client/CMakeLists.txt @@ -14,4 +14,3 @@ if (WIN32) endif() install_beside_console() -manually_install_ssl_eay() diff --git a/cmake/macros/InstallBesideConsole.cmake b/cmake/macros/InstallBesideConsole.cmake index d34f54ed77..e30a25a0f8 100644 --- a/cmake/macros/InstallBesideConsole.cmake +++ b/cmake/macros/InstallBesideConsole.cmake @@ -67,5 +67,6 @@ macro(install_beside_console) # set variables used by manual ssleay library copy set(TARGET_INSTALL_DIR ${COMPONENT_DESTINATION}) set(TARGET_INSTALL_COMPONENT ${SERVER_COMPONENT}) + manually_install_ssl_eay() endmacro() diff --git a/domain-server/CMakeLists.txt b/domain-server/CMakeLists.txt index e48657e20e..b7eb8c0138 100644 --- a/domain-server/CMakeLists.txt +++ b/domain-server/CMakeLists.txt @@ -41,4 +41,3 @@ if (WIN32) endif () install_beside_console() -manually_install_ssl_eay() From 6e8b54bc65fbaf29b2b553b127914ce7667cf337 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 15 Jan 2016 13:15:53 -0800 Subject: [PATCH 236/357] remove the branding tag in installer --- cmake/templates/NSIS.template.in | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 6c80dcfc01..1b5d22e430 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -36,6 +36,7 @@ ; Set name prior to inner loop so uninstaller has correct values Name "@CPACK_NSIS_PACKAGE_NAME@" + BrandingText " " !ifdef INNER !echo "Inner invocation" ; just to see what's going on From e3c9860f647ccc4df2beb738bd02700d64abda01 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 15 Jan 2016 13:46:58 -0800 Subject: [PATCH 237/357] add a dummy share option to the menu --- console/src/main.js | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/console/src/main.js b/console/src/main.js index 8576e6d907..668ddf304f 100644 --- a/console/src/main.js +++ b/console/src/main.js @@ -315,7 +315,7 @@ function buildMenuArray(serverState) { ======= var menuArray = [ { - label: "Server - Stopped", + label: 'Server - Stopped', enabled: false }, { @@ -330,26 +330,33 @@ function buildMenuArray(serverState) { type: 'separator' }, { - label: "Start Server", + label: 'Start Server', click: function() { homeServer.restart(); } }, { - label: "Stop Server", + label: 'Stop Server', visible: false, click: function() { homeServer.stop(); } }, { - label: "Settings", + label: 'Settings', click: function() { shell.openExternal('http://localhost:40100/settings'); }, enabled: false }, { - label: "View Logs", + label: 'View Logs', click: function() { openFileBrowser(logPath); } }, { type: 'separator' }, + { + label: 'Share', + click: function() { } + }, + { + type: 'separator' + }, { label: 'Quit', accelerator: 'Command+Q', From 4e948179597cc25d3b21915e935b9ca474cad5d0 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 15 Jan 2016 15:09:42 -0800 Subject: [PATCH 238/357] hookup share when passed action on settings page --- console/src/main.js | 2 +- .../resources/web/settings/js/settings.js | 129 +++++++++++++++--- .../web/settings/js/sweetalert.min.js | 2 +- 3 files changed, 114 insertions(+), 19 deletions(-) diff --git a/console/src/main.js b/console/src/main.js index 668ddf304f..d37b3f4ee7 100644 --- a/console/src/main.js +++ b/console/src/main.js @@ -352,7 +352,7 @@ function buildMenuArray(serverState) { }, { label: 'Share', - click: function() { } + click: function() { shell.openExternal('http://localhost:40100/settings/?action=share') } }, { type: 'separator' diff --git a/domain-server/resources/web/settings/js/settings.js b/domain-server/resources/web/settings/js/settings.js index c733256fe3..ddd0c471ad 100644 --- a/domain-server/resources/web/settings/js/settings.js +++ b/domain-server/resources/web/settings/js/settings.js @@ -126,6 +126,20 @@ var viewHelpers = { } } +var qs = (function(a) { + if (a == "") return {}; + var b = {}; + for (var i = 0; i < a.length; ++i) + { + var p=a[i].split('=', 2); + if (p.length == 1) + b[p[0]] = ""; + else + b[p[0]] = decodeURIComponent(p[1].replace(/\+/g, " ")); + } + return b; +})(window.location.search.substr(1).split('&')); + $(document).ready(function(){ /* * Clamped-width. @@ -272,9 +286,80 @@ $(document).ready(function(){ // $('body').scrollspy({ target: '#setup-sidebar'}) - reloadSettings(); + reloadSettings(function(success){ + if (success) { + handleAction(); + } else { + swal({ + title: '', + type: 'error', + text: "There was a problem loading the domain settings.\nPlease refresh the page to try again.", + }); + } + }); }); +function handleAction() { + // check if we were passed an action to handle + var action = qs["action"]; + + if (action == "share") { + // figure out if we already have a stored domain ID + if (Settings.data.values.metaverse.id.length > 0) { + // we need to ask the API what a shareable name for this domain is + getDomainFromAPI(function(data){ + // check if we have owner_places (for a real domain) or a name (for a temporary domain) + if (data && data.status == "success") { + var shareName; + if (data.domain.owner_places) { + shareName = data.domain.owner_places[0].name + } else if (data.domain.name) { + shareName = data.domain.name; + } + + var shareLink = "hifi://" + shareName; + + console.log(shareLink); + + // show a dialog with a copiable share URL + swal({ + title: "Share", + type: "input", + inputPlaceholder: shareLink, + inputValue: shareLink, + text: "Copy this URL to invite friends to your domain.", + closeOnConfirm: true + }); + + $('.sweet-alert input').select(); + + } else { + // show an error alert + swal({ + title: '', + type: 'error', + text: "There was a problem retreiving domain information from High Fidelity API.", + confirmButtonText: 'Try again', + showCancelButton: true, + closeOnConfirm: false + }, function(isConfirm){ + if (isConfirm) { + // they want to try getting domain share info again + showSpinnerAlert("Requesting domain information...") + handleAction(); + } else { + swal.close(); + } + }); + } + }); + } else { + // no domain ID present, just show the share dialog + createTemporaryDomain(); + } + } +} + function dynamicButton(button_id, text) { return $(""); } @@ -577,29 +662,33 @@ function placeTableRowForPlaceObject(place) { return placeTableRow(place.name, placePathOrIndex, false); } -function reloadPlacesOrTemporaryName() { +function getDomainFromAPI(callback) { // we only need to do this if we have a current domain ID var domainID = Settings.data.values.metaverse.id; if (domainID.length > 0) { var domainURL = Settings.METAVERSE_URL + "/api/v1/domains/" + domainID; - $.getJSON(domainURL, function(data){ - // check if we have owner_places (for a real domain) or a name (for a temporary domain) - if (data.status == "success") { - if (data.domain.owner_places) { - // add a table row for each of these names - _.each(data.domain.owner_places, function(place){ - $('#' + Settings.PLACES_TABLE_ID + " tbody").append(placeTableRowForPlaceObject(place)); - }); - } else if (data.domain.name) { - // add a table row for this temporary domain name - $('#' + Settings.PLACES_TABLE_ID + " tbody").append(placeTableRow(data.domain.name, '/', true)); - } - } - }); + $.getJSON(domainURL, function(data){ callback(data) }).fail(callback); } } +function reloadPlacesOrTemporaryName() { + getDomainFromAPI(function(data){ + // check if we have owner_places (for a real domain) or a name (for a temporary domain) + if (data.status == "success") { + if (data.domain.owner_places) { + // add a table row for each of these names + _.each(data.domain.owner_places, function(place){ + $('#' + Settings.PLACES_TABLE_ID + " tbody").append(placeTableRowForPlaceObject(place)); + }); + } else if (data.domain.name) { + // add a table row for this temporary domain name + $('#' + Settings.PLACES_TABLE_ID + " tbody").append(placeTableRow(data.domain.name, '/', true)); + } + } + }) +} + function appendDomainIDButtons() { var domainIDInput = $(Settings.DOMAIN_ID_SELECTOR); @@ -728,7 +817,7 @@ function createTemporaryDomain() { }); } -function reloadSettings() { +function reloadSettings(callback) { $.getJSON('/settings.json', function(data){ _.extend(data, viewHelpers) @@ -757,6 +846,12 @@ function reloadSettings() { placement: 'right', title: 'This setting is in the master config file and cannot be changed' }); + + // call the callback now that settings are loaded + callback(true); + }).fail(function() { + // call the failure object since settings load faild + callback(false) }); } diff --git a/domain-server/resources/web/settings/js/sweetalert.min.js b/domain-server/resources/web/settings/js/sweetalert.min.js index d81d1e906b..5c029c2532 100755 --- a/domain-server/resources/web/settings/js/sweetalert.min.js +++ b/domain-server/resources/web/settings/js/sweetalert.min.js @@ -1 +1 @@ -!function(e,t,n){"use strict";!function o(e,t,n){function a(s,l){if(!t[s]){if(!e[s]){var i="function"==typeof require&&require;if(!l&&i)return i(s,!0);if(r)return r(s,!0);var u=new Error("Cannot find module '"+s+"'");throw u.code="MODULE_NOT_FOUND",u}var c=t[s]={exports:{}};e[s][0].call(c.exports,function(t){var n=e[s][1][t];return a(n?n:t)},c,c.exports,o,e,t,n)}return t[s].exports}for(var r="function"==typeof require&&require,s=0;s=0;)n=n.replace(" "+t+" "," ");e.className=n.replace(/^\s+|\s+$/g,"")}},i=function(e){var n=t.createElement("div");return n.appendChild(t.createTextNode(e)),n.innerHTML},u=function(e){e.style.opacity="",e.style.display="block"},c=function(e){if(e&&!e.length)return u(e);for(var t=0;t0?setTimeout(o,t):e.style.display="none"});o()},h=function(n){if("function"==typeof MouseEvent){var o=new MouseEvent("click",{view:e,bubbles:!1,cancelable:!0});n.dispatchEvent(o)}else if(t.createEvent){var a=t.createEvent("MouseEvents");a.initEvent("click",!1,!1),n.dispatchEvent(a)}else t.createEventObject?n.fireEvent("onclick"):"function"==typeof n.onclick&&n.onclick()},g=function(t){"function"==typeof t.stopPropagation?(t.stopPropagation(),t.preventDefault()):e.event&&e.event.hasOwnProperty("cancelBubble")&&(e.event.cancelBubble=!0)};a.hasClass=r,a.addClass=s,a.removeClass=l,a.escapeHtml=i,a._show=u,a.show=c,a._hide=d,a.hide=f,a.isDescendant=p,a.getTopMargin=m,a.fadeIn=v,a.fadeOut=y,a.fireClick=h,a.stopEventPropagation=g},{}],5:[function(t,o,a){Object.defineProperty(a,"__esModule",{value:!0});var r=t("./handle-dom"),s=t("./handle-swal-dom"),l=function(t,o,a){var l=t||e.event,i=l.keyCode||l.which,u=a.querySelector("button.confirm"),c=a.querySelector("button.cancel"),d=a.querySelectorAll("button[tabindex]");if(-1!==[9,13,32,27].indexOf(i)){for(var f=l.target||l.srcElement,p=-1,m=0;m"),i.innerHTML=e.html?e.text:s.escapeHtml(e.text||"").split("\n").join("
"),e.text&&s.show(i),e.customClass)s.addClass(t,e.customClass),t.setAttribute("data-custom-class",e.customClass);else{var d=t.getAttribute("data-custom-class");s.removeClass(t,d),t.setAttribute("data-custom-class","")}if(s.hide(t.querySelectorAll(".sa-icon")),e.type&&!a.isIE8()){var f=function(){for(var o=!1,a=0;ao;o++)n=parseInt(e.substr(2*o,2),16),n=Math.round(Math.min(Math.max(0,n+n*t),255)).toString(16),a+=("00"+n).substr(n.length);return a};o.extend=a,o.hexToRgb=r,o.isIE8=s,o.logStr=l,o.colorLuminance=i},{}]},{},[1])}(window,document); \ No newline at end of file +!function(e,t,n){"use strict";!function o(e,t,n){function a(s,l){if(!t[s]){if(!e[s]){var i="function"==typeof require&&require;if(!l&&i)return i(s,!0);if(r)return r(s,!0);var u=new Error("Cannot find module '"+s+"'");throw u.code="MODULE_NOT_FOUND",u}var c=t[s]={exports:{}};e[s][0].call(c.exports,function(t){var n=e[s][1][t];return a(n?n:t)},c,c.exports,o,e,t,n)}return t[s].exports}for(var r="function"==typeof require&&require,s=0;s=0;)n=n.replace(" "+t+" "," ");e.className=n.replace(/^\s+|\s+$/g,"")}},i=function(e){var n=t.createElement("div");return n.appendChild(t.createTextNode(e)),n.innerHTML},u=function(e){e.style.opacity="",e.style.display="block"},c=function(e){if(e&&!e.length)return u(e);for(var t=0;t0?setTimeout(o,t):e.style.display="none"});o()},h=function(n){if("function"==typeof MouseEvent){var o=new MouseEvent("click",{view:e,bubbles:!1,cancelable:!0});n.dispatchEvent(o)}else if(t.createEvent){var a=t.createEvent("MouseEvents");a.initEvent("click",!1,!1),n.dispatchEvent(a)}else t.createEventObject?n.fireEvent("onclick"):"function"==typeof n.onclick&&n.onclick()},b=function(t){"function"==typeof t.stopPropagation?(t.stopPropagation(),t.preventDefault()):e.event&&e.event.hasOwnProperty("cancelBubble")&&(e.event.cancelBubble=!0)};a.hasClass=r,a.addClass=s,a.removeClass=l,a.escapeHtml=i,a._show=u,a.show=c,a._hide=d,a.hide=f,a.isDescendant=p,a.getTopMargin=m,a.fadeIn=v,a.fadeOut=y,a.fireClick=h,a.stopEventPropagation=b},{}],5:[function(t,o,a){Object.defineProperty(a,"__esModule",{value:!0});var r=t("./handle-dom"),s=t("./handle-swal-dom"),l=function(t,o,a){var l=t||e.event,i=l.keyCode||l.which,u=a.querySelector("button.confirm"),c=a.querySelector("button.cancel"),d=a.querySelectorAll("button[tabindex]");if(-1!==[9,13,32,27].indexOf(i)){for(var f=l.target||l.srcElement,p=-1,m=0;m"),i.innerHTML=e.html?e.text:s.escapeHtml(e.text||"").split("\n").join("
"),e.text&&s.show(i),e.customClass)s.addClass(t,e.customClass),t.setAttribute("data-custom-class",e.customClass);else{var d=t.getAttribute("data-custom-class");s.removeClass(t,d),t.setAttribute("data-custom-class","")}if(s.hide(t.querySelectorAll(".sa-icon")),e.type&&!a.isIE8()){var f=function(){for(var o=!1,a=0;ao;o++)n=parseInt(e.substr(2*o,2),16),n=Math.round(Math.min(Math.max(0,n+n*t),255)).toString(16),a+=("00"+n).substr(n.length);return a};o.extend=a,o.hexToRgb=r,o.isIE8=s,o.logStr=l,o.colorLuminance=i},{}]},{},[1]),"function"==typeof define&&define.amd?define(function(){return sweetAlert}):"undefined"!=typeof module&&module.exports&&(module.exports=sweetAlert)}(window,document); From 9aeda32f3fb3436ebefc32e88ae927b3fe8eb857 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 15 Jan 2016 15:30:34 -0800 Subject: [PATCH 239/357] remove committed conflict markers --- console/src/main.js | 85 ++++++++++----------------------------------- 1 file changed, 19 insertions(+), 66 deletions(-) diff --git a/console/src/main.js b/console/src/main.js index d37b3f4ee7..a214a7c687 100644 --- a/console/src/main.js +++ b/console/src/main.js @@ -255,8 +255,8 @@ function goHomeClicked() { var logWindow = null; function buildMenuArray(serverState) { -<<<<<<< HEAD var menuArray = null; + if (isShuttingDown) { menuArray = [ { @@ -266,6 +266,13 @@ function buildMenuArray(serverState) { ]; } else { menuArray = [ + { + label: 'Server - Stopped', + enabled: false + }, + { + type: 'separator' + }, { label: 'Go Home', click: goHomeClicked, @@ -275,30 +282,29 @@ function buildMenuArray(serverState) { type: 'separator' }, { - label: "Server - Stopped", - enabled: false - }, - { - label: "Start", + label: 'Start Server', click: function() { homeServer.restart(); } }, { - label: "Stop", + label: 'Stop Server', visible: false, click: function() { homeServer.stop(); } }, { - label: "Settings", + label: 'Settings', click: function() { shell.openExternal('http://localhost:40100/settings'); }, enabled: false }, { - label: "View Logs", - click: function() { logWindow.open(); } + label: 'View Logs', + click: function() { openFileBrowser(logPath); } }, { - label: "Open Log Directory", - click: function() { openFileBrowser(logPath); } + type: 'separator' + }, + { + label: 'Share', + click: function() { shell.openExternal('http://localhost:40100/settings/?action=share') } }, { type: 'separator' @@ -306,65 +312,12 @@ function buildMenuArray(serverState) { { label: 'Quit', accelerator: 'Command+Q', - click: function() { shutdown(); } + click: function() { app.quit(); } } ]; updateMenuArray(menuArray, serverState); } -======= - var menuArray = [ - { - label: 'Server - Stopped', - enabled: false - }, - { - type: 'separator' - }, - { - label: 'Go Home', - click: goHomeClicked, - enabled: false - }, - { - type: 'separator' - }, - { - label: 'Start Server', - click: function() { homeServer.restart(); } - }, - { - label: 'Stop Server', - visible: false, - click: function() { homeServer.stop(); } - }, - { - label: 'Settings', - click: function() { shell.openExternal('http://localhost:40100/settings'); }, - enabled: false - }, - { - label: 'View Logs', - click: function() { openFileBrowser(logPath); } - }, - { - type: 'separator' - }, - { - label: 'Share', - click: function() { shell.openExternal('http://localhost:40100/settings/?action=share') } - }, - { - type: 'separator' - }, - { - label: 'Quit', - accelerator: 'Command+Q', - click: function() { app.quit(); } - } - ]; ->>>>>>> shuffling and renaming of menu options - return menuArray; } From 8d47d70543e953c21caddf6df9db38355e57399d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 15 Jan 2016 15:37:22 -0800 Subject: [PATCH 240/357] remove old nsis template and image --- tools/nsis/installer_vertical.bmp | Bin 154544 -> 0 bytes tools/nsis/release.nsi | 219 ------------------------------ 2 files changed, 219 deletions(-) delete mode 100644 tools/nsis/installer_vertical.bmp delete mode 100644 tools/nsis/release.nsi diff --git a/tools/nsis/installer_vertical.bmp b/tools/nsis/installer_vertical.bmp deleted file mode 100644 index feefd2db8393d2a1b5eebdad741d59a525ab7335..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 154544 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 U03m=7KnNfN5CSnn;MJ@D4+83Kg8%>k diff --git a/tools/nsis/release.nsi b/tools/nsis/release.nsi deleted file mode 100644 index 4e79749da8..0000000000 --- a/tools/nsis/release.nsi +++ /dev/null @@ -1,219 +0,0 @@ -!include LogicLib.nsh -!include x64.nsh -!include MUI2.nsh - -;------------------------------------------------------------------------------------------------------ -; Source Directory Definition -; -; installer_srcdir = Source directory for Interface -; scripts_srcdir = Source directory for JS scripts - -!define installer_srcdir "$%INSTALLER_SOURCE_DIR%" -!define scripts_srcdir "$%INSTALLER_SCRIPTS_DIR%" - -; Install Directories, Icons and Registry entries -; -; setup = Name of the installer executable that will be produced -; uninstaller = Name of the uninstaller executable -; company = String to use for company name, includes build type suffix [eg. High Fidelity - PR] for non-release installers -; install_directory = Subdirectory where this specific version will be installed, in the case of dev and pr builds, its a -; unique subdirectory inside a company parent [eg. \High Fidelity - PR\1234\ ] - -!define setup "$%INSTALLER_NAME%" -!define uninstaller "uninstall.exe" -!define company "$%INSTALLER_COMPANY%" -!define install_directory "$%INSTALLER_DIRECTORY%" - -; Executables and icons for GUI applications that will be added as shortcuts. -!define interface_exec "interface.exe" -!define console_exec "server-console.exe" -!define interface_icon "interface.ico" -!define console_icon "server-console.ico" - -; Registry entries -!define regkey "Software\${install_directory}" -!define uninstkey "Software\Microsoft\Windows\CurrentVersion\Uninstall\${install_directory}" -!define instdir "$PROGRAMFILES64\${install_directory}" - -; Start Menu program group -!define startmenu_company "$SMPROGRAMS\${install_directory}" - -;------------------------------------------------------------------------------------------------------ -; Local Variables and Other Options - -var ChosenInstallDir - -SetCompressor bzip2 -ShowInstDetails hide -ShowUninstDetails hide -AutoCloseWindow true -ShowInstDetails show -SetDateSave on -SetDatablockOptimize on -CRCCheck on -SilentInstall normal -Icon "${installer_srcdir}\${interface_icon}" -UninstallIcon "${installer_srcdir}\${interface_icon}" -UninstallText "This will uninstall ${company}." -Name "${company}" -Caption "${company}" -OutFile "${setup}" - -;------------------------------------------------------------------------------------------------------ -; Components - -Section /o "DDE Face Recognition" "DDE" - SetOutPath "$ChosenInstallDir" - CreateDirectory $ChosenInstallDir\dde - NSISdl::download "https://s3-us-west-1.amazonaws.com/hifi-production/optionals/dde-installer.exe" "$ChosenInstallDir\dde-installer.exe" - ExecWait '"$ChosenInstallDir\dde-installer.exe" /q:a /t:"$ChosenInstallDir\dde"' -SectionEnd - -Section /o "Default Content Set" "CONTENT" - SetOutPath "$ChosenInstallDir\resources" - NSISdl::download "https://s3-us-west-1.amazonaws.com/hifi-production/content/temp.exe" "$ChosenInstallDir\content.exe" - ExecWait '"$ChosenInstallDir\content.exe" /S' - Delete "$ChosenInstallDir\content.exe" -SectionEnd - -Section "Registry Entries and Protocol Handler" "REGISTRY" - SetRegView 64 - SectionIn RO - WriteRegStr HKLM "${regkey}" "Install_Dir" "$ChosenInstallDir" - WriteRegStr HKLM "${uninstkey}" "DisplayName" "${install_directory} (remove only)" - WriteRegStr HKLM "${uninstkey}" "UninstallString" '"$ChosenInstallDir\${uninstaller}"' - WriteRegStr HKCR "${company}\Shell\open\command\" "" '"$ChosenInstallDir\${interface_exec} "%1"' - WriteRegStr HKCR "${company}\DefaultIcon" "" "$ChosenInstallDir\${interface_icon}" - - ; hifi:// protocol handler registry entries - WriteRegStr HKCR 'hifi' '' 'URL:Alert Protocol' - WriteRegStr HKCR 'hifi' 'URL Protocol' '' - WriteRegStr HKCR 'hifi\DefaultIcon' '' '$ChosenInstallDir\${interface_icon},1' - WriteRegStr HKCR 'hifi\shell\open\command' '' '$ChosenInstallDir\${interface_exec} --url "%1"' - - SetOutPath $ChosenInstallDir - WriteUninstaller "$ChosenInstallDir\${uninstaller}" - Exec '"$ChosenInstallDir\2013_vcredist_x64.exe" /q /norestart' - Exec '"$ChosenInstallDir\2010_vcredist_x86.exe" /q /norestart' -SectionEnd - -Section "Base Files" "BASE" - SectionIn RO - SetOutPath $ChosenInstallDir - File /r /x assignment-client.* /x domain-server.* /x interface.* /x server-console.* "${installer_srcdir}\" -SectionEnd - -Section "High Fidelity Interface" "CLIENT" - SetOutPath $ChosenInstallDir - File /a "${installer_srcdir}\interface.*" - File /a "${installer_srcdir}\${interface_icon}" -SectionEnd - -Section "High Fidelity Server" "SERVER" - SetOutPath $ChosenInstallDir - File /a "${installer_srcdir}\server-console.*" - File /a "${installer_srcdir}\domain-server.*" - File /a "${installer_srcdir}\assignment-client.*" -SectionEnd - -Section "Start Menu Shortcuts" "SHORTCUTS" - SetShellVarContext all - CreateDirectory "${startmenu_company}" - SetOutPath $ChosenInstallDir - CreateShortCut "${startmenu_company}\High Fidelity.lnk" "$ChosenInstallDir\${interface_exec}" "" "$ChosenInstallDir\${interface_icon}" - CreateShortCut "${startmenu_company}\Server Console.lnk" "$ChosenInstallDir\${console_exec}" "" "$ChosenInstallDir\${console_icon}" - CreateShortCut "${startmenu_company}\Uninstall ${company}.lnk" "$ChosenInstallDir\${uninstaller}" -SectionEnd - -Section "Uninstall" - SetRegView 64 - Delete "$INSTDIR\${uninstaller}" - Delete "$SMSTARTUP\High Fidelity Server Console.lnk" - RMDir /r "$INSTDIR" - RMDir /r "${startmenu_company}" - RMDir /r "$0" - DeleteRegKey HKLM "${uninstkey}" - DeleteRegKey HKLM "${regkey}" - DeleteRegKey HKCR "${company}" - DeleteRegKey HKCR 'hifi' -SectionEnd - -;------------------------------------------------------------------------------------------------------ -; Functions - -Function .onInit - StrCpy $ChosenInstallDir "${instdir}" - SectionSetText ${REGISTRY} "" - SectionSetText ${SHORTCUTS} "" - SectionSetText ${BASE} "" -FunctionEnd - -var ServerCheckBox -var ServerCheckBox_state -var RunOnStartupCheckBox -var RunOnStartupCheckBox_state - -Function RunCheckboxes - ${If} ${SectionIsSelected} ${SERVER} - ${NSD_CreateCheckbox} 36.2% 56% 100% 10u "&Start Home Server" - Pop $ServerCheckBox - SetCtlColors $ServerCheckBox "" "ffffff" - ${NSD_CreateCheckbox} 36.2% 65% 100% 10u "&Always launch your Home Server on startup" - Pop $RunOnStartupCheckBox - SetCtlColors $RunOnStartupCheckBox "" "ffffff" - ${EndIf} -FunctionEnd - -Function HandleCheckBoxes - ${If} ${SectionIsSelected} ${SERVER} - ${NSD_GetState} $ServerCheckBox $ServerCheckBox_state - ${If} $ServerCheckBox_state == ${BST_CHECKED} - SetOutPath $ChosenInstallDir - ExecShell "" '"$ChosenInstallDir\${console_exec}"' - ${EndIf} - ${NSD_GetState} $RunOnStartupCheckBox $RunOnStartupCheckBox_state - ${If} $ServerCheckBox_state == ${BST_CHECKED} - CreateShortCut "$SMSTARTUP\High Fidelity Server Console.lnk" "$ChosenInstallDir\${console_exec}" "" "$ChosenInstallDir\${console_icon}" - ${EndIf} - ${EndIf} -FunctionEnd - -;------------------------------------------------------------------------------------------------------ -; User interface macros and other definitions - -!define MUI_WELCOMEFINISHPAGE_BITMAP "installer_vertical.bmp" -!define MUI_WELCOMEPAGE_TITLE "High Fidelity - Integrated Installer" -!define MUI_WELCOMEPAGE_TEXT "Welcome to High Fidelity! This installer includes both High Fidelity Interface for VR access as well as the High Fidelity Server for you to host your own domain in the metaverse." -!insertmacro MUI_PAGE_WELCOME - -!define MUI_PAGE_HEADER_TEXT "Please select the components you want to install" -!define MUI_COMPONENTSPAGE_TEXT_DESCRIPTION_INFO "Hover over a component for a brief description" -!insertmacro MUI_PAGE_COMPONENTS - -!define MUI_DIRECTORYPAGE_VARIABLE $ChosenInstallDir -!define MUI_PAGE_HEADER_TEXT "High Fidelity" -!define MUI_PAGE_HEADER_SUBTEXT "" -!define MUI_DIRECTORYPAGE_TEXT_TOP "Choose a location for your High Fidelity installation." -!define MUI_DIRECTORYPAGE_TEXT_DESTINATION "Install Directory" -!insertmacro MUI_PAGE_DIRECTORY - -!insertmacro MUI_PAGE_INSTFILES - -!insertmacro MUI_UNPAGE_CONFIRM -!insertmacro MUI_UNPAGE_INSTFILES - -!define MUI_PAGE_CUSTOMFUNCTION_SHOW RunCheckboxes -!define MUI_PAGE_CUSTOMFUNCTION_LEAVE HandleCheckboxes -!define MUI_FINISHPAGE_RUN_NOTCHECKED -!define MUI_FINISHPAGE_RUN "$ChosenInstallDir\interface.exe" -!define MUI_FINISHPAGE_RUN_TEXT "Start High Fidelity Interface" -!insertmacro MUI_PAGE_FINISH - -!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN - !insertmacro MUI_DESCRIPTION_TEXT ${DDE} "DDE enables facial gesture recognition using a standard 2D webcam" - !insertmacro MUI_DESCRIPTION_TEXT ${CONTENT} "Demo content set for your home server" - !insertmacro MUI_DESCRIPTION_TEXT ${CLIENT} "The High Fidelity Interface Client for connection to domains in the metaverse." - !insertmacro MUI_DESCRIPTION_TEXT ${SERVER} "The High Fidelity Server - run your own home domain" -!insertmacro MUI_FUNCTION_DESCRIPTION_END - -!insertmacro MUI_LANGUAGE "English" From eede4d5c30c69027f81b3d9d9d256792b6ff525d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 15 Jan 2016 15:50:49 -0800 Subject: [PATCH 241/357] fix log open and remove 1x menubar --- console/src/images/console-menubar-osx.png | Bin 136860 -> 0 bytes console/src/main.js | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) delete mode 100644 console/src/images/console-menubar-osx.png diff --git a/console/src/images/console-menubar-osx.png b/console/src/images/console-menubar-osx.png deleted file mode 100644 index a940bb163f1b4169f6711df1ef25886e7596ab3e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 136860 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 (JwiPr~E!2J1ad~KLts@Z%C*S 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⋘M!Q&oBE?UITL>F3y^S@Jo(feDQt! zj<>Hb3(IWnG5qoVE?U#eS9j&<;hrEnc_Z^+aRA@?DGm*BcFfsPH+HRQQTO2JtyI4h1w+Hbf#tzdLUCHKX9zBn zmfSdxVMfEfQbg8fL-{MUOSnm;TMbg=Q09U1+YoA8C02gCOTU?rr1{z2_JFAC)w5Xd z$cxsS*U`%oRi-G0&E7-`UyClz)T4Qyl%tn;6DmwE3NCJ+@_9JE46z>j@#t);NqC|` zA{2Nle?z<8eE!WgaUQNX=eHyhnB-&Kq8maKBf5loDWj#XAYmPw=eBCn`)y7s`WoSl zJg=}>t8{0eNl$bP5YaO9&%Y>4?*^9aY$Vjm#f61|W|oAG)zHU2hCxPA&!_Z=nu{67 zIQH^vqT0i6wK_RXSkc-Wa%qEmM9c>~T0=bSh~Pc}#nM{pL-;PrEC6#O97E!@0ZjBl zAhONO!|oWINv&5HnB1AZn>UpdbzJlgd4JFaoqNr z=Rf}fNP<$W;xc0;GUitN=ptC%jV;Ld?uf>9PIcn<|9&+fy5u-Eq`Y;x~ODLpv4Z94Zh z*fQ+;TXPQo-qq(>gKB_JA~gf2mvOFEGK}1Afbks{w#*;b41BQiP=KMt9@08;B(W& z4cV+LqVDG%S3>AXnCAeJ$gSvddAG>I1Eyq*g(vz*`*`V0 z7jpz-fdbJGh6%)LIPX07BD=q516j_|T&F||gdCOvX!DeD9Xm(W!x4MridSG=@Gw32 zL4ON{x0q6^Fs(taK0a0W2mE8VY#+K+;B?TDLw$*9UWq0o%W=?5+|^XPFmJ-jwF1@A2(MqnX z6WIMz#qtSg!yP~R7vRn5YyUBdcY1*g%90A#u`!Bvu=ygs-a$=Rxy=W?Y=%?qJ+(ef z7HVc18s5z+@#@u<3*9aKS=KE0d^u@qMd&hRgU@zX`b40ows?hI{UDq2^=)?Ax{Fn~ zWc*m0TBw!18BRcby%ngKvDYUx^&ElPCX~_ey>fzl80;3lR7rg)>iFC<92{6Sf$icZfASbNloX=e3l< zo?#3b$FDyX0PQ?DqK6-x1=@Ld0J1snytz!=5y|a|al|2rcORA22=VF~pon{7&Dj?M zH_{?;xwdf^fF9NV1gH1&NAjmf4=oQ6i>tw)2jthd?=JN#`2W<-3|#cn?7~ee&#pv2 zo$eKRl6hUn)TjqME@03unoJvXfJf|HjdM@@%n;Pb-88A6K*6%zu#nd`$?JpPzl?5L z=30!f#~AiEG@FU~dlKOY#VoqtsdapL6Y+_-=|6;W2J%r2#V|b z{sRtzu$)w{tgkZxNoyIdFo)famH~G0ppSAN)`6k;O#JIJ4xN|)Ap(I1OG7_`D-3PV z3H6_t8Pa;+YI+k}cHu2@NerxzW=%)5Oa^&2j3$2Lkd#@C8R;af3rJuSltb|D3%am4_}U;k~`JudnsLz1{5+ zt2>G*BSEyoo#m{~*W9r_$qyNLo=z2IY1*s{I4as9eB46m%R&9$;7Jeiege~rkj<|7 z7hN=pv)~^>j z6%#@`hpd>o$Q&7C?YxOXC{Q%|7NAc2gV?xV5avxuk(|A453Z@nT^jGxfnP`F-HuWZ zas{W}yP=?jJm=fqE+gFKgf{W;y+(K_GYR~?7irZ4{eW1bs{?38aG&!e-=~krvoaYV zT-ltN$$IEk-kkBY-;@P0=5c9k&=gIulStNXNrQbK1H`g}EoK{~?plKf>2Wfq`K#Dx zL*nIZiX|=w*mpH~a3_Fh5^lKWbtuNDYx6t&1oWL(@yZSN!I#8T!cV^UsuyjTq7Y7w zV$yHxrI+U;BA6bqqO%NtVQz!G$$|$=Z%=b~#4X0sN*v(A+278g$P)9&YY^N#`x* zZv93jL{Z8?WD@&$howLYEmm&yVr6c~_?~PsMvImNfRRb7$6h_<$=bgdXT#nTkh{7p zyGz=%m{32yXdrt8(&uM8X=6NgQ@clkr;kMeN>{JkG~B{!j>>}}b!1~svDAq(59^T< z5{G5%#l)qr!c1&dHYNG{G3CFI7A62NvI5eZH`D7^@4|S~sqz+>Cnm7|BkDGkqt<+} zpd0|vj1#4lyH0a%${}v2<8f~;*G~RDq4a(Z6!!iUduH*1Iw6#;H^{>Ws)$a8<||?5 zZDnk)on>DiJfXIqua-8!U*eu?iEBBquSTQaK)wZrB%_7eQXr}zHuMvtJ!>aUw5k7e z%^a*!p&4$@u=>NQ@0waUVb-n7GbXLzo^Mj1@58gHtnY6t-5`t;%9uA|jm0LY8+;Rl z*|GK?8$@Q&qm?rB)d_Arf44J zn`#qrPn;iXn{liMHjeGIoM=N1w-b78GN?gL`nN|Y?mKAsxxp^9UU zq`y**5G2><_er2u>D}SKkavq-%YZ-*EF9bp$KD*qd%f+0_jC!-g+j zw4(P#hMAp+h-uJAV=SAqKkqkl-_BZ$cnNi!+lbnjnuO2o7hND<65c*#5LRq0)tPj3C#a(3~(oBw!iREE_JRMKa15x|(aR?hl zZ2a)&$C-H{Y)e_+0fnR$Kpn=%a)IPT(Ix@YK%~KVz1O?BY;qx(DNE4L%$mf~NqJPLBAzs&b%|V6j*;`C8icfT`XuAZ*caAiU!>8x#xcUUh0})X#WS{-}eI9Tx0N?QVtY4fWnI!#xuQ)dP{a{Q|r3?Oj zZgxaHtM)R0j?ae5$2h-gi{u+ooTw&P&D-96v}l^ohazY4QCZR5ccX6+O8SXsE6?Cs$K}dIi(}Tr%Tku+T?LwH zU;j&kT)^Vx1@)41C(#^GX$}jG?ZE~L0)(L$ay;PM3b!!$OUnHR}@sY3#TYhk+ z;FOPeHkkrM3onUVOJL9LqwX6VZW zXy@^6WxFNjl-ZvDbzRoa(GOxOw;l-zL}l`Gpk6ko>?R!rqbXugT5{7e-P<}nl~SN$ zpI@UUv;HltrSrR-H02E|TBLK-aq4zCMq&F|U6K(U7oUQP;>~DA_?IY_r*u9Ov*ga; z*ejn@j8DgsZuq=JPh`dnA5(HTHIiSXTiB)`{E?Kg#8=kXVdhv77;NCC7&q>o;!WO@ zRu~2+0F=p6M#6{EYKY#HlJX6sb7y8J)px+zaJh~Vd;qj|8spzLk3!0iCu77Gxw41c zO5>%zgs~@6;NAw=0YTYo=JTx;$ad5s@)l7@Gl#E2cS zifi>adK^d6XIP|4EQo4kX4p(VqMBvl(I^C%8yn5ZF)rUgZseuodX&Or-KF5+pkdB-vuxL^D ze*j2PNR0N4NPJZe8S18aIHi3NBPgk4Kk((OVLV%l*B|oe!BmGPh(0g8ZUV~ znv&!Rv|`dy4_6fczxNqN-mrRa;`eK&hIb{AaO5*M&?_Y^?NENjWr5;65`baVUXWgt z=oq02SD-u+wq)pkB*iq5oX|(W0eoxF`wpKf`~`6b$lw%4Z?_!84^B9`S@su`8AIM0 zUDq)No%p$|bYNV28d_W#%|}1`@sL>{gGq169t(3$DHkMDKk{Qw)Kmp$Ied^2Crvva zwN@TA)Mrd#gT~cPd?_p9L^tZrefrYxOwnL#FE&@MzBOsP5ugQrV^i}K&(&n7Rn~x# zJQagS46J(KX@ti{;3#0l&_T8vS~OT1?DiOO*C^E&B!XGl@Un@?Sqr4tygk(hh>zF1bxkg5 zE{BmHI}e=INXVc;ePATf*%>x|dDsbv@gdlp=&JIer^2XPmtQ!3fG>&OQe)9Lsbk)a+o$2uV7@ z!t*1-2^czgH&<4;+XABOh|~Zox1=%VtCjuVt-T&+;$;`>t^{)r3ktA~RWa@3WPed9 zeMDbL%!?<4*AA;QvA8vHxX%nbLAuoZ?(BMpsm#*R%Vudx?(lwh^8WSgzMJ+7BM;8v+{6w+otPPp8DzH`Q&J&dPt&~JPumOeJjrEXKGQ-;dn9tbBxv}6rKCzPuw#akNsqXx`#yg1Q?1u`pwnm1}_ z*;iydNUN6(bruv(>3c0bo~-E3x1{fA#bo9{WOGReB#S+pX-8-+S4#y2X36+V+M^&t zh?NSN-=Zy3_1)3G_f<4H*Vo1C;g?a78=}s-qR)Ts8XarEEkO*ku$%eo!IKbMnZCdt z_V`Kbd8N*j=PLIhLskoh=fyTP{vObr_-mD; z|58DWMWG~1TTdoNX}krVI@Ej}J?>+tJdPYCNoC+6n~xqQnE*117n^n4(T_HNxi)3+ zGnO%k?eKsMA*xE+z2y6AX@gwM+K9}%E8dTfG@{fGQZH;m{cuZKetRm3Sy=<`BW~H+ z&bqHIHD}~U>e?nf=hsu&rSbcJleCcafAb)iY8BoJ*pWLM^7!fWCn_f>?H%Fkjux}L zS^n+$^d6ls1%R!86jMj!+e<6O&5^ZJ21A+`&sMq>Ox$d6Eq}$}%y5hbp9xKmTD=X8 z){3D~PJVW>;Z5_p=WT7WDp+)Rbb&B?Ax4~wXodm1?(N@`AA!RhEaYy5|iJG>4R>nV$*zWV!3#Xs*4b*aw#?-(%l9~TC! zA+{VvC!&^fHt1UD^xRXRukJgtJ+E|oJnLaLzLE7SD zv!vqSV7e_PD*ift(Ge$j;?!r_%~Ec^Z7sqi*!GA`#A}cHucmAS{G!aJZ0TJ_h=(}P z=SMFMd*5rbggs!vQNO{9;ORLY^yCTcAAC&j_llj_IaDMeQQFg`f2{R+00T8R!9j`h zGYgHls%yFs=1Rd6?NQUG;Hd~nWc7x|jxgCJbJkT)zUb5kP9!}Rca`BcSl=PWw>n-- z==C+riwV8dC`3Rs2BIOJ1Qb`_+BMg-m^eX8v5wd((-utnJAobF81#mal=d?gS+^Oy zTDVFqv|y+f?4*X;HOzP)y!Z8jOs~Bi@m0yUpzlpVpPS`9TdD!OUL6nkbx&su?FAcE@9ezWMWq93@L? zV;`1XCF%>+rrkU8=(+Fo1RQ7<`K>?8Cfg)qnbrjYW}IhS}|p*6!g%5+C(AHN|SI{G*QG_IEd z0$Ek+$)Hfo2i2k_36=WQff=G~FnML{{?HSeBg3)AFFs5aEFMmsm9~K)klscb>q^1aQ<9Xb1oW@n{X*ZfTia)u7EaMRi`Tv9 z16xEU`GX;2f~`)CAr>W)Ne*72G}{CgZgCA?y}RNU^V{8y+e5vut0B=k z<^`ps3*x0Vr}H);t`#RRv^8kOUrZ}dlUd7rV#IJcPs z(YII>Spg-+caAYizZ*R)4O?rWosr$6L!hTWXo$-QmgcrY3f&|e(U zWcqb}`-aeD%_>DvD1E=}J;L09hiHbmh9$Qjdy`+vQnDKm54X|FKO%3qSB57VJL1B% zW*@w1z^g(QwV51h_<2G8u6p>(h5XIHmEF;wP8sPyZnr{Lg*07hI;%HP9UF?>0g<&t zx~LC+Xqm;dureGqV5U?L%(^;Q=}#k@C2+p7y*JS_a(nrC_kptvxYvv6?8Up7pexvV zL&H(281+CIqc+wp=*k05w%7zr*0U5r zSHW&@%GIlvtM98$j>iTr6MJM=QXCj$mrb42sZD;m*bKA}8q?9>k~#vhoJC$seW#B| zx?dJrzX)bQlPF$3QzZ|Yw_pUOOs2WPM*(tUkF3QdQ31~8Q2F>YWQ4Q>(I+W1+nYa#KORTHQ6$G(!R@DLoE zib%`6kzK1ft$@y}c@dX|Mb@86MZ)p9AftU@*TsO|e&;JQaJXPCbJdgqchcI|KBqC(c#i=z@1cT)0 z8*Hydh3DH3lPrc5U++c6I&}MZ>04d9N0TL1r`5x+=MAnQN5a?c8;VAgZ;1{zgZhZ( zK#7tUtQ&&$>od(`W0csAbql45_emElRzZWiC=y9Ixy;3L?Q8QxYn4d08u36+?*<{^ zLg$Hw03idA+$3^V7`}Cz6Fd~~YkG2V5;$O#nkAWD|29<-y_E0Z^U*wsIy`$;?I(;r z?)YZ3w_WF1ZQh9a?I0Q>w$`Pe*ju#AodCU=F-Jm zFxoZZuhw~;G;g%^%rsBVW#z?zb!C|@JB4KdrQcDPu1m<@!;W<)aSYrXv4u;>D7(4# z(S3`wcSGWRKVw;MPz!#Arnoth-3Atw&Mg>W7X>;mp%) zAizZ-cK&6k*pXh9kNjgTJqd z=?FSdg&V(q7lkbLpy3yCPr?sM0pC(1lx~7whLn>tu;iY*@@xj2&y{|%8+Z6p%B{9| z;fR1va;a}5$%YuOy(nN8A;*`9G2#7P*3%|za;q4CV%R;id5xajvw%a6_=pcXTV_Bu z3%x{XST{qL-mu>o5<|;+Qm+esuR<|G5i24!f*fF=d(`{2q#fww9z23$fon=JwlkCx z7LH2{*=XjVyDM6PyE?st7xj(*L5OQy_4T(z0HC{v8s9&e4ASGsPN4v|1Xx0iHF5b1 zax&Yav#OpDlvd%X>sK$F0_tr09SB`bUoR}r2g6f@* z$9J1Ip*WM*y{F;Fcq^jLF7ERZ8IUB>g97W^L5KLl62;Q!CUK7@uab^ys(ISB9pvif z4sud4;M`mBQoO+iuZDhQDsH7Dap`dyWQ9;~fa*ij>zGPK@|j^2`;*_#(R`K_u{Wph zI8K*~g}|~keMznKb+I8eif8ZpY+Pbz)Tp7=U(MZ03F1gIYooQ|S7u0-fA}T|Tl6Ly z2w(18r}=20cpuklNI6<7$x~*(?hg{zyg3(|!n#iR%e8s2nIEgrPlm`Q)Hx*BytTE4 z!VU{w+)DsF#xGC9)MS(%ROnN&WY%z|=e(XE-VZ(pl%^cqd$XnOMx?Sm(V4a}Zu9+N zI?vNyYHDsCE#rx?TsaNpwL2HdJI}dNKf43u9i^qogYV);Dqz{FuR(70d-d1(Uif5d zZNf>qD}vc>AcCB=;YzqGnw+oI#53~b);N0;=o1oAd)SlWBbu}!&;lM@!}RTZ?@p}_ z{{yo`UV`qpfwx(Hp5C8AV2xa>Qc}dKQwp_4kBN^QAqW078V|CA{j4krbJIxKuiJxR(1Q|~DblQcDOJ~1S;;Upp$|)VS zxX8oL(|8f)yUN)qM2wC;maCe~w%rfnV&B#Z?dv{^0whslQQ3IsMCJU9HVe0moPD40 z_N-`T1<^N#04p1;s;?!JyZZ%g0D8CTj(~p~5L?yLPJ*Wj$Y5XIQ!9RWQ1N!*ho271 zzLl?5!_Cb%&R)Uvr*8-I?pOZDL zv#*~hdN0U?2*s+n?VL<)PsI}VK zP}8cR^|I+gPwZU{QwfPf@0G7Hd6%B)(z9@8up;c@KNu`p@iqAI!Zs|^vHPEo-Rjku zO74^>=6~_e%|c4@s{d>Hw3U8Vus`?^Sy?tB$+26V!99y9f3pi8pg+m`B=jbWRFG+j2actnV}%F?IGlj39> z6Z7ol_i>W!UDe4NM--^}xAGEWb#YD2isalTEwB#?J~G(rj=UVIEq1N^?$^L!#as4t z3RNVNRsq6lE$&v zVaj4d4)EUZ_uXD39B;`4Uz!%O6q7CfVvF+3X^F3kWiKYSRStt`q1vZE;<6(#Z*JxdW;Nag zvV`wWa^{#;q;!yL<wF_ui1kO>NcG*G`_!WFANSOgYOF#4y^bnskn>Q}D0Wy9`F5#VM@g z=`GqD-iA~NPyfOocO|2SaUr`6t*hL2)`$Hx0z@BKt6z9&`<@ZV|9IN;xfZ&!`K1X# z(@hi>=BG1)M81rdGO!7W+IdF(O>Z+TA^80Un%dFNVjQO$>2}KW$CM~VP@U9?%AaVJ zTDg~>b?$cQD^65z8<0cWTzsc~|Ll)2g&)Zaq7~K?w(t8?Mv9|DE4yTiTJl6HW$^>S z_0kc~-n`#A-)Z$Anf=lP7O;LJPcY9S_KPl}FShZeBhf6 z_UyBBq`Ma_p;ou$Ku%1zq~5a#;Mr-tyLg#dr8?~s(vSPWIC4IQ2L7y#kvP(li|w|1 zXVhz&RREWt#g`|jXOb6zS6Gbi*S3esD*|>NxE-W7{UvG3sogE&i#hN@g z8jt>5MEo=FnnPsrdv->Rj->NTKITiE0KPwk88t@ZjY`>NJx1fX8H^?)c0Ltbwu80m zjK?p{u&v1E)39Tk^buqUNcNVsN!G?VA>enm%0|Dw=Y@1XBYbdB(a2=b{D9xbAE3)@ zzOiv`cKmGf#5o^OA1OG`Ceprp1|^L0)t4UO<4injdSU*u^@N=iO+z=h2i z*Tx8nb=LApp&Igt(NjTGs0+w=WTN-WXinw`E^nES3E z@4nHqZE3Y$b)M;{8fnV3fSQOJ+fOz2&P)dubAj#TS67N+c9OM>Ku_4cS(r3hPNPsW z=k=yz)AmF>|L8=sYj&L@RJYE;p2kRD+lQ72cai64sn)ME% zH;RhpaJNeb-zfSiBqdbwQ1wzl&m*@J^Xxqn`2OKwyzL;D)s9u6`Wm9-#b}xjA(n3w z$bGT^;4q^2_^mum@(qcDY2sM?@@@|?Ba+5aYKl}N;Nig@b%X8wULRauaSc`o97M|| zQ>Y1K5YDWl`0zF!Kd7o!0OT}DKzkSzLd*JumrCrTNVJF(c|(Cb^L?y$2s&WDm%W&n zQ=uOdnuFqfl#8keDcmAlH@Oyzuam7|fvr0Qxj_ilyRA~T6n1X)2|(F@f=2vyt~fgF z=wrF2ZSsG16Q_?C6Uzp($+KT|r6i4XjFF=AR|7I5^*q&{EqTC5OYh0HX zYd)&dzZh9dTV86h;0PI-wKK8_6n3yyDtrUi@Bct)(fwin;!Mk?DJlHp9>+6M_Lx6O zwhet6>suQg6xq-U_5?Xp<_Ogg$H3HJvWvuZBe4v#8xAitD)* zZxY`c2Y=T0YGRq^_#?2XU$>&i8-g^DrTLrHprg4W@Fj7VFWOlKOiBu(K2k0U3{f$E zBdJTbKF;y9i8QV%HUKgj@1(@zV{=rL@-6{6VO+@d2B3D6RcQ&C(DFS03H9@CC687o z%m1U1rQc>TCV+S_IatI4o8QgjB+qkO>zNyC3&8KRx}K3@$!nj6_3f+%FKEWd>x4Aa z?X&nkk1h5d_cYI3+ECB+LJyq4P8$48P#e#Ui3j=@`ajB{elF6ys-olF%7`m7E_^!hzznm#YUsK=z9K-_v zb_I25r@Q5EeoKZA>jQ`9HX#o0oX1{nKj5$&Kj>jqz4(!n^)`2Qf?Wi532Kse8lc8i zlBd+cr=h{c(A2?UTLn!jlpB>IK+@Qu-n62;#Ml0dM7A4~C_mL}>uQko0guX!O-U)` zUUXQ9Dm%+hIzAi3mq+4GvfDd!<=Vz(O*?d@>Ws4X1rEu~7tLK${2&q81;7(rVDC~; z`^G-4FQNK-i+_6jn=N=w;SQXvEC`x)3c5nOWN&UJ%sMf+*1L50)G`La{3@bvA==$Z z=~+H{0mi#p{-w-XJ^hobAMZcZI&}2TX`CvR`VdSW?$3cX3JTGeMYFfH)%Y}hvdeAP zB8mCRm57K@KupGjEt-hky=Y}G{wGHkqRhJQC-T^%S6gB(^tOzx&k@lz3pZJI^j1$B z*{yK3$KOu4sBo;T`&eDLG0YBa#X=p-lY{-|tn;21SR_dd-w(_gRTCG~qBkoa*C;(A z9=!c&lUpdZ_8Y~9Y`CdpNC*QZ`n#d`S8iG`iwT+EzkUh(ch}qOmcYsVuGn6`!CDqb zC&mg@CllmiX9&KzU3c8VTa(vy~n5HK5mdFS^Tc?fn`;oK2tQ{KhtGTsQEk3|MYo}?a!l=AZ(&h zG;BeMk3(X-7wj-6mY2aJXmn$Jm|{(Gmx^m0N4+|2j9H>vPuTC1K!1f0B?(6w9qv!W z@rl3D25qRFj@oIYj*a+CTA}}JWYuZWd=@I1==jjZ{dDPz@+FuKR$J8DhKd?PHiP*e z6wsLb%~Zry`a{WP32ZjaIz)7jAie5c&P@U42x53M=AVN~Y{PRj#s~&ecP%x41{&tD z<0Q^Ep;PRee_Z)pH-vad6o%rOTOC%hywl^qKAu3(9mwr8MvP#W91`Y1ugej5d2dd6XWO+zxu~iTMER$H)fBi)JwD!EN@f+{CoqEAv^%h zB2tia*vOfxkp(&Y(I?&f2HvCtm7PW_hM3M92gUwPGJiMpu}|`(sY{PD{fCeL!wos& zrOn#n&6gmSm+;$bSncA4AH)QB)U~zf##}dzGDmoV&exBEro9P&u%y+A@}9DP$(EZd zYE6BCwqCfE30&GuiB<9{3|N-={r>NA{2ll|g=%!a4SkK;dwIdTD zd!EB-5Z!`K^M5p$wXHR+3V%GH`*y)RapjtNV}IA7Jeemq$>S?>a; z^8Zh$|9yNCt|D3i_!P{8KDE1JmDJ7Vn&xE`DMInlZlokDgbp>?>vgGUjqs z{{zauvC+Y|kLa%%L)Glq3hJ54Ho=Q)0=o_z%GB4Ix&ykw>gl1W7s9#&Yd2p)&_AI` zwUx?x{|B}@_{`*ZUC9LHbge?q)wZ9z=rixk0wzNk%~CUG>u0}|3ExcCqrUXp zD98h4nAJ6_3TbeGdC*>DGuWywQZIk_iHksC4oeeX+I5#s^*cV6VX|JMMiaFtlu@EkuO zOLA_D@Z)MqCe+{)kHq;Y$tG^)Yzd(yp(%f_9*r0dzgHyHL=ZigGUg#Ky?kX?{X|I5 zr}FuKq$P~K!H`&hDO~&ZBrE2seA#m;L|AwOuekzB^tQ#m`H-qXv$kjvQGeC1rCT%3CVdOb4PtIK;| z!KH4ophU5@n6fS96sekG_l+}{ZtAUy!G-{o`{}|%_HJl)xCHfA;x%zRbf`sOZ=rYh z`t8gc=)Xg&h853ocQdwZ3q}oW|M6oF4`zeWN+9{!l&K4vhqQ$)oqHoOOFFW1pPEDI zri?cf2LdgiKeHATfA7EDo0Lq69O$ROy!zU(VE6k6-@l@DiY44}=T55w7BtGDH8;Ci z_rmK2-L#t&vwQW2cn$1#6G?l#MWr)`bzj=FnCYWEN86RA!dQ!itE7`FN1Z8treK!; zRKEQ;t6V8Ru`e0@xXK%Tmqf?$Clt~R7M-!*-DXa!6BWL*CeH6mX5r_X{Cdz_oF!EI zXx6*K@#%lVuTLCanR3-)WwaGHAzpo~QuO!CvYxirGD!`rH2SkE_6=FjR{*o;hVD5 z^hs#Yqzb`*mXI4y?UQeQhiP!;`SuW!Lkod&20zW` zo}ME4j+aG^%Y~jaZbq32ove4eMZNE17YWA!L>x;}7K{IfHvO`!$@2=rq@}qSHVDL)&qfrM|DO`BgRf5?E>J)! zitDPs6Qu9iMDw(c*(ktNUv~YXd5+6G6u}-}GCTBpKQg}s|tHPw`nt5QETzUHSxzZdJBYn;!|5AXaq7SYq@9pWX}W6TzlX!AVp+HuikRZ(dlb69?fwXuTN=Qfz@k#Yo1>m7 z=hl|?>FHTZ1J^xUV-HxAgCLeE{JzXC`t0g`&{)&0&#$2WgAce${p<}7Hml;^j>PVA zw#}G{S8J(f%GJlQcGPkV`z#Wsuur~LvqwL7hYAKRmxOsvQc`OV{_mvzZrN|ylI^vC z-{T`5$?n1yisAUzf=+ZuY1zs)(d%JR*lc<1&J^FceYfmiRUf;x5;i}m0y3>Et z#{b>YZnXRqtl)*$4NFUjrTLYk+^@eP6X;#1&h)($NLMYs8|P0KhxubSm$eXS5dQSv zOZ&G##fOE$)o#n zUObW*dHSO;0{$Q9D#%|^LS;dmIRV^e4)3<3)Bar>^dzIO6~U#&x0@3C+vfjbRz4+! z*@8-vUsKNgTUG6UsyZBu)V3S#RyF-Mg4rB+j>;#k zC9HM?)3>Xh8`nw$sTs62@_}4vUDEw$QFbn+Nnhh9D@ztvpD%vT{O2zl|1wLA_;VCj zFPI3lGOL3mVQ!NFd+l8>rPEUR4~p)`^YhxK1fujQLIs=tLxq0`mH3xX1k@xbL9 zKCRwH?UDD^!Wi2A;>N}0wxJ=v23Qt~UM&ogE z{;A93^M}+S`xx^i3gs3G#U?;+6s}cX9l@nSnN0xY6_kVb=vG*C8Ma@;Rc5|`W1NdW z8JRG~3nRks$o(qMdQ+i81piazZFpX-MeIFMOoc{@TtEX+{XJ!&>W!Vk4V1;^^I!Kr zF>@CO=|XJlR1znCDt4XEp?2@-n3U>T>?jE0=8Qzq_6@eUP7d-`RP9(j{^Vq^_?uA< zhh0iro%T+T89~7uJo5Zn+a!szQkylAW}|7R2R!q{g8ceMX}M$lWkL5d|KgIf0R%vs zB)^Ytr(?*7Uyf2&{C(-nw1nghIC@CTL=f{aI1DE0z?72iRpU)OuY)p=k0%c43EP=4 z#>*cAE2dJ+{mfnRiA-Sj6vJu1L_m@v=yFM8>+o&vAb_jt{Ozaizi-2|-J1=^P3A{2 znOmVsND4aw>WkNmlbj~OIz1Tr-Z6&vOcm=cvcKjy{{cSf;5MzzdX^GZtLSUAG_&H; zc=hagzN7=AOE&+g6%*k^qP=4ZZsk)TQnSiI8bncv@@{m0vOc06W(ut5KQcPT8(VAf z$OLkH%lH-o@m!^T6wJnKV#9gUA{*#0lX9LBnDu($Q5m<5DJzCqgcXB;;(dvh6GNLn zS7`x}Z2>%~g9=t;r!wN8oNR8%92((5gtMPoS5W8*0@1_e*f>@UVVwyh${kfvXH(Yp zjqG&~1X;vY^5ya6!S@j6F!(kb3xoZ1xFy7_s~&==?NI7aV?tSwlkh0Q$F4uFEB~sR zum)#39AmXfrI#bGFZe&F=js2Po)0s0oU}TBy%?Rp>KlRKcZ(OcQ6#){>RD62E@XV! z%F_B{wwYlYV&^VQ++|-}Twt%Tfhi2@ld&#BUQNc#_T)R@sfVM%iWz?{KCzgxxqcpY#`wUw38T<~VF@Oo; zG8#lLIJ&MZ;HccI(qx;_$LS3u$BJDx@n?@3p16zSRjA_>NVg&=j{CWqWoPHmt4~_i zAt)rNq-h_2$>-qU1W&sp%P8fGaxK>ot`RU;Rr9%2up}%{yuh^*8a5V+dE$ZJfjS%D z?#$)zr410uck^dKp22|pF-kt3hkeX->sBHo7@INbdb+Q^~(eJ4(B7LRX=%cIIDIV_cU(@+?b zyQQ2X7;Mpunkh>$_J6$q22ePOLjH(4)RJOtxAp_9ox0?9B!y|Jv_sDYNyHJPc2VUm zlq+tWDp?K!=FHav)UC1%A2NvC&dih=-l!QZVyS&&QcdtPU7TGuh0BFF#alRw^Bmd) zuc0;oM58vlyjZmj!PSkB%rG4_*i?<)CzQcF{qNWTd6q1^89}Zph{r~KZ3>pZt5r4g zV3m77XVE9p80v52)u8CT?>d+Dv2s+EJuT1hHZS&!8eQE;G_+@l3#e;E&QoSAg1XqZ zDqYj8lv)TGX|r;Ahu9iDLfXiZvlDmf*CRa>s))M-ZTlYSsB_M8tU)b0*nz@3n^hc( z6t;+ge0;UFC1fi0aIW1{SSW*-$$S^r!WVr)BwMyGPplcS7Nt z0-6Z`Z)9#wKik-0*{q)+bGRwCk@47vkytp#Q}^-|fAtB}VQxh0&kEO@H?AHnNLm}Z znc>g_2M#5^`r4h$OH}Yo`ZiA^%~XO!y*vtuu(1It*o*kiJq{Rvh z?QhUbZKeAX<%e z10CP5{AYf%P6kKGMQ1`$Gphy{zpk*3Zjn@qHWChk{^dH%{o6e38%Onah!k51SmquhQ_aE6zSEA9bec8M#HN5*(^VviIbJy`2XQIy2VKHh(h z{!1;bk6){_gM4$g8F`z$yC?M`Y>=UxJlNOsv8vd$h+PQq9c$muET*0&@}Lf;jcHAo zFq*D%zdz(HWH-unMh`Q?aE`YtKOIXUzz?%{{=^+32&IY8hp}d**Je;n;0%odro@hr z8-kF=KS{4Z*WFUa>5qZVf7RmUs}o8Q2+y=c%qv=)sGB8~Gy6xw^kX|@$8 zhlrZPGHw+AxRvZxWPt0MGYG3P;Pw$8$|P~TgtMXtH`e@1m6#W14(Y44`ROf9;oUJ_ z@xuaO3{7WfmkNEPk2`D*rgcs>-JFP!MFyg=2r`3_(1vlM>E&bPZcEb>pumu8;@CA7 zj&EI*%s$Z$tn;B9H#)^BmnT#?VMH&KZ>sYB1&vm z47~Llv9!X?mc||IYSv2E?b`pzlH_-|9Q0=2v?LA|6^5?}KtIa}?U`X3B_-rGC;2|z zHQ0>iJ%8g7BwL*dqr#b5%HXc63do35E1AU7|!&aom_l8$#1jmcq-^hEaH1$UdxuaEhBmRpMz{WZlFKqVNA2yBe)7)&mh^))X2=QJf32 zK$KeP|FB1LO37L_Ei=o8kf-2%nrwdgkCpVYg2Lt3AUH@nN<*=wCAqCVnDH#!q~7A}6pKMw-2y(dqS` zd!;R-DR2!$$8p(~ioEpefXtheBvW84PXv}No%u`YY8U3voqjH<#1J$cpD~5%A#1dA z?Ou=;7c-qy=p(_Kq7{AO-`hdqI@e)`=>DKX{0;Cuv~HFvu0AQ#H*AsARr+|AmS}~A zu#kN)`D+txPh1s880u)G%;U5uvX(5SVMz_0q-|znzaF_alh0Xcb($uH3&6EP2|kHC zZG`{T%vQTPl}y1_P2|x~he=$Wh#h1B!W8im?rpGbMj{WkGZPslt!6+Yew`|0L0NI1 zah`_TcHp;RhH;5QM6#jjZ!ZK=lDCyFpstyw+u~;UjQ2GZ@t)5c>)90>Wbz^67#=T_ z$d1G6QWa3H?2FANTn9QeuFGk&*1<=3w@h1#7M*YZibv1**6R{Jg5D!8ZGFX?dHv37+jRV8U>likCiuVwX)YjHrFh*n2ds( zW2B6AV-2;Ch$y8hWL8cETg*W1k!=#VJa`XjPM#m6D$P#^Cb*pLS?Y*qObRF&ag#$5 zQ_T_=FLpv9>(zUPLAQ!eA*7RL*W;@SRGK>J;4d{T7T;Ca#xZbyM>3+?bxY1!W!xr1 zwr_HaU3Rbuj{5X+| zYAije;qPHR4F^YoQ^pf2WLlDpFbYw_0cx^m6dv>qRec_WN3xueNsCdGK|Qyf1nere zNsdq_l=u0C5DL6gnKY3UzmW5_>|ceNJ7Xn*=OsiKr)#5o z3nP6<;HJb`**FO~*xVZQiyOWZUs-ir3rmXLm|iN~!xS{xkumYGkx4E`k#wq9DI>~u ze~Cau7PaQ;#{wp~X~v8+#TI~@-PB2fC&Z8}&xb072mZVKTxcLwHa z`xOzV!rEMwG2T^X4B6+E* zpVO=|tdSE9%EHU!jiB3P#A{*Y@gXd628N-WqazU?%eZXzHzL>~$6wO#UWjPPhhBzf(-pD`(QRP?m zvu<*PRuxP^gs@+Y#s8wq$qaX4g8=vdYycaC)dATnOl(!Ce`>}v-rvQ6XCmI_T-j7^ z?p|D;Lr8H7alJKK#K?zu02%gPo`=SH}5L+ZHtc(LzC`|`{i3TA{>bB zU@4Xp`xnlIbfH3nTax9B<}g9Ic}CQpr6xf@LOVQ34NMFdSjx8`Q;eww!+Ieo`RqH^M-^9( zgxliD>7)L(L-?jfLePN?GYmSGN6{s#OhT5B($HYnhC`8k5C)laEUx3Oy>OG@9leAk zBkUTg+F|IN9$qmb58QG-q$GQi#6vt*wFzBy$(Rv@we)CW|MCr&tl7$8X}B@eL#bh^ zvEKt@cH%2P1(7uo@KwMokA3F;^k#4}5^Z+j)>A>F$ohb$YP8&nr47M;101|1##)(df;h&~8d?4iVt zhFPYHYZVTmMZVNj z9^%4Lj(H_fxhUb6$t7MT0WcpoLxgxvYZ8fuaKQ3{!7;y96y919$=Ye0bQ=(pprVqr z;M-PfswJ9&qt}d6lcw}sbS6v;l)3^VDotGK^y2eP6vik&DjOOza~B8U4>-fDgvk9H zA)nz?GK78wY7(g{WL$~O1 zPQL}C!ivbK6Y({3RR5lOvf98j36l~5l#u?^(XL3bahQt7pQ0_maG}sdfE!XVClNffrQ3U_mcg^he2I01D5^xSdL*Fzr?OPi5HMT)KmttUepw zZ}H2EB1|VRxhU|55|XR5V;~kpak9-@LWsZhBo=S2UM~e!Ynl`~-8EwT5S{o^KlP;Y zzxxpG^inE zAUi1}1*kB!jY<;1x4(KtYO^*d1R@xcPGEo{eMz|jpnYcjL=`>eJZRTtM!b$5f)d+n zI^~|keU8zq8JPHiI68E1i=rJC9;_JZ(%1%PSYfH{=DOJ zb-B%Eyern>Q_I>rK&t!Hd-%0uEi|8TZ3H=rr-Vw#j1zBj zjhx~j3snUIZepAI7_vvZNREpf9`4m(U)cByKY9E2U2k@-%IPJuR4x7MCKfF9a#`{q z*`B~%!eGv1Vu*5)ehut}=qlN*X@uhF?r<*oH0%(6e5dv7qycalTRwP#oA?CKjNK%{ zkNz-HcoRE^;I(LMQ5P@wd`zc=rKtuvNyW9n+_qX9)WxLU&VidAc<~Z7whY~HyDm7b zzHly&ut`7U?7JDX3U<9M?4o&g7gx&}GtFac=5wQ_eyy9r3S?<|4bpk<6-};FJfhBL zAL(qfDu*9i8lp{PW%1d=I6tvHX^6M_jzHcT6W&KrTQ3T;FR*M0(Zm$Q3>+P*S&E23 zos~dO=nVn*7x7drEm!ZF*VMQATzW^52~?@h%}yz%SMTW*-6od=M4|E5upx#^xIMzB zepLI{lwS)GR$ZerqD_p-3#FAU5S=ayiF z_GYltVf9czP0h#?d8@WUn552ed@Efw8ft1(%-WS3WTbar@dGO$?!U={KmC!xxw#*Hk!?@$9L0Y7u=mtOC-v_Q*BD5e~{|rwq zuHmZ(X|@r0N($H5ym(Hi^O^zTKsWnw2ZSx&%v5Edkdo*}_8!QG9-6L1WZI&pk< zii3$S$>u|(9++FDdx3WY%oG*P710N^2=~;p8v7Nx#-<_ji*r=;=p5DttCBW_#l^K( z&&^YM$NtF-{)o9Nc6*#efmNp2EBb}_2&6}IWCbE$%Lc=d7?}CNxy0Y0D9qXfN!#M8 zS}ZRwL)>u!#`vz2XrT`K{e%Wl7oJK(kvXS~K23%_CS$N&Y#0IR3W~*lf~O z^3|Jrq)W>#V!r91uzQS+N}lpvw?gzQzF#y=qIX_S|6onXR7U~U^UEG*A%B+WKd>t4 zmtl_2ad=WbIJ<#^LM}tgYi*xvnMaJeTfuuU zk-XcxS5a^foD;(8v@Paf0}9}TNf0GYwv692qZG>sjGDp)4|3^!@0+q~3s01O%JkmC z0vEDQCR}hjmhi-6$6fDNhY>MfQulQm)sO< z_%-pS@FGH;FP9;mE(A>&aMKD*@dO7~h>V!R<`P)$lI;FWsCkAGIyWm9BwKF4v8E0E zT8Mq*M=h{WgxGk%N`lZ@0KC3q#lW#m&Mhy6;U8i;`G+Cw8;E+IOAEK7@bS7rB!!Sl_~80 zmZwYnD4?#1d@P_i>=gdfgiof?Ph1VYNh~d4&Pw5Ln}0+LB`oi6VYJgGQxL+K^y_f0 z6%$H6-I#gyE_fV;^wOzmYeAw8dMqS>pbY|JuURIQ>1F*rFW%?)^hrCdm7lGO1x(3r zkm5_looS>c_J#Ey>Vy1ulmAqKE2tM@W%dE1zc*}J5~_d{>n#F?m2UxeLQ#VU&!$`3 zzhPH}XV2(`wir|DSGsW?w_3`-_F+k~cg}qaO)3ejb_!~G;VVOEv1t&~g|Yi&8t#d+ z*#~C}EYoj_b1eb)D!3_wVAzoUYK$i!CjpZ1a0qlsiTm*aDM80lR#5F9nb?jBZJ_hk zC*OJm9zS+KWQc|3W9xTeFkr|pF>a|+UEYvlWCsw!N;W=%g$3vzk-+;!umekPLnh;1>s1eIYY)X*F>(}Q3Whpd(_dBJs4X( z_G6zDst?@;D-t}9!{?K$y2*qxUPc50_a&c%;0&tfgb_~UC9zGFi$-m*44+{)i|>DV zfB+7{{=bKxY}T8&lHzRO>^LgmKPpeF?e6E^kBy7BD%-)9b@f{4^&2&Tnt76pn)wox zeRDtCIofSmFCA8!l*b-*NWPV!#h!c)pNO+RO}lk%m-e!VbGFJ&P~46vcAEb$hj1u*BXqSpf&wzszZ%wp0D2nGhjIjTvN>t(<&rq9jc3$v@N)=cQPLjM9xw zaUru0FL|@v82cY~L{DT5&^DLVG;_Zu*;LSRkgtb8sy9Q`47jAn8_#f5fDg0)zER8R z3&zGAXCgk3I#-HCIXv!kNRPQxG(6TSY01!F3UMkL$0oVlHfzDsuG<&`td zfYA(9ESJkeD0Zs?Q;A}!@pLpS2dNadfMN6L-JA7z~LsR^Lvs1#E{ES5?t}^ z%nT#mpUFe)DqPiUCP^d=DP^G*SQAz`g=4TnkOA&))|zayh#fqgEkYAlGxKN*X4L+- z>tmdo^{6Htg(+J)=Xq{tdE6Ds2?YW9(Ks8Cu&^sS4nxM)zxw-no*bx6l?^Z>!Qj5n*ud^M<}sQtgyof;Jpyn~#4mSm z21`ykw~ylPZ%7`-piX8w!3XJs5}k9w_A|E0o1|2SlG}}gAgP2f$=~N4<}~w)KM+L17}}RaDPX1azzaN(8^pQKIV0e zYy05iIf29HKw-K6?z+mU4G&Vqv_VQ7Av5hyFB4NBygZW!jB9x3d@C^k{7P5=@Vg(p zoreczYxq0H@Mi(G;>CP8;5lkQkylHWZo?McO~lkXg^%1s;XGRCBMEe)U9_OPHuVAl zID63Uie_&vl2;N+V#U_Puko$eq$1@sFAV`-4DhORgUsL`JB&YYp*aE$sI-;KujGS6 ztkw~aJM`7}@gERSZ z3Rcq!QUs^rmf6=Ecq63l=J0SO9h;W%OEza31~UW6`>Zy6H8DkZ?Vovz?+YHimG?L) z5U3}j;-9}O$ZwwrKW}LUFy(GMxF^okAk@UBZ-ye0Qvr>Lmrh5Z1o|SyX&|E_U$SD!r6_b1 z*iW6)0M$3os7&Wd$Un)x!#p~;x2*fx>r|?tPw;?>`3~i(32Pg zUz=QhOM3}ubG?&_pgNIBc?iRhYhugYGGv5Z$}bX}j*v{hP_=WnmuB`9A_vJj0j++7mB z6$?c5NTjOdE>JAcfu3eMdi|DHV2v*^#{tXPVK4GA?IhgfgiD{Nnpl3=dzby$MCr2H z2=YMuraX*dAh2=R9%+v?gBS98SU*8G@$5{x=A6|i)11jIjR8L^@12QADkO(k(i2AT zsHeRizsOAQ0aH(@9&oyTx!;J#Q4usrb>0N2&`tW_0XnjVh#4%S_IaIFU*1{`4#dyfmbp1+AKk-n=1yRBgUzb0jydJGKk>HC*@7+n*93fRxqs)}<;~l60;__?#B=MnapwhaP=~NW{FGccpzBOZN^GpH7wi zsr+%IlWW$VIh97ADW8NM>6O)ZGoVzTZ!ISdoT5e-&_)dXJPYQP`UzDCkfw7n!rE?u zX4Ad0N+mvz5*gDP74ad727ga~!=R->KytHh>x5kP0Au`EafaJ=bDm}fb+JWR^zk9~ z=oECUuBd;J67jy9K~FLtD!M~bF_vhULe0}Og1qBIcEomYK|d)ds=8nM~m=?A{;{W7Hz57E5Kb zJFjBtm;KR2GN`>Z3bsIu3|KbFQyRP@lrTreHjV#O#nEwyMP{@+b0*z% zWxO!&X^3(-AmUn*dOJlvi-<#fBi9L&#h#D$l%(4&ya1R$gyjK|viQ&KK0Y1Gv$H!w z5ARp^)2d(JPrGcA*A&v&yc7bTCzt7fVIMP7KO4M0{rtI-5x4U4u6ARyKXGzCrf82F z?YG^XOnsmaQZJIGK|*y(h*6HDhV|_6Uk~bS%O+cLOgH8keoMX{sbMTpX8r9@)W*o3 z921Tpr$E_-C@uZ5)uRJ~U(D+zTd_{0MFU8(gVN)(qXHkzulZ>#{SDRS471KLP3lki zEpS>~!0VvkRSfP#@|xGA{6LpBLs+_!ty|C&aKq;>?HH`(L%RFIAN@2{l$u+md&lfG zDw<^WD;J4h$83X2Nd0?aH>bF*?g4Mq4!K$U zkDT{fM9=fl*4BrVH4yXoxJu6k0pqeGcoQ6p!06egX!vYkFu-x%#TUU8R3;C5}-!$z7`P$d1-PI2hSqKwaBCt z!iRcrt)bA616DExpxv#Ma5?Cw8C3|>;A0Ao<3!gz7pYMr3ve=8he8B&5nXHlgXa=|+RYcs$nldnVBH*kBje(_1zFU$g zc-n~5w6dF|xhg9%n^4N5&hsw%qcTHG8`nyjkxjy>8c2hn1Y-_bgpf|ax=KK42)=$l zn{1n`nP_kdE=5~-p78A~ZfQJJWMxCVfv$S0E59Ptq%-AqG$oHhQg<#G7xL`p zFcpgUV6i_jdM3OspAgYgb9^8?+WwvRDdptfwa__5lcnMOhM9Av*Pjr~RupGa6=P?+ zT;~4)F1mLehjTZbgS`(5ZzVMj z+}1goPC*55_I1+_ocOfCAAq!&kY$mkpfob;|C0TSWi%Abr0{{% zok5q*`yB0&Faf@Ok}-}zvtbJqy875Z_*qdQ-{z>)wh`wksQQblv_lHftvrrxQ>#k0 zprfhzdcK_cQBg`^d7!pjHt?k{ur&t#>T4DxkX?+p#ArrRTetSR?+{o5qkjWt4g1lU~k}%Gbaw@*n)E*hTnRrEGe;1bM7z=r>dW z5EA3vh;`(Y@sUNI>qeqe9s;#bN#ID?$ZNe%kr>o0I87Q=3vsc|e|9)1c|#ve&PT6f zUDSTA48wMjnV(0cs|eFqnW`5umTc|v{U%mFveHs65HDPDtH-m@3q9BqPxLhec%iXl zhKr#brGKUd;z-VGpN4jf*E=Z5NSdZ^)&|^X|OodxHX55&ozb6a=O)VuPx5l)hv91=K|Aez+00`(|8!#9uU;b40|sidxtQTF49`WZ1@eR}^cvotpRs(K|# z14q=M=49%Hud_cs)YGz`rZ>@{!u?U5XZjp|CvkVw)uOh*|GtGl=bTSe8kMP+BU1!C z5@cI?n(SfZepj9q)Xm|7EZ~LyR)Tiz!a9L_H2N_F^D9JATpUPjMaSFHeA78QdPd1j z`AmQ6$YMMX`l_D8CmN-w?_A*kzIko6J>ZL(!R2u9-mNk4%1IMes23SG zq!ik@NYs;+QC3#bJZOeh**VpYb%vZ)PpzxH;K!O1phmdXD<$N>thrZ|*tU30Y0gl$ zs{0Pp6y4=V*JyQp9V%z5e=j0WkyrV${xcH9lLjZ7DfSZjd`!+$jDsUN ztN-&W+!)Idl|azqcFq>K9m{WBmc)IX-}%!|wQd}0n<6=p5&DOsM5d%BVdP&~!|C2D zVVnwOuFeLIs8@SJG#n-%53OoVuZm$m(a@HGFJ zgT9asx0K8mFpTdfWrdIM^%&@=0G0~vg0P%;huRZiRD0_{Vv7@cFd?`Ch%K2u_;aHq z`&4p$g{-N$eeocV34hQvXpoOQx)t?oS)fmGmDpiR_sIiz(EZNe>BA=xCW;YjVaPgS z5^oUf8nsE8qsfN4#+io=yyKg_X`Y~`5?ahLVu;VXk?s^5{IF5H<|VnaP)VNHmTKPL z6=}Yb?gZ1^_bz1gi%)DY#hdV{uCTw5YWwAQM1ik5Br%)QB!}p_oAZ2l#u)GzN&ABC_pmcC5_JK41<(VfjoteeY6hy0Cs6^cBe}!fu3NcCtrAH0Y|ci)vrmHJc$L6 zw;=5YAqh4T$H!grlDA*lGrqt<={ounNpr3nrDOWS)X$U{M~oybLK5b}m9|=T*o%`C*^5$sr4iJQ)&fM2Ym8bqF|D!NbacC2GUH= zc&L~UYh+Tvgn7#O{toj)Ig?2Vg$DJA-v=#!4O)c=yAN8iEeIEyG%raxYNAxa*oH&~ zI}7F=^4pBBY3+h7bhwE!`fqY3jE{JfWzQ)JhkK2n-gPBSt>?c&0v1<~`s@NLyaG#2 zOEL3?W6<&z-4i6*f|3AuWOo{ato^B~-d?#ton&#a zc%a}jz7?7Cy%I{b26bIsTljToKUOMv({++QW_k-=(b(5TOII$}E6h5MSy10FG`}F5 zrym&l?J&`Jf9Jz%iZ?waVG-+&;0Sqvg)Tmr=0mA@JeEM8^8R9A+SfiM4?^CHtA4_g z$?XN{EPLHi_#7pT27iH3s&RGBSk0dGrj_?Dbf(K8m0>&g72-;2YN(zw>Lr-NS zODtKT2*F-ak1m<+$@jtniAVe+*(-cYi9K=GSb&OC((_KX^dQ^0sTn@SscT9em-Lf? zzBk|V(_eo8tKFnfa!)WS3}#x6=gz39Zg%T=b#4zDX>M?xRVKobt`bc%rOMA&1xB3$^fdj zw??(Lw@M#>kFFPSd$K>rq+$X!^GA`!@0H9q)Oei_-ssHtYa! zK)i36E!J1)Ab17tnJ-Mrw9xbbPYQ?h!LhXzoIo0(bOkx&Hp&-YDnt#-3QJVFi!u z8;zZJdLk)W<}>xH-g-PWxa^ztE^G#M>H1jTt@_UzXjk3ILV}-~z&)`qfUltZp$sJ6a z$VS`)>JMCtSSB%9Sh^~h(0;!$rYW@JyF)2zzx1q#Kac9#5?bUzr3p(dM~B#zItzc) z(Aw@8)^_i+ZdXUY-uf?8n_sQvV}5vl)f+`}ht9F;dAy6E)`a~_+qKM!5E@Imqqbub zfgDLj3oKFI@eI4|2;J($gHX2ur6Mb|MZv95$7|+R4Aduq*idzZ{!gqZ^`)P0ZF8{^ zRyyxQQwX@Z^@k>E(iuzMB96@~MMtYIl5m$MR!9EuztzlG#fNf&a~dJF>br$gr{y$| zB6F|9i22uf%T-_@9~x#-B@=3Z(KR48$v<&5Qew57#t{3U#HHB;ktqh}OP>ULG<AjbVZk(iTy1$l>J z0|0mo8s&tFieo~PEN$Ag-VVtp7CH)lbb5t|d9>?N+@$#Da`eh=)Q;2hOVy-4%q%yn z{8AUC@$UgdQjbSngHhmPS}Qg*aPG9i8RZ*RRcBoxwC z_7D;fefJ|{Em-@A<23BmUN%84;A+o^hw(L`Z~EeYAnJZxC!?J`HvbGQRYSOEzjl5JNYr*rmpTKf< z)_6v`A~Ri0B<*%Kx70Bt%Ru^ydJ2z#?4vmTb=1w=i@9Mum3gwuoYqOVzQhP=NsM?G z*1CAxtBcX$`i;w(nbKWFwZ8>Pjcsat&p>1_VpQ^ASOVa!u+ybxCCp8N9D7Ra^)c{u zfLPU7Phf#Kb2*&ebsZ|@jpr^<_~5W6{Waeg-SRnyH@R8F&g^!s>5BUO@WL!1V(CWn z^cb+voB1&C3iO=+8dA1l_>vKyJ^N=;49O?U zHp1c+ux%n%oPSfHdHgWjqtRxl?M?q$9P(rMKWSl!3DibK1~#xuy)*1zB0B$lJc9y3 z(xjmU7^4G`1gXFFa*f4=!qzyBf`0FGdo>E2zhjGKBjitX59RWhg40_*W+KzQ5=f8! zaEWVaK`pid^8y7^o6M${M*ynL$( zRI10=|F_KlEok@0)&6=2749ilMSCf`*Vvk4%!S1>63Fy@A6z&JV~Oakrb240b<_!* zsG@p;=q^Tn?fBmf>X;B1zHMCr=6XKK^%Y&tc?{8U{&={(s&Tm0p?}R5?8Fm~6sSK@ zx=0o;NfSr-@ZTDG5?H^jOrBneO8;AmfZM-}=|7-TC%}`jKz==`JjPdlWbpWu#~?$c z3e{k8LCMm8C$j*hni$To6JDzt{RYqKpXFZuY?EdC?n&2Xwhk|bpMYd#=jz}lSJs$KKrck+c}W%)uHY1eyDHfUppy24XYHm z3m$kT)yhx_XvkBvsE~g?Oa5Qsbu9JouwGvc{8-*c7i^+`tu;I!nJhU_e6oW3gI;Z( z+T_cDMH z5dV@kJDoe`a2(xcAg?0dkm1<+7f06%6JeuhTJ|tYv*Gx}$2a#MN?iI6xSt-s;0JZj zh0M85Q{8g?c0GT52!(+Qq7F_wB@FHqctj7-o5A|7{hx?WqIzlHYgrp=Y(RhN?UJ36 zhAqnMT~|*S6K(W!$+R~49X0)tOa@>`1n$-HZr0uzS#mEy5`Xwj@XR>$EVqWy$`}b? z<&5odsmDEi#BPP{Z~q=$3e8zrg}%JEVp0XeYBytwkcX>WJ0{-giSmg)n+d(j{o9ej z_z$iZ>P2PM?C|H8kdrTEm@JOZ{w%AUl4brdPiOD*n5sI)i`XGEPg-3Ue+o#?hFec= zbN(Sg;{?Hu`cdUt!pFIwPFUg@Y*tY;_|v?pIbKr(W~ro^09?K)`H2d|+v+I%HSheX zForvd`3{boJy_G8OkKmWh6;5Mhb&$CeMtP@Pf} zaHklhaJMtVMfZ+N8dpwjre9X9%!?oUK0&E)lG`4pI(2HCOi=#mgeOmgNQ1@U`wQ59 z3Sw}&Js;qbX@3LWy62=Gp8!i#;=kYS2?-irxhGyHm%qZHAlV~;U&3A-FQ|-dFJK;P z*vxlu&p*K|11DK}Nb-?Bh<&X{MXMk{KMVsnNrMrJP|fi)&T&8RX#M24hB-~X^kjPO zI+7Vit-}W2_Jhrt0vJf7xJeBk6V+h}VC8<3{8#Vf*;t%Imo_%MI6?;m5M*o2_Cy!& zd?`bv8uZVexmKetz^-JJoXN)zI>5z2mryv%MV<|K%YUa*mB{@a9{RpocxRMn`-fjQ z86NxjYU_<)IDqW8JEtk_G9VEL{NCDM<)kY7_xI8C_u_A^Q5_ulGw}|E6kB1bE;nSr zqSJA-WPcJ+`4YoX56|^dJ1kuQV|PeM4J>Vn0r>p`R3KFf_cAK5`{FOcwAs~+=gW*) z!U9|MvhZj-r#j)<^vw^cf4Vh?c-<$e!I-X?Ccb|J*|>1m$Yz0t9Z{A)V@VBOSb*ny zlK6xhcgeucQSA})dpa@xptq22GikW?8h+h4;jB0Yv~->28KC{7RA`Q0i4KEx$N!=1 zE!f)HyLMlkAVrH)G)Qr2ks^Vh0gAK~cc;aR6b&xL9g16_r8vdiAvndYI23nHaxT_- z*84pB-RC`L?+?Jd!c69v|8d{HdkhD}6>f81GkFziQyKZ65bvj|s_JTDHdaiPcQ}PM z&yO`wtD7>S=-&yu9y+=lC{gUNyK%h`5V{8DPq5bsmU1EgFqI}eN8`mo^(6oP6UoLb zc^3ondPsz6Z|}GzxLHbNlrfAY`n3lYZdr?&8GSe}^+_*W{$F1gIsmlc-hQqJR1%M- z>V9{kf@G2Q@jYW$JX9L2_6kCAn$jFD6e`pF z-<5Axz<_dooL?l)ZP&cL?0LJ{@eK+T=|+e=bqI?%+Wn(ik8GPN(w2IrS{ze46?;Q# z$EefT@wzp5@t)(z0j5cA;dF9Dd8+b-3XUFLhKkiH1cAmI5m=|PC-6}mzB>JNzt= zLfr_0Y{01{*m+Q$blcrv9V*$VizxW+`-LA3jNp#cy_EqX*VqNm6o|Ku^lp16=|f5D zZ1!SJJ`~3|lm+L$#pZcmVlXrAw0pMdkoU$q%CjaiZOJ3*`SGS4Z| zdH2Cp-O;U$iKN!9oQp_-omxR4UG`PhdiEws5J57r!I!wLNEHKiI=mfv$@R@YxI2c} zm+y%$o8RgL(Mi4#1T0xpwr9z>XFzZp6=bAkfv$|d%e}^JUylEn*2v>}N8(uZJ+x#%OaWM)0g@l{aT{wih@V#C+4WvY&f|9 zdzOXaZT(r#ORLRP$zAi)eb)(eITLfD6SF<-Yroj;_T8}E{Ka!XB>6{T^~nmsP8zh* z!sYWBbnYSmI~r$x^LVZb_mt87B78Dvr{d~le>L`0|BTyV4770t&uL)IPMyUxn5HSY4BCyqxK7JFIgpH5D5h+)s7^vw zEXmA035}0HGYvH&db9jEU$mQOj#3#}d)zu@#Jh1+G#olYaX9)wq&^7(*$FpW`HC(c zoKCMiM=SM5(KU(Fa?6;pf_?4P{V}?fvw-Hydi=4DnDFK4-q+7go76#iq{~LJGkzY& z0-a0#G$`fq|EaTr^1L)+qD$ zn9QhH*$dIY10KL^`BzGo7#o+(_;1-M97=+3f?+WIrI}{e!{S*~?(5toX_7m-E_TL1 zRSzkWwlLcL_;)z@2G=X{*zc@{+gruEZ}%vC?tJ>-k&N(XN{sg?nsFyXvQ~IoR)jx| z;*1Ch%+_*sm3YUGnWQFH9W>Ku)@XAO_w>8*7i{U8{3~+`A=SyYofRu&-*h7K7h>1R zWVj~pA+)X@8tls(e;)97JV&^ln;ktSNHCRh=+J?1%pv2Vhb>Klcv=ZEqgHt)*p-aD zFL?Zt5cc+?KJ+by5jC1}{RK#_t=L!G)APsc#lAw)jc*7QJ@@5`^S{o}@WrV|QHa*? zKSd!EjGhP1ql>fW_hUkk1BJSk2;Z2%3$z6I&+e#{ABn2?aLpc<`{z0c}@cMU|-$j1+kJMon^C ze@M%D+kS7to=9esQEExmUmx(qcqm>35il*uC92zAX?$Dyy^V+SX$*~YX(P3O{hE@* zJvbXh)b3du_^rW?<7b=kyVU}g7Hbw0=a+##pUW@spUf4zNu<8^&xT9Y2N+dIyBL3U zLkg}yZ=&$@=JBFYsZS+(>cMkr@_Ttw!ro2W!W?8xce4{bKBhNPK`X@X)@4HExk3x4 zrJ3f;%P~SZT^CF0X_5l+&@_d0fQYPDWVD@>ccP)9!5agiq$1)A3MqMLrlF>Vlvq_i zJ^blpXuOizr+FC0@hS=VMTBIi*`YCK$Kz#C>kK1OVvdg`MDY&0Umv@Z4kA=uM%3kbOou0mONu^u}MNA-R`A$N1Au{*LKxA^g3 zEJge&06;l87FJVuL0=PLsYo&)YS^@M{&pskqPr^2Z?XCY!XlNEj^R8LeF;1IR`5_h%hFLCpZ4k66z0*M7j$Gi$c$J- zv>-D}Vspw{(Jm|<T2_!q~5a5XRO$cy_>;@jAh#CP-7> zwYlC#Yj+a4C5YJ1p?A_X8x7Q9HB+@nn$Y>%VO;O9HGmT9sD{+-et#K??et$k z8+_4qD{&ydI4s)nfL41`FJ}Lu3ZXfYT(V{-U}JBx;SQc z@Ll3J{LEHg4y`nbT*2IHndwijYq>byfT;?rMQNW6j0%Y9Ciu-jR)d_IGWli7iyw>J z6QUFF?^K69W1;d5z;VOJ*sbhsz32O>*b)w_W7iOi^g3wlmgoPj%q0-TQGj&MTVWPH z+z|DCjE_HGkzNj75lyXHuZu>MRtToF4zsK)xkk71zOc2dqx7cFzZY9Rh4A#QuQ*Oj zE^pqQUe`A;=C!T4^NO`?O>adpybMQ-Rw0M!V`kYtS@@&27Y z@denFZz*dCaB5~U2M$lUIv{sXQ?5|1hhrt~zOxys=+CcAz&9K?)ac`G@u~?~&f;br zSEf<+ERk`f zG?i4$=5kde3c1S(h^!O?eybWZo1LcmpbVFeTT1$uSrFX9(e3Q*&DrE4TR+ilz8y%o z=#LOAsRi(hfl8$ddJf=K9|p|O$&+ydHhHRhJdxAnM)dZKsuW1}L?-!f;y4=o1sP1a z06SK+Gx2oy^L+NSy6EIKza?hprN;iOFWU>Iy6v)`bjEgf#Q!ASwO%-CmQ!dML6Ez@ z_pAPHk~@YN_)JH;sQ74v%G)20N^n_9vs&(&l^yMRcEris~6UUgG3 zMyvk%kBgO81XaEbuSLI64iq<%NJWVy-c+e#)BuQLgJz?y>+91R#`0fEjui&z*eHdNzq(l`xTcW9Jy$v!(}B$`9g?l?q(Ydj9=3A`8N`R8)*YI!J7nWJ#oH7AE4~i zK_imEGIfJ1$6w`WadUGXk?!Y!PmCutwtG1gr&*V>RGx^jAAdZ5i3+Y6smdkB`?Zr^ z7Nr{Z-fnuRXjQ32ra<@&UaT*y;K@iWU08aGFv6!v66YqW9TcHCSLTf0TZLY|=3!QV zJ&@H*L+{Qpa#nJ3r^oU{2bjnPiM? z#D*}o;>4d!R-Bgs7(d!!n;*ZK(Ci&OF@w{*C@*C<5@j#!E_q0iYfW{9K$8pGdy7y= zYX{h3_e4*m?g+2<>>2h^)D6lhD|d~I{GvBjT@veBQ@NHo39yhg^rZ8@asd1RzG!=4c^z4w~^@rLK3lHDEd*QvI z71O|1{kHi#wdpFySQOT5Q8E>bs->=h&5SiI?cQ1B^7u)p%f zB`r_!Y;mAJ`4MFzviG~24!YMfP0D)cOeZMl9sba)>t!sXJOvz(N?vPwNmyl$+H}Qs zBk{%TOpF8Av%o#Wmx==WjA>^O9A_Oh?-@G$YG4&eE2Z^<(g9s}-hU{NuVzz0mS<>o z%er*ZlpMhX@mn2n>v)GxtB`=0cK+xVLBqp2S9m6?2$HyY^7ZWW6W-fV%5&_V>$73z zIDr&6k@lNUUZkQd$4nr(9_;z8w|8u3kq495kH>5&VjX3S&BnSC`*{1;i^cubue%_0 zsp)kiwiP+DU!C0?bUX+1HV~$CvwO}vwJo5BKGXZ9#z!%J>s0J2c7N(`w}=Q;hA2ct z;7zNeB9wGX9-zt}+{}BSLGJ)8^JUFSv^%%wDV;6+*=lYbpU3&oybA3-Z8m4Eg3(MK zYwl5X3?s@|ThSG_@4^1fzIrWPaHhKAWUVEoc@4t=*l=CE-SS zJ0_mgw07o>sBxfRG3r#uNI;we^H8+nJ&%+v4Q3t3Tg}}cu2l%q*mSMx?(BGAT-O(` zerM+{dS{xV=Mxci(UW{=*dsMONcWFRaPe3^?7iVJdUC)H3VVjUqDo@He_jKiHB0Dn z^1ns5xCOEPDSf%iGVxxp9hD5_Q0ODB`kFK*q|v}C6sgZM-+$wmlGJdYV^6#-Ghjj4 z+@4x+;2g|;JSNP{rPl0;T4*#yIt0pnps_x^7bWtNe;fdeis}jEzBlw-5&5A+uT5;T`q-5j)29$V&DOK;BmEAjC;vB3!LrcQO%>!UJ=MaB7$ zadbkkvAu7GDV#wBVa;Za_h`6AkFqD+;x{qy^$Nqe_45vDM%U|tT_Y*DLFR}GvfOwH_#@lMe+mR7lqP4wxd!DnpC}M4|@0}nGrC9V9Q|ajcff#P6mmu2r35IP< z{23Fn6oy7V>85Zwe&feDvaRSRyt6swinxbvdL_IMQ-0#ku25#s!M)YMos?cU#)1GN znzL9T&_vkDOZ9wfaN-)N;Y^Ree~ttAEYaZ1G4hsxc^GF`To6KVOgJ=|URXY5(M+1vZNaL-d&nhnh>HG^_c*)z17Hd8CZ z)oPS1ZO{ed&mY9o?!tfo)UsXQQ_&q4HzD&La}|tK3%h$ip3$Nm#iQt-S+F7gkBGzh zqWOJ;>$dKLOZ&cD<%DMT#9_Hc0-tdH!*#9ET(_C$<+s%Y5)fPC0inbJ{uIe{6^3{d zQ8V@)V;+hr?;NdbB5f4K-nYPEvu`P!b_a~9^bL=g40xK;(9eS$6A z+4_o)gJKZcjsy6}*^}}H7pXF*pbWfFdcIC0rJ*f%=i0ADnHTnwm$BkQ zQIi2^gUVtBbULX6!ezl~)8*}t+VKK2-`af)1z}DR2kwlYiBKW>U9r_R`nN*pc3ins z2&rVaw$$VZsWknY4B@W}1tH7~@}{R&)*a$Cv&W1np0FR6-Z%9d+z=? zsrCtZN{zhSqxP64xHB*t!;z0KsY^K-qv`i8=lPM(-pk0)ys>&B*mZQIk_ z)CMaK>bo6lH5CiiORtufXrjz3>b+IIC?q^{PdwMnXCQ)sYGBxDBP&d{v1~S$t1D}7 zyr}xRW8)BEh=v*a1QXVw{Y&mpOq~IHK{XW86OH1IgB#+Mg3C;*^YbKOaEMH%Qn1CF z>a(fuYQpz6Ex~UZyT${tu5rHhBM|DFwEC7kUkP4@ zC*uw?8m-I|AY>PYFPXveiC8P$q&~mJx&GX!O9j#w!#&GJ9t}x%iitk;7`eKac5gwCcFr0AUvNf0^pj-VuiS?DM5q4A zsPxsoQ)8pfM)q8HwRI>|Rr^}J{OGE|$B@puHdjIMDrl+O)iIXM%=IH%#7`N(6_cW6 zgZsn82fgEZ6_R%LvQ=ZG9aSp2e9JYj(rKzg%w^tKE(M%>St~2g~p%6 z{?W;yYaea4nn8QOtYiHwyeXyyN`e8VMd~_H*chbWKE?jM;pdJoj12XSaef&V8dr>` z*yg8}gj1K2?d^EY#`05tHu9aZirqt%JSkE=Dt5h$WrDZr6vquG$9~*`?+OfrM*nm& zi3%4Yr$4m#{R|Uh0449<~rVU4YwqjlP;l;%bf|?@y_xyU5xy{iNePiM)oL8IJ9$ z$3A>)GT@0*#+X6ZE-4ITw*s^GuxxfMb8Co)zcDdFvuS;Nq%|>Gbnd2GS2yCg@1&b{ zuf)6Zdkrv>F7{PULOVEYuUjsqlplYvUzmyFWW5IQ4KL9Lmb9vpMY<(p^^>WGih*a` zc;4UmI21hR44QalF{Ot@!4FCa^UI05sZO4r0X*gpkwvfkd~3ow_9cR`fUqnMAY`Rj z&Dx4rGyQgTC4h9Hui`kZg}1sp4UT$LG3tDlgN*oq!&|vt@@As)dYkCj4+`5te@?%! zB$o8e|1&%D&=bvlO$JwHSrE9IH{}zaX@cLW#itfG8Uwuw??}3jC{Go?IMx^l#R4Uh zKUc33f0ZzyL)+#G@4XqcyhZaJ8Yx2Ov^)MXh@pR>sHo0Jls~z4Hl=Vx?=(sam=(s{ zmNZdBqsiplvvvp}Pv!eDj$S}XxX$xTo`?AB!$mcquh9!lOhzrd_zppd2QLS(qwR-v z^y%Cc|HU~_>G4|5I4YI&D1)US$OM1mdn>4qu;D$AE%u|HbV)>cU4nzVx8vd^l(WBay{xpY@cAbJ^{%*)AED8UcWv&g``}~ibGAn7 zp^8!eP^L&2$dHN`HTjVtlr?{8(e=2USKz9x>jo}lewO~gOASl75YS+hAn(C64(B~Y zvX-{>av|N*ln?m#q0L4nOCU1*bO4VaKPxl7er8?tLON0FGHIj;JBxf&Rn_^dU!m`OHCMI^^qT}H-})1H)`aVLqY^o<;=Erli?&Q? z$03pCM!c+t866YEgoAvUOg@OAt!tu+7CD3P-_+xq@!M!Qt$Bax@hE*tKaw5DM?55e zeHQd?tid_6F51~GIy*xvW}-F8fp63#+r-_bpIx>mHxk7C5K9L18E@^u; zlxj}2iS;(VD}W)%4p6zbm$AHt>!9y)7u&c^Q6a3`-a&^!9yf=FLUrf5373?0?jBAL zvmOS9aj?_nnTg*kJcerzGDKPK#Eh=Cd&l`OuKV5$65N+0x9pb7psvyb;uVBfaG6TN zEoz`uqm=U{;YZKb;ZgFd)mHh#uhEOm1Z0$&)CNyZ=*WKUD~R~qlXLTQQdE*Cs+XfL z94L2+EeRiMm>>9UZ9k=#U6ZOu8I&Mezm<>Xq$#W?+IkaiyH2v6z2>PK(owV&Sj?8TW_$W!N64PQKOujSB6d7zXYAzp&+l*g1@@k&4kmJLe0$+;OwZ>@hXdWkH}1)5 z8UFO}9>-e6g#x!fZXsH**)OKBeT3^uqA5M>q(5iJCV7-9V@%fj=Ldrvewf6@$;8fR znRU@`9otQJf|Kof^9RH|ugILLX(ai+;sDd0HB%?lGmIz^T?oCn!TiCuhO4kW3KpsM zBNFGX0hRz=E|*KaBXTFKue!hDj)5YdRk$~18VL<1qby+r7LM@jtuD(~++ukIamtp? zI_<$34d~cu_&z zk{^lmeNuKucFt}<-L)FILxo0M>;Xox^^&iI{L6^@mqvX>8TD^Y>3~Bb=r2a;w%2+D z235PG_mKZLql70dh3IMqN-CB5dU@oe*fq5|+B0XXxny~=ZWO$P_rDfc6nyKKgmY0x z^@09qBbTgWpM1IhIAd;T;}-a$`ZQZmI%@y{ZD$_7Wz*rTo5Rsa?=aiI!pwwnj?634#{XK-~HpgY`AhvWrynWn8rhD;T z(eiwNz73oSx592%3_m>NUkb>^=cjSzKq*{7l_99ML!MmH=rkJI?TFABR5A2P!Z>h2 zt4klNY0WYlE(ncGQ*rQOOAbnimgu^1WD!KEs`wgMkl$=a6&vp#JoW#Q4`xsUq9gW< zfpZ&lpC7R?=fAPlz5j---WIRq%CC)^{{z689033U&-fBs+0VCV?sew_3Az1>I!|u5EXg6l_D2Ks z!KWF?dDZJrQcw4DySg|^UqYiP&jyKD*aT;Z=1=FqFsVau`SF~iJQ~-#9J1+fi3@GEuFanK$m2_t zJ+cA*{;A&H%-ryErnVY7^LE*r=bqadJ8utn9nFaWCw&RFB7Wy$8pd9?r@K5mKUVp5 zV}6xRe>ZE;+u%pH&Gx1x7$XD~4X#!BNJ`QngdPs?@_ZUpCAaQR>es4dJa&y@m77j$ zCT!9S+l~+7fDTiCp2d#k7MJRUn6U2;dNdx;3c?br2ozheU8x8YDDfuh=!rK?)v#3X z`-fdwMGeRHNM)=Rtu3WfC`hO+szsi2DsK$_Oz3ftqVVgSIS3Ski7urpjS*=@Xw=*5 z)w6t~193xCuT4xTTK!x4)7^itGE09Y*C|~MJGUBqCHiTu zEpcq1rw!l@ol`NKWYhbV-jcJmwbWs}*Fbu$NkVgcZXO@ZCr8sg#aZ&;20l ztkTS9m*%22Re~qO@pOg*NzTTd%^*uim+E zhl2wM2v~(X2xoWyCYXOPqec2$>s#ng#q|D*r&d|quANn5nre6@{G;ViKeE=;KZ@p_ zZS3|CnV774vytzZ-EYQSa~x|q@wa^YNw$OK0z3d2llx#IBxy2&Jj=~GGUdD+OmH)c zN7gl3+*=O?InIu3E8Y=5yqECU@>t9+=dFpC|Df>*5u4xuT7s{Cz1!R1K-ivgPK73W z_~OBr!f3DteyQL5e{hj@B4|fJDgb_D&fxaU%Yq?s#oB`_iSQqCj~A68c1n&`{wVxbW+k>Jw#VPnvC!`px_tY;T*Sl- z6gvzVs{qE@} z+T4G2vXy^bsU-p7OltFN^fs$-f4u*7l19HhslvPa!hf$}WPUWujGkgLziwOV{`+rJ z#i|AO8WRxd9XDv4x-5q)c)`Za|49;ed}scf;U0b#X1nTL+-mgdchT^YSosq>Tr{OS zVM`#zGU4eC}r-u0T+?QkF zSH3|*P_;YZ67%fs-Rk>ehz<9DeA>ScdRUJr%GhV0vF~*4-LJmU`gz6~iz>jzlu{t~ zk_%V6r~jZ1^8FvyH!QEAX4047e}CJ5En74BN&Jr$U-*Ax#s9}m|0MM{N`1nx@Q0jA z;ZuK>_fmmv`LmQu<>0W(D8JDH)o-iHNck-<)2-x-Sb{dX|BdPHPUyzrV)P zkd8j$PZh_0M&T8+b>#e*Ess@>>Fx}?kQQ~}onBIa(sprHpfh|nH#V~2p<*>3>sF@B zZ!jDGw(&nf^|XKT8n*GDxE6t#o6hOBibo*9GCr@9ST-#iGBjrQax@`uM0N1Oo6GcnYkHrS~*}|N8PMP`g53^Tt8dvb zP2b*^9PcHL`bSjMu(iG6HBkGfM1b8MOT@31KStzQ3*}6eTp0LO$LQ$T%MKLF?$}wX z6a>&zUp@c>Q7sVw!!!&G2;WrsD4()X7JT9xclkjej)QE8dk*1i>hH2+s^`u1qQ^Lb!wT2{<{ zpQ<*NF4F9o?|m}LTdt9p+&=%lVBW4Xuc*C$|E{lfRfq?X=Y$c@ey#Y_TcM)T;|6z8 zOiZ!AYiaM!agd%_m{6)l3*4$MRbZsRo4J{tUo3^6F8g#Im<;&C$an2LgY~$!+L9r6 z6K)xGKIy&puN(`aC^jFLk30av_RV+;ro%|5%Jcu0WZC!c@F#z8e^xfceZ)Iz^GX@hUD<>{OJ|eM#AdWwuoDg@%Jyr3x%bEyw}#z z;y=*^Nj;tUKyp{|1ZL&Z-r;YFWh4BjWM%0$Vx1&fg=jsjA|utrO3 z?;d@Q)7dRr2yWTE7WrNotx@}Y_x`MRc&MFuYdvJ$dzm#;6)&We)4=Cdr)6n?Ut?4$ zVNN<;ZfwJr$p_95KEsFZ7D@1H>G}yUyxjln_T~4i7vJaPLG!&D{rpB4oEVXx^Z&xz z^q4F8QxJc@W#s3T(|=|^<9J{qR-bHFtQG#oJ$+<9Y4hIrX#km&6u<+!)o3{mkqDC9 zm@4Lc%DlKM?-9S^8R-GNe}+UHL#4mq+z9|ri9h(O)&%lgPk|6pErUeaKBN0olKSgLi2N-?}PZ}(lzJzGsgJo%GWEZTH{@Fvm2`+I~r z0)P+HT3tKyQ4LGKZMM01_F`}{Xz)csql86T5^o}exqJA5Retp=%+JYRUBqhXp=Qxr zA3W^9Ai`r?o^B8Ae&2xbIZ)u*! z>S48>zc^deA8=9IsSfAkVlWfD2XzCQSUVYH&?&*{>l|qBwyAbck3*Run4Otu1~~p7 z00Q{ZTEqhka-O7`>OIVw>cMT8PcFQlUG&Q2Ep|zekzyWkdr=h%XdLl-@zheSt4o)u zgJWely+Kl32kh5?eKn?37(>PggUWoD)pUSoD|b0^X_D?ya`$5V%>p#}Dv>$8;i`3c zbGY<>lc$>F!vGFu_v|DRc|dMxUc}cb9@z7Ar!Fw>t*)@{sZrszb9J)u!xK8jaOG6c z+Apqnj5KuPESTEt=B1l{$z-_0X(6>w7~y0F$Xm4|==z^8!N|7odsPYvR{R4<#ulgR zm{~(1$=ZmqUpId%u8{)C03W^oAbrONy`M~fSjt(Q{2~$)@yfZJqJ?@L#L!8gO~g*O z9VpjXa2eVbzo2em$I6V?X=khPe#Ngb!BkmZ#5+01r(@UnFH78};aNHdiT{xBTdM|5W%V zKUNa^Z(Zj9KR*@;mI`kNo^Lq(*hz@bA$Q40aS^j?R^E$HK-t=xYU546Lzhl)Az7DY z#SXn=mPvTVT}#AS8{O;|v&yVRpKL|8wfMon2NAx=!F_N^pd^89^9x09rn$3HgXC!k z%l$e8NJtR>;W`bwLpsXEAK2;&4eGjlt_t$)%%N93-MdK8y76yLyqG%nZ;l41<6!Qg zF}M+Ud2T#6c`Kqp7v2RHr_OYbE=1CKXj9zWAZTZ=pS*b0yo>q$p*8S4Hpl5|ES6`_ znkSIwo+{je2w<%XO~l2@7{q-$H^@Sy(rxSVSib5{8kO5W4Cg0-i!X1Vf5RXk zsE=2gO!ga>iB$^lDpSHka!cm;bQX^pJH7p}R&L)7Ibs~yw@6J!)l0_xlFaerO5z+7 zW5O0E019)$#CBuzH^|J!zL4dE;O&j@{Z_(kH41XkQnycX@|<7)DOWITg9#3Ay(JsW z?ViS!C0@^c%T{|J%<;PAehV<#EaQcGz#wZKL_~)7{=#_l>5SH6MoR&s zh3F=__F^pZ1_5YnH+~>lE7r?V$Wr@R&>k&k@=xN}Jj?{b29Fs`=rQ_cMb@26O+aSV zN({hY+0N2(Pe1?$p`WWxBOJm`kAU!>0_FE^Ju(I^yifa9w6N|yDPhngBNXz8c1HLF zkgI9O+8iCY=fX>eF3o|07ErEyM};=-P`4LDFIzSV7VOZuGkJGjxA zK7Dk;w408NR^cr~#ufJ5Xi|@KTTOUdOPmlZGu(*v54-=r0+LrB&u^Y3>Ry=}?!UpG zb=%ZDN|yDvdaqZ{qMHTmT$GrTD=;c9Y6&4RU!u9zZZIVQK{}0jUD8_(a2qvg;}t0< z_)<4Etl4ShL}=F>RWkdJiNCa=2k|7HU=l~N#4j)8F)@UbFW-Nty{hjbn{#gJXRD7} zZ(I(tZ}Ed|sE}7_K4sLKTXg+dVPy1s`vKSE+U@BV;EW1S+M=kGg9l;1w=M0lHIa37 zhfCUwPv5NZ>QlZ3&b-c^05?|rmZpYc0j4k&cK;x|Bmtbg9rR442-H@bOvzM^&0>2E zRAMU;@OwOc?*xk9b8!fj0qM%O#cTy33=$X)NAGKIgq@&^`3WX8^~2hg-I7}ty5J+$ z)lQ|DD%{5`&ZAXWIpEPQSNHO;Qar_;MD?s;xYl0P8x9nRF8$a&G_@1odMOCdTcP*c zU|syU^ANT8(M`=|<#WFx)`Ea->8;ON?(Qond$?*$+f{Q(~JC7nj;Tx0YRj`Y%fcOuf(Z(fzH2UN54; z?}*Zh)k6$5&O(B?x=aTi?&R=5))ip&z{&y-sTk#}L;BV=zo>dudU7)K3E5!-b3q)VG>1#@ z&6H^0tZ`<6N{CcY6@ol<8t>qMiL(&t)E|f7JICU4qpP{BpD3Mny5GW@oxKoJY?J3Z z#}%tsSwBXe5g->$qx&RLj<)y(D-?N3~nFymU7p!uR|3?;H^16ix6P$x%$^)+e_e!; zN*EP?fw#80BdU@8uY3gu!*7;bMHTe40iA7FC}~@srXLa?yUIuH9vT*{cBJ_ z<>-G63djgVq4H%X>G$V3YJ^Mr-O`AWtL7V&70mB{Y3&xdA`m>P*Ef)_kaJNrTP}5; zZ>GVE0U|%VkydBl_&gK@U*;mX+VyiZ+hchpm4vwzz3oqk=1G2{^OQi^4~qqaB6xM3 zZVDa$P|(|g_KxSUpVljhIS@mJki6%750&*B@S|*>`SP-rG#m0q2B{z&+WK%$wis5PW zgdD?bwP4_z3n#_%Yoh&qq98pPi$i{&wGX{t-QjDg^Lf*f%w5AHOO|N|!w@53fl?tMiDwxkrjv`S@XI z_2lCrP)z$KGAvOc1)dgMM?sSGUkq@^gPR8(tGRN!MeeiXTuI)Sqm4h+Q_Ig`cpl4^ zuIzt=Oz=8cggqYpSuKQDO@4 zWahi``Qo9khZM$;f9&hq4XeH=>;w1TGwtes|Cc4;bIAUv(7Tt_NG_u$ykfymqplreMjrbs?g+{0?IB6-oN zp=Wj3kTl%~tzzYH3QS*++^(kW(=?NT4Bm*$kU%O*9Gn>l`XlN?sdsh%@6JUFO&iQx-F!HeFnTq6uRx^ zrTw1| zFlQ0-qV1F>NDE+zC%;!~QaW;U7e$yR(l zbP(wSWF8#$x(*1|D|}> z%Zak4Kz{L@k2qh=+84ozj9wj%EH}82x?@Q*=@>_gXoNa(-Q)%4z3F7R1lgJ@K16f< zK!oXCVE?6{X?poQ`T`R2{2Fl5=@?Ww{pP+gOg{fzKAG?BLmXt4$a8G}Vh^$M z6)ks%Z+@jR?RGPo{W^bMp`^u!0uwd)$$FPsvDcjIAiapnm;OROi4A#PD%9)+#p8RG znf`s?L@qPceUDhc8m@HHX5?8Ql18~zUk{j1fkK96$VzDU#4EV8&UwOPaE=lN*t!77N-PNoud%pY zUvs}1ztxDEptoPdsy&HMU&C8Q2L6lcb0od6xhPvFn5A~z1o5}RIM69S)!^Y7B<#^M-hnoi?+Oa+T(*#SIC2YEo0sCms$zJ7lqC@=3E z=t>6qw^Jhou!|~!E?lqJR!}swCZ&(?*>dxupt8VuP2zSY<))8DFty4wi9dYF=c`bCV^lGSi*^CN z3AktuHZJk0fE8gr*{evrc*~mLC$^q|U?;thQ`~L-aZa;WoGO!JxnM7I_wk7rP7mGX zTQf9ZBZD@|uCwF#f-yN^7~`JxT%cvj%~aU=?!jNSw+;v+#bFQn*+=c(<}Y_)$w}q^ zaM;U!td#%Jg_dH2*V-Bony{-)Fbn$hSR0~ zX>RX=_flQ+inMPH&ZX5ZT^E$0teUVXO3yPgNE z^AC2YS^AH#+)X||ptIOhQfo&o2dHyo=6;&*x20AL#!}=PlgezCs|a+c2_?8bpBfWs zZR@vjysC>+VcY%2po{FygEkD()9qoOlPnpmJ&Ym2mAavBwUKc(-EpA- z&FfP25kn)G--iuP_RcAmmbE6RoaQChlgC({E3?+$K#4g(fX{!Q3V-mUDPQYQ!)4a6 z`*o)`6tJF){ogn$LU^cE-xm#_k_iKR-G2BGy}54tzANMG0#%qt@f+Fp%f6mAYsK}D z0fn^0ip3v%T)Ch3&jmAm9)c4I>7C!Aa=hdq&Zp{O#@TG}F$&E?UFQbfoeAb*OBE|& zO7G*kcl7zb3f?!MZM36(PO@7mCtCgdpnWLbq`pDZ&-|9{}OFWlM*VP-v?G ze!LX+OAfmCA)G#<65Yixu>=HN*S(#GSl9z21R7eHGxI4DEbjO1(0zg3D5u~xFIusl zROR_-&n{b+FVOBgVBw`f3(_BUP47I~=2^(@5pIvAdvtoQlEX>-Lg_lGC@ObKi2n|i10+C< zz2`)TS}uQb+imT0w`!1=`%898H7zc{^_96IvQvx1)(iCiQ1+HlZM|!|FA^YlptxIs zwm1}r;7*~Xf)yxEDee+ni$jY$6lrlS8eB>#S{#B)aR?SjvIkxN_3rh)W1n;O`NXFT zGH2%VJokOwzw4T1Uji{xUS-{vMbTt)>FKCwKj~0HW^^!3rR!45#QvuD|4kH|ro0^a z4vwusv)%lPtay(pN|iCmlEG$H8PI~4`B3qz9|vrbaE z_%^WREOi8l4C#Qh&Mm^F=a4vU#)7Ngso8Hx^B3wT-cvaHJ!<UChhqD@Odmh=`LD`s*1P93m7XXv z+Y4PXT|jDlkRgIO!t6fCiTxlA2!1#w{m1_+BhrEA-a_}+>&Pqx(3ITs(n{sH)Oh-h zrfS-`Okh7wF6ih&KKZqjxy8;&q9zOQR@$+nPv6>H| z50>ll%StU)D{uYwZRf)1d?pi(_L-^hnJQ`JnE2v#vVtRU3jh*i`~a+xXM(sX+L8ODUzu12^gmBhlj<>F^ zydItc&9WEg$pf!0^%_KI3U!Az?)Iq>Xki5~A(GA(0S0tnfQq){{#-Mz++F0k^oirm zTmEE4l0T7qLG-8KuP{-ZfToW zL$gu;;rLqJf#jh2<`4bJJXYsd_rv3Zz3Iobrlag%ehyMyq37_b8{y7lUBC)(jA7Fj*L&r`N5tx04?K$M zPm+-~GgHX&$bjT8?$BjW$|0;71G`305DLzNjUj^#vPpMZkQiVXm>>C%4O*DJ=9kf- z0r8^Vdk2%)z7?5nC zs`qOM&1r$<&A^NRAa@@`P3*x`ySo(+n+K^~8%`Ayn8CL~QAZs%bh6Q7U~!p{9N(udvKn;_OFdBj2@qbHSLU$5V>@>gfF1zQX1p2 z1eS21!u3`va%Zv0pMCGL{X>e%pH)U-EN_<@G}W>xchq&~>n1TCzRy*}@C_X+VKu>B zvmqOa45GPcrhhPk6kvPA&a}3{Mqc0&r`NjG3cpk-qrDE-kB3+Ci~RVj!eXWuqh@tb zt1DDSnr!3ku!mM<+21s?4&e8)i_3{=n8F+ZJ53Sz&ab3*|3bfYSCe(BiPk4jfP;*4 zk9rn^6no!*W0p#9Gdes-oe(3`4nw({Kg{n8G|7*JWy%vew}JsC#-*v#Y2h7WmB)Fw z)4{472AW(Noeq3dg3`21YI2yPkelDwKNol@~IF@Tf9Evlydf(Wi=%)Y{Ml zDw0R7qV0wjWz3sB;A=|&6oBQMVu&T}@D(T>7X&i@^PMq-zgc{W70Jes2$m!_WBtj| zXD^||&59jukI8jDSa#>>-ouL0+hGgKqr#;T`h>0-bnJ5tPQ@<#O^q1>|8YU{B7r$a z(9+o8*!!*=dsqE$TbE0Qxnpt_i?p9jU}pgbSsZY|z$Sifoy#RHjwJ7&5+o-tbt>}4xcg-z;onP4RgfFLeQ{#9VL+yzO5GlE3FbuBhg4pe;07D; zPkKnpR9VCd{@7=*m)?GCYO~z@D!v?YZ!}S1S!LT3qtyb5?C2cdj6Y4by$o7fVPXql zZjWV@E5eoei>b`{0;Wp?1pV{D?~ngURsD5kvDW~DP5U02)jv;n^HlK8lPt;co3qYso%A$d zf;-m_+rP854E%=JvkdKcLb7{-ckN6$83f2H-r&IB@ekGw$>H z?Pih+1dHbF?4H-Uz}w1!KUENE9lEA|x8+7B3S4Q+Db$&lD#YJt9H%{ZE&sV+_tIBA zXifqPx?2xp>+_nZopHhE`CBMh@K#&K{!=If{XZ58M*j)Y-H_?;)Wh!2)aXdJtnd`+ z55mXk=QDX$&!!MdwU-eo&&(G>0^J=4F>WSY(e45B7wGa{iBA11=CR)Lj?D$;U&`SB z$)Z^ROnTk^lvJF4kr?(K<1$UlnTl_;d9kYQPUT&FNR8nTr~MitoPOXm-(kv56iD~p zl`&AV-1NWa)AGc0vB@Gw;%_>TqTtd1(>~IbgFkc^5=cCHFnVwP=k3n%8>0^dSl>En zD_WsxJ$o%P1!CoC3(pzv-5>wltC{ew*fFV?YdEwl-|X%6p7<1*chwGjujuGLUAOIf zhww_2m&+c1CufIx$2HaNzdv^m1Z9wo@8sCvUPm8s<(+cDz|SETohv0RjzqTKa-wc} zk1SJCZ+d4gN7k--iG7QEgl;d?ybz!N?nha{U7%hrW(H&D!@CZh88DWaI0LU|!}e^= z<>+@T532i<>kc>sdDe*3S(Uz#61zb~|Div>5FPcfkTW_|3eZBNEps?P7Z{Binyte5 z>toyE1qaUccl0*|FJ6)90%l?`nC~JK>1jyD_b(k(R_*w$Sm{*oBRN(z@tI0u6b@^NpQ8q*r}?~8 zjaw@~S&nR#*Z1m6ZR==OP*+|1DrEy&a1Rz1H!UF@*HuBiCz*>iD>y(C?GgW!$?bD> z{n6s%!Rbzl;7Y}yKyK`;?7T4OvO>{o)s7XpF{XUYZKsqKx`@bjSjgD1ssM#Tm%zK0 zE%^rmo}2IV8cdJ@c#U@tkDdkgd(=k9cmmTZK>-2K1ZXC%!UTr2aWx3-0F`lEw)*A_=eZ@?#mPQ$DEt=7S;i0(SDe|3IGGRls6Tr}J0l5IKS>Crla z2h7vujfeIV1vA?#L6-UBE6Lr4Oxs4fvN!f+wJ!}?IgmNB>R|09;;E3e%N}MR8wEZq z1qnM1oSou?b@g15E->XW+Qu)cm@;IJfk?bGpjsy;OqQ3F=(|jVc>YDOK7G{5TIXG` zj)r+ZM$?`Kebzo>{DQX@fl%!6p?*>siNJ152{dTEpW4`D_Vf!`zYSG2ECz|>@IBB0 zLeGl=0&6G_KYIRUFT3u5Jg&#D&QUimo`w~-^RCMqyucVyde;16)9SE(&>Y9!iusfA z*Z1XXFi_m^kfiaZ^6}#>ay~vM=U*?rq(XoH$^Y$`a-esvoh;3==k>gve;dh^dFj_7 z>#Yv2$5S1uEuOSfx}%E0W4dya&WXB}ht(?Cie++dJ>jnNzLN($zz1x&c$bG?)uun# zAcY$6N8u>8=(;R4E4mo1@i6w~uw4&!ojzB#Bm^7EV6p4+~00g_}*Oya#`sz29D? z39+WLuhbEXjZzfVV<(G&fdgpNSVGx!)^3a_geB9%N0hurW+tETrquJ!=w{CpMSKw) zoy)bWB`D_?m~cy*{M(tW7qgNa!Lc4kaKy*&a<)g_sgG42OsF16^NxRmIPpYJjNMy3mBq70^*XqvLKoik{;=nx1!Snw)C zLMEY#ghsn`ki83j5j%&!&~X&3#YqoSz~lCtR07sOvio@C#q_^%ZDpr6yRnnsjdI^wp_uQ25S;Buhid~uqa-*AuXz(`bs zUQ$KyV~n`7ZZeL2+W$hYD3GeKe!|%L8rwSSh=^zK_EDcgz+j$f=ylxb-KKfBl#xF0Jns4Zqwjk*uu;v~JdB9BCW4_Suy4GemAXp$_N-9RQ z3bhkW3zTo-R#?z-Qt-MjQ_dW(!rkM_rXug}agt6QtPH%1u}AE@-Tb<*!`?piOD20z z+T+XN<3I-HUsfw)^*^mvE@ZNMpV$ZH!NCB<|9vvr%LhG2s3UG6hylVq^x>1vfKHX+ zG?l!E$pMjGXgDG2F!1hfSqEk#@DU6_`yD%4K#{)!-~G|rrj^uI^aR94qEbEwu*OY zj-U9T&!6~3KFzQ}q*kY_YThK8Z9gk}_KAIUaiHt@MaMsVc?^pHg(*bkka@BlYJW9e zOzJms7(qtB{%MFU^BF50F*}`EaloKz-j1!5lVJdtP=Lti?zP*iXUxso*tMzj*rpVx z`e7w!@Uk7n$c?jKzoQAegC3o<=7@gX5_*@p#yUPGVx=Cbq_-uz%B^TS14fV zA*!J!@h#6URmS2a^5r;a_L}7p6PJ=29G-vrXPF86@UxjelK5>^!EjIj4({%Vl44XO z5l4ulh_bk|mnLR6alq{%;n~*X%xukEL81ew-^4G|f*#S?4_Wb%i5dc;7~yyw);Jvz z(~Zv$Gs-Tcqm=K|2123$JX|VWHL7BGhJ+N{C)}S5i9QTH4Wr#0-?6?7m3;r1PLc@7 zJ!bY|i7C%QdG!>BY=fbQA|8O0nh)o z+zo341Ek7#xjG*@uZFIp{$uY1ji#Qg^Q()tH@wQG==ET)+Bg)#TBp~6-LdLTU4-$Z zBsc9vItk&JiYrd$(Io{$_c;;FdmX^{_K#TcZQv+1q0rDPnPfM@T36SF_zgS zNDd?}+GKEyF&R}g`%X0IJ=rW5mw1s;mqYMoUgix!<3Tc|TvUm=Lbj}T=+8ByO;>}1 z(xQ`FH6eBX+cUXQo^ZF(r1DtDhW%+r3Zl;r>*I`*A=cmHP^j3m?=mK*gT(y|&2S*UPM3 zTRl07#baYmWv5LBYF{#5*Jz%>%Jh1dJqs2tgR+?f6T)Q-38raIjwAXmpF}%1kFf+n zN;WpUk%r+6EziD%^8IlT({NzkVeS!pdJb9aH4C>AA=nv$H98v-uQh7`IdSM(UZ#8F zl)bd^4}G0ce1}WTag9b^Y4#;!P8&Vvn3N^|qgizof{FKyWMDmg_3}ZpGcC$CuA994 z<|^e#FEJT7DH%j4s$|G^O4WB3vR__%oHZhx?T_mFNdPU-br^r#D;Lwhg7h2<}oB099B9ljjCf^5s@8Nd_6k}{1grtv{ z5UC?1G%tA{K6`>g2AEdrk|V@qo)T=8Vd8pN_@+Vup4(m?I4{YsY~}^h-+@@?Sd6wQ zlJ1BSa{0_zuL$l`f=9ATE?O)OwNcyX0#tg_N$D@U+pQBnf?0!3)BE;Kg17C8^mgiA z5k2uG%ZGNPN6?q#$?x%m-AK&s=f7!{|NIF#^J=hsJ_N=P|MS4^Ju}=-{rV9_zF8N` zsh6K(%^aUKe3c|oYcV#6nHB$w=Sm?O%4&TxeMViyUtWL?JD+khUjF3#_MnK^g&oL7 zMj}pkD4#U}_j{W>Nk{M|PrdA+l^Hefj~^+r^ezMpcby>fQw|c+D>eDI@KNeY2qoVL zo>LT^`}_8yQHCxR|bY8cS^$kcI;o2KR1bKVdBKtF0-E!Ee<3W zf_l-TVQ-h1Ka||;PgUmY;bh_%Dhh;~>Qn%f)D)=k)emjlaytSTb4)Taz29Gq{o#HC z$p(W)$3x_V00Owd@;#&ap&WC>$w!37xwisl(pV9cU6G+QJ?_K;G(eXjK|Evh#nvO) zKtyc)6rnMU!ud^+bQe1x#q)!D@kw$5L88L>O5=@lu*R-vX4x{8+O!cxDjbx02cA&r11Y^gAGlS^d>LOfF0AY2v_?VyUbrC-1=0_zJd{P-Y&u$b$Z=h z8K?g2N!&Xy2(ioybu8Q>;eLDcOx7o@Eb3mh?xPHsluJZe(7xrV#OLLZIIcdy~M z?bGWqDw)MF`14yG;p_CkAl+;_^UOV|aztNg;CMlk{*Zl6=Q;KD;W2c5Hqc+bQqlCP zDl5}5`Amr<^4N8HJ#FIKN`dw{dQpS&W<+{e8aZocZt}FyJB_0|mKI)AnkS1qA|>71 z|1}>&Yu_=Gf6|@c%oYyB_e{3COy)q^A%1WbicFO{LBuE7_qcpYt%8QdF%CuXd43;s z3q*Tf20^UnIER~Diub6QPbPVTAf$LQgHERA_zm9_-y_4}Q=7TPu-e#sl>jBg7w~Be ze}M^;P**;_>B@0>e~g`f*bHv2N!*t|0MLQ4@Bjuc)dzyN8gKbG$aMv}4=@L52Nazz z1P&$%@?RCsBWY17-ywJI!BmyZhK$tfBJ~M2q_jF~pip0?P{Ule#~Z1#=p8OzkxYlV zShw*V6I|MFtiw+U_tMdh#M?qVw z3glVd1wnet%7<;FuvaOi7)kIe7}4uxm?q|>@&0($wB})1eA@+3S9AX?5q=9|!yG%Z z87~BTCuAPfr4LWt-Nr9KYS$boddnu?fK@8n6T;@~Cn%OR+3eLp68zAVF&=lqM6k!{ zO_QA?%>MO6<#K-Vm~bK!``r{y*T-TztUQIsY2Bw;Jn=AVyWFuL9}n^$t`yt-PjPde zAS#4|Oav1M&k4Hav0CH+FO~JaC(5NR*heesew%UjvlE!?WKN<{zg;1#n-0=cSEk|S zx9u8a3m~BVy1d+=YnwzteWpx~mQ@EgZfD38@3qM~rp1P@Qcse8-GpY$ld9!9Xy79n zNNW6k`U)h{kE!jlIN~RxoCP)|$nD3KyB`4c%96}{p%4Zp#^=|du!qHYA($gq`tL z*g*;$FK3clFeq=IDkt?j{hX~cpTqjp7e5@E+vUgahEQ$GRN<0Oai8)OY{m8VLx@Yc zdFB@fyVqoK#N`rBfxeUkh9SyTk@Dm%PGq?56r-Kp7a!%6NblFB@P7;hp7xgY$^_pJ z1i*qz_Sc5$XuhMfSh4lD#)z0|b*C5noj8)ghe~p16PoF?y`w|N86qSo1SYmhg;QXM zQj#*zFJt1+NIP?JssbI0S_&ZdPYF2VY(%q?Z*wkekaAQTsQe&hS7bY`+w)pkR%|v=8NVV8Gj<>VN^-j# zkVDo-QVB;Hkh_p~*XE*=cT1&}YpD7HKoLyIDu<=He(WjSWhAN?Co_5#%BeA}kf*n3QrraniQ&&k z9{8?P!KeRWm$G(KH@VJsqLj2s{KO?p=y%p|gIg!)cOS>V=G?BH1@C5~D@0?`)M7!3 z04og6%(!8Snnee1Y%s97V*`cF@)PaY6vIIQeoAj4r&c|#-zBKE; zV`+8f?g{dfuyi#he6@u4L5$#;s!U*vJ(E}0e4NO;5L!FvCo;BQKe^EO&wB$;Q2gHL z*}&fCJ!9l@pL#w`2r6|okgXyVmNi!glh57MVDr3shLjjxmpezlMZqBqW?8b-v=%%rNo0b2&8(1{zDZ;{mu2g9&860CycW&NcO!vNB;5fI?G zWRD_#RQJ<((&oiYFRIZyyQkeRA?z`P22ntAju^J7?FlWYL6Lo!H%-(<7_H5we+gzW zWe7kW?i)34nRhU_e)$BmoJEuPr>`>0NT7^wGjI>1{RjZtfyUa z9<%$y>}4$OPn0<{9UJe59WLG-^`K4OoJ*e~-J5rBM;^U_^LOCa&W)w9VoHIU75;t~ z#CI-yLa=~NheLBmtfbyZ?kl(cWbUaLs<4PXHJ*`}@&5U$^H;0WHwL}i7l0-VOdq*V zX8tDRJ?U$`e*BH6w}ZB#8FcZos26`Y@}IuXc_K2!FC^q&@J6omtrY;lhx|hbm$3o0 zOtHP#gWQckI}6YfQwM@U#xXr1o-wF>IJ;Mrlpd7wi0|aai<*EVL-yBubn;5wv1_k=~R=h$bw6o|pmq`>l1AB#0PV8Hl0T43OY z%#wOBqrv&4E+DbqVZ1OO{#&KfIaGn;qh4w{KtEPcpG7kaD@>pgQ{iB$5F`h{G_e*< zBqI57L*1$0P{4Ll0W8x&*Z25A-EQXfcg{~+2iu?vw|S{=ukMGPXw<`cNZ$Rh)2Y8r z&|T1 zLMJu_Q9Q-y+d%e7e)(%EAGO?r0QfXlGGVe0xzDgOC|@1AWxL5d?HR{Uw3sKJ@^tY+Mm{qwVTLntL(`DO4e zZHsutmAaR!Ai{)97f`}l6IEh5dRxjWxwX_mfB4Dwn`GnB>FcM*Zx#}gQEysLHTjL0 z3@;KOb~KIH_i=Q9V5j1_=blnwliDe+nJ#*52Z_qf%I9YSda#F}1RIww7LTnL!CNF> z))~*9Vuu^1?A;J>>_45RWepUkSeO0i3pSg+UXyE>=X}~P@|^UA-_P|meFcQ_$gypU zdKa%c^U&^9M^&PWg#F}O7R6Bs_SKk@OfiLm*+oC#T%G90C%H9ziAKoBPFL}2!Eucu7svDj(Mb=dxG7j7+I&)Us?$zmwEFxqpG< z=N#iJ$=5f4??)~B-uKgzQ()}WIR5e{JUOxG&a{R1q}phtR+^38=t^k>G_dcbe=Ogd zf{Xyv9s8LLZUB^fY8DzIIknJecWLUNmM%VVCOpcxfd$-4i+mCZ7v41ySF1l&n`6D> z9CUSbf*rZ6nbGueJiVqMCyI3J%p4LLH~VD0&BoyzyS9h!Y>Wg!O2voa--&$wv-xw88v@B2T5Z z{W?x>^6N8SMTIf2hWm5%5bPZE5|I8$0M{YP;@S=NS-}A>Q2tSYoq+3eU2%mgKRTQS zJNb$H{4b%N369i6Dyts;=UfXfqQ*=EGGNbYr z3-|!W@=O5KzEa3CT&}ihzV`Qxv7QYV(Z14)JWh-aw;LGcKHpZf@SUI|%;56jct@nl z=Fcl7`v>0Y6|xb1V#eL~5`d?*Ve^^RA@?Fq7CBsGS8^j|{_MK=L7&cxBMABth*%u^ zD*C*WcW+O;Q^kIb{uB_mgp+PS#pVVW`C zw~0P-y7~T^b^Fz`iK+tF<#=*o{Nu*sf?pVXbq>|+WHj2^lPCCVPA}8xk}`c+QD=9e zvf1LeYQjkKm|%J%a=nC?gg=`U1*x18nFgZ6(6@o;c=N@sHecpr z8GQJj(ecA!&$A|2*5}?-#>r!wRq=7y;?9-C^R-AVBxmZK3`+P!KnPq3@Rw({z@~|B z3tEJ;laH|Yd50DCR-{zvytsq}&akjD>e2{)5(%1q-;CgEP(whp9#9uE-{%-pVVEPp zKEUBLyk!@S&S5tlsFz`FTrtrniKXN7Jm9qM))HV+h)YiALBNw;1bH%zUv=a zSQQ&=DDs$hX2Od-`QbX~W9SC+#bexAud*7nMlFF?Vle%c1(DE@j5S2nOh}L#^6lP> z8q@Xb8eaWi;I?`CmR(263%YI25n#Y}=S*^TBZ2r7u+y#Z2P|!3;P((o%8&7Hs-?yg zz~S1Sm9(U7ioprXf+Y96$Nn5cnC*=sX={pHGa=vQOs6(so2V!G-71Q_3739NyIJY% z64A5uh_8ynJ8!edhEDcL5I4SWZ14`GSN!Ru--+-U)Q)n(hOV{kj!`y1S}}6(T4(|^ z$>XSk@QVJ1sdxK1hFq>HOeL%20GL0r>6+nAf#>)0)fmIYuPLJ8?ahfp&-B-coV#Al zK;qsgXC@{ADU7#-(i{`8MKvkAA8h5PhFY5XkGILrjDRgYQJL5(%{C0!O>QdAs0;?X zrYl%PdgWQDAtyE?q6mL30|GcpJMmGwRNp*Lv$;M5E0isNNz{%gcd(HJtIAE5G^)@x zmzp}ed4`|w3yq#XOkB4d6wuqS2un*~lTkJ&P6l*X6IO*0*Ym$CC(iO?`AvVFW_;2A z@;fLa;&6C%hxE3AvnKHw9;48{ZQTGM*N>wZ+S3p+a6zeu;|cO4rPad#BFej|>V8O? zugjYExU!RxhRD)UC{P?Za+e9TpkxcRYN?B77VUN#T)zH7Cd3LDZ0~gy^FzU@mR&t0 z3e?2ODEronG-of*o*U7`F)Ll^pZPz8Y*Wp|G;Cje{9Y)E`tyfGIrI8WmiY?Uur!u8 z1FJ8j$5G6#FffKc@7XCcG`ELRt4HIAHT&mUFD8z3WNgmr7L#7oxC2FtDkVimbU~ju z*1G3viB(XZBNh2hxAqnB@3XP`dc!wl`lR>h+^ldtj%t$8JR65+l4wkPGsqUcHrcuQDY_l$f7dIoS@6DC5G8d3hW;NhD*nij>}hOmpUOZw3F2*PHycG$Bp!G zS{vwZDSrf<5`B^IfZ{7hW-!U3;kVHf*${DXXotBF@R8 zV*%&1+AgVx2Oi?pr)!tvuh_f*)i&tep3zO!|QeiB>}6knWrwwO9I=i{?#@|cQH2)?l4$QUr7#T zdOaoG;RK74LjC4;5`KXzpa(k!+aeCJjP_2FJy%wu?*=h4nywOZjXaSFo{}4BBL|DI zidvPI$@Y1Yf->bmZmh+KpcqahUvnPaHRhxr-t~=X`76$HDJWT-PZCGA_4+IqoXcr7 zf5*vasCjb$t=)=V#S6tuAgv^xI1bQtG)|fi%Ya@OB!Wd z&kL}Vbi}&R$h%qF-(AXCo3tIbLPl&tvENkVXLWBlespkOCJUPsL5?vBgYR^%PxwY` z(emUTD`Dj>Oe7GvA1Ry4Y*45c0EdiCfcxD|VM4txVWm_nzUAWe39II411T;JA#U`y zcevdCzzJzt1y*^=I9BW#NDXb84Kv zbi9936&b|<(Xv*I{-f1(ix}|})nHnZAOQAh_^Ir(kZ1NmSdim$o(;tT7b7hnni^1? zmrMGS)w~2kZg=j@z1QQdd+YwX7#cPlsGpf#`N7E7IeWM1f?bqy;^(-2w|H}YDg6`j z*{>M_2vj|1#`8Z)7{JhCQ^Z%Wdvo;Xn-hK4eBrE;gm9EsLL%c6svd{dpV|{R?>V5ZCcr zzPs|_>GEgA6Rnxg?!Jnd{iHM$RbYXMhc`!l8&QXh>!r}USg+&w+Pruc4Pj^IrzdRs zX13nRC=%@c3$m-M>x&JX#u@6eO(&P+6n0G#lo=@v#$&?jr+HHI~wETrX0E!w^AldVp`=00~Xd`A2 zwlC|;pUS_rSr+0?N8OnteqG6~#v+PU27GYsxl|o9gBu}_iKorsiYKZN%yQ{!m+ddn zJzK4~Nn25^QHef$m6i%>D9&$^1;xMPKXTQ`5myW9P>7bt7{rtEdcgn0maS)wII=}L z;0XL-KjfyUCtc`{!A1Hnb+!`g%TwU}lQ0Z(rWNZ)0%fK-fZ7%2#F%sNjZsQy`PF8@}!F8PB+MPb)MKsrS!gHckuhlpxNWsD5qo$&_*@z5;2(J~QN`=I|&r`{;V=$hs@x9;g4)Qkxfd%ES zYDT#W!Rl@HB2F2ap6GFP{N2aX!B|sE9(NxGheEa9*-TWekU2XaQ4OA`)<=0L47K=| zO~GUp3se#n0HI;a4!(kxM4@IJ!R}3(M8ppUW}?hG(~u#L;ahJGTlO6%mjiceQrybNxF)T5>ExERzJUn_ zZ{jhgoIM_0??`c>1&Gd&9^qtMbQQ9w0Hm2( zm6dkm-x)5QzhoR1BRWz|1Cj};CCQ|AfGRoy2xvIQEyOjh2n>zJT@`@Piuv*$!@rzQ zCdk{F-(adt^5>>7YV%fG)jDgtbx)s99Lk)6vJz8YOvojqUdj*8+>7&Oooh(Cml3eA z3TsPXQlqfm6#;zk(^h8NPT0QSLcr`JQMbA)_3>eR#-78%re#ZnC_nxez>f!LNBjV; zOe@w<(#9^%dTh1Fk`qFNYk}vQd9_&LxVN7>Rf|m*G!kVlM>{!qv*CN5h`UhBA9D(K zjFWj5zH;Pq5Y`G9;6V{{kc(*%N~uPE5F^)BxXdhq?tnuGcJ@SES27ZW4Q>$qK&c@hBzvV+VSW0m*)nV#tZSstcaw_o(Kq^E>@&nS0H|7MtYVq(^k=sKVuNJ-qpg8zSG-JwB==H%u#Hv(!D%EvM_ zYJkJsqUTiRAEXS;&g3KAQ_@rN3FN6BAeb51T{X-#a}TU>F?_n*Cx;}Irrvc-o<`k$ z^vt$GU~`X2U4)s9e6W#F0ms+LKKjKLIIgusEFSd0=6K>O$3DqBuNh?&xb91Q_+PBl7*GO}67yP-tmjoUGcY+JSO8zrL#^8Gew0e>E4NmhSW%_V3J!QP z{ZA{7QEZUnS9Q(s%^1FHV`Nr|sUt2s8+WmDk_BA%v7yBpVncSW`tI1aycro$4}4rC zTIb&#?uscw{|fg&s&~%{GuN$E=DOFtNNs&JsFsMNj;6t$ChJ5vpc(bPxxscBxi_V^9p@g33^R)5u!);v&q@TsJs6y zj)Sf^NMl^vA`cUl3`~LJWn{=}q0kkzJ0||@D7FvdiubfKb8ynCd#6X458B@wQr&TM zyWKi?+o=nw2V!X;sO7a6btx4=@PxP3_sqX8z>^M>T93R{hUnK0wyWRZ^&-?AWaW-B ztPFkMf!%B+5sY%I<`?`Rj1^cK7my}MqM*KcXEy+dWzSqv<*1F!TM;0Ui-jajNR=R^ z;yg)!s|dlB@% zTr*KYiyKx0a)c%PT0LO7k0p0S4ZcNiUzj|(E598E?PZ|x(zEwrqrN3~vZj!G_rh4j zy%q(gS4eP|{wwv>eESzTT>SqE4*#Y9KL(}zN+eZxB=@yGnYw>)DT0~V@-tCRAQ|dY zDLhqQip%XXtS z@^QpsgOTL@9`nx?=?njr0HphGB8=ekPGswCyZYyqwzUf}KOK@pV@97D$%J%$C=N^_ z^l+`2T?rtMdDUsUonSLBW3VOJ)X3lOY~=N9=l-1y|K$g}16G{RJLOo6#`N{JjP|HA zHD!4H^w}R1Dz$?g>H8@*UQc=YMYxTafP{%oEkAppPo=YmG^>zn#_;-oQPcl8%YxVh zR92r#mpcBSGtEqiz4AZvnAee96!~`+fW)Ex?H2al5e-Yq><_Kuw6|!jP@d;@zr{j_ zQKFE;DYGo&!3JO7`{ni@{xDVm)#;w8ZT=vg!@1iZi+!JiwzqGKWJ|$Ki<%IzEFbg> zMcWN(WwYO6p|7s4UaU(0HO9V>`nvJA8~dAv-_;6AKlQO8%R^C9QdAIv8Equ7#xAmD zA=5ds---jNo4p3;Px<(e{j8Dl7`QAG&|j|L;Th|G2ZlSnt1rg3F>Ge`h15x z=6kE>y|Jpo^1r;KRc9VE5TmX1g|z?tf$Wvc$SOMs2&k6wJ-|j)e(iQOJR^iA@_ue~ z0ltoeApJ|W<&cL*n-m@}Pgf(4=ilVya@mY&;!Um{Z!F-(LU${(&H|R`A}s2Zx$oj1 z&!I8LY0OS-ek_J0m(@&Bhbt;M9c(qM_x8dqRJ&RmvBBAhw#9Pup+~}%>(Ei(kOsob zoZi%o48}BMYG%p!;(n_J1+R4tbRE^7c-~Z;UuqDscC+KztP6UP9jw57eNP6yuk~gho$%Ez~^qx>K z`FD_4+M;`nGkw*Yh+%ety*Kwq8wg9PXfN-o#cKr-a>V99wLs|rrz6vyMALaeDD88% zhW#ivY?<#d(#IfBozqq8t|smGar(*IpU%De7hU$c^kWJ2?*kZm#sWSNkV%S;H{Nh4 z*EzM`3dG4e@^`LpK+)K<)INZOKo|3NU>%`zDZZE zZ9%bP@11Gz5+(psHu}r+=Kh7W@mts(*`ypAsWYttnBqLiyJ%-MNZi^aq%eZ+nuqzI zK({7eue@NIt_x2kd-KKs_?lCy&*XQAmk!`(NLMAss&(dY`S+W0*c-3>x-s)NjP*xS zTuU`}e09}2!hk7PnK>m+GZ*2q{dk&pnLCmn_+<)R{Nt7)W0s0>!SjiQg#zlp zQ4<`^Ry5)Hz9Iyq&AxE$+laMTG5Y4GIl{V`_E_5^#nqwxS{oXa_ zNr{5kia7oIJ@CEcMFS&|1U6BC8i6L02*Qay7sD9x=kEe$co>E7iw}5-Sq6$aXR2aL z@Y%mW`Cwe%d)ey^tJI10#nn^T2PD;-we9vl&Xm;5n!oA$Isg*@daow04C1@A41eGc zoYFbFQbNaVTc;p>yNM=HaPYk>oN-P(&J^Y{QCJMwOE25IR5DumpmW4kI!VmDecio- z+hrf2cJJadO3qRRp2 z_gXKQwHAmGx2*52H;ppt^G??M{L|_U>;3Dse_=8`0m|>6-+6tl-?Sc~#n;BgFMOOp z`%-YZ^mt;(K@6jKE>ZSzLJ%aO%MyoCn=y=X2wa%3Bu~f!Cc&){|K!hP$~`(06(*`V zt7c@Vx%@)1xr})7?eie;JEr6?OhrBaXvJ?nm!ANj4{}wj#cO`_IXYRn3aa6OH9}_D zso#=FVKJ4|deJx$L#*cngvuwT+xdud%_-;KHGvy`M>Bv61r7c|<3lu;Mu3~QGneg05s^o{4!h(y-@n}3i{Ve!w$tFz5j#llS5x`n+62QBlAs`E9xG0zd!oU)W- zA-3p7PWUF^;5XRsqQ3$HCsK9(Mw$Y{)5DvkxG?wzTLD^=u7f4 zACj`y(KN)R-QeI^eX7{ysX<-BZNx*OOgVBaQ1@3omY~O1e&m7JMn~$!vb*m*TACTt zVsyg&nG&AX$mQa&P>%N*s9fetV%&V0uFPL4bu<0N{fdtJYdoePQH#ki73&yFtGf$- zdimt|RGqQSwPrnxk$sD$h)iRWx@ZZ9DcoWlp4~X@T=GUG0`cOZr*MX&bq#}2y1d@? zV!t?fvJGI;hGIjNI_RV!cP?S*Q1kbUJkR`}bamGY9AACD5X-%K^W!^@y6rI=I0t&b z?rudVjmCA;(JJV2s>BP_^1kfB)$jSQ5)(b`ZBO2K#{nI){8TRC8yo$vrWT7G@|lyj zwn1xBv8hm@+Z+Mm&R8qIfO!Pzfiq+%Cx_4MgE@(uhrIEO6=m8bmzH3f7A2`xX$_R$(7-=Qbt`rn2#PN{MrlQcL?X zi6h)bN~tMC%;$3KIO&*rg(RTffZ8KdL+N!v9!sJ&#AIvE)R{z;-SvLX)P+i8g!KiKM9b!ddf^nK7ry*H28E!F3;dM|jnk1Akdp4`8XDp-=iQ!c zJn)kn8j=MbD;J%ATY2$d%>Y%;-_ zDtK*Hg{yrB|~k;ANoDYfrE}=4Q9-cmq*~nlzdL=pjZO%X$Ij13of= z@ubDMJOx-rKb{?Q)cNIQ>6gOiu)WeR3|;ES4RZqYxtF@93iHM+X_a8_FsmxLDQ$V% zCt7GCx3+eksk%(}CVHMQ#N0DqqX0x`9sitaa%~g2zd(ALj0VO@l4+*xQ72Yo#W$x7 z82uiX_3ixu1q9_a@Km6K2@6kjPrw8I1|yndm~9laLgpZ;#7eW{!!p3V@8&e3p~Js< zy-5#2-B^czgS({O;v^e zdp{;nKB(2QShh{80u4{FT3cqTGOaJo1S47a(6V5rD3x7ZlWga77hkJl5as&oVkRA$ zsO-~zQtzCd7aPi=UZGqO+h+gHCpNWa@Ame9z&g!)U!P#IWFiumT#%Z~`;%Wq*jQHt zBNnSw^LFuWo|~PmA;KW@1A*fLxeDA~Vbaoi z(#K6S6)dVfNN? zB1zeNwN#G*08meygscJ$qK2+8P5LD7qsm=R#F`Dw#A8SZVuN8hh+m5RE8}#*QYe;K z!<|z-576fQCeibZGj}alCN+L=LjQw2mAWfR^$0-o1Y=ie01)v5e)#kQ%&gZiZ-D5!g%~t=X)yfJGJC-sEQvNS@%^d`VW!;v>Yh+lDWrM6qNG z5sn%Am&_$YPdagIoj-;#JP$=dH1zJzFR zjC7Hn5TsX=9OK1`)o-sGf#C>11LY_J;i{OJLP7r;=td-}Fa2|Wm8G9Ad+Qf@6^@-R z6dXhxHwWN$I7_~T^DyhIg7$JDFV|!MP~SbvYllB2hK5J1u63JitLtj)D(sN|iN@zt z+kaL=+d*1Gp>?eB*Hqsh*eP&s%9Vp}zEPfY7AgJO!P)X)ipgCSTs9fyzt8%WHTxsU z<&0&VRf{_KNbsOWgcVAYm;$v{g%w6mSA*nvTR19n!t2$K{ZqpsTAORMsX=zVDt@jh z9ilPb2cfhcb}69T4N#DDugLU#iz-H$vI;BBz*~uMj~V%mBZ@m2HNU5cQ@#(Vtm^@J zoQnkw@~<&~dRKJkz=M(pm}-y>yW}KM9edIAw|P4xNX9LyiI!|ibaq4)-t^8aeTYh@ z<~vi{Zu%5xCf0M}g7>0JyMD$qT6FB+s{AmOSP*-b!Z&U%5mM}V@~{JQtzDjKyhEfK z2_b|830rx!oRz(Pvo?N)BJItgiF8zYtJKWpuiI`Z7^8G>5BTCl`f-;R&jYKuwN*AP zynPrNYiytwy(>k@oa{V1`Pd}SL#`sShU)fIo2vPtXZnDkAS=RSOMEra478&X^74W2 ziRR}bh&+Cp11TM zY)52;J(VC}Pu(Ib&jsCXp&znJGU%Y^|I3@9?qs#A_@|NZJzLLd`WK-qQ^U~Sm5G4+ z@V?~Fn9pX|y*05hHFlCl7|i$|3Q8 zn32?z<`vJ^-)q%2MSDkosu+BY&RcTYkryQ&jW)zJx+uvzsFdID*|a3=$;Gonm$Hf% z5QKebZ$*=rbXn*hVm%+C_9{Yj=>v^J_581tbvh4gGYNUv1-zXgzS*k>MAkJ=Q9Ps0 zk#gd`Y?AVQdZbfh8m1#2>0!lGrhz@U09>t2M_>n@5cVOQjMgXxKQPCQKKWI@*xdP8 zz>{r@V`9e~wCftmLs{eGswsw!8~xhrnj`-ClQ@e=cuK;C0J%KhfkG0TOxOY2N;n;n zFW>&?!;OGd=x}jar_Jq-iiNN#?)sd)&b<7qaJ!FiP5gL=EdNZ^w~2hzIAv%=Z;m7| zF{e6$H`sMcr^yP{(8(gmOw?;BGx17>Co7P@TVzsAQHz6gCafgCIX^GbdR zdmR6}md&@Gv^Sj1|CZKybtiGyS>>j2tWG+Q4N!f~5ty6Uy^k?T8`}8@5TP>})oNh7 z9%^u$f1={^_bgRpefP`7yX^|y%BkYOb1D?rTxSn1`cOET-_4N+(jOcu$4&zn zAHU&q6)@dmu_fmyk*j%BP03*-Xw|b)WubT0Jz9y~vZZi;KP|XQZ<(BD3(n#rJCVcT zQSNbOIAOcE6MB4eTFZA*8fe|s@17Dw)o}C{^H`ey7e(Z1|ZuKJC7gV|W}u|?6^LoD8SvB}1jd60M!z8ac|L9S|J z_*LdjpkY!cHwImFFbrDbs{a$=&~kEKEZ1^0zViQCiESE>goKr|Xw6a}!K6s*GQbW& z^SEmEON`gYvelD^-*wzqH6y-9mwo;6a^d7jU}h3hneNrBOu?JtM)kfVsqf4hQ>UJ) zpu>yP_jp&NT=40&JgJVPfN6(LwJFo)=Kk3|x*7A+;MYW75n?{54MJoMgn>;_URuJ2 zBS}-|OjZtU$hu;=j{(t5x26idEDn9n+}+|=>WWl`g>eqS(O%f?oi=|m;FC|$AOi`g z!DyI*iy$w`Ci?TXfZUNrYqh3IkOR-?G6mS1wY=KiZ#1DCJ z4D(0KdXdTv79Q(`WeW1q@(YLhUKN2YmG6v*aPZxsk+` z-PTM%p6n7G3vVY={WXILTiRYclbJX=AOZ@85QIagUqP1ao-~-n1tH~OpIguA4nThH z!2n|g_LI<^*lE2G#5K4;rzA!%rW?KNn3!`Dm<)w?CL=+{25Z%nfw}+_wts5jJ+fR8 z%k@lbVt%~n5FVTo)Imn6V3u0sA6F%7_`6~sCu>&}a45_veJ1M(iRok7K9fk9Md4BJ z(4T_ke!LF(4OIDeZJ8F$?@g-K)BBqwg)>XeA=_n%LMnlxLsCc3J*FM)v~;LG(Ij*l z0#=>Adk=6Z6zx!~^2@ebV=&6sdUZCO$`{l?8$UCatJQ*&B0yyG4n(i_C~#QybjImb zk#tO<+|+7`qjBAr}KAI45J&jK_-`#G_um}Hs zFI_C#O$bJW0Uag`34i)NP6pM$8RL+>r9bSvKtZI_Wk!xeC9-J(t5D$xLPx9x#s@%7 z_P(-ENfcE?q~ECj=zGXZZIBfa7lNhml{-e5m!y;@?L%0~iqlchx|?7#6PBb*v0c2P zf+~9`_nZ%dfa<$ktGg910tUN{%nnA{zDBL(s82h6K|qy45A^&PX)H;`YZidQ&*P$p z+jMd103HHW0pPm?P6US?+;-$#S}CMCHNA3+PC|!1eVKj^Xe2~W5iM3Gm*2mNC~G0wU{=Y!3B}ihEv8XRY1VI5 zy^LHmwYyh?wSAGSFJ~W?hefe}WdDqdhyRT|kyP23DH(Yn{ynTL=_mSVo8)Hd*c@35 zxR4L=q4(kCGxht_6DsQr2sJV}xWJ=o` zEd}YrH`WDqY_3s-ea7rG+`5l|-b9s72Il*yX@V{ZVdig+n06*gmSiDd^wjXRe!p4e zG$g{w3M=nHpR6iqkaWr!cutT674qv?+e*@xZ(a@CMQpxjegj-&-xt}Ou%cD&Jyqe> za%03x3im%DMJA6Khf^*)V>1&>KVwmT^jVmBO(4K=6+iz8Uw<9OLid80`I3+VFF)nS$|c+34O zDM%~=_ghQj3gSttJr;p17*Wh>k*5ilRj(}P>5dhs<=(!WQ?K$NWXK2;d-%d` z-?n_T%lT7oUvkjRLFw9%<0@WC~!+@dd=K6R=EX~H|`a;otO+SJLP}Ppgii_ zbD*tSr~rcpOq;h$XVeRg=I|CJv+K;~c7H#^<^^s)9XtM1380WK+8R;SiS%7i$*ozz zHYRUww2I8`4F^s1<*%4zn7+D7hA_u%2jIEL=u=G*oS*Kq2g=^ngik zf~Do4V^dz%(c`to;^tB)kw%ZZ~R0j2xrg!Pvpw3q8Vvg@YAStlfW0??-jqS zVGiH`ub;k;hr@!TQWxwifBPm7WuK3A;P4`F6y^2IswM*YWe()&=J(qvMG-O=5uDkw ziy42*Xx(=Myv#R@FCs2JJ%m2f*n4HoEFxww^QmbcY?=@DOhm3(g@(YXJ@^&%&jlK4 zHm!LVU#V<8;R<+PCazZa_M0h4N7NjNW8{V}uHhH8uA-S2nO5Sp3f zHG>t2svSvgQJ*9MsPhaWd#X2Bal;%uZQP2?otSu94tTG#9^tY2U`$Z7^gg5`)d*A0g(4;i-yJ%_CV;RF$q|5=h znfjmfjyzyH2}Yy>tdRN%gJH8G$lEl+;8-#xsQ4xMl&RpPS!@$$SlbJGg%spt%mGVk zG#5pf0y`q->q3(h{bQGA8^)6Y?3LbIj7~G^w`3h(eNjmkE{`>nqGn!ej39>I1ZpTz zX>`9^AwBS(9?Zf<>tv3Uhba)IAf+;=JUWJ-yRsv8{1R<%(gzaxu!8U&xOJ201B%UF z74E;lup!ViK!dhuHNG`N1?$Ssa}?zkABC_fbWtOpA#0lw18?kXDs=Rh;j53wMHG``hN0!7^#9H+e35%xRWM z{Zc~2%lS$Cd9N*a9`FG6pUCFN{ba)C6~hqTBNpJWzyKq1QFviAF}Kel?(k;a(J!kk_Y#^LIXb#Q zVZg1x?j=p9$0y}b9`#B8wsBm%H^~}$CeNM)6g(sYqJ_xbE5vu96ODa_lr4Sm+*{mg z9riuBSK2V2v7KvimYh2Zz(vF%#XoXlurgz?p7r7a%J3M!xHj-q)t3l)%&I*4b--h7 zVhBaoe&wKmhg{imhyL&g6w?gFU(_9OoYrKTOVs};wOjQyC&qNnTk`Ho?18Htb~>zc z^n;3zR1Bv;v2F)-#8tr8@a*FP>*%p*`mMoz5PXM79kO{l90DT>*k}}p!|eT3f`6J*_HH2oL-8}E!)<5^>>P=n7w*Ak*Ht5 zjD(OMG!h=X)c7A3wCtqf*@Qo&$#TBj&bXWTQi6fEc$01?`tB#yMYu=BUL*rsO`#LP z(D?J)mhb2+7Xp&Fn6ygty3*iH!Ve=T+fmsJ-f)&-!e)yQ-STmLN07WXnBFHQT>^w+ zd{-%Hm4Rj?A($6|VqBp&STU!gs1-Fm5j9&Uq;x3@S@5&*-2YW8wp%H!etuu0f4+MB z2IIlw(%szAkYV&qBfF%$UFFyehM5zAC3K^V$@L>}oVvJ!b7RY;?}A(0=p4LMxb6EC zWtiD}bUb zKylp!pm8NZq0WL=T~=%tC?gL(_)t3V@!|U*I3brXiI_l`y$J0<;bLG`=mHYS85=>6 zVq}k)m5?&rNE@dTjg_|x7CJ(&>l!;8;BM!1^vmhFVQ-7s-enZMX*}BS^LNL68Cl4a;#;{f^iyjgAzLF?{huss5@V#QpQ z3SxygRm4#e-V$Qd_p$W4EMu$L%qL>f9Z*Y?C#ii}qzj}KIGTE|&>^phJD%DLaQ*qV z;_wd0<1;OTxq?F!Rhby-+cKrpfKE%zZco%a0sud<=7ZZfBx3^|b>7KV++(_QaqIVS z&LZ9W9UV>~#TlTbHK&PmixvE}K#4(Trsh?Mr854(i*9TTZm6~G0{BFGYiVgV8CXdZ z(l!FE5oU#ltSLoz3_tbm_^FT9uD*2QHm1KkoMEIOkIIm;St$la2Lq+VFhtGiiw*0| zgjF9MJl*CNPU9|m@hFSobn=~ybr4tmDk$F|fQO;yEoVa5D~?v{;i&@n$g}%|)6W>? zC1K-l?rKN5GbhFa6( zRX4Qqils^sd2)lYk_qi0kKRh;+z;_za}$=UF12#Kfx;wIt9fTK}nrtOf_@DS()UtNRn{F{tu>}W+b~OiXDpNt`Vo@G-oQ3Bv-|A2}h^8~fO-4d;gg zR{VbXSM4f%A*t_{6k)bmkvKxC=g!}c1k)$p8DRD@CMbz&P1@&7zT5(D6uj)kvPQv$ zpUl@o2KhQv*x5|(+SIVbLMorIGGl-~bP<|H5l;=2wEuLZlUi%c1VS(Omaj9Kc)_Wn z#xM5pB~9f~FNh6&f6tuE7@+uIE*HNOxcG)vuUCW~Wg8Aw{DF0c){SSD85Wm2&+_Di zN&3TiBOHja220v|U2dVWlikdwUs7Ff?8Yv*-e}v#F=Af3i^oif1sqaW>931Rc7sy0 z@=IK@wRG}I&OrO3g4;@as1}(>e?;80{3xec>HL98l@dw z=!9Fh2V4FD;#Hgaf#G~2A}JiLLtAdK!k#DQ!o}(N%qELG1@6uL=qb$Q2>kl7kQ?Wc z=ZI7Dx~|W@b}x(Wj9QH_rfgs8K9wGT6RU_jL3IidVL|D<4W2k&g%0JuwENSl77)K! zzq+uvF~H6>AmSYJu5g&y$2;lakR8+C@Dx8v}--ohpj6`e*HODKx}Z zHst7}x08UANA-yP>$PoIgmH7RX zOX@g;0Be!}hhn*-kIZ$uGzHR-}f7&%8aqcA+Jk(0B9U zaF3XWh#ex}4@x0jKf~LlGfO72wOy0K!dNL_-lonv-}&@~3dby|A7l-x+;ZWN`qgXJ z_WG~zv6IqH5^iDPym-iUd$vKon*H2mhMKLBZYw1gL)1&%s4;0LzKv#d*jN3ra>qkE z72fdok8HBU&SbtX+*=VYiE{VteN%ds@NtXH86qy(f2Z_dPqX#Da1qJf$M~e-u?A1K z(|kCR&zQAQE2w``jmCMr&Byy^|Mdp{{7z?wSU2Yi;^WlJ^1iT6p&W#EMOoCoookV? zb`*dlnY)O3<9zo1z9SZz2yBHAnq4!)nm#3m($&7>X>QaVt9?T@v8oY=3uT`efNsYD;qokVLDpr2IzRf8 z3(zPxIvv~t+3}5+-=X8}hA>A2jd4>wEtFz(*a%SUzPYCtF*(hu8<(aXJM>zb5%_NY zq>%ah%UbN;>aJB^#bCCu_{|7wKQm0@N<@#^^JyG<=xYl`cz ztc4tnQoQl*V5k-20c#o;yRF99%rBmq#DiG=Ph+k_@>z9bP=9T9az2)Hy$8}gav{PI zNcm5`Sx?0_E~_)Y*4CA5FFNX)hg2Vg_KHpv)Gp^u9O5F{uf+y#n?Hnb!X1!7{@)Tv z8mOPBJ=rGkT{pu&c4Zo@5>k|~rl*ft7m|MB@x7=mJ3l*AxTlcPj_Xtx6qGo=r%6B8 zS~`)wK}0A{=_T6i@HT9ivh*owj&$147$x0Aj~a@6Y6s7H?~r@?XSZ*|m|QHq#1(xj z#r-%a@cMdD35$V`XJ4oA9sR~iav4{eP(574kbsSEcwhIdCOdFoGU_36sAEVpV=#P7 zI9g8TecAExLq09rNz`q;GD3VBM0j?}r#4DxXEX6rc3D{Bb&Is9BkS2F?y?Sd+i(Vw zNkZprlWAF~MXp1I>0VB4AM8?8uJc!!^KruqDeNwv->fbuluPA3^i6n(U@M=Teimef z^O@J+wq#P0{MMYJeI$LUDU)Nwi~QzjYj64jS!@%oj5%!>CH#qMpn}x#C{aQDONO8G zvf|b@uS`SYojX(HK|$gG@>vbhd2Htr@%6?07g}&=H73GP{MoGM zn8BV{Q*z~Wq^w2ogur(WOry;4g^L6SJX|7y*Y+hwP9#9x{@h4}9zBq|m`7Oud+z&` zEJ1BI8cgX2^UU&Dm~0ewqjpGRG0ACMM2A6y(3UKOvSfs5fW}+@7-iD2MlkpJMDD{P z&dkfaPl~KBWW^2TDZxEN9S?<->tA(!xp%}HlK!=odu8w(o>+Lz5xL&15*9!)LiYkn zsuHmE;Cj=yJ?N60=&4ODn!V3We*+>W!Fc=5h)4xmE}Q1tFEj>g!YQ44z1FO@ z0iN2v%<~E-EVgLURn^r5FYi9VFjy^d?OJ4hRz=A7p4x4XS^4|2JmoWBJTiEc6o;>s zrF!<1St>8NtI&Jqy0kC_xJ5qq%bgIzVD`!40B2YCmnnN9;Rk0K<8Tq2qDCS5U=}XT z>$NL>ojvJC7~bGnsfs0|mH`-!;r;nX`+cLZ9DT#R45S_r2Nd#ws|-$pPD&C&rNKOM zbuwfWa#H650SOfQFuwlh$Q|5>MXkb!44{EtR|?Ba{S&Tog7tV z*bo!^+kB4h3L_CPJ>K1tkyY^O&*mgr^&nMkAl-`(c<0XqH-cxEOq`az;%_ckzyeNi z=Z$8R*gkf)cFz5^K=G~VU^6lD?unp*o!Fe8l$atvIwwI!T*nmA>=MrhY}*(xS(O<@ z<;1u9ba_53l@s*V6rl|%xhwe8iT#J`)%97V=-fS3Gi89Nf;0%uSnyMxRpAk03)A5^ z;;fZHE_Psx$Y)i?I$qri;zZ3amK66nF)q#ceV=9w zT}e%_)My7=H&TrhfF;^O2+KF7U1V~VND{n=85Vu_U7sq&V9NC)UVYbn#QKwlWwCk^ zm`kYZ5}8|$)aTPZ1K_t(64X^Q<5*o7VjguC=yq$3*P)X*6He?;UFF*E9@T_76247! zY_R_7e?}`=|MT_wdMM%9A4}^~aQKb0@BV%=(1&T;f2IR_PkkRUxE7`L0G*Tsoz#aG z108Rrn|sbnzri1sR9E(u@Lr?gMAZ-T?MVbZ@5yvWhoooIB4LMy6(njTim`LeykBd)Y;JBg2oJ_Os?E4blcoU#QQWMJuHQXR^v5*xJ+tj$b6zs z@ZJ@Z_`KY4BuI3hge0d`hO4(`;i&xQN8n^Gf~c`^Um{89vN2%w1Ez-fxZ{ccapEU~ zdB5p=msJkPLSD=pgteMH9&>+px<}41h69bt0Je-x;d)BG$UD_5n2aN#N12^!D(!G zO{Q(h1Efc@gEXlHGSMx_Su(TdXq;vH=q8$X+fVDNcpaj=QFZ9}ZBcnG{6z*qjm=TK zTPovd=HKf5&j8>@eS2d5kwQUl-O>fKM$g*p6R@*}oQ?9-UWGQ80AHMh*bqqyUpMu3 zCsH@CX+Vo3rB7p)Z)KM}`fp;e0htV~L`4&zdyf&&2w%o#>wk^WV!cNjVBd$_%v6nbzZ(Ng7mk{27J!AnyKZ zc$#r3Q3rE=15XhcOsz@0sxDuJ3PA1@JWKGU$ ziFC7fg|PWE4s>CMw`V6nvE?ei{uCgG@#A>R|N1OCAVTng7voT4y?+FH`M{-u>E3a8 ziD}4q?9CpCZv|cjRNaR>;Cn#%hY_#UF*wh3eMB|{RM97hH23SG5n}jrDI=rKi{|}7 zydwBEO%sP}V_G@qmz$Bk3!)5DXiQbmo5ND$=jS`-gdd&Ia1>Z49H6tP zmystt&udN{lqO+x%)YXn9n+|07|RnBpdSyR?E~i1u{ow2Ytd$SYo^ zjb;hiyeUOy-N6$p?3EQ^*cb6JP+-@>USg@y^N9j}IofNLNH2^=F`K^gQA)fok5h2{ zg3odeLj9Y(OmRui;+_CtxU3c;m*C;nhD$H73XWq9K>7^%>( zQ+#s*X#^od$I>QF!L_k*f6+M@SjiruDiyIkP`#(So|h|6%tP@*(_`?hhpmyIsBPgA z{iY9@a)pp0lUlft?uQhbBlfBJ`GpeRXv~v(bRE^H*9EPzkM8njOR1FB`7rK@a}Q9H z+UpNPZpz#5yw-{}R08U+Nj7 zTw$ErH_f`n--Ht7X#y12U2)sfMG%Q`2TO}JWIi=N;EkW!aL;cZgzqhx4JPWA%=*(& zz6=U7{NDxvoZJeb0T3vWb5E6+%^N**%MOyzmy=KuL3X1_8?2muHpH6H$9$*CZo2|@ zPCEg3e|<6Ho)nCU<#Am4o3<^`rWloSX^z`TjG#V!1mw3HH=k+Qmw48e5*&_vbk42+ zXK^D7P&5+(&P({a_fsinJ%n>(ljbi5*_q>K!i}LSZ1FZ8&Ne3x%vLf5Sal7c<5tN- zmPuNiNqL4KM^vwJf?GuLM89`fX) z-bnL_y!_|e{MlwO;R|WA!D%<5b@%?$WiPgBdBffA@JF|QI=0$AnEHLW(*Nk7*rg&{ z4wIpdm0=8l+mTgv-;u$XPRF%H{?)TTlD(F?%^KTEg z1@Bp=q>H~J_|MUd5O-P0%sYKxOAtE@y>*4JXG1_Ei5NQ!7$LuUZt>*&J@4pFOEbfg z)13GD-9)vy?JLK*9aGPfx{)^8!QQngebdv8Q?n|&84Z+yw9`uEKT7wH`bT$3kS0w) zw6qOx9{zDS{lnnjjoOz0c4*D)*3Z${f1m%SQAv)Di#UYVd)EAqE`Pe)E6K|LA0@}! z{?fZ5^Y_dfV*SkQ$!9ZRT3@(O2bPH8A4ZyK0_SgjbQ&%y$^u@71&1SNeTeKLezU?z z%}k2X9|L73(EKgyiPE2sueh#4E|9k8@-| z07k9xFT`Ad-hWh?Nuw*UF33g5!+?+c2)A{(MMWc659DXz+_dxq>V?vVa4v> z^;e}Ny5YF<8t=a&V~3({t@9}Vh+_kQ9cmh2N;S7a{b2)$DXS?YgS^fEX&utInkfFU3Kes}tp2^Ci@B?dGdH=ce?>%(Vq=_2He>?s6*8e5-FIWD5U|>is z$$vDztDHPti!)tAIsN@0HIWK6K@@eufJt4+wKH=xnl~T}7{vxu=^^L^VqpTYFh=}a zCFzOb)Wj0h*OH|(ZKXf`skJb^J5nU^ZYM{pkmBQz651{!4sv3v*)f61#keqR2Z{FYHKOP(G*~n!Q)sgtJVtC98 zr(+fE$lkwgj+97=`!Z_bK#R3onvvKi)H4Y~v>(aUwsu|{XL3lN4STxU+13SGeKA3U zeZD&mKD&M=6XqbrnvWXFiRNR+5W?U*yUBRrk?|la>!pjIfl|lljjDKvt9VR;9;u|i z;XF}9azPhkyvu}()_!g+5#3BhPWC4B7C=QMQXh$5^lakm&dd2AYs{>X~m{DDjm9e!EZ4el&9&^_ld>No?80%=mL5LiL@+|hIW!i zcaw&{BoP;rY|6ena|^#bSoMJ&lA)9O5dB8qsFEVl-w4n}OO~$1m8Dx37%vBj3o1!4 zX^QZxiZJMi5w-rMvEOuuM3X$|PV$T_RJE*Ay}>!6C`sO|gb7nBeGoGHNkasaI7^K1 z(8xENs4jSM7tep1cs7T+4TUksyJiVROZrE{hTQ`AyYyK-dK_Xeu-IL1}t zy-P+N;@Yr(hE7yCKVZTsZ>@Y|b6-fN10KykxMxEU!g*uS8J@ig%*GYL8Sw36mD8>p zG?7F{7DK4|tQ|AsBeRB>3g(;&ba@MPpANpc>scCq^uhzq2IYn(a?MEPiOO-)tB69n z_+}m z-Qf`TlbHR&3Yd0jf#f!Gf8I(#xl`sh<*4KMw^9sxSU#bX7C&et504Uk!6J5mnTg}i z>&X|_;!C-jN(-y=2{vU(!00YFjNvk}l=oAznTP3Ynr6RW!6t}`D z`?gcQ+kcrRKVYhR9OQ_;+&f7iE)~TbMP*3weS8fvc(>GaYh=4Qtb|Eb#h8ZeVoBO? zt75zhW-Ksys({+dz0CwG5MmH1Dl4oq-dRl~V+PSj*K*)oUEtF0ag}};7O(i}`m!v4 z)ggbuE`Ro5?BO0(ar;EkbiQ&IMU^t42oX^hz3Tu(XOmeLSIO?-kt0>JGqap0N`NEC zaJA@20Ha3sR^ZD+a?F z_u<;KQ#>Bw z>`pq)!9_SoMj*8cf6(+Mmg>8|P2%?T7tP&5Q_jGo_^QH`=W(RT^FdwVIUVf;5hK7Fi z29u|*bzA5CR?Y4G9WeJHgY&7Yj=T7~rMn#UBC?!pG=CQ8(u`jLFUGVqa4JZRxu;b~ zGTPF+wxKN%j5>{a4&U>%on!Bk!_MHG_+wlrP1Jxe{vc||EQ{>M{LGf4aX_YB^InOH zIP8p(sWWS9%ay_Oho-ji&-e``^XCWFT=SVyLiri;^}Ja7bz3V3UOYN;B=1Ym$MOvQ z0EVirjUeT#IUo*p&)P_voxel>W~biHMDycsm0XjAC7(4YlhV9}4c=WaaiFYYsIWDRYv%0SIY+l!E-phxl=|&3 zq0Hu1ntqlChWK8yg7_1m$LTwgy+VBH8ySI}M6E`l6YBMor@EOovI^k=Ya+J#c|9W7 zE8Wx)@?`zlte)f;-}UQwp21mu8=;D_@(?8Uf6T7P;L#vLiRa!mxqAKA_%eFyD7dq! z%W6@>5f35s0sj2j!r9C#^@w_Fg7Kd*Du@nH~Y#V8qI-DjJ|-n}xwqf);Q+FsqvvndRShxOBp8K7r1Hbcu8 z*MpTA&u_4xk^1-bpEugHEGaSFqG^wka?g@dCh&MeI_J%pYxC}fiQAk zImx7pdt_XLgs7~1Y4jn+t$VF) z8>}818GV06yLSaMhwAIdNG%9z%IlZP>xXh3m22@=Md~4t#TSIsd^QMBKdu4$CSSI7 zR=dNrye34n7hdZ6Mjb0XF--8_h2670t4X!VH}?)E7Zkrl?kDImxMJxt7oN#o;o!dR z#du1~qHKC2rdqO&qxcq#TXr3yc5b`>tQ0OZBKhpnp}q%^F?g2}65&pc*z~iLSwj70 zf^HnrU8!_VUSkV=Ca9F{G9yS@Rus#hfPbuBs56R8vs%L8qnHZzWw+iTK^N19@TJ zj_Te{2|cPkA7;*by>%}0t!|$)%jmLcyGoA>d)-PzQ2Wp$)|trXb$(Z?};rfStBaYO^ixNbFf+b=V8f-y)a8q zrWC80=kv&&rk#zubO?rkXF5Fo9+ge7h%Nf^(~JSN^wW}|N8JXTP6AXq ze>UjnhBlmPc-3Eoiy2y1jS}YmDAOD@WBBEW?z5=kS(Zvp{MY5P!6toAFmTTY6Epsc z-Z7-QM1?Er;Q6I#(Uhb8uFKNRlB`KGImI0v4#t*r*hPhA%-{8JVK7y72E|a_M5A%G#QZWse?TpDE>mE?CdK52q z%=JBv0mABVu-u_8E?XZ86iTOY|`E*t-(2~YZZ$(=8=S?I`7o0GFu95d*WVOJl~JE>lb zt}j6vt{T0kQzw4R^n&RNX4J8~V{abGyn0zRy+U3erB_A2V)1KVzxGSBe#&#P+mp3-@W}aXHm(vR z2M3ocEmIGHjSr&jaz#u4T?gAn_J79%5J!=;qwFg6mIavgclM0ee(B&cZhaLV-`=Iz zvbUG@L+My-S!%jA_p%hCg@9p5BJaEi6S2PAorjE)>|NwgC%UKtL$S&k{lq35Jv5%Z zI3($j{^y`aO9RN!0t#ks9&zZMjMcuM;;C%?_|Da+_V!RaZM$@XjfVmY);?qbs^0mv&zJ7zADR&~)QQVFF? z<+RO0m7iS~+d4ltZ3h3jp|rjkd+JK`7sDpjSn`lqqRw#tORtAw*wgQ?DCBz{?qk7z zmD&OX-B^aU8X7{SktMHBo*FRtVau?G%uBa-z?X)K-AWDh5#f}|*CD)jZbPDt{KF#rK8^gHFX+p{;E;Nb>=j**r}bTqfLpzg8wTm?tZTotXfL3|vqvP5t~`w{U&8 zh8>~h;x>sW=7J392OUx+gQn0CDq$A8lD$VGQ?KjX#Ylcf^o@t{K011>veKk@j{g{U z8j8dTi*<@qIlFtn_s)Ofl-#KLSaW%fdPJz~+gqRCm|=IPrv+fqZS}pHvc$?)QJho% z=w32F>~MjPq^2-K0ap;cu#q29N2q1(ezEC$?fx2=8KR=tyR>jo1#(( zDu-Alk3imY7DGh-uut!T(XMfc5~HOQQE;jO6mw0XkxkCwZmuier|U<7Hn%8om zP|(4Pd3KkB7b5x%e3e10pS#B_Zl^0&@F{?6&vm&gQ4hd&(|{t}$h8 z*7|iT;xXg11*b}jJ;9g9&O11wuIE5aCmDD9UXEH)8a~(F6pF5r;Va97O0XR5FQBo< z(w|LVkg@m)E!_Ds!-%#~*Ef)Zy?7?!`rEsexJTvn^*NO`ncHv1nyJU=y~YYj75OIsw8BLThX!}Y+#iXFv=QEj zp+DAn_L~UvXq>q^6BFrw@rfRkvXHJIn*AIUyKkXNurFjwYuVqnbIzSp4FdU&3CcHkZHP7jYe6*(`}URV(O1|qCvqSf>MdFg_2a5|YPb{f$4 zH0tXv$3FN{4zwjt35}*^q!Q{59K|*z>^I<(na6%@A{{4tHZr-UQrtHiaMKGJ=)6tn z!~o?-H;C_OI;275nAhOOjF1Zv9yvF0=$Ty8+Bx-XBCI=p(**k(T9w*y2;tl`ME)E7>Z_EWxIs>d8$LELahy+fC_wAhDzANpbW6$~0pG)^?Sd6c69d=Qa`}aRlES{Xf z>^%GI%BOJbXV7fCUP{UR2=PxBE&>#jqGISNlv{yD%&25zmGhPc@ye%J`HC3rY-4ov zF~FFISgaipIC)ZuIEfl7n%4pyVCS@B*QN8qFZ?p?kramD0&=i>9zl^ZLQ@ZxP~=;9 z6pa#D*LH}O+a%p!oADOWh(*|4XY#_;K5?bM+Gh z0TymhwMDb$mJBH!|A{GPsscTlJa^YG3!G|<;YhKf9 z=Y!KZ`1^b^Mf>JSqu8-Y#Ze1t$2Q-kIo*~wdWa-3eeHaX;1bzwf1kdi4D5^)s>Ub` zdK-_LR<`N9YeII_#Xbe6Tsrn;z~Gz=QxSE)rK`sfgN9GnF$J9>URK$jJ4Zewq}{od zX(MnB<}F0zr8$shig;1>BOX;@=_Z?ffiV~%Dxy%1Rr)}5o2;M-xaMEVv0I7Qqkk2PIlI{h(})AJqr(_e)znZfX;Iv;!{F) z8_RNZ!x+KFY&BXAySQ7Eoss{{+|HqRDV@ryb266pO#)!+ypU!r0(tDzphPifAfhsJ3Zb1){Ii5!b)WEf8HbS z**Ef=TGs_Xv6nJcHteC#^8hyiPd(Qrb!z;WYVfDnko83`$!%-d2%(Ue?!ue=_x%Bx zWv01d&hC!7`f1a=32uJY13qJ)VM**Z0luU2N9&hGcMh~Gm+qCWTN6qB!S?ALDuA0N zp9hlnkJ=W?hy`30d$~E?rp+IBN+8ZZOLSd%KFTW}*Pos(rPT8D?HA#+-G3;dKsYK2l;y~X)4*{Yqy6p^)PEY?RmG&_%WlT?C~!{CiVdR z!rjRkytHo0GuDc$(O|N8z_e9ca{EEP1y-ux$5s9YC3vXJC4A^tNQQy{3EPq~bW1r( zOk0rdsoON8zbl~3_Q~0?mAbD8_^E_zJh3lH7HiDivU03209N0n^lX-n(G%5c)_D3TeF@^!$wA#Eb28n0Nn=p!D?u_E)7zLDlz$ z?bcF5ORQ&{jXpl#%4f~&=Jkpna=F*8*}_)0B))5sr`FONlvY@E{=qZJhupM>${Xf)xz_v*D%`|aRc14u)-?>7y!)w=CU-cQ?f8*YtHU8(I4lI? zt{zZ0D>ufVKmGoZ>rj8_(j}{$yAx-!@lsCH0S28E8C*obRrMOdgN}f!ntAzGJ7Xdz z*ni$$GTT79R_jOp3VP=~UKdV`{H5FxF(&#rdGrR z7EgNq>K6VoWEFwdEwIilQd5@tG{K0G#77pq;&qt_rE!I3Ot1L&eO|6eTVTsoeS%fJ z5LmbzG;Yo7*Wg(fB{%(~ZA>)rJE-TUMg?wxi~NosGGa%7h#hT6y)wF%iA~yksr)?o z)2ewB1wfrdxdu^E=A_q8OgG!sDR`{1`H7`YZ?1AHpqCAAPx?_5&ovEB)L{L&DA zB(1|JUf{BK*5Jo{ERv(v?2EnkRyC#9sdeV^yYF1xs)E*;OwM}+d$ zm)-24(=xGp%8!@Jy~#epZSpi}>}e9!0*8BBs*6fc6s0 zz6Pq|?P=GQxorDnBiH$0be6hvE0X)kVjAd8KV}iZQWwGGQTLAkoa+^J;X$W@EZ(ht z5nB3DB6>1+s3?1PRxSC=T?=ks3%K!hpXWNw(p7Ks!{meNJU?JHNAjhNn;m|w_~Ek?S!sSrx0Iuh zYo(I+(iK$L92|ohYh`Mh6T|cRu5#U^RkM$(xR5SxhZSOEHqa3#PR3721Nt(exE9Zp z^hs5_FYU;wBEs%r=+j&y(#RQa4z{Z4J$6&@M|x0$DRrCu4q3U-VQR%W6Q~7Zqv`N4fcH zdh#4wM)dKg01ceczJ*|$1XrI`nl{2WEEOT-3YU z(HlYTzF6f9&Hi$uVh5j~o);^F-<4d8Gm}Fc zMA_r4Hc&|?8at}Xs6*l&Yoy%$U1c$hq`7VOE1R+yx0=qpI~u*)WTbFjF{_!oE-ASb zA^4gpF#qplW0?)Gu~)`k)tw$(WkXdjzD%U8^511Cc!B`OVW&MS(Xd~=H4n19zOM+& z?j6!4A6Ym}&vZVDgS>Yb$Sw6;`R=EUV1boPt2y3(1*+?tlSf>5-?S`R>|Ftp`Z*?# zU{4P-6yy;-Yi%Z{?i^u$wu0;I*eq|A8}M7i^C0cGxSOo9P7mhqd~;A*%AQo8zw=Z% zLqam==0%*R>8Ag!C^j~Vi&Eai#+z$3b;H~?%V)*J&3nhr@h{j+$qgrYYM0PpUnV0F zBZUvKoEt_@o-zU+cL&vIy|96tDV%#za}Sz%>s0E^Q#y;c=x<0|VDWPM)NzhiWAY*3 z7vbMIc|mtJl0Mxui2}mN<}noML~E}eC;jjvzBdHwDK}dy-vq~APGL(3o<5aw^rKT` zm`Tsf+G;2nm2u0({P(Shg6}WdeZ{XfA~X|}Omz^t7v34fi2)TF39nN{EO*_8T9xs_ zzbEKAp*xz-bI(5wR|^i}Of(yqMSFK%?euxu&3zLxHZgASVTDm0|8wb63RF`IS$G22yG{>9$^KatShdRdVXD+)?^=dk=`Pf_^)QMj6J?ru2=?`O{SWQxW zpy%n09?mhyqb8|h(Kg~k-C`v87(QXba)Lu+bL0?S19Z@xMqcJP?V`^T6t^2W*L0R` z(FaLuf{-%Ym(I9c0p4*ud*{qZ2PI)#?BVh$_=GSL`6LH54w)$;`$t8s?5CIVs;ggW z9pB?QJ$zEE_(BT%;mw3x_ABYTx1nPN?ae}0USE@l=^T`~@m36Q<%x_>tpEp?xU8(} zKmz_vwQ-zBoVupdm&X(CGWMph0dmi2h~j0L88h+Slqs_e4UIIs zj^fl32M}cs``ERf=5XE-JZQ<$-+p%Y@i)mBT*PbbIdl%rxviR|2<5%Ov)YI%QvK0z8(`hrJcz|`*qay_68|9a1x!!mMp=Ey}blI z9J;tl^7{0KfbLt5Fs$C8mK1XaU(p9%XELaxOnDdoinE5duV-x%1lt~mJtwZZH6zk4 zoU#&|C1fqXe*JXg{4op5Zj+#x$tBA^pF?oGDGm73L5ger1UbuuX9VXVnE7lwRWjaF zI#cn~d($&!VJtVe2NnwzuR{QvtL%P|7jk|PbZ5|*rgtcNjaWgJ>t*x{F_(j+B{hid z4$k?RD)1j$&cw9NTjF+^5QB_G#+jmvO;xDfa17~z?Q6BZ_6?;`K+r+)d{*b32)H+g zLeLEHMDOCjbt{x_Ya-M;)UIuvI9mBD;-x|zzUxl0x;W1O0X1B}%n`@{0TLodJHBRQ zEkLC2=59zdJ3o$kxWJ=xXeF}H7f>t^3!nzN9SUZL6nS+e6rkI|uOL{hWikqB;@tVIh{JJIiVXwOce zGGjtP47=s+EU0*$5wH50~_a}DtDN)e9t|8Foeg}O|0b; zYf1aKOGZ}K02|9Ox9=4vbBv;Wlv*NqqTK}DCIqgVq;vXw=&k7Vl>8Nov>+})a&UT( z>gMRw{;bcp%f4e0db1OTHZ^{{SK?4sA5tsylb%0glc6DDaOdM~b^MPA z1uE8Ni2uo{o|AP3uCgBTJmIm(Ic^%Qi(e-|EMVa$?lkPc_q&$fvVdN=l_31M-1d-? z&f3$*a@%ARy__tY>zV!b1`Mo>&d3WDr30?vzU|-5Gus^NxtCJ}cN|69tNBe%yft$v zYrC>9TEXVPt{Gu_$wLq7a_9!aZ}_~n$k@H<>iv6qk`injjT!aM4pM4r+dt1CRGa*g zVCI^VJ@hGBmzyTD(I?L{hK>i{Tz)Gpp>R62=aX&@)VL+O&vJ?K@Qwx003XeHeF-7` zrtlgw$?J8q322MmRm?T?RhJ;|T3mXxr2;AQP3z}&xD_|jpgHYeuH2}c7aEZyXAG$nEOnnU={bBaVE<}oV0KRh$F1Dp)d7u1D^2*iBI{}T5>~zcp zu?3}G*I%Vmq9N{&$5Fe<(T>raqjZ-y6B9;7=~sVgaaMvv-gApA-tEj+7w!zL7riia z39lVf`&l}5_EzNAm?i1fs(qEhwi)#P3h%@%=#f|IWb!1$jzg>U9yDrgm!-=21u{fz zmsoW<`@lD=kT*h1R2+7|XMfFf`Lr|u2jbkIh`dg_Eny&oiY_)0>zoAR<0rHUmGc9$ z-tMX*!k=v$RLawB#5( zUfsO5D|Cr?5A(LH#G9_2-qmO2MDiA!u06%^y*^YCRR5lL_1#%^#|iaWh_`0mFe?}) zraV2BsDr}Jtw7EdT9fXza;jPCIfe z$H%@_HNQ*kH{+jhUag^|JFN@bQE{!-E-%Tw{1fl_dcozvR?aVUkWK8C_9if$rs!A) z^=Jz(o-il_ZZ^GZS&$?HnMATGL{|7swrqbz_S_9rwbK1q@pQJA_31OP%&*fT1*j!f z>7+Hge;j!hkEbgKXDk?(v(bm7{5T7C$7ZB=ACPi8-DS_Sj1?i>*bP7u*T=?MoaLgS zch9M#$;u6UN3|fVLH0)u0E+$Zny=|3N>mB<#HKLAhjdU`^Oc+PhiXwCZo(XhoPh=p zeyW5@5yfaJ@zzq7+x%G#xi{le4{J?UeJ&~9s0wEY%_>F9+h4m%7Wv0hx?-qFF@ZOh znCf{vEG1_7f}%j5qjzbHq|KmOG%k{4d~Dg5Avv-~vWEw}-X$NTF zT_E;>_D6!l6erNVzvvymI7I@!iW(@&+V|F|dkoDbMO{sJc6laQsnS~S#Hl}N zQ!`yX#sq_llbMop1oijOr#U&k&PnC>dshUcSK1*RU8q>Ze9@@GOIFB_Gu#Zvo4-}l z7rt)2z*^di6c6F*8^RAoSr3Lv>@tQru0*)s#Ur|}P#uH%K^eY%<@(-wP_s|EQq3nV zm(-3&KBQItz@Dd{vfP8YKw1Nv%?okua)%ryX9*s5QDSU&y{o}D%~%#~yqzyfH|r&@LyyDc++WSsvNO=pkMz!@tWfJ!|nzpH&>j765* zqy;V)b4)-ST8sRE~uPXbSX`Zv>bkv7=b!6Ts@`?+d0BWuU^Aq3LLG-$Z!hFWiP z!(#!i-VLL#l7b6SANozbiB6SrPHTXc%WxZDh0Z!vl^kia__S1 zV1g@6kU@n)2glq_5LDJ(^biEkw>Gy`{JMxzI{rEK$_zS2x6Kg0&g=_BB6|gy%?$2b z>e0B^(adZB2ISx}t%-8>S8e6>m4Eo-lD5N8#PC=U6E(vw6bU{z!5_bK0tH&h1*Mm@ zNa{l^nm=AZvG&$`4-f)hN0J;@dpM@!YYUwFE`Dq>ZL!I`68S9!x%$cqgDo5XtaZdI z(}h}vybZpx;XJPn?{M~)+#sP;q$;Qt(_N`-dQ6WwZW1+EExYIcMxi}5n790#QaE(1 z=@bW_=lIb;M(yDX<*maAqnhV9_6;G=bxKzXKk>%t_hNpBee5ghyq(%hNU6=K*tB?W z((7~ObhY70>W?s&4MV=#aQ=9WGWEqf=Sm|RV`QeVvDppt9#T63B7-&vMRB7B;oq7J zK5p!(M|L0h`ut3w99MFGDFyeYhmF>4XyD=|zyN4kR195;1`LSc=Zk)S%0V*D($<}% z2?5)Q-Zz`!3(6c1tG=2MEDmm$aS<5!0b9Nj2V;IBZ>Cx!rcym5# z`LqjRDO0igO7+ik$WXL`nR}BSnqARhbYo6JuIx6`vHZ{BXU<#&x6N*yv}rwlcTw$O z8q~|oGjaw$Qx2)37`zlyXKi%%c-bT_@f-3Z47xcMCaVD1XJ2-vv{ZuRkA{$PQu|56 z-IbTBczgV>t9)oR8#*dbD_OWbgmidq{AOvw``IqgLt`LmYKl4-3oTb5k3MKq#iGnR zPH((nmSdka89v8Ui@5F^IamS_fj1W!8P0kr(cg2eV}lBMafkR!N5$|V=h+(Df|;V= z$yXy^F@=uaQ^jXWnY8Vkz{dt7J!d=8$;@w_)kuLx*$pWBIq%!e?3YtKe_hwrT8Jq1 zxY5)sE~c3GeDK%$t6c*RQS;zf=L4(duBIXG3xsjs5{fBnf3T#vYR<#KVY#$q@oN@1@;6{+H9kJ+)Nu?#mZ~JOZS*Sw6Grjb(@~zZ{9%hKPsL9@DM44a9Ml> zF75tL)5J|aADpi649c9mGxq)OY4N5X;eYSKd1g_S+G!tL?@LBF!l)xFGWYqHH~)5N z6|t~VXnwP>^Z*>06beJi0{W0qF?0eQI2_6JbZNZiX|UZdxo-3Y93t@|@i;OR!$VtO z79}vdL82{B;~A0GXfG$BrG>+@~5(63g=#RB$fp$inU{##krWD!_ zjMd{hG~0R^!2kCF5P>pM@+1M{crTBdU%N8>{UUMj1T(~xVCAA6@3?d2kDvnw+R3&D zJ~=#MHxZt?A5fv|?N$O>DAo7<^AJ}4`zHW&QZi$5kx^o8OAA>Krk`Bw?jaEG0}b$t zOt{NdR3VryJsA|fk)jWR3Mbe!U* zA{K&{oJ92;v!i0X;fGP^!4STp$YDp zNZHZ1<)-gd|6|z|z-~l2>l5mO)P9oi-ZUILvDyeHZ&Ig{Ful}Yx&DUua{_Pr83I{_ z>o_=UE2;CZga_k74-~ zL*2z%VdNtkGbC~OtDng4WdKB7>3UwZuVH^6zCZ@Ac}jI?7H3zNr_f!YRBdZ?UXVM& za*ebTYVTtDY2b^dX5@eRbq{X?c1#6O9k6sYej*pBc7GVrz{NRtvS| z+=jY9FC$$&##->#N~Rx$pL37|5r5ZgxVIlWLr+Zj)}n{9mHio*?6KRbc{g8E^p!!Q z_@$cJbC$RM^s?y!PsT=p4$#vjYLlc!d%AZjwb7c*ZYmb;mW(8>)OGJ`8UaUQqkd6G z7j6)B40VB#>d{0^ReHEEyyEOgs^3!#7o$4;;PVKDvC&b;{-^NM22@6R6OlB9`l&~K zFb?mIXqi&O>h90SHNjFaOA>jnqB!lCfHEAOe37|=_FVUkeivdF(Eau!S~Bj{^(O{6?!W6f!WvDWo6!;qY)+ z5JFI_7Lqbk_-a zk&71j&%ce*hnxVi9wwq-HOvX8fXc*4qDkqo)wT0ZYY&o1Q20Oy7-60{Xy5>2-o8+$ z6Eclrq6&YR>Fab!U!(+2aqeSezK{AU*WpNN`7|){qBl~ZB6+oIkArjSSRvc*>vI2k z_eECf;+Pjsn!5Y(CI+;(26>DI?X68Z;S^-IsTlY5g9B9!0d7P5CfD^PM0k7M(?46R z@6eb#9}{u$_m+I6={w?MYr@YtFG);nHROHQefj6XTD%o2-cB?E!rxc&KaixrS>v5d zWv^{^cFDtWF--CBXZ^bh<)n|3Yv|uWj0IR44=sc_eXXO+AA5^=)t{YA;JjbZ9+*AF z1;*-4%HskfizYZ6KgR!%A5s=x)cF9VEyNyq<`>L>gQho1^zD z{_gAB=*uFl_<9C)2-Q{B)bBf5wPzuQ_9A*4makZt0`H|p#n3GyHJ>m!ONFe1L)4AyEF)JB#{=neeGZf*PD2 zUYGc9|IX)={$lZO|@tzaOcbRpR(}X*$l}8;^9C;QQdd!V?-`ubfF(9VF-n zI@SyR1B3X0%d1sd4ws{LUa2z4n6_cF5zmc)5|iNX6y;15p-0v0Lz zz3+!)k)T16qUgDBNxGIWsyEp)$OFx_{lOWj5C>sJ=v4X_MWPfngWTvFg*6LUZ!+al zR_VXiP(ePp7^f@yWZ^c#(CS!TZ4G0rQ8{S!xPlIb+Pz2g4cwn3_Q99Q3yVoG4dDkV zq^|RV(SfqkIf!WnAb@dN8i0~Xlmi#K!AjXSNbquul&I!nR=s+YhaL32PeIgf`}d?SY>Mw_hS}(MW_K_bjYt>HrV6w2*ML}w_wCN%AG}8l znZEjlFb_#_mQ8u;!l3<19w3(HO5$Uy_lJZf!(z9S{tkVU-v`GzD#zFi zpOU1u?AJ(A;j+JN)1d2$^K*37n#yl_R*^cD{v{J7-Ix`-g;!0+OsB|$KAg_teA$%C zU&h;Be_IQ2*~(cbU||t*o_?@Mp3)FHAQ!bb5ysa`<`ZGAgq{w<(A0NmM$+VW&wI>> zo5^s7PvaS?H6Qke?51Mxwa=}ON%eNXYSGV2wCV13b&F&>QN)s>vJ~7C$(-)Xrue9s zNZPqSKz0IHbY}B5pacURy_#A&nP)$6Rg&lF4QDgBM+=m(q65b)SG%7;XNzA zxCN_|g#Oxn6R2&GZjr>iaEFU#W@0xAVrAY-P}Jfhe02m#(1Xv%CBkN4E&EqlzIDJl zCf0+DE3nf^#*_kV$J&@Gym!@gAETy#s%KyL3*qu-@H6w>Td;#qesmRKRKFA@i?nsP zPp^FO5>2#TDw!Xg`pyG8Flj+&!iNqlO@Wy_tX#Cdg&SXye=bvv3Y74=&;!0e9JF&) zbM&3GYgix4+fQnE+K8~zri(_VtZg0c*i1>+Y`F?erMBl8}9XhnrVBZeq3z`+^)&f-T8ljJ*$Z16P)-O?%zl%?~Wh z;MB5W>PN(PchQD_>d*r(Wi%1zz?JRbxIV&u(prXLIzzMMfw4at!)r`V@!d4cK@wJW z?MH`a&1{A21L)=DH~(_n8cEhLI4;1}VkB#EE=~_I5k8eTz3v@noPNAGK5rlOEs+)i zUjJbjxKFgS0~+AN00IXXmrsIB@2OE{B_^xqjJCm+F6>CzPN_09N-~V$PKV1@Z7>>L zQ(=7&)&RyzqBW;O)`N9$S&edyONWLF$$xL6@CgH;_GRQR5Y5t)(DQ~ldHX{tlIQ^8 z3CX$|o@tn(W>Cnw787<-m?JxAuyWD5$L0RqR$6k-LGnX7XKhIaPx0J-O{l<89+LzJF6VI*{4cFPT}sZVoiS zn{(ZNF<%WRfpi4kTMZXRwLgG|41ObKa?X2yLJwj2 zPv?LE-V5k;@BntNHxJ!!^Znn`pkv(*k#?~{4r?E&gIll;PR9=Wr~6yn1CG3960h); zIu|DKl683g8(R(S2$6?wZ zf-E%{8vnAesf4CL(zxM1T}2q4Q}xJvYS8W=dvdC| z0B6~|-LO7y*!iVK=J|zx4lD_EIv|(CDR!Y$Qr73_j_z}xww;{pLJ&(yX!4;O*%wlc zwGaBRwT2m8K-k*+smYWE9KVX!Y=)aRLOsn73st)P_vt=5>(FXyr6Y=(1e?;ETg^L1?Ry4BC{Y-6B;p%=6u)+L(Pi zqF#Qz%eHY+D6dwFr?mU8r!Z~x<+PLi4eo-wfh#{Kyhf`amgd$a;2t@X)5tnUMCv|y z>N~Xlf=-r8hnN4TZwK?7-J5iNVWLbsF#dy!wtV+@C+w2f&1?njKP(O^1o*mtVvMyB z$b{}%M;=fA1=x}qncI#&-$yAx@BKI0(IM-DEJMrTvKHsSl|p?T)8BbuqL3grdJPoU z<}Gm0-SY>G8pa1m46reyA?DHPvPfpYg;O47Lc-L$Cd(h|pR^DYpZ3aCQX(ybEiMW>_?JZt?MxHb4>ar4fuA$A(d}+5awEp0k3Zf$HomF2F|G95WV43iJty}*u+K} zrLf-Hc;z~9}TPWvGF>g8}*)pCvU*gSNVdK3jHOWVfKUhGz{d+?JA88z6kp$K3rN`{9skPjkAw%Wf$Ym$g1Ox`6iM zHgrI8USF~=C@2m)!O96lgdg-JwdH>0{T(ZC^sIZT#I zF@!mc10eEhsQGZ*7R@bg&MFV~-enZN58f`=pQnc#qt^1>Dh3b!y;Z)J|NdD%`}d1| zwt^VX36pMdD};4Nhf0;OAs0&;-ad=y{ zS{m@jjl<2;hL;CnOJ=r0m>brRQB}mab=RCqO2NOkuZHm5KYPhOW$_Qcg4qjWyc@HM zFknPooc+J#g;{G4%c@_u1sdS5a>@%N6D~fmXwRyaTQ{pXIP3tg|8Uw@GeP-P?-SGW z3D|shZ$(&82zdMN5yv!x!kGEoLvcB8_#5&U$K5NpY38eemO&spixA*tT$%O9zpwlwvl*JzGo|n!vA{=&D7j870zfe?< zDS{x(gNOX$dM(qK|Du|L_J5o2kG8s(;+`u&wQPXc_3r{lie@oH4FpIgveptL)chM2w@CEoN{uDgP8Q}hRN z@=2GOIk*o^c6qnuqrc7<`(9MFw=%6#Llu!=#E3ABIbf!I_A+8?2p$9gJ~&;Lx9Pbs z@;%hft0Zx!{qFjb-8iao#GSYou9c={Pf%tB06BjHuchOw>i5HGwI|JFzd z%K#uJpE|g#U>{~Xlve7vQ+6y4gdFH zGKBB@g!82*Y+qA$!JB#Rr6Yr4e}lfNcp|G~F{|M2==V@N1Do$kY8bDd z$kLtErXipT%`9xL*Ep(a8IX(hxmbE4-K!>XbpGH{VExHa4X5yc#?|?oQ7o*0QU3ex z$*3NRA2C?FGz%+0mea#6 z&9=69EFisMZ(^$RFj<*qUATF%1;^Y$AIs>0{163iw??(m*QiI@lM1yB+O1q#=DI_S z)`ImOAZIJ^n)p&xecpavtzZA!jPr1n(pBQ$Ien$9-*|h7t&U&A9(cE^OF^=}Q##}G+=mD9~KW|RC&PY5W)$Qx(fP%}T@)>8`VSuR;!NX?&pU14>S-Lse8Agq7dbMqs)iR$oNz) z&!8hob*QW7Z!vAU9NmE3oe5lUFd9vXu;b#}1LOZQjaFcyDxUN}>e*jIOhM`sKA13? z+a*;QA5b*H%a6B%Io!D;Gqh)e0|zMv@FC`IY}n$LDADjzMg$)l09Xf@*@nB_Vmg5~ zzz8>kT0e-_whe6k;}$vqBk_X|t)gMoD=+z_H;kIn=}@6-Ku*3r&S>RGX-&tzq$WSm zpDljfB#Kk(9U~{VOeQyBf%VInakfAS0B~IvuRx<^eg*MM>*CJ?#ApRtZiK_f(Fo}N z;*>bkyTWP87om}dkNXd)Po#CDSfamiCX--Rwf2-7_+CI{1Ebe$bew4pb2*q}>EZ_f zGuzOEO^6mNz)C^nX_1e^%iCcLf-1<+Cwm_p Date: Fri, 15 Jan 2016 15:56:47 -0800 Subject: [PATCH 242/357] don't set AC version for data directory fix --- assignment-client/src/AssignmentClientApp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment-client/src/AssignmentClientApp.cpp b/assignment-client/src/AssignmentClientApp.cpp index 8b9b5360c9..f75f9d13a9 100644 --- a/assignment-client/src/AssignmentClientApp.cpp +++ b/assignment-client/src/AssignmentClientApp.cpp @@ -47,7 +47,7 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : setOrganizationName(BuildInfo::MODIFIED_ORGANIZATION); setOrganizationDomain("highfidelity.io"); setApplicationName("assignment-client"); - setApplicationName(BuildInfo::VERSION); +// setApplicationName(BuildInfo::VERSION); // use the verbose message handler in Logging qInstallMessageHandler(LogHandler::verboseMessageHandler); From 0355e816b06ec0909ce52f26287ae244b7a3dc45 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 15 Jan 2016 16:02:24 -0800 Subject: [PATCH 243/357] comment out manual ssleay copying --- cmake/macros/ManuallyInstallSSLEay.cmake | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cmake/macros/ManuallyInstallSSLEay.cmake b/cmake/macros/ManuallyInstallSSLEay.cmake index 405bf6b1d3..eef5ab0ed7 100644 --- a/cmake/macros/ManuallyInstallSSLEay.cmake +++ b/cmake/macros/ManuallyInstallSSLEay.cmake @@ -18,11 +18,11 @@ macro(manually_install_ssl_eay) # so we have to call find_package(OpenSSL) here even though this target may not specifically need it find_package(OpenSSL REQUIRED) - install( - FILES $<$:${SSL_EAY_LIBRARY_DEBUG}> $<$>:${SSL_EAY_LIBRARY_RELEASE}> - DESTINATION ${TARGET_INSTALL_DIR} - COMPONENT ${TARGET_INSTALL_COMPONENT} - ) + # install( + # FILES $<$:${SSL_EAY_LIBRARY_DEBUG}> $<$>:${SSL_EAY_LIBRARY_RELEASE}> + # DESTINATION ${TARGET_INSTALL_DIR} + # COMPONENT ${TARGET_INSTALL_COMPONENT} + # ) endif() endmacro() From 2af10d6baab6cb1eff15bae4ebcb34faa38e13e5 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 15 Jan 2016 16:02:32 -0800 Subject: [PATCH 244/357] fix shutdown call for console --- console/src/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/console/src/main.js b/console/src/main.js index b350685b8b..3e829e833c 100644 --- a/console/src/main.js +++ b/console/src/main.js @@ -312,7 +312,7 @@ function buildMenuArray(serverState) { { label: 'Quit', accelerator: 'Command+Q', - click: function() { app.quit(); } + click: function() { shutdown(); } } ]; From d4597f9e8b7bc8f38fa82642747d40a6fce8d81c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 18 Jan 2016 10:11:36 -0800 Subject: [PATCH 245/357] Revert "comment out manual ssleay copying" This reverts commit 0355e816b06ec0909ce52f26287ae244b7a3dc45. --- cmake/macros/ManuallyInstallSSLEay.cmake | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cmake/macros/ManuallyInstallSSLEay.cmake b/cmake/macros/ManuallyInstallSSLEay.cmake index eef5ab0ed7..405bf6b1d3 100644 --- a/cmake/macros/ManuallyInstallSSLEay.cmake +++ b/cmake/macros/ManuallyInstallSSLEay.cmake @@ -18,11 +18,11 @@ macro(manually_install_ssl_eay) # so we have to call find_package(OpenSSL) here even though this target may not specifically need it find_package(OpenSSL REQUIRED) - # install( - # FILES $<$:${SSL_EAY_LIBRARY_DEBUG}> $<$>:${SSL_EAY_LIBRARY_RELEASE}> - # DESTINATION ${TARGET_INSTALL_DIR} - # COMPONENT ${TARGET_INSTALL_COMPONENT} - # ) + install( + FILES $<$:${SSL_EAY_LIBRARY_DEBUG}> $<$>:${SSL_EAY_LIBRARY_RELEASE}> + DESTINATION ${TARGET_INSTALL_DIR} + COMPONENT ${TARGET_INSTALL_COMPONENT} + ) endif() endmacro() From f9c84f09133dd3e7839b42069fd9cfd6eddddb5a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 18 Jan 2016 10:23:07 -0800 Subject: [PATCH 246/357] include console targets in all for PR/prod --- console/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/console/CMakeLists.txt b/console/CMakeLists.txt index 86bb1a38b6..02ac68d74e 100644 --- a/console/CMakeLists.txt +++ b/console/CMakeLists.txt @@ -51,6 +51,6 @@ elseif (WIN32) optional_win_executable_signing() endif() -if (NOT PR_BUILD AND NOT PRODUCTION_BUILD) - set_target_properties(${TARGET_NAME} PROPERTIES EXCLUDE_FROM_ALL TRUE EXCLUDE_FROM_DEFAULT_BUILD TRUE) +if (PR_BUILD OR PRODUCTION_BUILD) + set_target_properties(${TARGET_NAME} PROPERTIES EXCLUDE_FROM_ALL FALSE EXCLUDE_FROM_DEFAULT_BUILD FALSE) endif () From ba6c4d90dff9f7a948ebf3e3cdd411d464fb4e1d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 18 Jan 2016 10:34:42 -0800 Subject: [PATCH 247/357] install the ssleay32 dll, not lib --- cmake/macros/ManuallyInstallSSLEay.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/macros/ManuallyInstallSSLEay.cmake b/cmake/macros/ManuallyInstallSSLEay.cmake index 405bf6b1d3..41e7e9eaf3 100644 --- a/cmake/macros/ManuallyInstallSSLEay.cmake +++ b/cmake/macros/ManuallyInstallSSLEay.cmake @@ -19,7 +19,7 @@ macro(manually_install_ssl_eay) find_package(OpenSSL REQUIRED) install( - FILES $<$:${SSL_EAY_LIBRARY_DEBUG}> $<$>:${SSL_EAY_LIBRARY_RELEASE}> + FILES "${OPENSSL_DLL_PATH}/ssleay32.dll" DESTINATION ${TARGET_INSTALL_DIR} COMPONENT ${TARGET_INSTALL_COMPONENT} ) From 7d4a7983ed32dd6b13bd3adfdfa646bc075f54f4 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 18 Jan 2016 10:38:38 -0800 Subject: [PATCH 248/357] update the installer icon and header --- cmake/installer/Installer.ico | Bin 31238 -> 27121 bytes cmake/installer/add-remove.ico | Bin 27121 -> 0 bytes cmake/installer/installer-header.bmp | Bin 102656 -> 102656 bytes cmake/macros/GenerateInstallers.cmake | 5 ++--- 4 files changed, 2 insertions(+), 3 deletions(-) delete mode 100644 cmake/installer/add-remove.ico diff --git a/cmake/installer/Installer.ico b/cmake/installer/Installer.ico index c4316f5de6d0b2925fbb6cacdbd3d4c8f78422c8..8d84d9d094e49570e1e664819169a29156a45d64 100644 GIT binary patch literal 27121 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 z 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 Q@E{g@A+I;dv-9Ww2X31H^8f$< diff --git a/cmake/installer/add-remove.ico b/cmake/installer/add-remove.ico deleted file mode 100644 index 8d84d9d094e49570e1e664819169a29156a45d64..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27121 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 MroX{S3xy#62aBKbeEIv+HB5IMG)U>qn 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 R0000000000z-=uk=s$YR{73)* literal 102656 zcmeI5cU;rg{{OADy$X*qsj?IVWC%U)TwhWGo|JzrV&_qUhv{`>zdVlWsC27|$1Fc=I5gTY`h z7z_r3!C){L3?%lh$u(0q#-VlSqJYjx*{?@Hqfq{W!GTF$;C_6iQ zWMl*@5rcU#^!4>cMMW7I8EI*0xw^U%i9~gEb!%(u($dn&$;lV<88DcalaY~;)YMcn zGcz3>9esWMDzB)YA)zy7`eA?UFXJ=>sbDsx;d3l(bnW?I( zB9qAk0zpeli$bAvcXy*NzrVk~ySsaEaBy;RvZ<-b-Q8VVTO0mlXlQ76clYDRkI^5- zU@*Ul$B!Skw6svER04sZt*!0k#YH5klqVt#(Uv$HcKBt%zNmq;XDA z>+2gE8=IJz$j{HWw6r7;2%4Ij#>U2MHXA2SF_`CMU|=9NHrB|BPjubAAjA<|SloY%C)q!_3T# zNF?g$=!AuZjgODRbNHphWKT~|dwcus+qd~;*w15lcz9-JW^iyYIy&0W&=4g~8yXsL zx(0(0U}|crsHn)+))vw!-rnAK?%Y{i6bREgc)-ED1cw{G29 zD#LsC?hOnKjEs!T&CT`n^aKS3>FVn0=x`IKR4TQjqvO$|M*<%MgLw&g^ypD-ZLO=T ztCp6Qwzjsty?uRs{o*1wA@h*O%*@Q}?ChgQkLGv?$gr!c>!+W7YHx4v=;#oTVP9Wg ze}DhLz`)?(;DZMb9zTBE-rnx*?M>jJrS&9nIyX1>5C@vLwxk;5p-@hG&J0}apPBI zc<-6NAdxaS_$(!&qv_n-Tzh+aeSLjXQ`3zbH(FX+kQ>6G z^cikAIywq+8y_E!kB^7Msk*wltE(&SIK}+$@$lipva&LJdwXqdZ7nS=J3G6gqN1Up zp}TkQLQMgk8zF*2N*o>@eyS%zkT^R#+t$`rTU*=M*a$M@cSDe2S63H$@&5jQa>LQl z(ed%|si`UGJ7q8!&~d7vp+Tim+uPfpQJ2JE{#%%xoo#Gvba!{x($XRj2&Sf{DJdyE zJUTkKGP!-58@{3H9z<~bN*o#*da4p9Cnu+;r(0WFtE;Q)>+642hET!hmmvh65Ou<+ zMNdx;jYcE#(AL(*9jBQ8Y92p++|kkD@9$3_5Oj2O^z`(?!ou3x+Pb>BT3cJ&+S+d3 zyor*TphP%2_Vhfj5~rr7T3TAFs;X*hYwPRl8yXs(?S{W3!?Ce3Nd7>bqP4Zv&CLxG zrv?TFiHV6rLqj-SgZVFFVPWC!-MdUCQ(s>nPIo>&K6Q0cn( z@+VHq%ggboKITu$g9i_Cb8{^$EVQ+?H8nLYEiKd1(r(Zt95gjG2?T2M23wYm17CN=r-O zU6321b1$kJE|npKoT#7e88Sq37JYqvkY$3Cc6fMrcXv1L{l@$uEG#Va_V!Y#R1FOc z9UX4Ri<_HUZf^) zu<)r$i;J#EiEG>+Vo|BWq;c%5M;D$(s_4V~E7OSYJ zsI|5ACms-TLZi-8hb)jAf(%izbb6ZWhG>53#XM&W=9d^BA5Y@JVzH8wlT%VsQd3jY z)6;*G68SSWU|YGlxilKh!NI}H%d5J&`o@hL0#yvuVAI*zdHwqJ?Cfkf`hpBmY*v7-RgUhl9bq0LI71 z6L=&hCMG5Qti-gmw5KW&1&IQu)3P$IAy!vc7Zel(1qC@cIJmpJ2L=Xud3iAy46sFk zI1w3HO-)T!R#r~VlNT3o!>X#P!oori4-Yz>?(gsK;^IOklUXcQQ&UrWdpmlOUy>o3 zb;53l`ExQhHWtStK0ZDn;fWHHd8DRtkETnN$e*r3N-QrgFDxu%GMP?JPR`EGR4Ucq z-=9vWhlGTO#VJwhWy>#P{GHCQp}%$v9Ylj9GtAqJn~g z*w|PynQUig=jrK5rBZ!;eFFjl0s{jX3`R&uh?kdFX=!OgLxVs)5sL2x1qEqoX^;y7 z8KSaCd3kwEOpLd;cSJ-4gTV+23Zm2Letv#58qLkk&Cbrw-`~Hqw6ueVKwBv)K?<~$ z!jJ{O3}KY`&+zTQyo8L6jYaW@j*gCrd7?yQi2OmKfG4uqY&e%DCMJ4$dD+<5xVX4@ zd3jMN6dH}@=jTVK(}RP984N~5LS}NYTKd z6qODIQZ#tX5c5YdIyxG`BQi2FD(Z<6ks%5MiO3Tnd`nJFrqO6NHa7P5_O7n3o}QlG z-rhbwK45}DK|vuQAz@)*5fKrwv9UfrK8cBm_4W0TI7K}+&CSiZxw*;7$&iv2kRgpm z3kwU2jg5_nhzJi4XD}GS!NG7erBbOB3dPII%hlD@#>U3U$tf{0v8AP@tE=m&bwk*L zf!az1+z{37F_;(3=;&xT4If2-ro87`872)s429ruCB4MF()S{DJcmA4*A&Z>}(E) z6B-&C5D<`*loS&a6BQN3WHQ6T!jKjE`uh6#_;`7Fd3boZy1F_#I$By*(m{;^N}!>gwU);qC2>BEg`bAO?d0CKw&fRdiBPQba_A zzrR0}8~6)4F2hUs9EqYx37i-SZ^N=iz4dU{$~8ihiMkB?7FOG`>hijR+vjg9?PD|B{tc64;K zv$HcdH@C2`2n`LbtE=nn?d|UF=5G{7%h_Pd4fM0&IVQ{>#mLAAolXx73=9ei3J(4! zCBo@6Dk>^AHa0vw+{44e!otGD#KgkF0%AZXCnpyd7dJPzUp2vmgaj6g1=W8lm71BE zSy@?$rX(^lGGb%7e+H~JJv}`jARs(EJUcr(H8mAkVN6U+WMm|Y3Q>ZTLg8AWySqDB zp@V~it*x!4r6q|(vbD91kB@I{ZM}QHA`t_;J% z!hC#utgNg^B$BDAsfC4wwY4>vptG~HtE($Sf<8VzG#WP&3=9km2?+@eePV*Kv9a;- z@kvSCnqyj8T6T7JQc{wyuWxa2aT$-w%F6Wg^yuj5xHxV;HaR&tJUrab&o4JOH!CYE zEiEl2B_$~-DIp;NtS}-X0!4)Z0Ra#ddV70AROsU30#;~aV`FJ)X<}kxWMt&x;*yn> z)!EtE-`|gBonVd_#fE781qSnixqtt@FAqOIzkq-Mq{I*&R4Uch*4Bszi9~`^sDKGV zI+RMK!Ye=|7# z_AV(YfubS&$}dB#LChb;{rmT+JZLnUuP;}LAVcW(G%_;M)6+9BFnE3wgmfr>B$$+x z1j&}n%uJ{%78Dft`}@PFR7pumdU`q%tdEaRe0+RyadBQ=9-Gb1%*;$rPv^HnNX~#2 z1_cFy6+*4h!^6YP%}u}x&CJY9Ot>=C)zvjNHVz63s;{rVckf<*e?Na)Dc&%H`J=dh z|2~C>kB<*{8I?+Pc6Nr^zl`uh4tMn)zkCT3=4mX=R3K?;Qee-R4t48}j1Ab%tX zRYeYmQ(RokX0vHDT3%jWadB~KYHE0Rcyx3$yh2%7Sz%!zhr`Lq$q}%^xVYaI6@nF- znwlCL8ygrH=<4bc2n2I;^O%^Jwzjr`fdLTXz`y|Bw}$zn7#<$>;sHt|lgVagX0XSe zNF?g%=@}XtKEDY*H4@}E!Q9;3{QUf)qN2*m%7lc3;Nalm;^MTlw6L(S(9lo{g;HEx zTwY!d{cpcyg;7yIM}^OCg+@k3ut`Rnhn<~WMn*oIM|}%0FEaxJ12Hi%`uh4RDk@4! zN~)@=8X6i}THI48n4qz-v8kykn4qn#t-ZayqoX64Om=hQrbC|^2}VXnqI4+g0)@FG z4(DeRgpDyxO-*bz+rz`d*Vh-;idI)wL+P-jglmQQ`T1zc23R4K>>)wQWHKQ^iW<40 zd(GY5-PM&_vUhNBfQC8?3kx$dGh~H2I@}ZKwQJYZ)YO!D7#bSFKKz&Y=K=E~nV6W! z$;q*>uuxG^k(ZZOR8&+^QBhY{2NQ%;3`BxvW@b4iTX3Ofv;U9G032Cn`L2nfi^%4%{QP`%b+xOjtD2gcoSfX{%a;`u6|Y{ss-~v4)C5gT1S3Iy6BL+H zg7$2F6NH-JQ%w*qJ1Z_Orqk)pJQ5NT>gwv6o11HDYAP!$pED|ah82>@Ki3MM8Wkcd zgkylby!_?Mmo+pr+}zx1YHDCDFb4Dca`WcRfPjE&*RILR%1TR1U%q_#%9Sh1%F1AZ znwpy0+JYu%X=!O~%{4&>hbN6O(3!T>1fkO#y3UXZW@SB@G=y|$X=!O?C0Br@rKQmS zR$g8{JUpD2muF*R z9k6D%kw zC@n25DJfyGSblzfv9Yl?Z{CC*yb}}LtI8%PCnqK*#>dB-o0~m6Jalw)TwPt+Z1(l* z*Go%F`J+PUUV{Xwz)Ta`biqH<DJgmJ;zb!5nM;>0 zDJUqQND!GIbf!T%)WX8T%8Hu~<)2Z4bSSiE!?p_kL0yC~IwwISz zPEHOij6x-Q)X4qRnI_c8jmCS?Ow&`XkU-$pDb&@~RaI4y70SuUNlQy#xNt#COiWZ% zR9;@*-rl~Vq5_W@VxFJz@o^s?A7y3bbLY;TIdcXCc;UhY0TWyr2?}(kArpM+j1t;b zfzqKcikqI!HNo86Tn>kmk&yu#nQq^{JwHF+)6>({)rGpI2L}g7M@I(-2L}cQV8RGy zZx678Vf^QBqR!@bDNO9)AAs0_J6AdU~2fA{{?|{OsAYA|fK<;^ODe zpO=!7LM8~2pqkomFhLXvLQx*IXT!D%0TX1i*)SLw78VAX7RWSqc6Q#nbqkI1fgASs z_usvHx4XOh_U+s4?d^B(-i7a7U0q#3K!B>MDuF-<3=9NO!%S0h^3S!xXGDcC)AUp; zG&D3s-D^*c3c(5`BqYSd#Lk^Nck<*(0)c=JrI_cZx3^bHN=jH*SWHYzLPBDx3GzpR zy1Kec+q01gF0BbJ-By9xv!S&tF)=YRGBQ3sp2Ojkm6g@i)xpk|jt=e;LfB5<+sj?^ z0_V@JuCC6`&c43B$;nB$er0ZMuA!l!qM{-@JKNFG@zSMBy1Kfdp`kfBIczrj_p(CN zy#^(Ffv6B!;kk3?Bqb#~Iy#>J`C~APi;H=Ad7`4COHJ_kBSB|p=Vz>JVlsa=L8wQh zq;NaRV8DUJVr6D#=H=xT78X`lSAz!I+S-2l>8JMg_S?6)mrcM>ZC6)Ue}DhOhY$I` zYjbmR)z#I|v6h{k4cB){Nl6(P7(_%wWM^lmr>Fnwri-QHz5hZ~C@Co^Dk_?qn#%w2 zFqr4W%gak#T>Rq2ix3IQ%gaA!Iutt7o@ZMHjKHJyYtX?G9UYyJkdT_1%4V}U98P6r zC1|jvrKP#K8Llvc1!(v0-{)T?F)}hzQBeVRvQ$)5z?n8VIXON)J~}$u)6-K~Sy@t2 z($v&6CMG5$BLgJ=FGPj>Z8H!R{*o0+NJuz1IN%+mn17AY(NRrJ%?lSU$jZt>I#fwX zNkv5kBEe_3XFEALp=}kgyccb-N82i3{Ti%nN=Qfu2?_D{_YV#ZW-^&EF)>L=Nw7n^ ztgH+)*wD~WQ&ZE>(9qi2IxsN6pJ^Nz7+|y60RaJVadGqW^N$}tE-ETYO-+UMhT-Ai z!NI}){{9pS#l*x!Qc_YvLc-eGIyN>oB_$;;F7Dr%X+n+M(7gr;Qh9lKIXO8gDJc~d zm4ShQf9?5WFpGtIU*$`MJAJDV`F1tVxDK|6N(C9?~}g%)2;B*rAt9U zLI38%$6yv0xuptgYik7s1!RI+T3Sm7bp~K|w)eWTb_K z1*~eZu&{tUs;jH3mzNifMhgrK1Q|w0M`vee3+(W0X=w=#4t95UXR%mt-Oj%*?>RfJh{&s;Vj|D9FmnN=Qf?J$m%u z!Gkg~GM=8EF)=YrCi9n;J~=r(*?-8t>0+rBs;H8XE8-rlzKrmX>yQc1})C zZf7@a$8zHnQ7v0V zU0q#GO-*n>85tQ6;Hgum4j(?eXV0FToScr14kD3w;J^VjH8o#f->|T-fPerR?dS2{ zXU{aD@m^I`)s&PJ{F8(EeVL!1r&6gJ8XC`-QQ{xeg~k|fZ*K;JQBqQppP$cQFu=}w zdV1vL^kCbo9%+5-m;5Q#*{)6!@({_$R9g-aW`;ayx^T_K5t!Ti1q4-cD~ znxaV1*!X7?gl!dQM#;m&!`YY;2T{M7MYLqkJ6vV{51QBzZ+qw_0~AYAB~ot@p( z)Wl#gBqSvE?b~EhzzFoXybhy(&bUtb^Qo~*5{!409=o5^H? z1``qzm`o;&`m$IoxN95kx%Tt(^YQU+R&EYN3Dqw+47bq$$DJl8SJ%0>lad8n=IW1k;1UW-8napCbT3cILES8j% z)b{P$g@l9-9XfRM=+XWA_j`ML!!vAXXpoeYl$Di*k_Qz1i9{mo2GAabYkR zpuwo9sNmpWSgai%AD_&_-`}4~rFwdLIypHp7z~t(oSWmOWt5ebuU@^Xpui0P&!0ap zDk^&V^yw2PP8>dbc>n(Wd-m+vzJ2?aEnA9;ir|CU+1agFvErR~-ucU4{_@HzuPj@( zZ29u#Z@u-_x^?S*{P9O?YinO$Unp}tb?Fm>!N5NxnEy1BlapjJ84c>fwhCKYTRS_u z$jHdnR_-0~ii(P#efHTGUwpB9_wK!W_Z~QK;LxE%|M&%=#`R^l9ZGb5fM3k`t+)mM=K z5%8Pq)~yp26}7jwr%)(R?zge|IVyB;a2OjK+6X`;^xhp*R5Ok`RAX1^UXIqcI?=*XAhF$!Gj0Uag@bkojrRNI#HqcsHUc- zsi}$F(9Dc`D7Ch>_Ve=t4F(4XQz#TVogNYr5*{874Q4JbE)EV3R#sMyj*k2le8Ab+ zSwuucLPA1VSoqYbQ^$@SJ9OyKci(-td-v{dzWL_MFTec1|NB2*UtjpcB_$>Ayz|bA z6)V62m$H2M^4DH_?W2!Ax_I%TlarIXyF1!{Xl`!a($exDdf=FsilU;T!otGx^75*x zDp*$5*4747dwqR({T} zym|B1ty{nR^2=|&`DW+NoqP7|`R=>#4jw!xBqU^FVgk?e!Gj0N%F1G5Vz8hFy1@lx zXl`y!B9VN3eId=rU@*vJGECwJ1qH!Nt8ylZJdsbLj_=g{U zICA93!Gj0)?%lg<*RF5A`R4P_KmYjSkA;MU?%%%;f9u+{Yp?KFsy=>RdF7Sm%a?E3 zv`JoG-r3pN$;rvW!XhCdVPdth z+zpKapAdr)pscJ6ZXAn?i;IYe2n`K|ZWHLAgc)=A)z;QFJw1J5Vj?gwaP8W)ue|cg zyYIfcX3d&)>(*`9u;G(WKKbmk&yWm-goM8P?z{c__a8od7!|LRlaqh^@y81nF2Ho~ zl`B_ZQzCLheSLjTPtX4Te)y30@86G%jC6N*2N?zj2L}ZO!6jt|1_r9Cs=>j*{9jH< zNr|wqFv`FjIB?+GZ@)zX{N$5QR;^m)=jR81rK6)`&6+j*T6-QgZrphJ@?}RyN7x)r zp**<(2es$H$r;kQ2?+_feH8ONOifL-x3@PoHr}{#qqepd7Mj5&4s13XI#Lo76QiS} zIUG)3Utex+?wK=Z{_>Z(zYM_*w{6?Db0=4Z`}XbIxpOB!Y$AFgQ5q>FMd=;X$QR>2$iUuP?0LB@hT28XD)%pQlhLH*enT z?d?rSNDvbfJ9X+5%D{a4?YBF3?gR(?tENbS+joq`i&bmf*XGI)mPiLZQHeLmynRq-o1PG@84fnR|lV= zxw#p3Mj;u(jIg@8x|*7rot+&-f{2BMh0xGYXJ=<({S;>#et3U0vZ(%+JqXxNzZ@ z6vxks6)RqU{q=S0*2&7s(&_Z1q@=jGIJmGItz^u}$;r>pFXmBGQ-k+7VSX3-`uZv= zDhdk=3knL*4GwU{EnG9rWHJK-1DQ-_U0vPHn>QUD9k*`X`q#hyb?w@KCQvSrKX zpMU=K*I#enzJ2%Z-QRxu?T#HgQ0z88Kkwq=a^l1ZNl8g5DJgy#Dkvxv78de<3AMGg zMn*<3n&Ii`NhXtFuOJLTz+z9xz#Kh#^w6Py65!UYTQ_gs{Lx1rz4_*wN=iy-wmmpF z_|;cm<=5I$UVH7ex88bd?b@}XqM}}2UU0!Z|3)}ug84kIU%!q=cQL;&3kwT(?%XLU z;Z6zVH8nkP;sm&%jEoEv4V9IZFJHdQ;czA=C#R;SN=r-C)YME(O<{8> zv}D7AYiVg|D8WM)=+UD`|M8E1?Ay0*_wL<0cI^1_%P&9u^wUk7HmzU3{*5=@ICt(G zD&^PK)_(NSM@vPAcce)z%O-k!;1hVwuh;m~q^Hk+N3lLI%`|Gp0& zgF(#A%{4bSb2uD0ks>QZHyOb`3TX0dY;4TS%TrKLSigS#haY|@;D$SP><|$VK~?pM zi3t*kgk%V{du3&=!JR#O7PbnDii#2l1hhcd$%#7?0XubJbrPgNQ4M1E?%mtAZ36*r z+_-Vwx^-{7@rJOlFe*m$_4OS(bO^~!fE6oNy!-CE&^2meViFu291;?OwlYRVMWN;V z>FL}nqVn_eJ3Bk^g)f*F!1VNVQ&SUcCreIFMt5s6nM`z>n2(Q-r>AFpe0)PgLwtO^ zh=|C#b?ZL<_~S3W_~PrYxo!x3VhRchND&VoK6G+&I(hP>n3xzkl)|+#5G3mA>KYkw zcj-fWfW5uFm6g?n3*6mh&;tW)*ar_Dgep7|;HFKR)~s3c=9_QI%gZAN93LN-l9Ce8 z9q{U_udZ6PYQu&N2M!z{5C|~ZkFG047i7f8$Fo?h)YR0htgN=SHWcAvFfWG5$;sN< zS~!uy;4l85t=mDk>~2EF~qy-^qsVH-w&2Gcz+A8yhn-GchqS5a5XuCj=bui!Z+T^i!?_ zu3EKf_3G7*j*ch>oS2wUR8(9lz~#%AuUfTg)22=P_U%(qQGw|XDwVqm0PW|8PPw?a zIM_PX*x0zVKL>+(VT_KBmY0`9>t=LxH1w{ZJEq}sTbKt-O-(H=Ep>Kw-nVbx#*G`l z{PIgE8gARRO<7r)f8M9Au8v3~o;hOt!PL z^YHM<$jHde%_WgYyLa#Y^wUpauwwi6?UIs`sA#yj$SvO|CMI6JdR0V3^(6(*c_W9?ZuV26Z?|=XMjvYI^y}kLB(%js9 z=FAxZ2VA*w<)@#1x^Le;DJdxn3k!F5cm6vvkO_u`aj!~@iHRvMFUKW6%%70%?(WRY z%<%B=u&}V;;9&l1jNIM1iy)x6+RMu;Gc%LLVyUaEL(+23o;|yE?K*t;aAag8EUO1b zM@LyKmcG6|T;CusFMsvwRhZ@1)6*l7NIE(?$BrF4e3&ahAtA1ow{G1E&2q<%9ivbv z0tJG&xVRlVcJK@Eop;{Zx^?UR{re>(Bn%7;oSnJTQm~zv|Dvd%prFuD?nb!${Cr&U z!~Ds)b?a7gaxx@m{QdoDG_Dn*`%^%MW@ctSK0X;48R6mKa&mIpc?by!?b)-3NF?64 zafAPBoSmI*XlMuz54W_mgpEls6{xAHdG+d5=>LS`qmYo0sHmuojZHy8fk2Gb*49QO z5?8NYjRg4Sn{RI2y7l0}gQB9M+S=N%3IHx^Lw96QsZ?}HO=e~$x=;p#`I9q0Ki|^Q z5)%_cr*oI(QmIr}1VJW~9UZw7=+@TOrlzJQCMGl*Ej2ZjMx%*~i$k(>_wLFHUTob2i8@$m52 zwQJXk6)Ql1ufP8KmMvQj9Xcc;BBH9QiiV_MzaqLL12$v$`}?P)q};i4N8rO?Fn@k# zXJ>0_Y8VWLudgpeg=i53jNO@;nHd@yl1LX&i(3uVZ3jqPV!&-`^juF+#U$+SqVcbefr&852$h+ zg2Go{ef8E`Z=u8Ih7B8z9z7~9E`Is)Wdea<%)``_duyETA0%*@P$goMDrKnDkhYuB#*_~VaXfBp3bAAIn}8*d=>tzEnJ=+UF+&!3l- zl~q?)hiftn4Gqz9RA_z!6ATClxPJZmzh=G|%%7Zrfq~T2R99D5w4xJPp@D&cuCA_@ zmX^A@x~Zutold7xsmjXAM~)mhdi3b&)2D@nh0mTn3zdiyCr+F^c@icgzW(~_FTVI< z^XAQK*REZ?diCG__P00Rd=rI!t5>f+eE6`mw6v_Otdf$Fz=C2hLD(PVCz=-W#x+(FK*bd;iHc}TC--&d+)smI|)I6D_5>Obm)+roZO{Lm*nN; z1#a$!I23x`Y;A4b-QDx@@^Hxy^HR~)))o>Hf}%naiF?UA4CKNM?~01ttJW+mENC>E zwYBxdix*FxJbC8K88I=j^XJb?OH0ek%S%d1u3NY6!w)}Py?XV#@4oxyn{O^##x42n z+qVx^dCSVmUb%8bMMXtjT^-%m2CLh^1nuqZ)6>&o`7j3avhn!w6h-+Jq*GepCzw^Q%01^k`~oYJ7aWySuxxvN9th zBPJ%s&(9AMstyhg#>U2adU`G{E@5F|2?+@t4yUQ9X=rF@Vq#)?dKwqmF&GR6gTY`h h7z_r3!C){L3 Date: Mon, 18 Jan 2016 10:57:45 -0800 Subject: [PATCH 249/357] make sure ADD_REMOVE_ICON_NAME set for nsis --- cmake/macros/GenerateInstallers.cmake | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cmake/macros/GenerateInstallers.cmake b/cmake/macros/GenerateInstallers.cmake index fcd7b4f19b..5ae1226ffc 100644 --- a/cmake/macros/GenerateInstallers.cmake +++ b/cmake/macros/GenerateInstallers.cmake @@ -27,8 +27,9 @@ macro(GENERATE_INSTALLERS) if (WIN32) set(CPACK_NSIS_MUI_ICON "${HF_CMAKE_DIR}/installer/installer.ico") - # reference the installer icon for Add/Remove icon - set(ADD_REMOVE_ICON_BAD_PATH "${CPACK_NSIS_MUI_ICON}") + # install and reference the Add/Remove icon + set(ADD_REMOVE_ICON_NAME "installer.ico") + set(ADD_REMOVE_ICON_BAD_PATH "${HF_CMAKE_DIR}/installer/${ADD_REMOVE_ICON_NAME}") fix_path_for_nsis(${ADD_REMOVE_ICON_BAD_PATH} ADD_REMOVE_ICON_PATH) set(CPACK_NSIS_INSTALLED_ICON_NAME ${ADD_REMOVE_ICON_NAME}) From 7be6a4aaf9d945e6355bb3e99d0ce5ef4140c897 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 18 Jan 2016 11:13:16 -0800 Subject: [PATCH 250/357] fix null logWindow closure during shutdown --- console/src/main.js | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/console/src/main.js b/console/src/main.js index 3e829e833c..c046a4fb68 100644 --- a/console/src/main.js +++ b/console/src/main.js @@ -71,6 +71,9 @@ function shutdown() { }); if (idx == 0) { isShuttingDown = true; + + userConfig.save(configPath); + if (logWindow) { logWindow.close(); } @@ -521,14 +524,6 @@ app.on('ready', function() { homeServer = new ProcessGroup('home', [domainServer, acMonitor]); logWindow = new LogWindow(acMonitor, domainServer); - // make sure we stop child processes on app quit - app.on('quit', function(){ - console.log('App quitting'); - userConfig.save(configPath); - logWindow.close(); - homeServer.stop(); - }); - var processes = { home: homeServer }; From 0e78358a853f4507f2004322a75a824dc3a813e6 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 18 Jan 2016 11:24:06 -0800 Subject: [PATCH 251/357] fix reference to logWindow when not debug --- console/src/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/console/src/main.js b/console/src/main.js index c046a4fb68..dac37894f9 100644 --- a/console/src/main.js +++ b/console/src/main.js @@ -232,7 +232,7 @@ LogWindow.prototype = { this.window.loadURL('file://' + __dirname + '/log.html'); if (!debug) { - logWindow.setMenu(null); + this.window.setMenu(null); } this.window.on('closed', function() { From 21074fe4e4ff95c6a5e1bdb662646a9ca2398700 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 18 Jan 2016 11:28:14 -0800 Subject: [PATCH 252/357] changes to alert wording for quit confirm --- console/src/main.js | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/console/src/main.js b/console/src/main.js index dac37894f9..8cedefaf89 100644 --- a/console/src/main.js +++ b/console/src/main.js @@ -63,12 +63,18 @@ const ipcMain = electron.ipcMain; var isShuttingDown = false; function shutdown() { if (!isShuttingDown) { - var idx = dialog.showMessageBox({ - type: 'question', - buttons: ['Yes', 'No'], - title: 'High Fidelity', - message: 'Are you sure you want to quit?' - }); + var idx = 0; + + // if the home server is running, show a prompt before quit to ask if the user is sure + if (homeServer.state == ProcessGroupStates.STARTED) { + idx = dialog.showMessageBox({ + type: 'question', + buttons: ['Yes', 'No'], + title: 'Are you sure?', + message: 'Quitting will stop your Server Console and your Home domain will no longer be running.' + }); + } + if (idx == 0) { isShuttingDown = true; From 7186a538b28360f9b717ad9926f0353a79390cea Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 18 Jan 2016 11:31:49 -0800 Subject: [PATCH 253/357] immediately shutdown if home server is stopped --- console/src/main.js | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/console/src/main.js b/console/src/main.js index 8cedefaf89..c75ce4cc34 100644 --- a/console/src/main.js +++ b/console/src/main.js @@ -87,15 +87,22 @@ function shutdown() { homeServer.stop(); } - var timeoutID = setTimeout(app.quit, 5000); - homeServer.on('state-update', function(processGroup) { - if (processGroup.state == ProcessGroupStates.STOPPED) { - clearTimeout(timeoutID); - app.quit(); - } - }); - updateTrayMenu(null); + + if (homeServer.state == ProcessGroupStates.STOPPED) { + // if the home server is already down, take down the server console now + app.quit(); + } else { + // if the home server is still running, wait until we get a state change or timeout + // before quitting the app + var timeoutID = setTimeout(app.quit, 5000); + homeServer.on('state-update', function(processGroup) { + if (processGroup.state == ProcessGroupStates.STOPPED) { + clearTimeout(timeoutID); + app.quit(); + } + }); + } } } } From 66a15e8f82ea34522d31881827c9b278f8f122e5 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 18 Jan 2016 11:49:53 -0800 Subject: [PATCH 254/357] make the installer DPI aware --- cmake/templates/NSIS.template.in | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 1b5d22e430..ec60bc9824 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -37,6 +37,7 @@ ; Set name prior to inner loop so uninstaller has correct values Name "@CPACK_NSIS_PACKAGE_NAME@" BrandingText " " + ManifestDPIAware true !ifdef INNER !echo "Inner invocation" ; just to see what's going on From 82374c7330b864a94dd7f7521f2dfdc73f0aea73 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 18 Jan 2016 11:53:28 -0800 Subject: [PATCH 255/357] add a 4x console tray icon --- console/resources/console-tray@4x.png | Bin 0 -> 4359 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 console/resources/console-tray@4x.png diff --git a/console/resources/console-tray@4x.png b/console/resources/console-tray@4x.png new file mode 100644 index 0000000000000000000000000000000000000000..5f04aadf797de781d3817023bb02b4bf49715c5f GIT binary patch literal 4359 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 literal 0 HcmV?d00001 From da1a72ed19b92d9877abf82fce68fec7ac131cca Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 18 Jan 2016 11:59:16 -0800 Subject: [PATCH 256/357] manually set installer/uninstaller dpi aware --- cmake/templates/NSIS.template.in | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index ec60bc9824..65496c28dc 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -37,7 +37,6 @@ ; Set name prior to inner loop so uninstaller has correct values Name "@CPACK_NSIS_PACKAGE_NAME@" BrandingText " " - ManifestDPIAware true !ifdef INNER !echo "Inner invocation" ; just to see what's going on @@ -989,6 +988,11 @@ FunctionEnd ; determine admin versus local install Function un.onInit + ; manually set this process to DPI aware for fonts on high-dpi screens + ${If} ${AtLeastWinVista} + System::Call 'user32::SetProcessDPIAware()' + ${EndIf} + ; In order for the uninstaller to be able to remove itself, we have to do some trickery here. ; If the $EXEPATH does not contain the $TEMP dir, this instance is not the copied one ; so we move it to the $TEMP dir and then execute the copied uninstaller. @@ -1214,6 +1218,11 @@ SectionEnd Function .onInit + ; manually set this process to DPI aware for fonts on high-dpi screens + ${If} ${AtLeastWinVista} + System::Call 'user32::SetProcessDPIAware()' + ${EndIf} + !ifdef INNER ; If INNER is defined, then we aren't supposed to do anything except write out ; the installer. This is better than processing a command line option as it means From 5f709c72d90785a39501fc72c3a56166a880f5ba Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 18 Jan 2016 12:03:49 -0800 Subject: [PATCH 257/357] pass build-version through packager script --- console/package.json | 2 +- console/packager.js | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/console/package.json b/console/package.json index a2c59703ea..954adb61fd 100644 --- a/console/package.json +++ b/console/package.json @@ -9,7 +9,7 @@ ], "devDependencies": { "electron-compilers": "^1.0.1", - "electron-packager": "^5.1.1", + "electron-packager": "^5.2.1", "electron-prebuilt": "0.35.4" }, "repository": { diff --git a/console/packager.js b/console/packager.js index 341ae0c1a7..311e54efd2 100644 --- a/console/packager.js +++ b/console/packager.js @@ -13,11 +13,15 @@ var argv = require('yargs').argv; // check which icon we should use, beta or regular var iconName = argv.production ? "console" : "console-beta"; +// see if we were passed a build version +var buildVersion = argv.buildVersion ? argv.buildVersion : "dev"; + // setup the common options for the packager var options = { dir: __dirname, name: "server-console", version: "0.35.4", + 'build-version': buildVersion, overwrite: true, prune: true, arch: "x64", From 62c354ba606bc5087f405670d8aff439b5b361b9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 18 Jan 2016 12:05:11 -0800 Subject: [PATCH 258/357] pass build version with packaged-console target --- console/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/console/CMakeLists.txt b/console/CMakeLists.txt index 02ac68d74e..9382f89053 100644 --- a/console/CMakeLists.txt +++ b/console/CMakeLists.txt @@ -10,7 +10,7 @@ add_custom_target(${TARGET_NAME}-npm-install WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) add_custom_target(${TARGET_NAME} - COMMAND npm run packager -- --out ${CMAKE_CURRENT_BINARY_DIR} ${PRODUCTION_OPTION} + COMMAND npm run packager -- --out ${CMAKE_CURRENT_BINARY_DIR} ${PRODUCTION_OPTION} --build-version ${BUILD_VERSION} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} DEPENDS ${TARGET_NAME}-npm-install ) From 81426c05f49a1a3ef8c377ad22b2868e75ded7ed Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 18 Jan 2016 12:08:43 -0800 Subject: [PATCH 259/357] add WinVer header for nsis dpi tests --- cmake/templates/NSIS.template.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 65496c28dc..1eb0b04f57 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -984,6 +984,8 @@ Function HandlePostInstallOptions FunctionEnd +!include WinVer.nsh + ;-------------------------------- ; determine admin versus local install Function un.onInit From 5745a35f4eab93a03cf8a49fab8daa408124e158 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 18 Jan 2016 12:49:09 -0800 Subject: [PATCH 260/357] remove passing of build version to packager --- console/CMakeLists.txt | 2 +- console/packager.js | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/console/CMakeLists.txt b/console/CMakeLists.txt index 9382f89053..02ac68d74e 100644 --- a/console/CMakeLists.txt +++ b/console/CMakeLists.txt @@ -10,7 +10,7 @@ add_custom_target(${TARGET_NAME}-npm-install WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) add_custom_target(${TARGET_NAME} - COMMAND npm run packager -- --out ${CMAKE_CURRENT_BINARY_DIR} ${PRODUCTION_OPTION} --build-version ${BUILD_VERSION} + COMMAND npm run packager -- --out ${CMAKE_CURRENT_BINARY_DIR} ${PRODUCTION_OPTION} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} DEPENDS ${TARGET_NAME}-npm-install ) diff --git a/console/packager.js b/console/packager.js index 311e54efd2..341ae0c1a7 100644 --- a/console/packager.js +++ b/console/packager.js @@ -13,15 +13,11 @@ var argv = require('yargs').argv; // check which icon we should use, beta or regular var iconName = argv.production ? "console" : "console-beta"; -// see if we were passed a build version -var buildVersion = argv.buildVersion ? argv.buildVersion : "dev"; - // setup the common options for the packager var options = { dir: __dirname, name: "server-console", version: "0.35.4", - 'build-version': buildVersion, overwrite: true, prune: true, arch: "x64", From b196c74eebf87c9d590fa26ae18c767298b7e17c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 18 Jan 2016 13:30:03 -0800 Subject: [PATCH 261/357] force a 32x32 icon for windows console tray --- console/resources/console-tray.png | Bin 1560 -> 2450 bytes console/resources/console-tray@2x.png | Bin 2450 -> 4359 bytes console/resources/console-tray@4x.png | Bin 4359 -> 0 bytes 3 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 console/resources/console-tray@4x.png diff --git a/console/resources/console-tray.png b/console/resources/console-tray.png index 6ff889828cf835da2c386fbdaf9b8f19ca6f5f4a..7295647c2052386749c3a594b66f37a380fc295b 100644 GIT binary patch delta 1665 zcmV-{27dXN43ZNeiBL{Q4GJ0x0000DNk~Le0000W0000W2nGNE0CReJ^syl;0th)p zH84gpK`@ix0veNU0vZT8MKv%+GC?tukOEHuIg{W5I{`tHkOCQ#H3LC^$s$OA000I6 zNkl6A_j%Hq3^ZkpClxOdAjx|3VID4h6&1N|-MWMoD^`4krGPhY-na=NbZ%~LV^&sH zJ#XK>ZGQ3Mg}%PNzM-R|V-D}g#>PhTY>SZLoA>Lyyu4^&V8Cd9(az3}Qd3jEadB}u zQ(0LV+}+(x_)iH53ABCtc3QuFz4Uk>Bpv zu|pIT6jb2Z-68{jHf-47oR^nZvwHPvp(u*DaN&YL9f+k0JQtTPT@t7R0Y##)u&{O8 zwr##94e;~xvxV|nEtMRIbon3|e0T1SyBLV)+=HMn*;m`i%CVt0*fgi~9Qd_%Rg)>7c~K#DoIjBAlI_ z>A-;lWJ(Yn3C(J9^ypDS4avM-xpIZWth#UCzI_sZ0g(#7`1trZB`7E;5d~t+2!}|R zG=RO*!gfZ*#Kc5Gng~v5o`E?c_o2lZO%pl%Q9v(gy*Xj!T&Tcz)%ADp-VyR__8itV zK0eOpg)8shzYpY>m~v)6dHlP3wn>Z&7k>&({bHb#D++vp00Cy6%JaDB=K}*$c*|KH+ z{{8#1$h73?)2H%x_wHTl@9#I89xa)ioRme&Sb<3B6fkg#ieE zXGwnf^5sj_Gk6c{z%XJE`lG3-X_VaE-6=3I(Dl@*Q-h4Q7^$k0YB zPFqz{3d`LP$~K^xG~)jtr5sHrAWX+@-MZC>5gcHWmLo(y*RNl1<49npe-SOec=4j7 z_Z~cWFvOyZNqBhp%94_jzjp85y^vE&FDAUFtgK9c^T}`FvB2=E1K$XLRJ)jH zUd^~WKrnxT2R|bsD;YkSHCb{sV}8MHeeBq=f054LfE&30uW3~S%w0}#(ey%b{Q&2_ z#jQ7xnT)B+X>@cn#l^+-qs1z3-@aXl3E5@xa?0dF3pg0pr>CbSze7kJ(WY_mJOPJ? zA;&%#JWhN)$3YV)vO&CS!zETI|2O3E(!V@!mgqR^5y0kvC6lR+0jD^h9<$&yLp&<;`z1xc|1aR`NO z3hg9F?2;`*#zHA*iGzhC5;cSnglH*sivRIX(AT?<`YA zRoK56u)e+yMD7SzS66UxaRFEWv&q+NHp?$BFW(^9+)KON4&xw}v)Qa@Z)|M9=H@2g zG{ifK!GsPT6FfqH+)6;?B$G)f7K?z~un|-FboT*m&^5uVqs!p0#KH`)9Ku&AGuuaUMZ8z$!BeC?JMd;L1Gh^3H#(178X9B z2Hq|$Eh%Z4{*8()Q#zf7larGk?oABK->y_DUAB!noeo;97MnFygQ|R{)oNd({T$Cj yQZ~Ny2hWcu>+9>?olb{Migw|z00RIvJ#>b0N+#9-0000Pj>K diff --git a/console/resources/console-tray@2x.png b/console/resources/console-tray@2x.png index 7295647c2052386749c3a594b66f37a380fc295b..5f04aadf797de781d3817023bb02b4bf49715c5f 100644 GIT binary patch delta 3707 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 AV*mgE delta 1806 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 From 552b2d2bdccb630f501e6f8fadf5f42b4783e1da Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 18 Jan 2016 13:32:57 -0800 Subject: [PATCH 262/357] add an installer ico with more sizes --- cmake/installer/Installer.ico | Bin 27121 -> 156561 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/cmake/installer/Installer.ico b/cmake/installer/Installer.ico index 8d84d9d094e49570e1e664819169a29156a45d64..f6ec3c71086a001797e323f6e5fc4df93efddf0d 100644 GIT binary patch literal 156561 zcmeFa2{=|;`#-)387ot0B11AnhKe+pXObvQN|LG2AT*IOhs7sdq3CpT>BaJv-iE$y4St#bx)fh7zj3E)F^^rAVdfU zCW4412trWs_s@ZB1kuAp(172UN)Uwq2!aq1`Th5tQ3UZ&i6ACV?*0E5f(X(kh^bS1 zf0rPLPHTej@%jDpWL5?uVK+gjtM`7^B#4qd48+Qnz2`?0L|Y95F_|EUQ3OGV5Wjy< zLoXfl7(IG4!OqT33?Dw67%^f5F>BT=1v4|VXcH5YTZV>)orZ>nZ|2RLciY0kB2iOQ zbH>P#BMBB37TSOK`1lA84i4JoczJo5w6wGWX3d)Q-qqEWEGQ@-uUxr8UcGviJb3UR zxqkh6a_-!@UB<@7dj$mrS@9<}Ha6OQd3bo3baZs`jg5`Ty1F`YAl$fdgTy&zW@aY^ z1O!-_nVD(#pFMl_P9q~D^39t!{r=V7-k#Lb(xUzL_U&8RH4F_6BS8D~>C>gAO`Gq-NH;gPZ=ao=ok=}CJ@V_Bi5~3_w8IjLqh{J ze*5m+xpU2D!#dW`}Vir(Dy4>uKf0S+qP}w z^5x6FjUUccQBnD%qM{-P-d9vq^Z@^WH-LHb=8;R6F8%g@dQkkMuCDHn|FW{O5?owd z3@R!rso+iU=s>8iuP04ROu&ozJUl$im`Bw7;o{;Vl$4Y_m6erWVy>W1F?Xo>1AbId zQR$d9YnCrJH}^1V{s;&N5S*Nxw7G<9C@LySYHDf*X=`g=*V58@t)->ap{uKVLr+gH zTt!7i7V{T0<3IfT{6xn{f+!wF5IzjQzXk(!Uh^=5_Fu>uL4qKr(#sjPKVL;$T%2}a z+?#qaFfb6KMvWp&O-+^7uU{YF;NWoC($ey&hK9zwIdkTGG%+!GWov8O=;`Tsz`?=6 zN=8P8CTuY8scYbfYm6U1{!cemQ&SV$v}seOhK9yxK|w)s%9JVOk|j$>Pft&B`}XZL zxiEY7Y;xSVakSrDU0oX-92~6CH}rsPoG@X+x356Ajg8F$YisLP9v&Xj+S;0|tgQS4 zf70X0lP6?oXecQxEKE+HKArUQ^V=^jF8;gVBnVm?=&x^YZ@*kyTl?$8i4(~S7cS6W z>brRP@+FOL1q1}hprD{rqN1X-hM(8G*f3|^v!6zvxDe~#lr{BFE06FC4TMJxw*N?fPjE3@Gtlnd?+F!!f9`Be+$1gH#dJfpF&Sh5A~LYckkYj{QUeR zK@g;ii_0H=TeN5qsi>$(IyyQoLmz=xt*x!s;rza`6xYG|=-XSjZhgBB(?ZB!o|gPEMLM z32j*H>gsAFAtCWODk|zvr(#`!tc8qw@#4iFe!qC}B5l3u4{dF2q>zvh#v?Z@EG%mD z=+R_DLqmV3l4)saf9hiZYX@ZCK$tssE@@+9b0;b)>Wa9y_%|8Z7YPXov^LPAyu6&$ z*Vm`5oddzi$qDy=y?giWhw}3BPOZs>g@vT9t}Z!s>QvIo%IXhmZC`kM zdy}(f&H5M=6m&;cR+jwq=~LfRXu$di{xL8xpp8RhWF$?WxOVN@cl&3{mMvHd-bX}4 z6i%2hfi?&GLq z04XUcV&TGtIp9~wslEsd3?$9X&A+YD!29>_$uVQb(B|ES4IBFYg

How do I use it?

- Console is your personal domain server in High Fidelity. - It allows your local machine to manage your server by clicking on the - High Fidelity icon in your ... In the menu that opens, you can: + You can manage your server by clicking on the High Fidelity icon in your + + In the menu that opens, you can:

From faba45d1e7fa22eb57bef14fb4b3d0eacfda81ce Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 18 Jan 2016 10:41:02 -0800 Subject: [PATCH 309/357] Add missing semicolons --- console/src/main.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/console/src/main.js b/console/src/main.js index a518c812fc..7711fdb2e4 100644 --- a/console/src/main.js +++ b/console/src/main.js @@ -164,7 +164,7 @@ function binaryMissingMessage(displayName, executableName, required) { var paths = pathFinder.searchPaths(executableName, argv.localReleaseBuilds); message += paths.join("\n"); } else { - message += "It is expected to be found beside this executable.\n" + message += "It is expected to be found beside this executable.\n"; message += "You may need to re-install the Server Console."; } @@ -179,7 +179,7 @@ if (!dsPath) { } if (!acPath) { - dialog.showErrorBox("Assignment Client Not Found", binaryMissingMessage("assignment-client", "assignment-client", true)) + dialog.showErrorBox("Assignment Client Not Found", binaryMissingMessage("assignment-client", "assignment-client", true)); app.quit(); } From 70371e41bf0e79aaf39621623d2a7bd59f1feb31 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 18 Jan 2016 10:41:16 -0800 Subject: [PATCH 310/357] Fix bad if comparison in splash.html --- console/src/splash.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/console/src/splash.html b/console/src/splash.html index 3af68755ba..432670dde0 100644 --- a/console/src/splash.html +++ b/console/src/splash.html @@ -53,7 +53,7 @@ - - - + + Log + + + + +

- +
    + + +
-
    - - -
- -
-
-
-
-
-
-
-
- +
+
+
+
+ From 413d3822342cf4703304ee31e3b1f4796a4f6f96 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 19 Jan 2016 15:50:36 -0800 Subject: [PATCH 352/357] remove commented console log --- console/src/log.js | 1 - 1 file changed, 1 deletion(-) diff --git a/console/src/log.js b/console/src/log.js index 45c65af8e1..33a3f37db6 100644 --- a/console/src/log.js +++ b/console/src/log.js @@ -72,7 +72,6 @@ ready = function() { var logTail = new Tail(cleanFilePath, '\n', { start: 0, interval: 500 }); logTail.on('line', function(msg) { - // console.log('msg', msg, stream); appendLogMessage(0, msg, stream); }); From a64305c993078c339d2641265c772fba7e9c746c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 19 Jan 2016 15:52:02 -0800 Subject: [PATCH 353/357] fix for indentation in log.js --- console/src/log.js | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/console/src/log.js b/console/src/log.js index 33a3f37db6..56ed6a88b7 100644 --- a/console/src/log.js +++ b/console/src/log.js @@ -128,10 +128,10 @@ ready = function() { tabStates[currentTab].atBottom = $currentTab[0].scrollTop >= ($currentTab[0].scrollHeight - $currentTab.height() - (2 * padding)); currentTab = tabId; - $('ul.tabs li').removeClass('current'); - $('.tab-pane').removeClass('current'); + $('ul.tabs li').removeClass('current'); + $('.tab-pane').removeClass('current'); - $('li[data-tab=' + tabId + ']').addClass('current'); + $('li[data-tab=' + tabId + ']').addClass('current'); var $pidLog = $("#" + tabId); $pidLog.addClass('current'); @@ -141,17 +141,14 @@ ready = function() { } $('ul.tabs li').click(function(){ - setCurrentTab($(this).attr('data-tab')); - }); + setCurrentTab($(this).attr('data-tab')); + }); setCurrentTab('domain-server'); setCurrentTab('assignment-client'); var filter = ""; - // Register for log events - // Process added - function shouldDisplayLogMessage(message) { return !filter || message.toLowerCase().indexOf(filter) >= 0; } From 00eefa3ad1e398cc9f5a136ab903f2cbcf36e47b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 19 Jan 2016 15:52:32 -0800 Subject: [PATCH 354/357] remove commented line from log.js --- console/src/log.js | 1 - 1 file changed, 1 deletion(-) diff --git a/console/src/log.js b/console/src/log.js index 56ed6a88b7..d7aae8a432 100644 --- a/console/src/log.js +++ b/console/src/log.js @@ -161,7 +161,6 @@ ready = function() { var size = ++tabStates[id].size; if (size > maxLogLines) { - // $logLines.first().remove(); $pidLog.find('div.log-line:first').remove(); removed = true; } From 1184660909d1a4e6d84e1bcefaac6bde3721a769 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 19 Jan 2016 15:54:57 -0800 Subject: [PATCH 355/357] fix path in server-console for AC data directory --- console/src/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/console/src/main.js b/console/src/main.js index 0ecf8a0f42..090c08693b 100644 --- a/console/src/main.js +++ b/console/src/main.js @@ -87,7 +87,7 @@ function getRootHifiDataDirectory() { } function getAssignmentClientResourcesDirectory() { - return path.join(getRootHifiDataDirectory(), '/assignment-client/resources'); + return path.join(getRootHifiDataDirectory(), '/assignment-client'); } function getApplicationDataDirectory() { From e3d58ad8454545721af49a9eb975c2a277e15e35 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 19 Jan 2016 15:55:30 -0800 Subject: [PATCH 356/357] change application data to Server Console --- console/src/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/console/src/main.js b/console/src/main.js index 090c08693b..63bfc16185 100644 --- a/console/src/main.js +++ b/console/src/main.js @@ -91,7 +91,7 @@ function getAssignmentClientResourcesDirectory() { } function getApplicationDataDirectory() { - return path.join(getRootHifiDataDirectory(), '/Console'); + return path.join(getRootHifiDataDirectory(), '/Server Console'); } console.log("Root hifi directory is: ", getRootHifiDataDirectory()); From de1355dab95fa6b371874773d82d33744afec535 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 19 Jan 2016 15:58:31 -0800 Subject: [PATCH 357/357] add comment to window-all-closed empty callback --- console/src/main.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/console/src/main.js b/console/src/main.js index 63bfc16185..28aba0eb31 100644 --- a/console/src/main.js +++ b/console/src/main.js @@ -234,6 +234,9 @@ function openFileBrowser(path) { } } +// NOTE: this looks like it does nothing, but it's very important. +// Without it the default behaviour is to quit the app once all windows closed +// which is absolutely not what we want for a taskbar application. app.on('window-all-closed', function() { });

>1@y2lCMG8G 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 From d6c7c772ab7ffbcda7b7d430dab3c9075dcf4c0e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 18 Jan 2016 13:55:32 -0800 Subject: [PATCH 263/357] force 2x tray icon depending on scaleFactor --- console/resources/console-tray.png | Bin 2450 -> 1560 bytes console/resources/console-tray@2x.png | Bin 4359 -> 2450 bytes console/src/main.js | 16 ++++++++++++---- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/console/resources/console-tray.png b/console/resources/console-tray.png index 7295647c2052386749c3a594b66f37a380fc295b..6ff889828cf835da2c386fbdaf9b8f19ca6f5f4a 100644 GIT binary patch delta 768 zcmV+b1ONPz6POGkiBL{Q4GJ0x0000DNk~Le0000G0000G2nGNE03Y-JVX+}A0th!l zL^LotFf)_j0veNU0vZT6Lqs$%IWRPnkOEHuF_Yi|I{`A2kOCQ#H3LC^2q||60007p zNkl(!V@!mgqR^5y0kvC6lR+0jD^h9<$&yLp&<;`z1xc|1aR`NO z3hg9F?2;`*#zHA*iGzhC5;cSnglH*sivRIX(AT?<`YA zRoK56u)e+yMD7SzS66UxaRFEWv&q+NHp?$BFW(^9+)KON4&xw}v)Qa@Z)|M9=H@2g zG{ifK!GsPT6FfqH+)6;?B$G)f7K?z~un|-FboT*m&^5uVqs!p0#KH`)9Ku&AGuuaUMZ8z$!BeC?JMd;L1Gh^3H#(178X9B z2Hq|$Eh%Z4{*8()Q#zf7larGk?oABK->y_DUAB!noeo;97MnFygQ|R{)oNd({T$Cj yQZ~Ny2hWcu>+9>?olb{Migw|z00RIvJ#>b0N+#9-0000Pj>K delta 1665 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 AV*mgE diff --git a/console/src/main.js b/console/src/main.js index c75ce4cc34..28fe76a55e 100644 --- a/console/src/main.js +++ b/console/src/main.js @@ -115,9 +115,6 @@ const configPath = path.join(getApplicationDataDirectory(), 'config.json'); var userConfig = new Config(); userConfig.load(configPath); -const TRAY_FILENAME = (osType == "Darwin" ? "console-tray-Template.png" : "console-tray.png"); -const TRAY_ICON = path.join(__dirname, '../resources/' + TRAY_FILENAME); - // print out uncaught exceptions in the console process.on('uncaughtException', function(err) { console.error(err); @@ -516,8 +513,19 @@ app.on('ready', function() { app.dock.hide(); } + var trayFilename = null; + + if (osType == "Darwin") { + trayFilename = "console-tray-Template.png"; + } else { + const scaleFactor = require('screen').getPrimaryDisplay().scaleFactor + trayFilename = (scaleFactor > 1 ? "console-tray@2x.png" : "console-tray.png"); + } + + const trayIcon = path.join(__dirname, '../resources/' + trayFilename); + // Create tray icon - tray = new Tray(TRAY_ICON); + tray = new Tray(trayIcon); tray.setToolTip('High Fidelity Server Console'); tray.on('click', function() { From 83120594f56f36dd1e8b01ecf1ada48a62e75927 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 18 Jan 2016 14:12:41 -0800 Subject: [PATCH 264/357] make installer icon lowercase --- cmake/installer/{Installer.ico => installer.ico} | Bin 1 file changed, 0 insertions(+), 0 deletions(-) rename cmake/installer/{Installer.ico => installer.ico} (100%) diff --git a/cmake/installer/Installer.ico b/cmake/installer/installer.ico similarity index 100% rename from cmake/installer/Installer.ico rename to cmake/installer/installer.ico From 95ae7e2ba84c14255c85c9c9dadb28b799de02c6 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 18 Jan 2016 14:18:29 -0800 Subject: [PATCH 265/357] use an ico for console tray on windows --- console/resources/console-tray.ico | Bin 0 -> 5430 bytes console/src/main.js | 5 +++-- 2 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 console/resources/console-tray.ico diff --git a/console/resources/console-tray.ico b/console/resources/console-tray.ico new file mode 100644 index 0000000000000000000000000000000000000000..becc1b8e8b5bc3bd677093a21f348fe077c712a6 GIT binary patch literal 5430 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 literal 0 HcmV?d00001 diff --git a/console/src/main.js b/console/src/main.js index 28fe76a55e..476155b19f 100644 --- a/console/src/main.js +++ b/console/src/main.js @@ -517,9 +517,10 @@ app.on('ready', function() { if (osType == "Darwin") { trayFilename = "console-tray-Template.png"; + } else if (osType == "Windows_NT") { + trayFilename = "console-tray.ico"; } else { - const scaleFactor = require('screen').getPrimaryDisplay().scaleFactor - trayFilename = (scaleFactor > 1 ? "console-tray@2x.png" : "console-tray.png"); + trayFilename = "console-tray.png"; } const trayIcon = path.join(__dirname, '../resources/' + trayFilename); From 2311627599aa417b7379720a50b31b28c474fcc1 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 18 Jan 2016 14:20:33 -0800 Subject: [PATCH 266/357] set installer to be DPI aware --- cmake/templates/NSIS.template.in | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 1eb0b04f57..0ebdafa86e 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -37,6 +37,7 @@ ; Set name prior to inner loop so uninstaller has correct values Name "@CPACK_NSIS_PACKAGE_NAME@" BrandingText " " + ManifestDPIAware true !ifdef INNER !echo "Inner invocation" ; just to see what's going on @@ -679,7 +680,6 @@ FunctionEnd ReserveFile "NSIS.InstallOptions.ini" ReserveFile "@POST_INSTALL_OPTIONS_PATH@" - ReserveFile "${NSISDIR}\Plugins\InstallOptions.dll" ;-------------------------------- ;Installer Sections @@ -990,11 +990,6 @@ FunctionEnd ; determine admin versus local install Function un.onInit - ; manually set this process to DPI aware for fonts on high-dpi screens - ${If} ${AtLeastWinVista} - System::Call 'user32::SetProcessDPIAware()' - ${EndIf} - ; In order for the uninstaller to be able to remove itself, we have to do some trickery here. ; If the $EXEPATH does not contain the $TEMP dir, this instance is not the copied one ; so we move it to the $TEMP dir and then execute the copied uninstaller. @@ -1220,11 +1215,6 @@ SectionEnd Function .onInit - ; manually set this process to DPI aware for fonts on high-dpi screens - ${If} ${AtLeastWinVista} - System::Call 'user32::SetProcessDPIAware()' - ${EndIf} - !ifdef INNER ; If INNER is defined, then we aren't supposed to do anything except write out ; the installer. This is better than processing a command line option as it means From 92388949fd41d7c52392a1a4ab1c0482616b89d6 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 18 Jan 2016 14:28:21 -0800 Subject: [PATCH 267/357] return to png tray icon for win/linux --- console/src/main.js | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/console/src/main.js b/console/src/main.js index 476155b19f..fbb627f13a 100644 --- a/console/src/main.js +++ b/console/src/main.js @@ -504,6 +504,9 @@ function detectExistingStackManagerResources() { return false; } +const trayFilename = (osType == "Darwin" ? "console-tray-Template.png" : "console-tray.png"); +const trayIcon = path.join(__dirname, '../resources/' + TRAY_FILENAME); + // This method will be called when Electron has finished // initialization and is ready to create browser windows. app.on('ready', function() { @@ -513,18 +516,6 @@ app.on('ready', function() { app.dock.hide(); } - var trayFilename = null; - - if (osType == "Darwin") { - trayFilename = "console-tray-Template.png"; - } else if (osType == "Windows_NT") { - trayFilename = "console-tray.ico"; - } else { - trayFilename = "console-tray.png"; - } - - const trayIcon = path.join(__dirname, '../resources/' + trayFilename); - // Create tray icon tray = new Tray(trayIcon); tray.setToolTip('High Fidelity Server Console'); From 0ac7665db84c94bfff717685f653cf583fbd53ed Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 18 Jan 2016 14:35:36 -0800 Subject: [PATCH 268/357] add various root files to console package ignore --- console/packager.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/console/packager.js b/console/packager.js index 341ae0c1a7..bf8ddd68d4 100644 --- a/console/packager.js +++ b/console/packager.js @@ -23,7 +23,7 @@ var options = { arch: "x64", platform: platform, icon: "resources/" + iconName, - ignore: "logs|(S|s)erver(\\s|-)(C|c)onsole-\\S+|electron-packager" + ignore: "logs|(S|s)erver(\\s|-)(C|c)onsole-\\S+|electron-packager|README.md|CMakeLists.txt|packager.js|.gitignore" } const EXEC_NAME = "server-console"; From 59d47501533b17d547d1f8dff84b61f5a048266d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 18 Jan 2016 14:46:34 -0800 Subject: [PATCH 269/357] fix casing of consts in console main --- console/src/main.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/console/src/main.js b/console/src/main.js index fbb627f13a..a15cfb01f4 100644 --- a/console/src/main.js +++ b/console/src/main.js @@ -30,7 +30,7 @@ const ProcessGroupStates = hfprocess.ProcessGroupStates; const osType = os.type(); -const APP_ICON = path.join(__dirname, '../resources/console.png'); +const appIcon = path.join(__dirname, '../resources/console.png'); function getRootHifiDataDirectory() { if (osType == 'Windows_NT') { @@ -238,7 +238,7 @@ LogWindow.prototype = { return; } // Create the browser window. - this.window = new BrowserWindow({ width: 700, height: 500, icon: APP_ICON }); + this.window = new BrowserWindow({ width: 700, height: 500, icon: appIcon }); this.window.loadURL('file://' + __dirname + '/log.html'); if (!debug) { @@ -404,7 +404,7 @@ function maybeInstallDefaultContentSet(onComplete) { // Show popup var window = new BrowserWindow({ - icon: APP_ICON, + icon: appIcon, width: 640, height: 480, center: true, @@ -481,7 +481,7 @@ function maybeShowSplash() { if (!suppressSplash) { var window = new BrowserWindow({ - icon: APP_ICON, + icon: appIcon, width: 1600, height: 737, center: true, @@ -505,7 +505,7 @@ function detectExistingStackManagerResources() { } const trayFilename = (osType == "Darwin" ? "console-tray-Template.png" : "console-tray.png"); -const trayIcon = path.join(__dirname, '../resources/' + TRAY_FILENAME); +const trayIcon = path.join(__dirname, '../resources/' + trayFilename); // This method will be called when Electron has finished // initialization and is ready to create browser windows. From b7998935b0ad8b5aa650a799a83158ad4297a84e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 18 Jan 2016 14:56:06 -0800 Subject: [PATCH 270/357] install a json file with build info beside console --- cmake/macros/SetPackagingParameters.cmake | 8 ++++---- cmake/templates/console-build-info.json.in | 4 ++++ console/CMakeLists.txt | 9 +++++++++ 3 files changed, 17 insertions(+), 4 deletions(-) create mode 100644 cmake/templates/console-build-info.json.in diff --git a/cmake/macros/SetPackagingParameters.cmake b/cmake/macros/SetPackagingParameters.cmake index 5491d6f5d9..4007fb43c0 100644 --- a/cmake/macros/SetPackagingParameters.cmake +++ b/cmake/macros/SetPackagingParameters.cmake @@ -31,15 +31,15 @@ macro(SET_PACKAGING_PARAMETERS) elseif (RELEASE_TYPE STREQUAL "PR") set(DEPLOY_PACKAGE TRUE) set(PR_BUILD 1) - set(BUILD_VERSION "PR${RELEASE_NUMBER}") - set(BUILD_ORGANIZATION "High Fidelity - PR#${RELEASE_NUMBER}") - set(INTERFACE_BUNDLE_NAME "High Fidelity PR#${RELEASE_NUMBER}") + set(BUILD_VERSION "PR#${RELEASE_NUMBER}") + set(BUILD_ORGANIZATION "High Fidelity - ${BUILD_VERSION}") + set(INTERFACE_BUNDLE_NAME "High Fidelity ${BUILD_VERSION}") set(INTERFACE_ICON_PREFIX "interface-beta") set(CONSOLE_ICON "console-beta.ico") else () set(DEV_BUILD 1) set(BUILD_VERSION "dev") - set(BUILD_ORGANIZATION "High Fidelity - Dev") + set(BUILD_ORGANIZATION "High Fidelity - ${BUILD_VERSION}") set(INTERFACE_BUNDLE_NAME "Interface") set(INTERFACE_ICON_PREFIX "interface-beta") set(CONSOLE_ICON "console-beta.ico") diff --git a/cmake/templates/console-build-info.json.in b/cmake/templates/console-build-info.json.in new file mode 100644 index 0000000000..c1ef010e08 --- /dev/null +++ b/cmake/templates/console-build-info.json.in @@ -0,0 +1,4 @@ +{ + "releaseType": "@RELEASE_TYPE@", + "buildIdentifier": "@BUILD_VERSION@" +} diff --git a/console/CMakeLists.txt b/console/CMakeLists.txt index 02ac68d74e..175a3263ab 100644 --- a/console/CMakeLists.txt +++ b/console/CMakeLists.txt @@ -53,4 +53,13 @@ endif() if (PR_BUILD OR PRODUCTION_BUILD) set_target_properties(${TARGET_NAME} PROPERTIES EXCLUDE_FROM_ALL FALSE EXCLUDE_FROM_DEFAULT_BUILD FALSE) + + # configure our build info json file and install it beside the console + set(CONSOLE_BUILD_INFO_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/console-build-info.json") + configure_file("${HF_CMAKE_DIR}/templates/console-build-info.json.in" ${CONSOLE_BUILD_INFO_OUTPUT}) + install( + FILES ${CONSOLE_BUILD_INFO_OUTPUT} + DESTINATION ${CONSOLE_INSTALL_DIR} + COMPONENT ${SERVER_COMPONENT} + ) endif () From 6fac57904bf844e60338f7f1723bcbf64a204434 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 18 Jan 2016 15:10:05 -0800 Subject: [PATCH 271/357] put build-info in .app resources on OS X --- console/CMakeLists.txt | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/console/CMakeLists.txt b/console/CMakeLists.txt index 175a3263ab..0bebf88cd6 100644 --- a/console/CMakeLists.txt +++ b/console/CMakeLists.txt @@ -54,12 +54,18 @@ endif() if (PR_BUILD OR PRODUCTION_BUILD) set_target_properties(${TARGET_NAME} PROPERTIES EXCLUDE_FROM_ALL FALSE EXCLUDE_FROM_DEFAULT_BUILD FALSE) + if (APPLE) + set(BESIDE_CONSOLE_DIR "${CONSOLE_INSTALL_APP_PATH}/Contents/Resources") + else () + set(BESIDE_CONSOLE_DIR ${CONSOLE_INSTALL_DIR}) + endif () + # configure our build info json file and install it beside the console - set(CONSOLE_BUILD_INFO_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/console-build-info.json") + set(CONSOLE_BUILD_INFO_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/build-info.json") configure_file("${HF_CMAKE_DIR}/templates/console-build-info.json.in" ${CONSOLE_BUILD_INFO_OUTPUT}) install( FILES ${CONSOLE_BUILD_INFO_OUTPUT} - DESTINATION ${CONSOLE_INSTALL_DIR} + DESTINATION ${BESIDE_CONSOLE_DIR} COMPONENT ${SERVER_COMPONENT} ) endif () From a83c3a3385bf055b90aa60917a582228119d3242 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 18 Jan 2016 15:23:51 -0800 Subject: [PATCH 272/357] write to registry when sections not selected --- cmake/templates/NSIS.template.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 0ebdafa86e..f13862e5cc 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -155,8 +155,8 @@ Var AR_RegFlags ; We do not do that here because it would absolutely cause issues with shared dependencies ;!insertmacro "Remove_${${SecName}}" - ;WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\Components\${SecName}" \ - ; "Installed" 0 + WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\Components\${SecName}" \ + "Installed" 0 Goto "exit_${SecName}" From 4fb5a142f73217c49ca4d58c7bdb3281aa472323 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 18 Jan 2016 15:50:44 -0800 Subject: [PATCH 273/357] check during uninstall for running applications --- cmake/macros/SetPackagingParameters.cmake | 3 +++ cmake/templates/CPackProperties.cmake.in | 2 ++ cmake/templates/NSIS.template.in | 29 ++++++++++++++++++++++- 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/cmake/macros/SetPackagingParameters.cmake b/cmake/macros/SetPackagingParameters.cmake index 4007fb43c0..279cf095f4 100644 --- a/cmake/macros/SetPackagingParameters.cmake +++ b/cmake/macros/SetPackagingParameters.cmake @@ -54,6 +54,9 @@ macro(SET_PACKAGING_PARAMETERS) set(CONSOLE_EXEC_NAME "server-console.exe") + set(DS_EXEC_NAME "domain-server.exe") + set(AC_EXEC_NAME "assignment-client.exe") + # start menu shortcuts set(INTERFACE_SM_SHORTCUT_NAME "High Fidelity") set(CONSOLE_SM_SHORTCUT_NAME "Server Console") diff --git a/cmake/templates/CPackProperties.cmake.in b/cmake/templates/CPackProperties.cmake.in index bf1a4ec033..eb78e5880b 100644 --- a/cmake/templates/CPackProperties.cmake.in +++ b/cmake/templates/CPackProperties.cmake.in @@ -13,6 +13,8 @@ set(INTERFACE_SHORTCUT_NAME "@INTERFACE_SM_SHORTCUT_NAME@") set(INTERFACE_WIN_EXEC_NAME "@INTERFACE_EXEC_PREFIX@.exe") set(CONSOLE_SHORTCUT_NAME "@CONSOLE_SM_SHORTCUT_NAME@") set(CONSOLE_WIN_EXEC_NAME "@CONSOLE_EXEC_NAME@") +set(DS_EXEC_NAME "@DS_EXEC_NAME@") +set(AC_EXEC_NAME "@AC_EXEC_NAME@") set(HIGH_FIDELITY_PROTOCOL "@HIGH_FIDELITY_PROTOCOL@") set(PRODUCTION_BUILD "@PRODUCTION_BUILD@") set(POST_INSTALL_OPTIONS_PATH "@POST_INSTALL_OPTIONS_PATH@") diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index f13862e5cc..b85d5010af 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -984,7 +984,31 @@ Function HandlePostInstallOptions FunctionEnd -!include WinVer.nsh +!define FindProc_NOT_FOUND 1 +!define FindProc_FOUND 0 +!macro FindProc result processName + ExecCmd::exec "%SystemRoot%\System32\tasklist /NH /FI $\"IMAGENAME eq ${processName}$\" | %SystemRoot%\System32\find /I $\"${processName}$\"" + Pop $0 ; The handle for the process + ExecCmd::wait $0 + Pop ${result} ; The exit code +!macroend + +Var processFound + +!macro PromptForRunningApplication applicationName displayName + !insertmacro FindProc $processFound ${applicationName} + + ${If} $processFound == FindProc_FOUND + MessageBox MB_OK|MB_ICONEXCLAMATION "The High Fidelity ${displayName} is running. Please close it first." /SD IDOK + ${EndIf} +!macroend + +!macro CheckForRunningApplications + !insertmacro PromptForRunningApplication "@INTERFACE_WIN_EXEC_NAME@" "Client" + !insertmacro PromptForRunningApplication "@CONSOLE_WIN_EXEC_NAME@" "Server Console" + !insertmacro PromptForRunningApplication "@DS_EXEC_NAME@" "domain-server" + !insertmacro PromptForRunningApplication "@AC_EXEC_NAME@" "assignment-client" +!macroend ;-------------------------------- ; determine admin versus local install @@ -1001,6 +1025,9 @@ Function un.onInit Quit ${EndIf} + ; make sure none of the installed applications are still running + !insertmacro CheckForRunningApplications + ; attempt to elevate the uninstaller to admin status uac_tryagain: !insertmacro UAC_RunElevated From c924be57fc2e82c1adb5ab6f2bec7e9f82a6479b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 18 Jan 2016 15:54:50 -0800 Subject: [PATCH 274/357] use FindProcDLL plug-in to check if running --- cmake/templates/NSIS.template.in | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index b85d5010af..d65175edd9 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -984,23 +984,14 @@ Function HandlePostInstallOptions FunctionEnd -!define FindProc_NOT_FOUND 1 -!define FindProc_FOUND 0 -!macro FindProc result processName - ExecCmd::exec "%SystemRoot%\System32\tasklist /NH /FI $\"IMAGENAME eq ${processName}$\" | %SystemRoot%\System32\find /I $\"${processName}$\"" - Pop $0 ; The handle for the process - ExecCmd::wait $0 - Pop ${result} ; The exit code -!macroend - -Var processFound !macro PromptForRunningApplication applicationName displayName - !insertmacro FindProc $processFound ${applicationName} + FindProcDLL::FindProc ${applicationName} - ${If} $processFound == FindProc_FOUND + IntCmp $R0 1 0 notRunning MessageBox MB_OK|MB_ICONEXCLAMATION "The High Fidelity ${displayName} is running. Please close it first." /SD IDOK - ${EndIf} + Abort + notRunning: !macroend !macro CheckForRunningApplications From 8e9b7bc37bcde3dd05723c3f8a61b47a5b56e2c8 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 18 Jan 2016 15:56:44 -0800 Subject: [PATCH 275/357] use variable for console display name --- cmake/templates/NSIS.template.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index d65175edd9..2d7d8c6abf 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -996,7 +996,7 @@ FunctionEnd !macro CheckForRunningApplications !insertmacro PromptForRunningApplication "@INTERFACE_WIN_EXEC_NAME@" "Client" - !insertmacro PromptForRunningApplication "@CONSOLE_WIN_EXEC_NAME@" "Server Console" + !insertmacro PromptForRunningApplication "@CONSOLE_WIN_EXEC_NAME@" "@CONSOLE_SHORTCUT_NAME@" !insertmacro PromptForRunningApplication "@DS_EXEC_NAME@" "domain-server" !insertmacro PromptForRunningApplication "@AC_EXEC_NAME@" "assignment-client" !macroend From e2ee3da9d144f648b80197ddc817152f151b5b3f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 18 Jan 2016 16:00:37 -0800 Subject: [PATCH 276/357] fix comparison for FindProc call --- cmake/templates/NSIS.template.in | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 2d7d8c6abf..2a5618ce8a 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -988,17 +988,17 @@ FunctionEnd !macro PromptForRunningApplication applicationName displayName FindProcDLL::FindProc ${applicationName} - IntCmp $R0 1 0 notRunning + ${If} $R0 == 1 MessageBox MB_OK|MB_ICONEXCLAMATION "The High Fidelity ${displayName} is running. Please close it first." /SD IDOK Abort - notRunning: + ${EndIf} !macroend !macro CheckForRunningApplications - !insertmacro PromptForRunningApplication "@INTERFACE_WIN_EXEC_NAME@" "Client" - !insertmacro PromptForRunningApplication "@CONSOLE_WIN_EXEC_NAME@" "@CONSOLE_SHORTCUT_NAME@" - !insertmacro PromptForRunningApplication "@DS_EXEC_NAME@" "domain-server" - !insertmacro PromptForRunningApplication "@AC_EXEC_NAME@" "assignment-client" + !insertmacro PromptForRunningApplication "$INSTDIR\@INTERFACE_WIN_EXEC_NAME@" "Client" + !insertmacro PromptForRunningApplication "$INSTDIR\@CONSOLE_WIN_EXEC_NAME@" "@CONSOLE_SHORTCUT_NAME@" + !insertmacro PromptForRunningApplication "$INSTDIR\@DS_EXEC_NAME@" "domain-server" + !insertmacro PromptForRunningApplication "$INSTDIR\@AC_EXEC_NAME@" "assignment-client" !macroend ;-------------------------------- From 96c3adaa197a6ffba644b46fef5ba072e553ea94 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 18 Jan 2016 16:15:31 -0800 Subject: [PATCH 277/357] use nsProcess to check if process is running --- cmake/templates/NSIS.template.in | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 2a5618ce8a..c7d2f05fb5 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -984,21 +984,22 @@ Function HandlePostInstallOptions FunctionEnd +!include nsProcess.nsh !macro PromptForRunningApplication applicationName displayName - FindProcDLL::FindProc ${applicationName} + ${nsProcess::FindProcess} ${applicationName} $R0 - ${If} $R0 == 1 + ${If} $R0 == 0 MessageBox MB_OK|MB_ICONEXCLAMATION "The High Fidelity ${displayName} is running. Please close it first." /SD IDOK Abort ${EndIf} !macroend !macro CheckForRunningApplications - !insertmacro PromptForRunningApplication "$INSTDIR\@INTERFACE_WIN_EXEC_NAME@" "Client" - !insertmacro PromptForRunningApplication "$INSTDIR\@CONSOLE_WIN_EXEC_NAME@" "@CONSOLE_SHORTCUT_NAME@" - !insertmacro PromptForRunningApplication "$INSTDIR\@DS_EXEC_NAME@" "domain-server" - !insertmacro PromptForRunningApplication "$INSTDIR\@AC_EXEC_NAME@" "assignment-client" + !insertmacro PromptForRunningApplication "@INTERFACE_WIN_EXEC_NAME@" "Client" + !insertmacro PromptForRunningApplication "@CONSOLE_WIN_EXEC_NAME@" "@CONSOLE_SHORTCUT_NAME@" + !insertmacro PromptForRunningApplication "@DS_EXEC_NAME@" "domain-server" + !insertmacro PromptForRunningApplication "@AC_EXEC_NAME@" "assignment-client" !macroend ;-------------------------------- From 7d8fc6f702cb0936e85c63e8e7c6a3f010f00e73 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 18 Jan 2016 16:26:53 -0800 Subject: [PATCH 278/357] check for running apps during install --- cmake/templates/NSIS.template.in | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index c7d2f05fb5..efae56339b 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -1245,6 +1245,9 @@ Function .onInit Quit !endif + ; make sure none of the installed applications are still running + !insertmacro CheckForRunningApplications + StrCmp "@CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL@" "ON" 0 inst ReadRegStr $0 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "UninstallString" From 9b20d07886282cd951f1178c893382783c518c24 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 18 Jan 2016 16:54:09 -0800 Subject: [PATCH 279/357] prompt for closure of running applications --- cmake/templates/NSIS.template.in | 41 ++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index efae56339b..e13f107619 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -986,20 +986,39 @@ FunctionEnd !include nsProcess.nsh -!macro PromptForRunningApplication applicationName displayName +!macro PromptForRunningApplication applicationName displayName action prompter ${nsProcess::FindProcess} ${applicationName} $R0 ${If} $R0 == 0 - MessageBox MB_OK|MB_ICONEXCLAMATION "The High Fidelity ${displayName} is running. Please close it first." /SD IDOK - Abort + !define UniqueID ${__LINE__} + + ; the process is running, ask the user if they want us to close it + MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION "${displayName} cannot be ${action} while ${displayName} is running. Would you like the ${prompter} to try closing it?" + IDOK AttemptClose_${UniqueID} IDCANCEL Abort_${UniqueID} /SD IDCANCEL + + AttemptClose_${UniqueID}: + ; attempt to close the given process + ${nsProcess::CloseProcess} ${applicationName} $R0 + + ; check if the process was closed + ${If} $R0 == 0 + ; closed the running application + Goto Next_${UniqueID} + ${Else} + ; couldn't close the running application, bail + Abort + ${EndIf} + Abort_${UniqueID}: + Abort + Next_${UniqueID}: ${EndIf} !macroend -!macro CheckForRunningApplications - !insertmacro PromptForRunningApplication "@INTERFACE_WIN_EXEC_NAME@" "Client" - !insertmacro PromptForRunningApplication "@CONSOLE_WIN_EXEC_NAME@" "@CONSOLE_SHORTCUT_NAME@" - !insertmacro PromptForRunningApplication "@DS_EXEC_NAME@" "domain-server" - !insertmacro PromptForRunningApplication "@AC_EXEC_NAME@" "assignment-client" +!macro CheckForRunningApplications action prompter + !insertmacro PromptForRunningApplication "@INTERFACE_WIN_EXEC_NAME@" "@INTERFACE_SHORTCUT_NAME@" ${action} ${prompter} + !insertmacro PromptForRunningApplication "@CONSOLE_WIN_EXEC_NAME@" "@CONSOLE_SHORTCUT_NAME@" ${action} ${prompter} + !insertmacro PromptForRunningApplication "@DS_EXEC_NAME@" "Domain Server" ${action} ${prompter} + !insertmacro PromptForRunningApplication "@AC_EXEC_NAME@" "Assignment Client" ${action} ${prompter} !macroend ;-------------------------------- @@ -1018,7 +1037,8 @@ Function un.onInit ${EndIf} ; make sure none of the installed applications are still running - !insertmacro CheckForRunningApplications + !insertmacro CheckForRunningApplications "uninstalled" "Uninstaller" + ${nsProcess:Unload} ; attempt to elevate the uninstaller to admin status uac_tryagain: @@ -1246,7 +1266,8 @@ Function .onInit !endif ; make sure none of the installed applications are still running - !insertmacro CheckForRunningApplications + !insertmacro CheckForRunningApplications "installed" "Installer" + ${nsProcess:Unload} StrCmp "@CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL@" "ON" 0 inst From 51c476f5217839d9afd5effcf80ff91b3830d066 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 18 Jan 2016 16:59:28 -0800 Subject: [PATCH 280/357] make message box for closing app multiline --- cmake/templates/NSIS.template.in | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index e13f107619..e347cd856e 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -993,7 +993,8 @@ FunctionEnd !define UniqueID ${__LINE__} ; the process is running, ask the user if they want us to close it - MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION "${displayName} cannot be ${action} while ${displayName} is running. Would you like the ${prompter} to try closing it?" + MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION \ + "${displayName} cannot be ${action} while ${displayName} is running. Would you like the ${prompter} to try closing it?" \ IDOK AttemptClose_${UniqueID} IDCANCEL Abort_${UniqueID} /SD IDCANCEL AttemptClose_${UniqueID}: From 84c2387c02779193f2689955149a837887150779 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 18 Jan 2016 17:03:46 -0800 Subject: [PATCH 281/357] repairs for usage of MessageBox --- cmake/templates/NSIS.template.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index e347cd856e..3679e3b73a 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -994,8 +994,8 @@ FunctionEnd ; the process is running, ask the user if they want us to close it MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION \ - "${displayName} cannot be ${action} while ${displayName} is running. Would you like the ${prompter} to try closing it?" \ - IDOK AttemptClose_${UniqueID} IDCANCEL Abort_${UniqueID} /SD IDCANCEL + "${displayName} cannot be ${action} while ${displayName} is running.$\r$\nWould you like the ${prompter} to try closing it?" \ + /SD IDCANCEL IDOK AttemptClose_${UniqueID} IDCANCEL Abort_${UniqueID} AttemptClose_${UniqueID}: ; attempt to close the given process From 31805be6aff2b4337474b381ef36a89f81e805b6 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 18 Jan 2016 17:06:31 -0800 Subject: [PATCH 282/357] undefine the UniqueID label helper in macro --- cmake/templates/NSIS.template.in | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 3679e3b73a..ae71c16860 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -1012,6 +1012,7 @@ FunctionEnd Abort_${UniqueID}: Abort Next_${UniqueID}: + !undef UniqueID ${EndIf} !macroend From 03f2b5ec642ae844569a9aa56b4052cdf51bca04 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 18 Jan 2016 17:09:29 -0800 Subject: [PATCH 283/357] repair nsProcess unload macro call for uninstaller --- cmake/templates/NSIS.template.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index ae71c16860..54b628683b 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -1040,7 +1040,7 @@ Function un.onInit ; make sure none of the installed applications are still running !insertmacro CheckForRunningApplications "uninstalled" "Uninstaller" - ${nsProcess:Unload} + ${nsProcess::Unload} ; attempt to elevate the uninstaller to admin status uac_tryagain: @@ -1269,7 +1269,7 @@ Function .onInit ; make sure none of the installed applications are still running !insertmacro CheckForRunningApplications "installed" "Installer" - ${nsProcess:Unload} + ${nsProcess::Unload} StrCmp "@CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL@" "ON" 0 inst From 21a0d7cd4b38c53fa99040abc62a4360f2dfc258 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 18 Jan 2016 17:58:15 -0800 Subject: [PATCH 284/357] add checkbox to post install options for PR copy --- cmake/templates/NSIS.template.in | 82 ++++++++++++++++---------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 54b628683b..f72a7953b6 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -821,13 +821,14 @@ FunctionEnd ; Make sure nsDialogs is included before we use it !include "nsdialogs.nsh" -Var POST_INSTALL_DIALOG -Var OPTIONS_LABEL -Var DESKTOP_CLIENT_CHECKBOX -Var DESKTOP_SERVER_CHECKBOX -Var SERVER_STARTUP_CHECKBOX -Var LAUNCH_NOW_CHECKBOX -Var CURRENT_OFFSET +Var PostInstallDialog +Var OptionsLabel +Var DesktopClientCheckbox +Var DesktopServerCheckbox +Var ServerStartupCheckbox +Var LaunchNowCheckbox +Var CurrentOffset +Var CopyForPRCheckbox !macro SetPostInstallOption Checkbox OptionName Default ; reads the value for the given post install option to the registry @@ -854,66 +855,65 @@ Function PostInstallOptionsPage ShowWindow $R3 0 nsDialogs::Create 1018 - Pop $POST_INSTALL_DIALOG + Pop $PostInstallDialog - ${If} $POST_INSTALL_DIALOG == error + ${If} $PostInstallDialog == error Abort ${EndIf} ${NSD_CreateLabel} 0 0 100% 12u "Setup Options" - Pop $OPTIONS_LABEL + Pop $OptionsLabel ; Set label to bold CreateFont $R2 "Arial" 10 700 - SendMessage $OPTIONS_LABEL ${WM_SETFONT} $R2 0 + SendMessage $OptionsLabel ${WM_SETFONT} $R2 0 ; Force label redraw - ShowWindow $OPTIONS_LABEL ${SW_HIDE} - ShowWindow $OPTIONS_LABEL ${SW_SHOW} + ShowWindow $OptionsLabel ${SW_HIDE} + ShowWindow $OptionsLabel ${SW_SHOW} - StrCpy $CURRENT_OFFSET "15u" + StrCpy $CurrentOffset 15 ${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@} - ${NSD_CreateCheckbox} 0 15u 100% 10u "&Create a desktop shortcut for @INTERFACE_SHORTCUT_NAME@" - Pop $DESKTOP_CLIENT_CHECKBOX - StrCpy $CURRENT_OFFSET "30u" + ${NSD_CreateCheckbox} 0 $CurrentOffset 100% 10u "&Create a desktop shortcut for @INTERFACE_SHORTCUT_NAME@" + Pop $DesktopClientCheckbox + IntOp $CurrentOffset $CurrentOffset + 15 ; set the checkbox state depending on what is present in the registry - !insertmacro SetPostInstallOption $DESKTOP_CLIENT_CHECKBOX @CLIENT_DESKTOP_SHORTCUT_REG_KEY@ ${BST_CHECKED} + !insertmacro SetPostInstallOption $DesktopClientCheckbox @CLIENT_DESKTOP_SHORTCUT_REG_KEY@ ${BST_CHECKED} ${EndIf} ${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@} - ${NSD_CreateCheckbox} 0 $CURRENT_OFFSET 100% 10u "&Create a desktop shortcut for High Fidelity @CONSOLE_SHORTCUT_NAME@" - Pop $DESKTOP_SERVER_CHECKBOX + ${NSD_CreateCheckbox} 0 $CurrentOffset 100% 10u "&Create a desktop shortcut for High Fidelity @CONSOLE_SHORTCUT_NAME@" + Pop $DesktopServerCheckbox ; set the checkbox state depending on what is present in the registry - !insertmacro SetPostInstallOption $DESKTOP_SERVER_CHECKBOX @CONSOLE_DESKTOP_SHORTCUT_REG_KEY@ ${BST_UNCHECKED} + !insertmacro SetPostInstallOption $DesktopServerCheckbox @CONSOLE_DESKTOP_SHORTCUT_REG_KEY@ ${BST_UNCHECKED} - ${If} $CURRENT_OFFSET == "15u" - StrCpy $CURRENT_OFFSET "30u" - ${Else} - StrCpy $CURRENT_OFFSET "45u" - ${EndIf} + IntOp $CurrentOffset $CurrentOffset + 15 - ${NSD_CreateCheckbox} 0 $CURRENT_OFFSET 100% 10u "&Launch High Fidelity @CONSOLE_SHORTCUT_NAME@ on startup" - Pop $SERVER_STARTUP_CHECKBOX + ${NSD_CreateCheckbox} 0 $CurrentOffset 100% 10u "&Launch High Fidelity @CONSOLE_SHORTCUT_NAME@ on startup" + Pop $ServerStartupCheckbox ; set the checkbox state depending on what is present in the registry - !insertmacro SetPostInstallOption $SERVER_STARTUP_CHECKBOX @CONSOLE_STARTUP_REG_KEY@ ${BST_CHECKED} + !insertmacro SetPostInstallOption $ServerStartupCheckbox @CONSOLE_STARTUP_REG_KEY@ ${BST_CHECKED} - ${If} $CURRENT_OFFSET == "30u" - StrCpy $CURRENT_OFFSET "45u" - ${Else} - StrCpy $CURRENT_OFFSET "60u" - ${EndIf} + IntOp $CurrentOffset $CurrentOffset + 15 ${EndIf} - ${NSD_CreateCheckbox} 0 $CURRENT_OFFSET 100% 10u "&Launch High Fidelity Now" - Pop $LAUNCH_NOW_CHECKBOX + ${NSD_CreateCheckbox} 0 $CurrentOffset 100% 10u "&Launch High Fidelity Now" + Pop $LaunchNowCheckbox ; set the checkbox state depending on what is present in the registry - !insertmacro SetPostInstallOption $LAUNCH_NOW_CHECKBOX @LAUNCH_NOW_REG_KEY@ ${BST_CHECKED} + !insertmacro SetPostInstallOption $LaunchNowCheckbox @LAUNCH_NOW_REG_KEY@ ${BST_CHECKED} + + ${If} @PR_BUILD@ == 1 + ; push the offset + IntOp $CurrentOffset $CurrentOffset + 15 + + ${NSD_CreateCheckbox} 0 $CurrentOffset 100% 10u "&Copy data from production install" + ${EndIf} nsDialogs::Show FunctionEnd @@ -931,7 +931,7 @@ VAR LAUNCH_NOW_STATE Function HandlePostInstallOptions ${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@} ; check if the user asked for a desktop shortcut to High Fidelity - ${NSD_GetState} $DESKTOP_CLIENT_CHECKBOX $DESKTOP_CLIENT_STATE + ${NSD_GetState} $DesktopClientCheckbox $DESKTOP_CLIENT_STATE ${If} $DESKTOP_CLIENT_STATE == ${BST_CHECKED} CreateShortCut "$DESKTOP\@INTERFACE_SHORTCUT_NAME@.lnk" "$INSTDIR\@INTERFACE_WIN_EXEC_NAME@" @@ -944,7 +944,7 @@ Function HandlePostInstallOptions ${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@} ; check if the user asked for a desktop shortcut to Server Console - ${NSD_GetState} $DESKTOP_SERVER_CHECKBOX $DESKTOP_SERVER_STATE + ${NSD_GetState} $DesktopServerCheckbox $DESKTOP_SERVER_STATE ${If} $DESKTOP_SERVER_STATE == ${BST_CHECKED} CreateShortCut "$DESKTOP\@CONSOLE_SHORTCUT_NAME@.lnk" "$INSTDIR\@CONSOLE_WIN_EXEC_NAME@" @@ -954,7 +954,7 @@ Function HandlePostInstallOptions ${EndIf} ; check if the user asked to have Server Console launched every startup - ${NSD_GetState} $SERVER_STARTUP_CHECKBOX $SERVER_STARTUP_STATE + ${NSD_GetState} $ServerStartupCheckbox $SERVER_STARTUP_STATE ${If} $SERVER_STARTUP_STATE == ${BST_CHECKED} CreateShortCut "$SMSTARTUP\@CONSOLE_SHORTCUT_NAME@.lnk" "$INSTDIR\@CONSOLE_WIN_EXEC_NAME@" @@ -966,7 +966,7 @@ Function HandlePostInstallOptions ${EndIf} ; check if we need to launch an application post-install - ${NSD_GetState} $LAUNCH_NOW_CHECKBOX $LAUNCH_NOW_STATE + ${NSD_GetState} $LaunchNowCheckbox $LAUNCH_NOW_STATE ${If} $LAUNCH_NOW_STATE == ${BST_CHECKED} !insertmacro WritePostInstallOption @LAUNCH_NOW_REG_KEY@ YES From 7c3d8be80f50193dcf465c3dd1924301e46b85f9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 18 Jan 2016 17:59:14 -0800 Subject: [PATCH 285/357] change wording to pr post install option --- cmake/templates/NSIS.template.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index f72a7953b6..139e5a60f9 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -912,7 +912,7 @@ Function PostInstallOptionsPage ; push the offset IntOp $CurrentOffset $CurrentOffset + 15 - ${NSD_CreateCheckbox} 0 $CurrentOffset 100% 10u "&Copy data from production install" + ${NSD_CreateCheckbox} 0 $CurrentOffset 100% 10u "&Copy settings and content from production install" ${EndIf} nsDialogs::Show From fb5d26b282611f5f44126b96c366b49f0857c648 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 18 Jan 2016 18:02:27 -0800 Subject: [PATCH 286/357] add PR_BUILD to shared CPack properties --- cmake/templates/CPackProperties.cmake.in | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/templates/CPackProperties.cmake.in b/cmake/templates/CPackProperties.cmake.in index eb78e5880b..f02ffb0b50 100644 --- a/cmake/templates/CPackProperties.cmake.in +++ b/cmake/templates/CPackProperties.cmake.in @@ -17,6 +17,7 @@ set(DS_EXEC_NAME "@DS_EXEC_NAME@") set(AC_EXEC_NAME "@AC_EXEC_NAME@") set(HIGH_FIDELITY_PROTOCOL "@HIGH_FIDELITY_PROTOCOL@") set(PRODUCTION_BUILD "@PRODUCTION_BUILD@") +set(PR_BUILD "@PR_BUILD@") set(POST_INSTALL_OPTIONS_PATH "@POST_INSTALL_OPTIONS_PATH@") set(CLIENT_COMPONENT_NAME "@CLIENT_COMPONENT@") set(SERVER_COMPONENT_NAME "@SERVER_COMPONENT@") From 5e6910edbbd7a4e4e27b9e1f3c85087481af74cd Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 18 Jan 2016 18:14:48 -0800 Subject: [PATCH 287/357] complete copy of production settings to PR --- cmake/templates/CPackProperties.cmake.in | 1 + cmake/templates/NSIS.template.in | 53 +++++++++++++++--------- 2 files changed, 35 insertions(+), 19 deletions(-) diff --git a/cmake/templates/CPackProperties.cmake.in b/cmake/templates/CPackProperties.cmake.in index f02ffb0b50..34c3797209 100644 --- a/cmake/templates/CPackProperties.cmake.in +++ b/cmake/templates/CPackProperties.cmake.in @@ -18,6 +18,7 @@ set(AC_EXEC_NAME "@AC_EXEC_NAME@") set(HIGH_FIDELITY_PROTOCOL "@HIGH_FIDELITY_PROTOCOL@") set(PRODUCTION_BUILD "@PRODUCTION_BUILD@") set(PR_BUILD "@PR_BUILD@") +set(MODIFIED_ORGANIZATION "@MODIFIED_ORGANIZATION@") set(POST_INSTALL_OPTIONS_PATH "@POST_INSTALL_OPTIONS_PATH@") set(CLIENT_COMPONENT_NAME "@CLIENT_COMPONENT@") set(SERVER_COMPONENT_NAME "@SERVER_COMPONENT@") diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 139e5a60f9..40def20300 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -828,7 +828,8 @@ Var DesktopServerCheckbox Var ServerStartupCheckbox Var LaunchNowCheckbox Var CurrentOffset -Var CopyForPRCheckbox +Var OffsetUnits +Var CopyFromProductionCheckbox !macro SetPostInstallOption Checkbox OptionName Default ; reads the value for the given post install option to the registry @@ -873,9 +874,10 @@ Function PostInstallOptionsPage ShowWindow $OptionsLabel ${SW_SHOW} StrCpy $CurrentOffset 15 + StrCpy $OffsetUnits u ${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@} - ${NSD_CreateCheckbox} 0 $CurrentOffset 100% 10u "&Create a desktop shortcut for @INTERFACE_SHORTCUT_NAME@" + ${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Create a desktop shortcut for @INTERFACE_SHORTCUT_NAME@" Pop $DesktopClientCheckbox IntOp $CurrentOffset $CurrentOffset + 15 @@ -885,7 +887,7 @@ Function PostInstallOptionsPage ${EndIf} ${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@} - ${NSD_CreateCheckbox} 0 $CurrentOffset 100% 10u "&Create a desktop shortcut for High Fidelity @CONSOLE_SHORTCUT_NAME@" + ${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Create a desktop shortcut for High Fidelity @CONSOLE_SHORTCUT_NAME@" Pop $DesktopServerCheckbox ; set the checkbox state depending on what is present in the registry @@ -893,7 +895,7 @@ Function PostInstallOptionsPage IntOp $CurrentOffset $CurrentOffset + 15 - ${NSD_CreateCheckbox} 0 $CurrentOffset 100% 10u "&Launch High Fidelity @CONSOLE_SHORTCUT_NAME@ on startup" + ${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Launch High Fidelity @CONSOLE_SHORTCUT_NAME@ on startup" Pop $ServerStartupCheckbox ; set the checkbox state depending on what is present in the registry @@ -902,7 +904,7 @@ Function PostInstallOptionsPage IntOp $CurrentOffset $CurrentOffset + 15 ${EndIf} - ${NSD_CreateCheckbox} 0 $CurrentOffset 100% 10u "&Launch High Fidelity Now" + ${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Launch High Fidelity Now" Pop $LaunchNowCheckbox ; set the checkbox state depending on what is present in the registry @@ -912,7 +914,8 @@ Function PostInstallOptionsPage ; push the offset IntOp $CurrentOffset $CurrentOffset + 15 - ${NSD_CreateCheckbox} 0 $CurrentOffset 100% 10u "&Copy settings and content from production install" + ${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Copy settings and content from production install" + Pop $CopyFromProductionCheckbox ${EndIf} nsDialogs::Show @@ -923,17 +926,18 @@ FunctionEnd WriteRegStr HKLM "@REGISTRY_HKLM_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\@POST_INSTALL_OPTIONS_REG_GROUP@" "${OptionName}" ${Option} !macroend -Var DESKTOP_CLIENT_STATE -Var DESKTOP_SERVER_STATE -Var SERVER_STARTUP_STATE -VAR LAUNCH_NOW_STATE +Var DesktopClientState +Var DesktopServerState +Var ServerStartupState +Var LaunchNowState +Var CopyFromProductionState Function HandlePostInstallOptions ${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@} ; check if the user asked for a desktop shortcut to High Fidelity - ${NSD_GetState} $DesktopClientCheckbox $DESKTOP_CLIENT_STATE + ${NSD_GetState} $DesktopClientCheckbox $DesktopClientState - ${If} $DESKTOP_CLIENT_STATE == ${BST_CHECKED} + ${If} $DesktopClientState == ${BST_CHECKED} CreateShortCut "$DESKTOP\@INTERFACE_SHORTCUT_NAME@.lnk" "$INSTDIR\@INTERFACE_WIN_EXEC_NAME@" !insertmacro WritePostInstallOption "@CLIENT_DESKTOP_SHORTCUT_REG_KEY@" YES ${Else} @@ -944,9 +948,9 @@ Function HandlePostInstallOptions ${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@} ; check if the user asked for a desktop shortcut to Server Console - ${NSD_GetState} $DesktopServerCheckbox $DESKTOP_SERVER_STATE + ${NSD_GetState} $DesktopServerCheckbox $DesktopServerState - ${If} $DESKTOP_SERVER_STATE == ${BST_CHECKED} + ${If} $DesktopServerState == ${BST_CHECKED} CreateShortCut "$DESKTOP\@CONSOLE_SHORTCUT_NAME@.lnk" "$INSTDIR\@CONSOLE_WIN_EXEC_NAME@" !insertmacro WritePostInstallOption @CONSOLE_DESKTOP_SHORTCUT_REG_KEY@ YES ${Else} @@ -954,9 +958,9 @@ Function HandlePostInstallOptions ${EndIf} ; check if the user asked to have Server Console launched every startup - ${NSD_GetState} $ServerStartupCheckbox $SERVER_STARTUP_STATE + ${NSD_GetState} $ServerStartupCheckbox $ServerStartupState - ${If} $SERVER_STARTUP_STATE == ${BST_CHECKED} + ${If} $ServerStartupState == ${BST_CHECKED} CreateShortCut "$SMSTARTUP\@CONSOLE_SHORTCUT_NAME@.lnk" "$INSTDIR\@CONSOLE_WIN_EXEC_NAME@" !insertmacro WritePostInstallOption @CONSOLE_STARTUP_REG_KEY@ YES @@ -965,10 +969,21 @@ Function HandlePostInstallOptions ${EndIf} ${EndIf} - ; check if we need to launch an application post-install - ${NSD_GetState} $LaunchNowCheckbox $LAUNCH_NOW_STATE + ${If} @PRODUCTION_BUILD@ == 1 + ; check if we need to copy settings/content from production for this PR build + ${NSD_GetState} $CopyFromProductionCheckbox $CopyFromProductionState - ${If} $LAUNCH_NOW_STATE == ${BST_CHECKED} + ${If} $CopyFromProductionState == ${BST_CHECKED} + ; we need to copy whatever is in the data folder for production build to the data folder for this build + CreateDirectory "$APPDATA\@MODIFIED_ORGANIZATION@" + CopyFiles "$APPDATA\High Fidelity\" "$APPDATA\@MODIFIED_ORGANIZATION@\" + ${EndIf} + ${EndIf} + + ; check if we need to launch an application post-install + ${NSD_GetState} $LaunchNowCheckbox $LaunchNowState + + ${If} $LaunchNowState == ${BST_CHECKED} !insertmacro WritePostInstallOption @LAUNCH_NOW_REG_KEY@ YES ; both launches use the explorer trick in case the user has elevated permissions for the installer From 2094a752941d2b595e0dd21449161987d5bb99b5 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 18 Jan 2016 18:18:06 -0800 Subject: [PATCH 288/357] use correct var from packaging properties for copy --- cmake/templates/CPackProperties.cmake.in | 2 +- cmake/templates/NSIS.template.in | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmake/templates/CPackProperties.cmake.in b/cmake/templates/CPackProperties.cmake.in index 34c3797209..7b3d0ae53e 100644 --- a/cmake/templates/CPackProperties.cmake.in +++ b/cmake/templates/CPackProperties.cmake.in @@ -18,7 +18,7 @@ set(AC_EXEC_NAME "@AC_EXEC_NAME@") set(HIGH_FIDELITY_PROTOCOL "@HIGH_FIDELITY_PROTOCOL@") set(PRODUCTION_BUILD "@PRODUCTION_BUILD@") set(PR_BUILD "@PR_BUILD@") -set(MODIFIED_ORGANIZATION "@MODIFIED_ORGANIZATION@") +set(BUILD_ORGANIZATION "@BUILD_ORGANIZATION@") set(POST_INSTALL_OPTIONS_PATH "@POST_INSTALL_OPTIONS_PATH@") set(CLIENT_COMPONENT_NAME "@CLIENT_COMPONENT@") set(SERVER_COMPONENT_NAME "@SERVER_COMPONENT@") diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 40def20300..097d8c7623 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -975,8 +975,8 @@ Function HandlePostInstallOptions ${If} $CopyFromProductionState == ${BST_CHECKED} ; we need to copy whatever is in the data folder for production build to the data folder for this build - CreateDirectory "$APPDATA\@MODIFIED_ORGANIZATION@" - CopyFiles "$APPDATA\High Fidelity\" "$APPDATA\@MODIFIED_ORGANIZATION@\" + CreateDirectory "$APPDATA\@BUILD_ORGANIZATION@" + CopyFiles "$APPDATA\High Fidelity\" "$APPDATA\@BUILD_ORGANIZATION@\" ${EndIf} ${EndIf} From 1deaebd54436b934e65b643d05806346167b8c90 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 18 Jan 2016 18:25:02 -0800 Subject: [PATCH 289/357] check the copy box by default --- cmake/templates/NSIS.template.in | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 097d8c7623..f481e4aaa7 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -916,6 +916,8 @@ Function PostInstallOptionsPage ${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Copy settings and content from production install" Pop $CopyFromProductionCheckbox + + ${NSD_SetState} $CopyFromProductionCheckbox ${BST_CHECKED} ${EndIf} nsDialogs::Show @@ -976,7 +978,7 @@ Function HandlePostInstallOptions ${If} $CopyFromProductionState == ${BST_CHECKED} ; we need to copy whatever is in the data folder for production build to the data folder for this build CreateDirectory "$APPDATA\@BUILD_ORGANIZATION@" - CopyFiles "$APPDATA\High Fidelity\" "$APPDATA\@BUILD_ORGANIZATION@\" + CopyFiles "$APPDATA\High Fidelity\*" "$APPDATA\@BUILD_ORGANIZATION@" ${EndIf} ${EndIf} From d7c5036a42f056e5e3ea8b94979e12a3d232fa20 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 18 Jan 2016 18:26:15 -0800 Subject: [PATCH 290/357] fix release type check for prod copy --- cmake/templates/NSIS.template.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index f481e4aaa7..2b44bca360 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -971,7 +971,7 @@ Function HandlePostInstallOptions ${EndIf} ${EndIf} - ${If} @PRODUCTION_BUILD@ == 1 + ${If} @PR_BUILD@ == 1 ; check if we need to copy settings/content from production for this PR build ${NSD_GetState} $CopyFromProductionCheckbox $CopyFromProductionState From 6ee02582511c73c36f1ccb60fcc8f0b6b6d1f220 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 19 Jan 2016 08:57:33 -0800 Subject: [PATCH 291/357] add an error message for app data create --- cmake/templates/NSIS.template.in | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 2b44bca360..6063ab475c 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -978,7 +978,14 @@ Function HandlePostInstallOptions ${If} $CopyFromProductionState == ${BST_CHECKED} ; we need to copy whatever is in the data folder for production build to the data folder for this build CreateDirectory "$APPDATA\@BUILD_ORGANIZATION@" - CopyFiles "$APPDATA\High Fidelity\*" "$APPDATA\@BUILD_ORGANIZATION@" + + IfErrors CopyData + + ; if we're here there was an error creating the data folder for this build + MessageBox mb_IconStop|mb_TopMost|mb_SetForeground "Could not create directory $APPDATA\@BUILD_ORGANIZATION@, error $0" + + CopyData: + CopyFiles "$APPDATA\High Fidelity\*" "$APPDATA\@BUILD_ORGANIZATION@" ${EndIf} ${EndIf} From 42a6f9daa1d7fbe4913f18c20c527c6b9104df0a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 19 Jan 2016 09:33:06 -0800 Subject: [PATCH 292/357] hard code the matching app data path --- cmake/templates/CPackProperties.cmake.in | 2 ++ cmake/templates/NSIS.template.in | 15 +++++++++------ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/cmake/templates/CPackProperties.cmake.in b/cmake/templates/CPackProperties.cmake.in index 7b3d0ae53e..08b23f4657 100644 --- a/cmake/templates/CPackProperties.cmake.in +++ b/cmake/templates/CPackProperties.cmake.in @@ -19,6 +19,8 @@ set(HIGH_FIDELITY_PROTOCOL "@HIGH_FIDELITY_PROTOCOL@") set(PRODUCTION_BUILD "@PRODUCTION_BUILD@") set(PR_BUILD "@PR_BUILD@") set(BUILD_ORGANIZATION "@BUILD_ORGANIZATION@") +set(APP_DATA_ROOT "@APP_DATA_ROOT@") +set(APP_DATA_PATH "@APP_DATA_ROOT@/@BUILD_ORGANIZATION@") set(POST_INSTALL_OPTIONS_PATH "@POST_INSTALL_OPTIONS_PATH@") set(CLIENT_COMPONENT_NAME "@CLIENT_COMPONENT@") set(SERVER_COMPONENT_NAME "@SERVER_COMPONENT@") diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 6063ab475c..d7cc3f715c 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -977,15 +977,18 @@ Function HandlePostInstallOptions ${If} $CopyFromProductionState == ${BST_CHECKED} ; we need to copy whatever is in the data folder for production build to the data folder for this build - CreateDirectory "$APPDATA\@BUILD_ORGANIZATION@" + CreateDirectory "@APP_DATA_PATH@" - IfErrors CopyData + ; copy the data from production build to this PR build + CopyFiles "@APP_DATA_ROOT@\High Fidelity\*" "@APP_DATA_PATH@" - ; if we're here there was an error creating the data folder for this build - MessageBox mb_IconStop|mb_TopMost|mb_SetForeground "Could not create directory $APPDATA\@BUILD_ORGANIZATION@, error $0" + ; handle an error in copying files + IfError 0 NoError - CopyData: - CopyFiles "$APPDATA\High Fidelity\*" "$APPDATA\@BUILD_ORGANIZATION@" + MessageBox mb_IconStop|mb_TopMost|mb_SetForeground \ + "There was a problem copying your production content and settings to @APP_DATA_PATH@ for this PR build.$\r$\nPlease try to copy them manually." + + NoError: ${EndIf} ${EndIf} From 04a5dbed7dc19b6ed9a61d0ca57bd4992909dd06 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 19 Jan 2016 09:42:00 -0800 Subject: [PATCH 293/357] set shell context to user prior to app data copy --- cmake/templates/CPackProperties.cmake.in | 2 -- cmake/templates/NSIS.template.in | 10 +++++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/cmake/templates/CPackProperties.cmake.in b/cmake/templates/CPackProperties.cmake.in index 08b23f4657..7b3d0ae53e 100644 --- a/cmake/templates/CPackProperties.cmake.in +++ b/cmake/templates/CPackProperties.cmake.in @@ -19,8 +19,6 @@ set(HIGH_FIDELITY_PROTOCOL "@HIGH_FIDELITY_PROTOCOL@") set(PRODUCTION_BUILD "@PRODUCTION_BUILD@") set(PR_BUILD "@PR_BUILD@") set(BUILD_ORGANIZATION "@BUILD_ORGANIZATION@") -set(APP_DATA_ROOT "@APP_DATA_ROOT@") -set(APP_DATA_PATH "@APP_DATA_ROOT@/@BUILD_ORGANIZATION@") set(POST_INSTALL_OPTIONS_PATH "@POST_INSTALL_OPTIONS_PATH@") set(CLIENT_COMPONENT_NAME "@CLIENT_COMPONENT@") set(SERVER_COMPONENT_NAME "@SERVER_COMPONENT@") diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index d7cc3f715c..74cbdcd36f 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -976,17 +976,21 @@ Function HandlePostInstallOptions ${NSD_GetState} $CopyFromProductionCheckbox $CopyFromProductionState ${If} $CopyFromProductionState == ${BST_CHECKED} + SetShellVarContext current + + StrCopy $0 "$APPDATA\@BUILD_ORGANIZATION@" + ; we need to copy whatever is in the data folder for production build to the data folder for this build - CreateDirectory "@APP_DATA_PATH@" + CreateDirectory $0 ; copy the data from production build to this PR build - CopyFiles "@APP_DATA_ROOT@\High Fidelity\*" "@APP_DATA_PATH@" + CopyFiles "$APPDATA\High Fidelity\*" $0 ; handle an error in copying files IfError 0 NoError MessageBox mb_IconStop|mb_TopMost|mb_SetForeground \ - "There was a problem copying your production content and settings to @APP_DATA_PATH@ for this PR build.$\r$\nPlease try to copy them manually." + "There was a problem copying your production content and settings to $0 for this PR build.$\r$\nPlease copy them manually." NoError: ${EndIf} From 7b1fc8d65c2c83a2fa50a59741f87239537266ea Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 19 Jan 2016 09:45:26 -0800 Subject: [PATCH 294/357] repair call to strcpy for dir variable --- cmake/templates/NSIS.template.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 74cbdcd36f..589483a093 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -978,7 +978,7 @@ Function HandlePostInstallOptions ${If} $CopyFromProductionState == ${BST_CHECKED} SetShellVarContext current - StrCopy $0 "$APPDATA\@BUILD_ORGANIZATION@" + StrCpy $0 "$APPDATA\@BUILD_ORGANIZATION@" ; we need to copy whatever is in the data folder for production build to the data folder for this build CreateDirectory $0 From be6606cefd628fe2fcb0ad88e842f1b3b361d28c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 19 Jan 2016 09:49:13 -0800 Subject: [PATCH 295/357] fix for error check during PR copy --- cmake/templates/NSIS.template.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 589483a093..1d9138cfaa 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -987,7 +987,7 @@ Function HandlePostInstallOptions CopyFiles "$APPDATA\High Fidelity\*" $0 ; handle an error in copying files - IfError 0 NoError + IfErrors 0 NoError MessageBox mb_IconStop|mb_TopMost|mb_SetForeground \ "There was a problem copying your production content and settings to $0 for this PR build.$\r$\nPlease copy them manually." From e8525e4886ccb0762fff632087e2328e20e2a05f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 19 Jan 2016 09:58:07 -0800 Subject: [PATCH 296/357] cleanup messages, clear errors before copy --- cmake/templates/NSIS.template.in | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 1d9138cfaa..ee8c5c8c08 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -983,6 +983,8 @@ Function HandlePostInstallOptions ; we need to copy whatever is in the data folder for production build to the data folder for this build CreateDirectory $0 + ClearErrors + ; copy the data from production build to this PR build CopyFiles "$APPDATA\High Fidelity\*" $0 @@ -990,7 +992,7 @@ Function HandlePostInstallOptions IfErrors 0 NoError MessageBox mb_IconStop|mb_TopMost|mb_SetForeground \ - "There was a problem copying your production content and settings to $0 for this PR build.$\r$\nPlease copy them manually." + "There was a problem copying your production content and settings to $0 for this PR build.$\r$\n$\r$\nPlease copy them manually." NoError: ${EndIf} From a27d35566d78246b8f9dfe35604c605e893478c3 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 19 Jan 2016 10:49:18 -0800 Subject: [PATCH 297/357] stub of temporary name download on DS start --- domain-server/src/DomainServer.cpp | 48 ++++++++++++++++++++++++++++-- domain-server/src/DomainServer.h | 5 ++++ 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 70dd55f9c9..bc0eed3ded 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -82,7 +82,9 @@ DomainServer::DomainServer(int argc, char* argv[]) : // (need this since domain-server can restart itself and maintain static variables) AccountManager::getInstance(true); - _settingsManager.setupConfigMap(arguments()); + auto args = arguments(); + + _settingsManager.setupConfigMap(args); // setup a shutdown event listener to handle SIGTERM or WM_CLOSE for us #ifdef _WIN32 @@ -111,6 +113,8 @@ DomainServer::DomainServer(int argc, char* argv[]) : // preload some user public keys so they can connect on first request _gatekeeper.preloadAllowedUserPublicKeys(); + + optionallyGetTemporaryName(args); } } @@ -210,6 +214,47 @@ bool DomainServer::optionallySetupOAuth() { return true; } +static const QString METAVERSE_DOMAIN_ID_KEY_PATH = "metaverse.id"; + +void DomainServer::optionallyGetTemporaryName(const QStringList& arguments) { + // check for the temporary name parameter + const QString GET_TEMPORARY_NAME_SWITCH = "--get-temp-name"; + + if (arguments.contains(GET_TEMPORARY_NAME_SWITCH)) { + + // make sure we don't already have a domain ID + const QVariant* idValueVariant = valueForKeyPath(_settingsManager.getSettingsMap(), METAVERSE_DOMAIN_ID_KEY_PATH); + if (idValueVariant) { + qWarning() << "Temporary domain name requested but a domain ID is already present in domain-server settings." + << "Will not request temporary name."; + return; + } + + // we've been asked to grab a temporary name from the API + // so fire off that request now + auto& accountManager = AccountManager::getInstance(); + + // ask our auth endpoint for our balance + JSONCallbackParameters callbackParameters; + callbackParameters.jsonCallbackReceiver = this; + callbackParameters.jsonCallbackMethod = "handleTempDomainSuccess"; + callbackParameters.errorCallbackReceiver = this; + callbackParameters.errorCallbackMethod = "handleTempDomainError"; + + accountManager.sendRequest("/api/v1/domains/temporary", AccountManagerAuth::None, + QNetworkAccessManager::GetOperation, callbackParameters); + } +} + +void DomainServer::handleTempDomainSuccess(QNetworkReply& requestReply) { + QJsonObject jsonObject = QJsonDocument::fromJson(requestReply.readAll()).object(); +} + +void DomainServer::handleTempDomainError(QNetworkReply& requestReply) { + qWarning() << "A temporary name was requested but there was an error creating one. Try again via domain-server relaunch" + << "or from the domain-server settings."; +} + const QString DOMAIN_CONFIG_ID_KEY = "id"; const QString METAVERSE_AUTOMATIC_NETWORKING_KEY_PATH = "metaverse.automatic_networking"; @@ -260,7 +305,6 @@ void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) { // set our LimitedNodeList UUID to match the UUID from our config // nodes will currently use this to add resources to data-web that relate to our domain - const QString METAVERSE_DOMAIN_ID_KEY_PATH = "metaverse.id"; const QVariant* idValueVariant = valueForKeyPath(settingsMap, METAVERSE_DOMAIN_ID_KEY_PATH); if (idValueVariant) { nodeList->setSessionUUID(idValueVariant->toString()); diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index f5d5ff8f40..78459164d0 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -74,6 +74,9 @@ private slots: void sendHeartbeatToIceServer(); void handleConnectedNode(SharedNodePointer newNode); + + void handleTempDomainSuccess(QNetworkReply& requestReply); + void handleTempDomainError(QNetworkReply& requestReply); private: void setupNodeListAndAssignments(const QUuid& sessionUUID = QUuid::createUuid()); @@ -81,6 +84,8 @@ private: bool optionallyReadX509KeyAndCertificate(); bool optionallySetupAssignmentPayment(); + void optionallyGetTemporaryName(const QStringList& arguments); + bool didSetupAccountManagerWithAccessToken(); bool resetAccountManagerAccessToken(); From de36f3eeb2a9af5a0e8f61d404459b6d02046256 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 18 Jan 2016 14:22:48 -0800 Subject: [PATCH 298/357] Update ServerPathUtils::getDataDirectory to use custom path lookup --- libraries/shared/src/ServerPathUtils.cpp | 31 ++++++++++++++++++++---- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/libraries/shared/src/ServerPathUtils.cpp b/libraries/shared/src/ServerPathUtils.cpp index d253265103..0f9ebabbbe 100644 --- a/libraries/shared/src/ServerPathUtils.cpp +++ b/libraries/shared/src/ServerPathUtils.cpp @@ -1,16 +1,37 @@ +// +// ServerPathUtils.cpp +// libraries/shared/src +// +// Created by Ryan Huffman on 01/12/16. +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// #include "ServerPathUtils.h" #include #include +#include +#include QString ServerPathUtils::getDataDirectory() { - auto directory = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); - if (directory.isEmpty()) { - directory = '.'; - } - return directory; + auto homeDirectory = QDir(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)); + +#ifdef Q_OS_WIN + homeDirectory.cd("AppData/Roaming/"); +#elif Q_OS_OSX + homeDirectory.cd("Library/Application Support/"); +#else + homeDirectory.cd(".local/share/"); +#endif + + homeDirectory.cd(qApp->organizationName() + "/" + qApp->applicationName()); + + return homeDirectory.absolutePath(); } QString ServerPathUtils::getDataFilePath(QString filename) { return QDir(getDataDirectory()).absoluteFilePath(filename); } + From 74806d9d2bb08a1a6fbf91e3199a9eaad2400109 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 19 Jan 2016 11:28:29 -0800 Subject: [PATCH 299/357] migrate old DS config file to new path --- libraries/shared/src/HifiConfigVariantMap.cpp | 40 +++++++++++++++++-- libraries/shared/src/HifiConfigVariantMap.h | 1 + libraries/shared/src/ServerPathUtils.cpp | 14 +++---- 3 files changed, 44 insertions(+), 11 deletions(-) diff --git a/libraries/shared/src/HifiConfigVariantMap.cpp b/libraries/shared/src/HifiConfigVariantMap.cpp index 4f9a741aad..b8743c8dfc 100644 --- a/libraries/shared/src/HifiConfigVariantMap.cpp +++ b/libraries/shared/src/HifiConfigVariantMap.cpp @@ -9,8 +9,11 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "HifiConfigVariantMap.h" + #include #include +#include #include #include #include @@ -18,8 +21,8 @@ #include #include +#include "ServerPathUtils.h" #include "SharedLogging.h" -#include "HifiConfigVariantMap.h" QVariantMap HifiConfigVariantMap::mergeCLParametersWithJSONConfig(const QStringList& argumentList) { @@ -110,14 +113,43 @@ void HifiConfigVariantMap::loadMasterAndUserConfig(const QStringList& argumentLi // load the user config const QString USER_CONFIG_FILE_OPTION = "--user-config"; + static const QString USER_CONFIG_FILE_NAME = "config.json"; int userConfigIndex = argumentList.indexOf(USER_CONFIG_FILE_OPTION); if (userConfigIndex != -1) { _userConfigFilename = argumentList[userConfigIndex + 1]; } else { - _userConfigFilename = QString("%1/%2/%3/config.json").arg(QStandardPaths::writableLocation(QStandardPaths::ConfigLocation), - QCoreApplication::organizationName(), - QCoreApplication::applicationName()); + // we weren't passed a user config path + _userConfigFilename = ServerPathUtils::getDataFilePath(USER_CONFIG_FILE_NAME); + + // as of 1/19/2016 this path was moved + + // figure out what the old path was + auto oldConfigFilename = QString("%1/%2/%3/%4").arg(QStandardPaths::writableLocation(QStandardPaths::ConfigLocation), + QCoreApplication::organizationName(), + QCoreApplication::applicationName(), + USER_CONFIG_FILE_NAME); + + // check if there's already a config file at the new path + QFile newConfigFile { _userConfigFilename }; + if (!newConfigFile.exists()) { + QFile oldConfigFile { oldConfigFilename }; + + if (oldConfigFile.exists()) { + // we have the old file and not the new file - time to copy the file + + // make the destination directory if it doesn't exist + QDir().mkdir(ServerPathUtils::getDataDirectory()); + + if (oldConfigFile.copy(_userConfigFilename)) { + qDebug() << "Migrated config file from" << oldConfigFilename << "to" << _userConfigFilename; + } else { + qWarning() << "Could not copy previous config file from" << oldConfigFilename << "to" << _userConfigFilename + << "- please try to copy manually and restart."; + } + } + } + } loadMapFromJSONFile(_userConfig, _userConfigFilename); diff --git a/libraries/shared/src/HifiConfigVariantMap.h b/libraries/shared/src/HifiConfigVariantMap.h index 75b8be1984..bf1e84dffc 100644 --- a/libraries/shared/src/HifiConfigVariantMap.h +++ b/libraries/shared/src/HifiConfigVariantMap.h @@ -13,6 +13,7 @@ #define hifi_HifiConfigVariantMap_h #include +#include class HifiConfigVariantMap { public: diff --git a/libraries/shared/src/ServerPathUtils.cpp b/libraries/shared/src/ServerPathUtils.cpp index 0f9ebabbbe..ca87a28610 100644 --- a/libraries/shared/src/ServerPathUtils.cpp +++ b/libraries/shared/src/ServerPathUtils.cpp @@ -16,19 +16,19 @@ #include QString ServerPathUtils::getDataDirectory() { - auto homeDirectory = QDir(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)); + auto dataPath = QStandardPaths::writableLocation(QStandardPaths::HomeLocation); #ifdef Q_OS_WIN - homeDirectory.cd("AppData/Roaming/"); -#elif Q_OS_OSX - homeDirectory.cd("Library/Application Support/"); + dataPath += "/AppData/Roaming/"; +#elif defined(Q_OS_OSX) + dataPath += "/Library/Application Support/"; #else - homeDirectory.cd(".local/share/"); + dataPath += "/.local/share/"; #endif - homeDirectory.cd(qApp->organizationName() + "/" + qApp->applicationName()); + dataPath += qApp->organizationName() + "/" + qApp->applicationName(); - return homeDirectory.absolutePath(); + return QDir::cleanPath(dataPath); } QString ServerPathUtils::getDataFilePath(QString filename) { From 483e0f419b246cb923bbe3f7ea5d18af29650a8e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 19 Jan 2016 11:37:49 -0800 Subject: [PATCH 300/357] use mkpath to create new data directory --- libraries/shared/src/HifiConfigVariantMap.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/libraries/shared/src/HifiConfigVariantMap.cpp b/libraries/shared/src/HifiConfigVariantMap.cpp index b8743c8dfc..96fa2cd9b1 100644 --- a/libraries/shared/src/HifiConfigVariantMap.cpp +++ b/libraries/shared/src/HifiConfigVariantMap.cpp @@ -139,13 +139,16 @@ void HifiConfigVariantMap::loadMasterAndUserConfig(const QStringList& argumentLi // we have the old file and not the new file - time to copy the file // make the destination directory if it doesn't exist - QDir().mkdir(ServerPathUtils::getDataDirectory()); - - if (oldConfigFile.copy(_userConfigFilename)) { - qDebug() << "Migrated config file from" << oldConfigFilename << "to" << _userConfigFilename; - } else { - qWarning() << "Could not copy previous config file from" << oldConfigFilename << "to" << _userConfigFilename + auto dataDirectory = ServerPathUtils::getDataDirectory(); + if (QDir().mkpath(dataDirectory)) { + if (oldConfigFile.copy(_userConfigFilename)) { + qDebug() << "Migrated config file from" << oldConfigFilename << "to" << _userConfigFilename; + } else { + qWarning() << "Could not copy previous config file from" << oldConfigFilename << "to" << _userConfigFilename << "- please try to copy manually and restart."; + } + } else { + qWarning() << "Could not create application data directory" << dataDirectory << "- unable to migrate previous config file."; } } } From 858adf383eb2f1d2feaef2b7002fe105f071fa84 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 19 Jan 2016 11:38:31 -0800 Subject: [PATCH 301/357] update comment for config migration --- libraries/shared/src/HifiConfigVariantMap.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/shared/src/HifiConfigVariantMap.cpp b/libraries/shared/src/HifiConfigVariantMap.cpp index 96fa2cd9b1..95c8519314 100644 --- a/libraries/shared/src/HifiConfigVariantMap.cpp +++ b/libraries/shared/src/HifiConfigVariantMap.cpp @@ -122,7 +122,7 @@ void HifiConfigVariantMap::loadMasterAndUserConfig(const QStringList& argumentLi // we weren't passed a user config path _userConfigFilename = ServerPathUtils::getDataFilePath(USER_CONFIG_FILE_NAME); - // as of 1/19/2016 this path was moved + // as of 1/19/2016 this path was moved so we attempt a migration for first run post migration here // figure out what the old path was auto oldConfigFilename = QString("%1/%2/%3/%4").arg(QStandardPaths::writableLocation(QStandardPaths::ConfigLocation), From 4cbbd24c7e1f7bc92edb650ebf83e68f86c36826 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 19 Jan 2016 13:04:05 -0800 Subject: [PATCH 302/357] complete handling of immediate temp name grab --- domain-server/src/DomainServer.cpp | 71 +++++++++++++++---- domain-server/src/DomainServer.h | 3 + .../src/DomainServerSettingsManager.cpp | 7 +- .../src/DomainServerSettingsManager.h | 4 +- libraries/networking/src/LimitedNodeList.cpp | 2 - libraries/shared/src/LogHandler.cpp | 2 + libraries/shared/src/LogHandler.h | 3 +- 7 files changed, 70 insertions(+), 22 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index bc0eed3ded..40ab9150a2 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -242,16 +242,49 @@ void DomainServer::optionallyGetTemporaryName(const QStringList& arguments) { callbackParameters.errorCallbackMethod = "handleTempDomainError"; accountManager.sendRequest("/api/v1/domains/temporary", AccountManagerAuth::None, - QNetworkAccessManager::GetOperation, callbackParameters); + QNetworkAccessManager::PostOperation, callbackParameters); } } void DomainServer::handleTempDomainSuccess(QNetworkReply& requestReply) { QJsonObject jsonObject = QJsonDocument::fromJson(requestReply.readAll()).object(); + + // grab the information for the new domain + static const QString DATA_KEY = "data"; + static const QString DOMAIN_KEY = "domain"; + static const QString ID_KEY = "id"; + static const QString NAME_KEY = "name"; + + auto domainObject = jsonObject[DATA_KEY].toObject()[DOMAIN_KEY].toObject(); + if (!domainObject.isEmpty()) { + auto id = domainObject[ID_KEY].toString(); + auto name = domainObject[NAME_KEY].toString(); + + qInfo() << "Received new temporary domain name" << name; + qDebug() << "The temporary domain ID is" << id; + + // store the new domain ID and auto network setting immediately + QString newSettingsJSON = QString("{\"metaverse\": { \"id\": \"%1\", \"automatic_networking\": \"full\"}}").arg(id); + auto settingsDocument = QJsonDocument::fromJson(newSettingsJSON.toUtf8()); + _settingsManager.recurseJSONObjectAndOverwriteSettings(settingsDocument.object()); + + // store the new ID and auto networking setting on disk + _settingsManager.persistToFile(); + + // change our domain ID immediately + DependencyManager::get()->setSessionUUID(QUuid { id }); + + // change our automatic networking settings so that we're communicating with the ICE server + setupICEHeartbeatForFullNetworking(); + + } else { + qWarning() << "There were problems parsing the API response containing a temporary domain name. Please try again" + << "via domain-server relaunch or from the domain-server settings."; + } } void DomainServer::handleTempDomainError(QNetworkReply& requestReply) { - qWarning() << "A temporary name was requested but there was an error creating one. Try again via domain-server relaunch" + qWarning() << "A temporary name was requested but there was an error creating one. Please try again via domain-server relaunch" << "or from the domain-server settings."; } @@ -417,19 +450,7 @@ void DomainServer::setupAutomaticNetworking() { _settingsManager.valueOrDefaultValueForKeyPath(METAVERSE_AUTOMATIC_NETWORKING_KEY_PATH).toString(); if (_automaticNetworkingSetting == FULL_AUTOMATIC_NETWORKING_VALUE) { - // call our sendHeartbeatToIceServer immediately anytime a local or public socket changes - connect(nodeList.data(), &LimitedNodeList::localSockAddrChanged, - this, &DomainServer::sendHeartbeatToIceServer); - connect(nodeList.data(), &LimitedNodeList::publicSockAddrChanged, - this, &DomainServer::sendHeartbeatToIceServer); - - // we need this DS to know what our public IP is - start trying to figure that out now - nodeList->startSTUNPublicSocketUpdate(); - - // setup a timer to heartbeat with the ice-server every so often - QTimer* iceHeartbeatTimer = new QTimer(this); - connect(iceHeartbeatTimer, &QTimer::timeout, this, &DomainServer::sendHeartbeatToIceServer); - iceHeartbeatTimer->start(ICE_HEARBEAT_INTERVAL_MSECS); + } if (!didSetupAccountManagerWithAccessToken()) { @@ -479,6 +500,26 @@ void DomainServer::setupAutomaticNetworking() { dataHeartbeatTimer->start(DOMAIN_SERVER_DATA_WEB_HEARTBEAT_MSECS); } +void DomainServer::setupICEHeartbeatForFullNetworking() { + auto limitedNodeList = DependencyManager::get(); + + // call our sendHeartbeatToIceServer immediately anytime a local or public socket changes + connect(limitedNodeList.data(), &LimitedNodeList::localSockAddrChanged, + this, &DomainServer::sendHeartbeatToIceServer); + connect(limitedNodeList.data(), &LimitedNodeList::publicSockAddrChanged, + this, &DomainServer::sendHeartbeatToIceServer); + + // we need this DS to know what our public IP is - start trying to figure that out now + limitedNodeList->startSTUNPublicSocketUpdate(); + + if (!_iceHeartbeatTimer) { + // setup a timer to heartbeat with the ice-server every so often + _iceHeartbeatTimer = new QTimer { this }; + connect(_iceHeartbeatTimer, &QTimer::timeout, this, &DomainServer::sendHeartbeatToIceServer); + _iceHeartbeatTimer->start(ICE_HEARBEAT_INTERVAL_MSECS); + } +} + void DomainServer::loginFailed() { qDebug() << "Login to data server has failed. domain-server will now quit"; QMetaObject::invokeMethod(this, "quit", Qt::QueuedConnection); diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index 78459164d0..a4892b446b 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -90,6 +90,7 @@ private: bool resetAccountManagerAccessToken(); void setupAutomaticNetworking(); + void setupICEHeartbeatForFullNetworking(); void sendHeartbeatToDataServer(const QString& networkAddress); unsigned int countConnectedUsers(); @@ -149,6 +150,8 @@ private: DomainServerSettingsManager _settingsManager; HifiSockAddr _iceServerSocket; + + QTimer* _iceHeartbeatTimer { nullptr }; // this looks like it dangles when created but it's parented to the DomainServer friend class DomainGatekeeper; }; diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index 888df219dd..9190e4f99f 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -193,7 +193,7 @@ bool DomainServerSettingsManager::handleAuthenticatedHTTPRequest(HTTPConnection qDebug() << "DomainServerSettingsManager postedObject -" << postedObject; // we recurse one level deep below each group for the appropriate setting - recurseJSONObjectAndOverwriteSettings(postedObject, _configMap.getUserConfig()); + recurseJSONObjectAndOverwriteSettings(postedObject); // store whatever the current _settingsMap is to file persistToFile(); @@ -407,8 +407,9 @@ QJsonObject DomainServerSettingsManager::settingDescriptionFromGroup(const QJson return QJsonObject(); } -void DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJsonObject& postedObject, - QVariantMap& settingsVariant) { +void DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJsonObject& postedObject) { + auto& settingsVariant = _configMap.getUserConfig(); + // Iterate on the setting groups foreach(const QString& rootKey, postedObject.keys()) { QJsonValue rootValue = postedObject[rootKey]; diff --git a/domain-server/src/DomainServerSettingsManager.h b/domain-server/src/DomainServerSettingsManager.h index 7f71a89da5..d6dd5070a9 100644 --- a/domain-server/src/DomainServerSettingsManager.h +++ b/domain-server/src/DomainServerSettingsManager.h @@ -46,7 +46,7 @@ private slots: private: QJsonObject responseObjectForType(const QString& typeValue, bool isAuthenticated = false); - void recurseJSONObjectAndOverwriteSettings(const QJsonObject& postedObject, QVariantMap& settingsVariant); + void recurseJSONObjectAndOverwriteSettings(const QJsonObject& postedObject); void updateSetting(const QString& key, const QJsonValue& newValue, QVariantMap& settingMap, const QJsonObject& settingDescription); @@ -56,6 +56,8 @@ private: double _descriptionVersion; QJsonArray _descriptionArray; HifiConfigVariantMap _configMap; + + friend class DomainServer; }; #endif // hifi_DomainServerSettingsManager_h diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 0b194b017e..67406286a4 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -788,8 +788,6 @@ void LimitedNodeList::processSTUNResponse(std::unique_ptr packe } void LimitedNodeList::startSTUNPublicSocketUpdate() { - assert(!_initialSTUNTimer); - if (!_initialSTUNTimer) { // if we don't know the STUN IP yet we need to have ourselves be called once it is known if (_stunSockAddr.getAddress().isNull()) { diff --git a/libraries/shared/src/LogHandler.cpp b/libraries/shared/src/LogHandler.cpp index 7dd1aceb3d..c1cf969f36 100644 --- a/libraries/shared/src/LogHandler.cpp +++ b/libraries/shared/src/LogHandler.cpp @@ -42,6 +42,8 @@ LogHandler::LogHandler() : const char* stringForLogType(LogMsgType msgType) { switch (msgType) { + case LogInfo: + return "INFO"; case LogDebug: return "DEBUG"; case LogWarning: diff --git a/libraries/shared/src/LogHandler.h b/libraries/shared/src/LogHandler.h index a74a6287d7..ee8e426c34 100644 --- a/libraries/shared/src/LogHandler.h +++ b/libraries/shared/src/LogHandler.h @@ -22,11 +22,12 @@ const int VERBOSE_LOG_INTERVAL_SECONDS = 5; enum LogMsgType { + LogInfo = QtInfoMsg, LogDebug = QtDebugMsg, LogWarning = QtWarningMsg, LogCritical = QtCriticalMsg, LogFatal = QtFatalMsg, - LogSuppressed + LogSuppressed = 100 }; /// Handles custom message handling and sending of stats/logs to Logstash instance From 74b2a44050f7b1b7e8c8c73cfcc1743a40ac734f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 19 Jan 2016 13:08:34 -0800 Subject: [PATCH 303/357] merge the master and user configs after a settings change --- domain-server/src/DomainServerSettingsManager.cpp | 3 +++ libraries/shared/src/HifiConfigVariantMap.cpp | 4 ++++ libraries/shared/src/HifiConfigVariantMap.h | 2 ++ 3 files changed, 9 insertions(+) diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index 9190e4f99f..e10007784f 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -482,6 +482,9 @@ void DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJ settingsVariant.remove(rootKey); } } + + // re-merge the user and master configs after a settings change + _configMap.mergeMasterAndUserConfigs(); } void DomainServerSettingsManager::persistToFile() { diff --git a/libraries/shared/src/HifiConfigVariantMap.cpp b/libraries/shared/src/HifiConfigVariantMap.cpp index 95c8519314..5d21473fd8 100644 --- a/libraries/shared/src/HifiConfigVariantMap.cpp +++ b/libraries/shared/src/HifiConfigVariantMap.cpp @@ -157,6 +157,10 @@ void HifiConfigVariantMap::loadMasterAndUserConfig(const QStringList& argumentLi loadMapFromJSONFile(_userConfig, _userConfigFilename); + mergeMasterAndUserConfigs(); +} + +void HifiConfigVariantMap::mergeMasterAndUserConfigs() { // the merged config is initially matched to the master config _mergedConfig = _masterConfig; diff --git a/libraries/shared/src/HifiConfigVariantMap.h b/libraries/shared/src/HifiConfigVariantMap.h index bf1e84dffc..e92561cff5 100644 --- a/libraries/shared/src/HifiConfigVariantMap.h +++ b/libraries/shared/src/HifiConfigVariantMap.h @@ -26,6 +26,8 @@ public: QVariantMap& getUserConfig() { return _userConfig; } QVariantMap& getMergedConfig() { return _mergedConfig; } + void mergeMasterAndUserConfigs(); + const QString& getUserConfigFilename() const { return _userConfigFilename; } private: QString _userConfigFilename; From 27e375e8e6ccef4db727f254e79c3774833450b8 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 19 Jan 2016 13:12:00 -0800 Subject: [PATCH 304/357] launch domain-server with option to grab name --- console/src/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/console/src/main.js b/console/src/main.js index a15cfb01f4..a518c812fc 100644 --- a/console/src/main.js +++ b/console/src/main.js @@ -530,7 +530,7 @@ app.on('ready', function() { maybeShowSplash(); if (dsPath && acPath) { - domainServer = new Process('domain-server', dsPath, [], logPath); + domainServer = new Process('domain-server', dsPath, ["--get-temp-name"], logPath); acMonitor = new ACMonitorProcess('ac-monitor', acPath, ['-n6', '--log-directory', logPath, '--http-status-port', httpStatusPort], httpStatusPort, logPath); From a69b2fabd387bdffade039a35400ce7ff2437c32 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 19 Jan 2016 13:13:43 -0800 Subject: [PATCH 305/357] don't prompt to attempt process close --- cmake/templates/NSIS.template.in | 23 +++-------------------- 1 file changed, 3 insertions(+), 20 deletions(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index ee8c5c8c08..50ee18e970 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -1026,26 +1026,9 @@ FunctionEnd !define UniqueID ${__LINE__} ; the process is running, ask the user if they want us to close it - MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION \ - "${displayName} cannot be ${action} while ${displayName} is running.$\r$\nWould you like the ${prompter} to try closing it?" \ - /SD IDCANCEL IDOK AttemptClose_${UniqueID} IDCANCEL Abort_${UniqueID} - - AttemptClose_${UniqueID}: - ; attempt to close the given process - ${nsProcess::CloseProcess} ${applicationName} $R0 - - ; check if the process was closed - ${If} $R0 == 0 - ; closed the running application - Goto Next_${UniqueID} - ${Else} - ; couldn't close the running application, bail - Abort - ${EndIf} - Abort_${UniqueID}: - Abort - Next_${UniqueID}: - !undef UniqueID + MessageBox MB_OK|MB_ICONEXCLAMATION \ + "${displayName} cannot be ${action} while ${displayName} is running.$\r$\nPlease close ${displayName} and try again." + Abort ${EndIf} !macroend From 56f6ef434d083604f96fa23e093c2c003a8864d7 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 19 Jan 2016 13:16:55 -0800 Subject: [PATCH 306/357] remove define of UniqueID --- cmake/templates/NSIS.template.in | 2 -- 1 file changed, 2 deletions(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 50ee18e970..9c0473f45f 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -1023,8 +1023,6 @@ FunctionEnd ${nsProcess::FindProcess} ${applicationName} $R0 ${If} $R0 == 0 - !define UniqueID ${__LINE__} - ; the process is running, ask the user if they want us to close it MessageBox MB_OK|MB_ICONEXCLAMATION \ "${displayName} cannot be ${action} while ${displayName} is running.$\r$\nPlease close ${displayName} and try again." From 3e013833c86bd840e77c5ca93bdac030bc4b71cf Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 19 Jan 2016 13:28:30 -0800 Subject: [PATCH 307/357] fix redundant app display name in alert --- cmake/templates/NSIS.template.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 9c0473f45f..f4ed460aa0 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -1025,7 +1025,7 @@ FunctionEnd ${If} $R0 == 0 ; the process is running, ask the user if they want us to close it MessageBox MB_OK|MB_ICONEXCLAMATION \ - "${displayName} cannot be ${action} while ${displayName} is running.$\r$\nPlease close ${displayName} and try again." + "${displayName} cannot be ${action} while ${displayName} is running.$\r$\nPlease close it and try again." Abort ${EndIf} !macroend From cb5c1b12c54a17d16803af29c0e555de62ace2b6 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 18 Jan 2016 10:40:53 -0800 Subject: [PATCH 308/357] Fix copy in splash.html --- console/src/splash.html | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/console/src/splash.html b/console/src/splash.html index 567c09f88e..3af68755ba 100644 --- a/console/src/splash.html +++ b/console/src/splash.html @@ -29,9 +29,12 @@