42 Log::info(
'Administrator privileges confirmed - proceeding with startup');
45 $this->splash =
new Splash();
46 $this->restart =
false;
51 $this->filesToScan = array();
53 $gauge = self::GAUGE_SERVICES * count(
$bearsamppBins->getServices() );
54 $gauge += self::GAUGE_OTHERS + 1;
63 $bearsamppWinbinder->setHandler( $this->splash->getWbWindow(), $this,
'processWindow', 1000 );
64 $bearsamppWinbinder->mainLoop();
65 $bearsamppWinbinder->reset();
97 if ($bearsamppRoot->getProcs() !==
false) {
105 foreach ($listProcs as
$proc) {
108 Log::trace(
'Found ' . count($listProcs) .
' running processes');
110 Log::trace(
'No processes found or unable to retrieve process list');
115 $this->
writeLog(
'List bins modules:');
116 foreach ($bearsamppBins->getAll() as $module) {
117 if (!$module->isEnable()) {
119 Log::trace(
'Bin module ' . $module->getName() .
' is disabled');
121 $this->
writeLog(
'-> ' . $module->getName() .
': ' . $module->getVersion() .
' (' . $module->getRelease() .
')');
122 Log::trace(
'Bin module ' . $module->getName() .
': ' . $module->getVersion() .
' (' . $module->getRelease() .
')');
127 $this->
writeLog(
'List tools modules:');
128 foreach ($bearsamppTools->getAll() as $module) {
129 if (!$module->isEnable()) {
131 Log::trace(
'Tool module ' . $module->getName() .
' is disabled');
133 $this->
writeLog(
'-> ' . $module->getName() .
': ' . $module->getVersion() .
' (' . $module->getRelease() .
')');
134 Log::trace(
'Tool module ' . $module->getName() .
': ' . $module->getVersion() .
' (' . $module->getRelease() .
')');
139 $this->
writeLog(
'List apps modules:');
140 foreach ($bearsamppApps->getAll() as $module) {
141 if (!$module->isEnable()) {
143 Log::trace(
'App module ' . $module->getName() .
' is disabled');
145 $this->
writeLog(
'-> ' . $module->getName() .
': ' . $module->getVersion() .
' (' . $module->getRelease() .
')');
146 Log::trace(
'App module ' . $module->getName() .
': ' . $module->getVersion() .
' (' . $module->getRelease() .
')');
155 Log::trace(
'Preparing application - refreshing hostname');
158 Log::trace(
'Checking launch startup settings');
193 Log::trace(
'Checking System PATH registry key');
209 if (!$this->restart && empty($this->error)) {
210 Log::trace(
'Startup completed successfully - refreshing Git repositories');
213 $this->
writeLog(
'Started in ' . $startupTime .
's');
214 Log::trace(
'Application started successfully in ' . $startupTime .
' seconds');
219 $minutes = floor($startupTime / 60);
220 $seconds = fmod($startupTime, 60);
221 $formattedTime = sprintf(
'%d:%05.2f', $minutes, $seconds);
222 Log::trace(
'=== TOTAL STARTUP TIME: ' . $formattedTime .
' ===');
225 Log::trace(
'Startup issues detected - incrementing progress bar');
226 $this->splash->incrProgressBar(2);
229 if ($this->restart) {
230 Log::trace(
'Restart required - preparing to restart application');
232 $this->splash->setTextLoading(
239 Log::trace(
'Deleting all services before restart');
245 Log::trace(
'Setting execution action to RESTART');
249 if (!empty($this->error)) {
250 Log::trace(
'Errors occurred during startup: ' . $this->error);
251 $this->
writeLog(
'Error: ' . $this->error);
259 Log::trace(
'Waiting for loading window to initialize');
268 $bearsamppWinbinder->destroyWindow($window);
269 $bearsamppWinbinder->reset();
275 Log::trace(
'Exiting startup process cleanly');
290 $this->splash->incrProgressBar();
293 if (!is_dir($archivesPath)) {
294 Log::trace(
"Creating archives directory: " . $archivesPath);
295 mkdir($archivesPath, 0777,
true);
299 $date = date(
'Y-m-d-His', time());
300 $archiveLogsPath = $archivesPath .
'/' . $date;
301 $archiveScriptsPath = $archiveLogsPath .
'/scripts';
304 Log::trace(
"Creating archive directories for current rotation");
305 if (!is_dir($archiveLogsPath)) {
306 Log::trace(
"Creating logs archive directory: " . $archiveLogsPath);
307 mkdir($archiveLogsPath, 0777,
true);
309 Log::trace(
"Logs archive directory already exists: " . $archiveLogsPath);
312 if (!is_dir($archiveScriptsPath)) {
313 Log::trace(
"Creating scripts archive directory: " . $archiveScriptsPath);
314 mkdir($archiveScriptsPath, 0777,
true);
316 Log::trace(
"Scripts archive directory already exists: " . $archiveScriptsPath);
322 $handle = @opendir($archivesPath);
324 Log::trace(
"Failed to open archives directory: " . $archivesPath);
328 while (
false !== ($file = readdir($handle))) {
329 if ($file ==
'.' || $file ==
'..') {
332 $archives[] = $archivesPath .
'/' . $file;
336 Log::trace(
"Found " . count($archives) .
" existing archives");
341 Log::trace(
"Removing " . $total .
" old archives");
342 for ($i = 0; $i < $total; $i++) {
343 Log::trace(
"Deleting old archive: " . $archives[$i]);
349 $isFileLocked =
function($filePath) {
350 if (!file_exists($filePath)) {
354 $handle = @fopen($filePath,
'r+');
355 if ($handle ===
false) {
356 Log::trace(
"File appears to be locked: " . $filePath);
367 $handle = @opendir($srcPath);
369 Log::trace(
"Failed to open logs directory: " . $srcPath);
376 while (
false !== ($file = readdir($handle))) {
377 if ($file ==
'.' || $file ==
'..' || is_dir($srcPath .
'/' . $file)) {
381 $sourceFile = $srcPath .
'/' . $file;
382 $destFile = $archiveLogsPath .
'/' . $file;
385 if ($isFileLocked($sourceFile)) {
386 Log::trace(
"Skipping locked log file: " . $file);
392 if (copy($sourceFile, $destFile)) {
397 Log::trace(
"Failed to copy log file: " . $file);
399 }
catch (Exception $e) {
401 Log::trace(
"Exception copying log file " . $file .
": " . $e->getMessage());
405 Log::trace(
"Logs archived: " . $logsCopied .
" copied, " . $logsSkipped .
" skipped");
410 $handle = @opendir($srcPath);
412 Log::trace(
"Failed to open tmp directory: " . $srcPath);
419 while (
false !== ($file = readdir($handle))) {
420 if ($file ==
'.' || $file ==
'..' || is_dir($srcPath .
'/' . $file)) {
424 $sourceFile = $srcPath .
'/' . $file;
425 $destFile = $archiveScriptsPath .
'/' . $file;
428 if ($isFileLocked($sourceFile)) {
429 Log::trace(
"Skipping locked script file: " . $file);
435 if (copy($sourceFile, $destFile)) {
440 Log::trace(
"Failed to copy script file: " . $file);
442 }
catch (Exception $e) {
444 Log::trace(
"Exception copying script file " . $file .
": " . $e->getMessage());
448 Log::trace(
"Scripts archived: " . $scriptsCopied .
" copied, " . $scriptsSkipped .
" skipped");
453 $handle = @opendir($logsPath);
455 Log::trace(
"Failed to open logs directory for purging: " . $logsPath);
460 $logsPurgeSkipped = 0;
462 while (
false !== ($file = readdir($handle))) {
463 if ($file ==
'.' || $file ==
'..' || $file ==
'archives' || $file ==
'.gitignore' || is_dir($logsPath .
'/' . $file)) {
467 $filePath = $logsPath .
'/' . $file;
470 if ($isFileLocked($filePath)) {
471 Log::trace(
"Skipping locked log file during purge: " . $file);
477 if (file_exists($filePath) && unlink($filePath)) {
482 Log::trace(
"Failed to purge log file: " . $file);
484 }
catch (Exception $e) {
486 Log::trace(
"Exception purging log file " . $file .
": " . $e->getMessage());
490 Log::trace(
"Logs purged: " . $logsDeleted .
" deleted, " . $logsPurgeSkipped .
" skipped");
503 $this->splash->incrProgressBar();
505 $this->
writeLog(
'Clear tmp folders' );
506 Util::clearFolder( $bearsamppRoot->getTmpPath(), array(
'cachegrind',
'composer',
'openssl',
'mailpit',
'xlight',
'npm-cache',
'pip',
'opcache',
'.gitignore') );
510 $opcachePath =
$bearsamppRoot->getTmpPath() . DIRECTORY_SEPARATOR .
'opcache';
512 if (!is_dir($opcachePath)) {
513 $this->
writeLog(
'Creating opcache directory: ' . $opcachePath);
514 if (!@mkdir($opcachePath, 0755,
true) && !is_dir($opcachePath)) {
515 $this->
writeLog(
'Failed to create opcache directory: ' . $opcachePath);
520 if (!is_writable($opcachePath)) {
521 $this->
writeLog(
'Opcache directory is not writable: ' . $opcachePath);
532 $this->
writeLog(
'Clean old behaviors' );
535 $this->splash->incrProgressBar();
538 $bearsamppRegistry->deleteValue(
540 'SOFTWARE\Microsoft\Windows\CurrentVersion\Run',
553 $this->splash->incrProgressBar();
566 if ( !empty( $procsKilled ) ) {
568 $procsKilledSort = array();
569 foreach ( $procsKilled as
$proc ) {
571 $procsKilledSort[] =
'-> ' . basename( $unixExePath ) .
' (PID ' .
$proc[
Win32Ps::PROCESS_ID] .
') in ' . $unixExePath;
573 sort( $procsKilledSort );
574 foreach ( $procsKilledSort as
$proc ) {
588 $this->splash->incrProgressBar();
589 $this->
writeLog(
'Refresh hostname' );
601 $this->
writeLog(
'Check launch startup' );
603 if ( $bearsamppConfig->isLaunchStartup() ) {
619 $this->splash->incrProgressBar();
623 if ( empty( $currentBrowser ) || !file_exists( $currentBrowser ) ) {
636 $this->splash->incrProgressBar();
639 $this->
writeLog( sprintf(
'OS: %s', $os ) );
650 $this->splash->incrProgressBar();
651 $this->
writeLog(
'Refresh aliases' );
664 $this->splash->incrProgressBar();
665 $this->
writeLog(
'Refresh vhosts' );
678 $this->splash->incrProgressBar();
680 $this->
writeLog(
'Last path: ' . $bearsamppCore->getLastPathContent() );
693 $this->splash->incrProgressBar();
699 if ($lastPath === $currentPath) {
700 Log::debug(
'Path unchanged, skipping file scan (performance optimization)');
701 Log::trace(
'Last path: "' . $lastPath .
'" matches current path: "' . $currentPath .
'"');
702 $this->filesToScan = [];
703 $this->
writeLog(
'Files to scan: 0 (path unchanged - scan skipped)');
706 $this->
writeLog(
'Performance: File scan skipped, saving 3-8 seconds');
711 Log::debug(
'Path changed, performing full file scan');
712 Log::trace(
'Last path: "' . $lastPath .
'" differs from current path: "' . $currentPath .
'"');
713 $this->
writeLog(
'Path changed detected - performing full scan');
719 $this->
writeLog(
'Files to scan: ' . count($this->filesToScan) .
' (scanned in ' . $scanDuration .
's)');
730 $this->splash->incrProgressBar();
733 $this->
writeLog(
'Nb files changed: ' .
$result[
'countChangedFiles'] );
734 $this->
writeLog(
'Nb occurences changed: ' .
$result[
'countChangedOcc'] );
744 file_put_contents(
$bearsamppCore->getLastPath(), $this->rootPath );
745 $this->
writeLog(
'Save current path: ' . $this->rootPath );
756 $this->splash->incrProgressBar();
760 $this->
writeLog(
'Current app path reg key: ' . $currentAppPathRegKey );
761 $this->
writeLog(
'Gen app path reg key: ' . $genAppPathRegKey );
762 if ( $currentAppPathRegKey != $genAppPathRegKey ) {
764 if ( !empty( $this->error ) ) {
765 $this->error .= PHP_EOL . PHP_EOL;
768 $this->error .= PHP_EOL . $bearsamppRegistry->getLatestError();
771 $this->
writeLog(
'Need restart: checkPathRegKey' );
772 $this->restart =
true;
789 $this->splash->incrProgressBar();
793 $this->
writeLog(
'Current app bins reg key: ' . $currentAppBinsRegKey );
794 $this->
writeLog(
'Gen app bins reg key: ' . $genAppBinsRegKey );
795 if ( $currentAppBinsRegKey != $genAppBinsRegKey ) {
797 if ( !empty( $this->error ) ) {
798 $this->error .= PHP_EOL . PHP_EOL;
801 $this->error .= PHP_EOL . $bearsamppRegistry->getLatestError();
804 $this->
writeLog(
'Need restart: checkBinsRegKey' );
805 $this->restart =
true;
822 $this->splash->incrProgressBar();
825 $this->
writeLog(
'Current system PATH: ' . $currentSysPathRegKey );
830 $this->
writeLog(
'New system PATH: ' . $newSysPathRegKey );
832 if ( $currentSysPathRegKey != $newSysPathRegKey ) {
834 if ( !empty( $this->error ) ) {
835 $this->error .= PHP_EOL . PHP_EOL;
838 $this->error .= PHP_EOL . $bearsamppRegistry->getLatestError();
841 $this->
writeLog(
'Need restart: checkSystemPathRegKey' );
842 $this->restart =
true;
846 $this->
writeLog(
'Refresh system PATH: ' . $currentSysPathRegKey );
861 $this->splash->incrProgressBar();
864 $bearsamppBins->update();
865 $bearsamppTools->update();
866 $bearsamppApps->update();
877 $this->splash->incrProgressBar();
878 if ( !$bearsamppOpenSsl->existsCrt(
'localhost' ) ) {
880 $bearsamppOpenSsl->createCrt(
'localhost' );
896 Log::trace(
'Starting installServices method');
898 if (!$this->restart) {
899 Log::trace(
'Normal startup mode - processing services');
907 Log::trace(
'Restart mode - skipping service installation');
908 $this->splash->incrProgressBar(self::GAUGE_SERVICES * count(
$bearsamppBins->getServices()));
911 Log::trace(
'Completed installServices method');
924 Log::trace(
'Starting sequential service installation');
928 $servicesToStart = [];
932 $currentServiceIndex = 0;
935 $currentServiceIndex++;
942 if ($serviceInfo[
'restart']) {
943 $this->
writeLog(
'Need restart: installService ' . $serviceInfo[
'bin']->getName());
944 Log::trace(
'Restart required for service: ' . $serviceInfo[
'bin']->getName());
945 $this->restart =
true;
947 $this->splash->incrProgressBar(self::GAUGE_SERVICES - 1);
951 if (!empty($serviceInfo[
'error'])) {
952 $serviceErrors[$sName] = $serviceInfo;
954 $this->splash->incrProgressBar(self::GAUGE_SERVICES - 1);
958 if ($serviceInfo[
'needsStart']) {
959 $servicesToStart[$sName] = $serviceInfo;
963 $this->splash->incrProgressBar(self::GAUGE_SERVICES - 1);
968 if (!empty($servicesToStart)) {
969 Log::trace(
'Starting ' . count($servicesToStart) .
' services sequentially');
972 $totalServices = count($servicesToStart);
974 foreach ($servicesToStart as $sName => $serviceInfo) {
976 $name = $serviceInfo[
'name'];
977 $service = $serviceInfo[
'service'];
980 $this->splash->setTextLoading(
'Starting ' . $name .
' (' . $serviceCount .
'/' . $totalServices .
')');
981 $this->splash->incrProgressBar();
987 $success = $service->start();
992 $this->
writeLog($name .
' service started in ' . $duration .
's');
993 Log::trace(
'Service ' . $name .
' started successfully in ' . $duration .
' seconds');
996 $this->splash->setTextLoading($name .
' started successfully');
998 $error = $service->getError();
1000 $error =
'Failed to start service';
1003 $serviceErrors[$sName] = $serviceInfo;
1004 $serviceErrors[$sName][
'error'] =
$error;
1008 if (!empty($serviceInfo[
'syntaxCheckCmd'])) {
1010 $cmdSyntaxCheck = $serviceInfo[
'bin']->getCmdLineOutput($serviceInfo[
'syntaxCheckCmd']);
1011 if (!$cmdSyntaxCheck[
'syntaxOk']) {
1012 $serviceErrors[$sName][
'error'] .= PHP_EOL .
'Syntax error: ' . $cmdSyntaxCheck[
'content'];
1014 }
catch (\Exception $e) {
1021 $this->splash->incrProgressBar(self::GAUGE_SERVICES - 2);
1026 foreach ($serviceErrors as $sName => $serviceInfo) {
1027 if (!empty($serviceInfo[
'error'])) {
1028 Log::trace(
'Service error occurred for ' . $sName .
': ' . $serviceInfo[
'error']);
1029 if (!empty($this->error)) {
1030 $this->error .= PHP_EOL . PHP_EOL;
1037 $this->
writeLog(
'Service installation completed in ' . $installDuration .
's');
1038 Log::trace(
'Service installation completed in ' . $installDuration .
' seconds');
1056 'service' => $service,
1060 'syntaxCheckCmd' =>
null,
1063 'needsStart' =>
false,
1068 $syntaxCheckCmd =
null;
1088 if (!file_exists($bin->getDataDir()) || count(glob($bin->getDataDir() .
'/*')) === 0) {
1089 Log::trace(
'Pre-initializing MySQL data directory');
1104 $name = $bin->getName() .
' ' . $bin->getVersion() .
' (' . $service->getName() .
')';
1106 $serviceInfo[
'bin'] = $bin;
1107 $serviceInfo[
'name'] = $name;
1108 $serviceInfo[
'port'] =
$port;
1109 $serviceInfo[
'syntaxCheckCmd'] = $syntaxCheckCmd;
1112 if ($currentIndex > 0 && $totalCount > 0) {
1113 $this->splash->setTextLoading(
'Checking ' . $bin->getName() .
' service (' . $currentIndex .
'/' . $totalCount .
')');
1115 $this->splash->incrProgressBar();
1118 $serviceAlreadyInstalled =
false;
1119 $serviceToRemove =
false;
1125 if ($serviceInfos ===
false && $service->isInstalled()) {
1126 Log::trace(
'MySQL service appears to be hanging, forcing restart');
1129 $serviceToRemove =
true;
1133 $serviceInfos = $service->infos();
1134 }
catch (\Exception $e) {
1135 Log::trace(
"Exception during service check: " . $e->getMessage());
1136 $serviceInfos =
false;
1137 }
catch (\Throwable $e) {
1138 Log::trace(
"Throwable during service check: " . $e->getMessage());
1139 $serviceInfos =
false;
1143 if ($serviceInfos !==
false) {
1144 $serviceAlreadyInstalled =
true;
1145 $this->
writeLog($name .
' service already installed');
1149 $serviceGenPathName = trim(str_replace(
'"',
'', $service->getBinPath()));
1151 $serviceVbsPathName = trim(str_replace(
'"',
'', $installedPathParts[0]));
1153 $serviceGenPathName = trim(str_replace(
'"',
'', $service->getBinPath() . ($service->getParams() ?
' ' . $service->getParams() :
'')));
1157 $normalizedGenPath = preg_replace(
'/\s+/',
' ', $serviceGenPathName);
1158 $normalizedVbsPath = preg_replace(
'/\s+/',
' ', $serviceVbsPathName);
1160 if ($normalizedGenPath !== $normalizedVbsPath && $serviceGenPathName != $serviceVbsPathName) {
1161 $serviceToRemove =
true;
1162 $this->
writeLog($name .
' service has to be removed');
1167 if ($serviceToRemove) {
1168 if (!$service->delete()) {
1169 $serviceInfo[
'restart'] =
true;
1170 return $serviceInfo;
1176 if ($isPortInUse !==
false) {
1178 if ($service->isRunning()) {
1180 $this->
writeLog($name .
' service already running on port ' .
$port);
1181 Log::trace(
'Service ' . $name .
' already running - no need to start');
1182 $serviceInfo[
'needsStart'] =
false;
1183 return $serviceInfo;
1188 return $serviceInfo;
1192 if (!$serviceAlreadyInstalled || $serviceToRemove) {
1193 if (!$service->create()) {
1195 return $serviceInfo;
1199 $serviceInfo[
'needsStart'] =
true;
1200 return $serviceInfo;
1211 $this->splash->incrProgressBar();
1212 if ( $bearsamppTools->getGit()->isScanStartup() ) {
1215 $repos = $bearsamppTools->getGit()->findRepos(
false );
1216 $this->
writeLog(
'Update GIT repos: ' . count( $repos ) .
' found' );
1229 Log::trace(
'Starting specialized Apache service check with timeout protection');
1232 $serviceCheckStartTime = microtime(
true);
1233 $serviceCheckTimeout = 10;
1237 $serviceInfos =
false;
1240 $serviceList = Win32Service::getServices();
1241 if (is_array($serviceList) && isset($serviceList[$service->getName()])) {
1242 Log::trace(
'Apache service found in service list, getting details');
1246 $serviceInfos = $service->infos();
1249 if (microtime(
true) - $serviceCheckStartTime > $serviceCheckTimeout) {
1250 Log::trace(
"Apache service check timeout exceeded, assuming service needs reinstall");
1254 Log::trace(
'Apache service not found in service list');
1258 return $serviceInfos;
1259 }
catch (\Exception $e) {
1260 Log::trace(
"Exception during Apache service check: " . $e->getMessage());
1262 }
catch (\Throwable $e) {
1263 Log::trace(
"Throwable during Apache service check: " . $e->getMessage());
1278 Log::trace(
'Starting specialized MySQL service check with timeout protection');
1281 $serviceCheckStartTime = microtime(
true);
1282 $serviceCheckTimeout = 8;
1286 $serviceInfos =
false;
1289 $serviceList = Win32Service::getServices();
1290 if (is_array($serviceList) && isset($serviceList[$service->getName()])) {
1291 Log::trace(
'MySQL service found in service list, getting details');
1294 $serviceInfos = $service->infos();
1297 if (microtime(
true) - $serviceCheckStartTime > $serviceCheckTimeout) {
1298 Log::trace(
"MySQL service check timeout exceeded, assuming service needs reinstall");
1302 Log::trace(
'MySQL service not found in service list');
1306 return $serviceInfos;
1307 }
catch (\Exception $e) {
1308 Log::trace(
"Exception during MySQL service check: " . $e->getMessage());
1310 }
catch (\Throwable $e) {
1311 Log::trace(
"Throwable during MySQL service check: " . $e->getMessage());
prepareService($sName, $service, $bearsamppBins, $bearsamppLang, $currentIndex=0, $totalCount=0)
installServicesSequential($bearsamppBins, $bearsamppLang)
checkMySQLServiceWithTimeout($service, $bin)
checkApacheServiceWithTimeout($service)
processWindow($window, $id, $ctrl, $param1, $param2)
const STARTUP_STARTING_TEXT
const STARTUP_REFRESH_GIT_REPOS_TEXT
const STARTUP_SERVICE_ERROR
const STARTUP_CHECK_PATH_TEXT
const STARTUP_SCAN_FOLDERS_TEXT
const STARTUP_CHANGE_PATH_TEXT
const STARTUP_PREPARE_RESTART_TEXT
const STARTUP_ROTATION_LOGS_TEXT
const STARTUP_SERVICE_CREATE_ERROR
const STARTUP_SERVICE_PORT_ERROR
const STARTUP_GEN_SSL_CRT_TEXT
const STARTUP_ERROR_TITLE
const STARTUP_CLEAN_OLD_BEHAVIORS_TEXT
const STARTUP_REFRESH_ALIAS_TEXT
const STARTUP_REGISTRY_ERROR_TEXT
const STARTUP_KILL_OLD_PROCS_TEXT
const STARTUP_CHECK_BROWSER_TEXT
const STARTUP_REFRESH_HOSTNAME_TEXT
const STARTUP_REGISTRY_TEXT
const STARTUP_UPDATE_CONFIG_TEXT
const STARTUP_REFRESH_VHOSTS_TEXT
const STARTUP_CLEAN_TMP_TEXT
static info($data, $file=null)
static debug($data, $file=null)
static trace($data, $file=null)
static disableLaunchStartup()
static deleteFolder($path)
static setAppPathRegKey($value)
static getAppBinsRegKey($fromRegistry=true)
static getAppPathRegKey()
static changePath($filesToScan, $rootPath=null)
static isPortInUse($port)
static getFilesToScan($path=null, $useCache=true, $forceRefresh=false)
static clearFolder($path, $exclude=array())
static enableLaunchStartup()
static setSysPathRegKey($value)
static getSysPathRegKey()
static setAppBinsRegKey($value)
static formatWindowsPath($path)
static formatUnixPath($path)
static getDefaultBrowser()
static killBins($refreshProcs=false)