Merge branch 'master' into electron-17

This commit is contained in:
Vikas Shashidhar 2017-06-05 16:27:44 +05:30 committed by GitHub
commit 22fff88ded
50 changed files with 893 additions and 246 deletions

View File

@ -1,3 +0,0 @@
{
"presets": ["es2015"]
}

3
.gitignore vendored
View File

@ -14,7 +14,6 @@ DerivedData/
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata/
*.moved-aside
*.xccheckout
*.xcscmblueprint
@ -23,3 +22,5 @@ xcuserdata/
*.dSYM.zip
*.dSYM
installer/mac/build/
installer/mac/SymphonySettingsPlugin/SymphonySettingsPlugin.xcodeproj/xcuserdata
installer/mac/SymphonySettingsPlugin/SymphonySettingsPlugin.xcodeproj/project.xcworkspace/xcuserdata

View File

@ -1 +0,0 @@
The .aip file located here is produced by 'Advanced Installer' (http://www.advancedinstaller.com/). Running this file through advanced installer will generate a Microsoft Windows MSI file.

View File

@ -3,7 +3,7 @@
<plist version="1.0">
<dict>
<key>BuildMachineOSBuild</key>
<string>16E195</string>
<string>16F73</string>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>

View File

@ -6,7 +6,7 @@
<dict>
<key>Resources/Base.lproj/MyInstallerPane.nib</key>
<data>
3HG8UEw6WFkbwFZjfhIU/OzjLks=
G7x4W+5j1tDqlKgoKCr5helllTU=
</data>
<key>Resources/InstallerSections.plist</key>
<data>
@ -37,7 +37,7 @@
<dict>
<key>hash2</key>
<data>
WevXKKGDjV20uPQvqf0GCvSehTCXdBwwHhIijv6ffPg=
5C6LFVcm159sGwREu78C3xnjlAHRN9oglcYR3P6rmhM=
</data>
</dict>
<key>Resources/InstallerSections.plist</key>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="12120" systemVersion="16E195" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="12120" systemVersion="16F73" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="12120"/>
@ -19,6 +19,7 @@
<outlet property="contentView" destination="TUK-W2-vig" id="gTd-A7-dof"/>
<outlet property="minimizeOnCloseCheckBox" destination="XPe-yO-v9Y" id="ewr-3C-eNJ"/>
<outlet property="parentSection" destination="-2" id="FB7-UV-e8k"/>
<outlet property="podUrlTextBox" destination="uwa-xi-M5X" id="vLY-gf-Cu7"/>
</connections>
</customObject>
<customView id="TUK-W2-vig" userLabel="View">
@ -26,34 +27,34 @@
<autoresizingMask key="autoresizingMask"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="kEO-Mr-GRW">
<rect key="frame" x="18" y="201" width="98" height="28"/>
<rect key="frame" x="8" y="186" width="182" height="43"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Pod Url" id="iRN-3c-tUz">
<textFieldCell key="cell" sendsActionOnEndEditing="YES" title="Pod Url (This is where Symphony will be installed)" id="iRN-3c-tUz">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="iAw-NP-Tbm">
<rect key="frame" x="18" y="150" width="114" height="28"/>
<rect key="frame" x="8" y="140" width="182" height="28"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Minimize on Close" id="z1k-Zj-Big">
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Minimize Symphony on Close" id="z1k-Zj-Big">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="KOx-3P-dPz">
<rect key="frame" x="18" y="99" width="98" height="28"/>
<rect key="frame" x="8" y="94" width="146" height="28"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Auto Launch" id="9id-I6-Bxu">
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Auto-launch Symphony" id="9id-I6-Bxu">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<button fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="XPe-yO-v9Y">
<rect key="frame" x="159" y="160" width="22" height="18"/>
<rect key="frame" x="204" y="150" width="22" height="18"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="check" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="uvu-EE-3sp">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
@ -61,7 +62,7 @@
</buttonCell>
</button>
<button fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="zJM-2d-YYz">
<rect key="frame" x="159" y="111" width="22" height="18"/>
<rect key="frame" x="204" y="104" width="22" height="18"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="check" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="o5T-Og-ooq">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
@ -69,16 +70,13 @@
</buttonCell>
</button>
<textField verticalHuggingPriority="750" fixedFrame="YES" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="uwa-xi-M5X">
<rect key="frame" x="161" y="207" width="237" height="22"/>
<rect key="frame" x="206" y="197" width="192" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" title="my.symphony.com" placeholderString="Ex: my.symphony.com" drawsBackground="YES" id="5g9-ba-etY">
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" alignment="left" title="my.symphony.com" placeholderString="Ex: my.symphony.com" drawsBackground="YES" id="5g9-ba-etY">
<font key="font" metaFont="system"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<action selector="capturePodUrl:" target="Qsn-FY-4qK" id="Fr4-tm-ORc"/>
</connections>
</textField>
</subviews>
</customView>

View File

@ -11,5 +11,6 @@
@property (weak) IBOutlet NSButton *minimizeOnCloseCheckBox;
@property (weak) IBOutlet NSButton *autoLaunchCheckBox;
@property (weak) IBOutlet NSTextField *podUrlTextBox;
@end

View File

@ -14,13 +14,12 @@
return [[NSBundle bundleForClass:[self class]] localizedStringForKey:@"PaneTitle" value:nil table:nil];
}
- (IBAction)capturePodUrl:(NSTextField *)sender {
- (void)willExitPane:(InstallerSectionDirection)dir {
// Set the default protocol to https
NSString *protocol = @"https://";
// Capture the pod url entered by the user
NSString *podUrl = sender.stringValue;
NSString *podUrl = [_podUrlTextBox stringValue];
// If the pod url is empty, by default, set it to my.symphony.com
if ([podUrl length] == 0) {

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

11
installer/mac/intro.html Normal file
View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<title>Welcome to the Symphony Installer</title>
</head>
<body>
<br/>
<br/>
<p style="font-size: 13px; font-family: Sans-Serif; color: #000">&nbsp;&nbsp;&nbsp;We'll walk you through the steps to install Symphony</p>
</body>
</html>

View File

@ -16,5 +16,27 @@ sed -i "" -E "s#\"url\" ?: ?\".*\"#\"url\"\: \"$pod_url\"#g" $newPath
sed -i "" -E "s#\"minimizeOnClose\" ?: ?([Tt][Rr][Uu][Ee]|[Ff][Aa][Ll][Ss][Ee])#\"minimizeOnClose\":\ $minimize_on_close#g" $newPath
sed -i "" -E "s#\"launchOnStartup\" ?: ?([Tt][Rr][Uu][Ee]|[Ff][Aa][Ll][Ss][Ee])#\"launchOnStartup\":\ $launch_on_startup#g" $newPath
## Add app to login items
if [ $launch_on_startup == true ]; then
cat > ~/Library/LaunchAgents/com.symphony.symphony-desktop.agent.plist << EOT
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.symphony.symphony-desktop.agent</string>
<key>ProgramArguments</key>
<array>
<string>$installPath/Symphony.app/Contents/MacOS/Symphony</string>
</array>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>
EOT
else
launchctl unload ~/Library/LaunchAgents/com.symphony.symphony-desktop.agent.plist
fi
## Remove the temp settings file created ##
rm -f $tempFilePath

View File

@ -494,12 +494,12 @@
<key>BACKGROUND_PATH</key>
<dict>
<key>PATH</key>
<string>/Users/vishwas/Desktop/background.jpg</string>
<string>background.png</string>
<key>PATH_TYPE</key>
<integer>0</integer>
<integer>3</integer>
</dict>
<key>CUSTOM</key>
<integer>0</integer>
<integer>1</integer>
<key>SCALING</key>
<integer>1</integer>
</dict>
@ -568,14 +568,6 @@
<key>LIST_TITLE_KEY</key>
<string>InstallerSectionTitle</string>
</dict>
<dict>
<key>ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS</key>
<string>ICPresentationViewDestinationSelectController</string>
<key>INSTALLER_PLUGIN</key>
<string>TargetSelect</string>
<key>LIST_TITLE_KEY</key>
<string>InstallerSectionTitle</string>
</dict>
<dict>
<key>ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS</key>
<string>ICPresentationViewInstallerPluginController</string>
@ -584,9 +576,17 @@
<key>PATH</key>
<string>SymphonySettingsPlugin.bundle</string>
<key>PATH_TYPE</key>
<integer>1</integer>
<integer>3</integer>
</dict>
</dict>
<dict>
<key>ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS</key>
<string>ICPresentationViewDestinationSelectController</string>
<key>INSTALLER_PLUGIN</key>
<string>TargetSelect</string>
<key>LIST_TITLE_KEY</key>
<string>InstallerSectionTitle</string>
</dict>
<dict>
<key>ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS</key>
<string>ICPresentationViewInstallationTypeController</string>
@ -615,7 +615,19 @@
<key>INTRODUCTION</key>
<dict>
<key>LOCALIZATIONS</key>
<array/>
<array>
<dict>
<key>LANGUAGE</key>
<string>English</string>
<key>VALUE</key>
<dict>
<key>PATH</key>
<string>intro.html</string>
<key>PATH_TYPE</key>
<integer>3</integer>
</dict>
</dict>
</array>
</dict>
<key>LICENSE</key>
<dict>

View File

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 36 KiB

2
installer/win/README.md Normal file
View File

@ -0,0 +1,2 @@
The .aip file located here is produced by 'Advanced Installer' (http://www.advancedinstaller.com/).
Running this file through advanced installer will generate a Microsoft Windows MSI file.

View File

@ -73,81 +73,81 @@
<ATTRIBUTE name="CurrentFeature" value="MainFeature"/>
</COMPONENT>
<COMPONENT cid="caphyon.advinst.msicomp.MsiFilesComponent">
<ROW File="LICENSE.electron.txt" Component_="blink_image_resources_200_percent.pak" FileName="LICENS~1.TXT|LICENSE.electron.txt" Attributes="0" SourcePath="..\dist\win-unpacked\LICENSE.electron.txt" SelfReg="false" NextFile="LICENSES.chromium.html"/>
<ROW File="LICENSES.chromium.html" Component_="blink_image_resources_200_percent.pak" FileName="LICENS~1.HTM|LICENSES.chromium.html" Attributes="0" SourcePath="..\dist\win-unpacked\LICENSES.chromium.html" SelfReg="false" NextFile="natives_blob.bin"/>
<ROW File="ScreenSnippet.exe" Component_="ScreenSnippet.exe" FileName="SCREEN~1.EXE|ScreenSnippet.exe" Attributes="0" SourcePath="..\node_modules\screen-snippet\bin\Release\ScreenSnippet.exe" SelfReg="false" DigSign="true"/>
<ROW File="Symphony.config_1" Component_="Symphony.config" FileName="SYMPHO~1.CON|Symphony.config" Attributes="0" SourcePath="..\dist\win-unpacked\config\Symphony.config" SelfReg="false" NextFile="ScreenSnippet.exe"/>
<ROW File="Symphony.exe" Component_="Symphony.exe" FileName="Symphony.exe" Attributes="0" SourcePath="..\dist\win-unpacked\Symphony.exe" SelfReg="false" NextFile="ui_resources_200_percent.pak" DigSign="true"/>
<ROW File="am.pak" Component_="am.pak" FileName="am.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\am.pak" SelfReg="false" NextFile="ar.pak"/>
<ROW File="app.asar" Component_="appupdate.yml" FileName="APP~1.ASA|app.asar" Attributes="0" SourcePath="..\dist\win-unpacked\resources\app.asar" SelfReg="false" NextFile="electron.asar"/>
<ROW File="appupdate.yml" Component_="appupdate.yml" FileName="APP-UP~1.YML|app-update.yml" Attributes="0" SourcePath="..\dist\win-unpacked\resources\app-update.yml" SelfReg="false" NextFile="app.asar"/>
<ROW File="ar.pak" Component_="am.pak" FileName="ar.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\ar.pak" SelfReg="false" NextFile="bg.pak"/>
<ROW File="bg.pak" Component_="am.pak" FileName="bg.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\bg.pak" SelfReg="false" NextFile="bn.pak"/>
<ROW File="blink_image_resources_200_percent.pak" Component_="blink_image_resources_200_percent.pak" FileName="BLINK_~1.PAK|blink_image_resources_200_percent.pak" Attributes="0" SourcePath="..\dist\win-unpacked\blink_image_resources_200_percent.pak" SelfReg="false" NextFile="content_resources_200_percent.pak"/>
<ROW File="bn.pak" Component_="am.pak" FileName="bn.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\bn.pak" SelfReg="false" NextFile="ca.pak"/>
<ROW File="ca.pak" Component_="am.pak" FileName="ca.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\ca.pak" SelfReg="false" NextFile="cs.pak"/>
<ROW File="content_resources_200_percent.pak" Component_="blink_image_resources_200_percent.pak" FileName="CONTEN~1.PAK|content_resources_200_percent.pak" Attributes="0" SourcePath="..\dist\win-unpacked\content_resources_200_percent.pak" SelfReg="false" NextFile="content_shell.pak"/>
<ROW File="content_shell.pak" Component_="blink_image_resources_200_percent.pak" FileName="CONTEN~2.PAK|content_shell.pak" Attributes="0" SourcePath="..\dist\win-unpacked\content_shell.pak" SelfReg="false" NextFile="d3dcompiler_47.dll"/>
<ROW File="cs.pak" Component_="am.pak" FileName="cs.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\cs.pak" SelfReg="false" NextFile="da.pak"/>
<ROW File="d3dcompiler_47.dll" Component_="d3dcompiler_47.dll" FileName="D3DCOM~1.DLL|d3dcompiler_47.dll" Attributes="0" SourcePath="..\dist\win-unpacked\d3dcompiler_47.dll" SelfReg="false" NextFile="ffmpeg.dll"/>
<ROW File="da.pak" Component_="am.pak" FileName="da.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\da.pak" SelfReg="false" NextFile="de.pak"/>
<ROW File="de.pak" Component_="am.pak" FileName="de.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\de.pak" SelfReg="false" NextFile="el.pak"/>
<ROW File="el.pak" Component_="am.pak" FileName="el.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\el.pak" SelfReg="false" NextFile="enGB.pak"/>
<ROW File="electron.asar" Component_="appupdate.yml" FileName="ELECTR~1.ASA|electron.asar" Attributes="0" SourcePath="..\dist\win-unpacked\resources\electron.asar" SelfReg="false" NextFile="Symphony.config_1"/>
<ROW File="enGB.pak" Component_="am.pak" FileName="en-GB.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\en-GB.pak" SelfReg="false" NextFile="enUS.pak"/>
<ROW File="enUS.pak" Component_="am.pak" FileName="en-US.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\en-US.pak" SelfReg="false" NextFile="es.pak"/>
<ROW File="es.pak" Component_="am.pak" FileName="es.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\es.pak" SelfReg="false" NextFile="es419.pak"/>
<ROW File="es419.pak" Component_="am.pak" FileName="es-419.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\es-419.pak" SelfReg="false" NextFile="et.pak"/>
<ROW File="et.pak" Component_="am.pak" FileName="et.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\et.pak" SelfReg="false" NextFile="fa.pak"/>
<ROW File="fa.pak" Component_="am.pak" FileName="fa.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\fa.pak" SelfReg="false" NextFile="fakebidi.pak"/>
<ROW File="fakebidi.pak" Component_="am.pak" FileName="FAKE-B~1.PAK|fake-bidi.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\fake-bidi.pak" SelfReg="false" NextFile="fi.pak"/>
<ROW File="ffmpeg.dll" Component_="ffmpeg.dll" FileName="ffmpeg.dll" Attributes="0" SourcePath="..\dist\win-unpacked\ffmpeg.dll" SelfReg="false" NextFile="icudtl.dat"/>
<ROW File="fi.pak" Component_="am.pak" FileName="fi.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\fi.pak" SelfReg="false" NextFile="fil.pak"/>
<ROW File="fil.pak" Component_="am.pak" FileName="fil.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\fil.pak" SelfReg="false" NextFile="fr.pak"/>
<ROW File="fr.pak" Component_="am.pak" FileName="fr.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\fr.pak" SelfReg="false" NextFile="gu.pak"/>
<ROW File="gu.pak" Component_="am.pak" FileName="gu.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\gu.pak" SelfReg="false" NextFile="he.pak"/>
<ROW File="he.pak" Component_="am.pak" FileName="he.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\he.pak" SelfReg="false" NextFile="hi.pak"/>
<ROW File="hi.pak" Component_="am.pak" FileName="hi.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\hi.pak" SelfReg="false" NextFile="hr.pak"/>
<ROW File="hr.pak" Component_="am.pak" FileName="hr.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\hr.pak" SelfReg="false" NextFile="hu.pak"/>
<ROW File="hu.pak" Component_="am.pak" FileName="hu.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\hu.pak" SelfReg="false" NextFile="id.pak"/>
<ROW File="icudtl.dat" Component_="blink_image_resources_200_percent.pak" FileName="icudtl.dat" Attributes="0" SourcePath="..\dist\win-unpacked\icudtl.dat" SelfReg="false" NextFile="libEGL.dll"/>
<ROW File="id.pak" Component_="am.pak" FileName="id.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\id.pak" SelfReg="false" NextFile="it.pak"/>
<ROW File="it.pak" Component_="am.pak" FileName="it.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\it.pak" SelfReg="false" NextFile="ja.pak"/>
<ROW File="ja.pak" Component_="am.pak" FileName="ja.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\ja.pak" SelfReg="false" NextFile="kn.pak"/>
<ROW File="kn.pak" Component_="am.pak" FileName="kn.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\kn.pak" SelfReg="false" NextFile="ko.pak"/>
<ROW File="ko.pak" Component_="am.pak" FileName="ko.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\ko.pak" SelfReg="false" NextFile="lt.pak"/>
<ROW File="libEGL.dll" Component_="libEGL.dll" FileName="libEGL.dll" Attributes="0" SourcePath="..\dist\win-unpacked\libEGL.dll" SelfReg="false" NextFile="libGLESv2.dll"/>
<ROW File="libGLESv2.dll" Component_="libGLESv2.dll" FileName="LIBGLE~1.DLL|libGLESv2.dll" Attributes="0" SourcePath="..\dist\win-unpacked\libGLESv2.dll" SelfReg="false" NextFile="LICENSE.electron.txt"/>
<ROW File="lt.pak" Component_="am.pak" FileName="lt.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\lt.pak" SelfReg="false" NextFile="lv.pak"/>
<ROW File="lv.pak" Component_="am.pak" FileName="lv.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\lv.pak" SelfReg="false" NextFile="ml.pak"/>
<ROW File="ml.pak" Component_="am.pak" FileName="ml.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\ml.pak" SelfReg="false" NextFile="mr.pak"/>
<ROW File="mr.pak" Component_="am.pak" FileName="mr.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\mr.pak" SelfReg="false" NextFile="ms.pak"/>
<ROW File="ms.pak" Component_="am.pak" FileName="ms.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\ms.pak" SelfReg="false" NextFile="nb.pak"/>
<ROW File="natives_blob.bin" Component_="blink_image_resources_200_percent.pak" FileName="NATIVE~1.BIN|natives_blob.bin" Attributes="0" SourcePath="..\dist\win-unpacked\natives_blob.bin" SelfReg="false" NextFile="node.dll"/>
<ROW File="nb.pak" Component_="am.pak" FileName="nb.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\nb.pak" SelfReg="false" NextFile="nl.pak"/>
<ROW File="nl.pak" Component_="am.pak" FileName="nl.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\nl.pak" SelfReg="false" NextFile="pl.pak"/>
<ROW File="node.dll" Component_="node.dll" FileName="node.dll" Attributes="0" SourcePath="..\dist\win-unpacked\node.dll" SelfReg="false" NextFile="snapshot_blob.bin"/>
<ROW File="pl.pak" Component_="am.pak" FileName="pl.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\pl.pak" SelfReg="false" NextFile="ptBR.pak"/>
<ROW File="ptBR.pak" Component_="am.pak" FileName="pt-BR.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\pt-BR.pak" SelfReg="false" NextFile="ptPT.pak"/>
<ROW File="ptPT.pak" Component_="am.pak" FileName="pt-PT.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\pt-PT.pak" SelfReg="false" NextFile="ro.pak"/>
<ROW File="ro.pak" Component_="am.pak" FileName="ro.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\ro.pak" SelfReg="false" NextFile="ru.pak"/>
<ROW File="ru.pak" Component_="am.pak" FileName="ru.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\ru.pak" SelfReg="false" NextFile="sk.pak"/>
<ROW File="sk.pak" Component_="am.pak" FileName="sk.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\sk.pak" SelfReg="false" NextFile="sl.pak"/>
<ROW File="sl.pak" Component_="am.pak" FileName="sl.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\sl.pak" SelfReg="false" NextFile="sr.pak"/>
<ROW File="snapshot_blob.bin" Component_="blink_image_resources_200_percent.pak" FileName="SNAPSH~1.BIN|snapshot_blob.bin" Attributes="0" SourcePath="..\dist\win-unpacked\snapshot_blob.bin" SelfReg="false" NextFile="Symphony.exe"/>
<ROW File="sr.pak" Component_="am.pak" FileName="sr.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\sr.pak" SelfReg="false" NextFile="sv.pak"/>
<ROW File="sv.pak" Component_="am.pak" FileName="sv.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\sv.pak" SelfReg="false" NextFile="sw.pak"/>
<ROW File="sw.pak" Component_="am.pak" FileName="sw.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\sw.pak" SelfReg="false" NextFile="ta.pak"/>
<ROW File="ta.pak" Component_="am.pak" FileName="ta.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\ta.pak" SelfReg="false" NextFile="te.pak"/>
<ROW File="te.pak" Component_="am.pak" FileName="te.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\te.pak" SelfReg="false" NextFile="th.pak"/>
<ROW File="th.pak" Component_="am.pak" FileName="th.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\th.pak" SelfReg="false" NextFile="tr.pak"/>
<ROW File="tr.pak" Component_="am.pak" FileName="tr.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\tr.pak" SelfReg="false" NextFile="uk.pak"/>
<ROW File="ui_resources_200_percent.pak" Component_="blink_image_resources_200_percent.pak" FileName="UI_RES~1.PAK|ui_resources_200_percent.pak" Attributes="0" SourcePath="..\dist\win-unpacked\ui_resources_200_percent.pak" SelfReg="false" NextFile="views_resources_200_percent.pak"/>
<ROW File="uk.pak" Component_="am.pak" FileName="uk.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\uk.pak" SelfReg="false" NextFile="vi.pak"/>
<ROW File="vi.pak" Component_="am.pak" FileName="vi.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\vi.pak" SelfReg="false" NextFile="zhCN.pak"/>
<ROW File="views_resources_200_percent.pak" Component_="blink_image_resources_200_percent.pak" FileName="VIEWS_~1.PAK|views_resources_200_percent.pak" Attributes="0" SourcePath="..\dist\win-unpacked\views_resources_200_percent.pak" SelfReg="false" NextFile="am.pak"/>
<ROW File="zhCN.pak" Component_="am.pak" FileName="zh-CN.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\zh-CN.pak" SelfReg="false" NextFile="zhTW.pak"/>
<ROW File="zhTW.pak" Component_="am.pak" FileName="zh-TW.pak" Attributes="0" SourcePath="..\dist\win-unpacked\locales\zh-TW.pak" SelfReg="false" NextFile="appupdate.yml"/>
<ROW File="LICENSE.electron.txt" Component_="blink_image_resources_200_percent.pak" FileName="LICENS~1.TXT|LICENSE.electron.txt" Attributes="0" SourcePath="..\..\dist\win-unpacked\LICENSE.electron.txt" SelfReg="false" NextFile="LICENSES.chromium.html"/>
<ROW File="LICENSES.chromium.html" Component_="blink_image_resources_200_percent.pak" FileName="LICENS~1.HTM|LICENSES.chromium.html" Attributes="0" SourcePath="..\..\dist\win-unpacked\LICENSES.chromium.html" SelfReg="false" NextFile="natives_blob.bin"/>
<ROW File="ScreenSnippet.exe" Component_="ScreenSnippet.exe" FileName="SCREEN~1.EXE|ScreenSnippet.exe" Attributes="0" SourcePath="..\..\node_modules\screen-snippet\bin\Release\ScreenSnippet.exe" SelfReg="false" DigSign="true"/>
<ROW File="Symphony.config_1" Component_="Symphony.config" FileName="SYMPHO~1.CON|Symphony.config" Attributes="0" SourcePath="..\..\dist\win-unpacked\config\Symphony.config" SelfReg="false" NextFile="ScreenSnippet.exe"/>
<ROW File="Symphony.exe" Component_="Symphony.exe" FileName="Symphony.exe" Attributes="0" SourcePath="..\..\dist\win-unpacked\Symphony.exe" SelfReg="false" NextFile="ui_resources_200_percent.pak" DigSign="true"/>
<ROW File="am.pak" Component_="am.pak" FileName="am.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\am.pak" SelfReg="false" NextFile="ar.pak"/>
<ROW File="app.asar" Component_="appupdate.yml" FileName="APP~1.ASA|app.asar" Attributes="0" SourcePath="..\..\dist\win-unpacked\resources\app.asar" SelfReg="false" NextFile="electron.asar"/>
<ROW File="appupdate.yml" Component_="appupdate.yml" FileName="APP-UP~1.YML|app-update.yml" Attributes="0" SourcePath="..\..\dist\win-unpacked\resources\app-update.yml" SelfReg="false" NextFile="app.asar"/>
<ROW File="ar.pak" Component_="am.pak" FileName="ar.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\ar.pak" SelfReg="false" NextFile="bg.pak"/>
<ROW File="bg.pak" Component_="am.pak" FileName="bg.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\bg.pak" SelfReg="false" NextFile="bn.pak"/>
<ROW File="blink_image_resources_200_percent.pak" Component_="blink_image_resources_200_percent.pak" FileName="BLINK_~1.PAK|blink_image_resources_200_percent.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\blink_image_resources_200_percent.pak" SelfReg="false" NextFile="content_resources_200_percent.pak"/>
<ROW File="bn.pak" Component_="am.pak" FileName="bn.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\bn.pak" SelfReg="false" NextFile="ca.pak"/>
<ROW File="ca.pak" Component_="am.pak" FileName="ca.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\ca.pak" SelfReg="false" NextFile="cs.pak"/>
<ROW File="content_resources_200_percent.pak" Component_="blink_image_resources_200_percent.pak" FileName="CONTEN~1.PAK|content_resources_200_percent.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\content_resources_200_percent.pak" SelfReg="false" NextFile="content_shell.pak"/>
<ROW File="content_shell.pak" Component_="blink_image_resources_200_percent.pak" FileName="CONTEN~2.PAK|content_shell.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\content_shell.pak" SelfReg="false" NextFile="d3dcompiler_47.dll"/>
<ROW File="cs.pak" Component_="am.pak" FileName="cs.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\cs.pak" SelfReg="false" NextFile="da.pak"/>
<ROW File="d3dcompiler_47.dll" Component_="d3dcompiler_47.dll" FileName="D3DCOM~1.DLL|d3dcompiler_47.dll" Attributes="0" SourcePath="..\..\dist\win-unpacked\d3dcompiler_47.dll" SelfReg="false" NextFile="ffmpeg.dll"/>
<ROW File="da.pak" Component_="am.pak" FileName="da.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\da.pak" SelfReg="false" NextFile="de.pak"/>
<ROW File="de.pak" Component_="am.pak" FileName="de.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\de.pak" SelfReg="false" NextFile="el.pak"/>
<ROW File="el.pak" Component_="am.pak" FileName="el.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\el.pak" SelfReg="false" NextFile="enGB.pak"/>
<ROW File="electron.asar" Component_="appupdate.yml" FileName="ELECTR~1.ASA|electron.asar" Attributes="0" SourcePath="..\..\dist\win-unpacked\resources\electron.asar" SelfReg="false" NextFile="Symphony.config_1"/>
<ROW File="enGB.pak" Component_="am.pak" FileName="en-GB.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\en-GB.pak" SelfReg="false" NextFile="enUS.pak"/>
<ROW File="enUS.pak" Component_="am.pak" FileName="en-US.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\en-US.pak" SelfReg="false" NextFile="es.pak"/>
<ROW File="es.pak" Component_="am.pak" FileName="es.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\es.pak" SelfReg="false" NextFile="es419.pak"/>
<ROW File="es419.pak" Component_="am.pak" FileName="es-419.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\es-419.pak" SelfReg="false" NextFile="et.pak"/>
<ROW File="et.pak" Component_="am.pak" FileName="et.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\et.pak" SelfReg="false" NextFile="fa.pak"/>
<ROW File="fa.pak" Component_="am.pak" FileName="fa.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\fa.pak" SelfReg="false" NextFile="fakebidi.pak"/>
<ROW File="fakebidi.pak" Component_="am.pak" FileName="FAKE-B~1.PAK|fake-bidi.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\fake-bidi.pak" SelfReg="false" NextFile="fi.pak"/>
<ROW File="ffmpeg.dll" Component_="ffmpeg.dll" FileName="ffmpeg.dll" Attributes="0" SourcePath="..\..\dist\win-unpacked\ffmpeg.dll" SelfReg="false" NextFile="icudtl.dat"/>
<ROW File="fi.pak" Component_="am.pak" FileName="fi.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\fi.pak" SelfReg="false" NextFile="fil.pak"/>
<ROW File="fil.pak" Component_="am.pak" FileName="fil.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\fil.pak" SelfReg="false" NextFile="fr.pak"/>
<ROW File="fr.pak" Component_="am.pak" FileName="fr.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\fr.pak" SelfReg="false" NextFile="gu.pak"/>
<ROW File="gu.pak" Component_="am.pak" FileName="gu.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\gu.pak" SelfReg="false" NextFile="he.pak"/>
<ROW File="he.pak" Component_="am.pak" FileName="he.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\he.pak" SelfReg="false" NextFile="hi.pak"/>
<ROW File="hi.pak" Component_="am.pak" FileName="hi.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\hi.pak" SelfReg="false" NextFile="hr.pak"/>
<ROW File="hr.pak" Component_="am.pak" FileName="hr.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\hr.pak" SelfReg="false" NextFile="hu.pak"/>
<ROW File="hu.pak" Component_="am.pak" FileName="hu.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\hu.pak" SelfReg="false" NextFile="id.pak"/>
<ROW File="icudtl.dat" Component_="blink_image_resources_200_percent.pak" FileName="icudtl.dat" Attributes="0" SourcePath="..\..\dist\win-unpacked\icudtl.dat" SelfReg="false" NextFile="libEGL.dll"/>
<ROW File="id.pak" Component_="am.pak" FileName="id.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\id.pak" SelfReg="false" NextFile="it.pak"/>
<ROW File="it.pak" Component_="am.pak" FileName="it.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\it.pak" SelfReg="false" NextFile="ja.pak"/>
<ROW File="ja.pak" Component_="am.pak" FileName="ja.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\ja.pak" SelfReg="false" NextFile="kn.pak"/>
<ROW File="kn.pak" Component_="am.pak" FileName="kn.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\kn.pak" SelfReg="false" NextFile="ko.pak"/>
<ROW File="ko.pak" Component_="am.pak" FileName="ko.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\ko.pak" SelfReg="false" NextFile="lt.pak"/>
<ROW File="libEGL.dll" Component_="libEGL.dll" FileName="libEGL.dll" Attributes="0" SourcePath="..\..\dist\win-unpacked\libEGL.dll" SelfReg="false" NextFile="libGLESv2.dll"/>
<ROW File="libGLESv2.dll" Component_="libGLESv2.dll" FileName="LIBGLE~1.DLL|libGLESv2.dll" Attributes="0" SourcePath="..\..\dist\win-unpacked\libGLESv2.dll" SelfReg="false" NextFile="LICENSE.electron.txt"/>
<ROW File="lt.pak" Component_="am.pak" FileName="lt.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\lt.pak" SelfReg="false" NextFile="lv.pak"/>
<ROW File="lv.pak" Component_="am.pak" FileName="lv.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\lv.pak" SelfReg="false" NextFile="ml.pak"/>
<ROW File="ml.pak" Component_="am.pak" FileName="ml.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\ml.pak" SelfReg="false" NextFile="mr.pak"/>
<ROW File="mr.pak" Component_="am.pak" FileName="mr.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\mr.pak" SelfReg="false" NextFile="ms.pak"/>
<ROW File="ms.pak" Component_="am.pak" FileName="ms.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\ms.pak" SelfReg="false" NextFile="nb.pak"/>
<ROW File="natives_blob.bin" Component_="blink_image_resources_200_percent.pak" FileName="NATIVE~1.BIN|natives_blob.bin" Attributes="0" SourcePath="..\..\dist\win-unpacked\natives_blob.bin" SelfReg="false" NextFile="node.dll"/>
<ROW File="nb.pak" Component_="am.pak" FileName="nb.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\nb.pak" SelfReg="false" NextFile="nl.pak"/>
<ROW File="nl.pak" Component_="am.pak" FileName="nl.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\nl.pak" SelfReg="false" NextFile="pl.pak"/>
<ROW File="node.dll" Component_="node.dll" FileName="node.dll" Attributes="0" SourcePath="..\..\dist\win-unpacked\node.dll" SelfReg="false" NextFile="snapshot_blob.bin"/>
<ROW File="pl.pak" Component_="am.pak" FileName="pl.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\pl.pak" SelfReg="false" NextFile="ptBR.pak"/>
<ROW File="ptBR.pak" Component_="am.pak" FileName="pt-BR.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\pt-BR.pak" SelfReg="false" NextFile="ptPT.pak"/>
<ROW File="ptPT.pak" Component_="am.pak" FileName="pt-PT.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\pt-PT.pak" SelfReg="false" NextFile="ro.pak"/>
<ROW File="ro.pak" Component_="am.pak" FileName="ro.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\ro.pak" SelfReg="false" NextFile="ru.pak"/>
<ROW File="ru.pak" Component_="am.pak" FileName="ru.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\ru.pak" SelfReg="false" NextFile="sk.pak"/>
<ROW File="sk.pak" Component_="am.pak" FileName="sk.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\sk.pak" SelfReg="false" NextFile="sl.pak"/>
<ROW File="sl.pak" Component_="am.pak" FileName="sl.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\sl.pak" SelfReg="false" NextFile="sr.pak"/>
<ROW File="snapshot_blob.bin" Component_="blink_image_resources_200_percent.pak" FileName="SNAPSH~1.BIN|snapshot_blob.bin" Attributes="0" SourcePath="..\..\dist\win-unpacked\snapshot_blob.bin" SelfReg="false" NextFile="Symphony.exe"/>
<ROW File="sr.pak" Component_="am.pak" FileName="sr.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\sr.pak" SelfReg="false" NextFile="sv.pak"/>
<ROW File="sv.pak" Component_="am.pak" FileName="sv.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\sv.pak" SelfReg="false" NextFile="sw.pak"/>
<ROW File="sw.pak" Component_="am.pak" FileName="sw.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\sw.pak" SelfReg="false" NextFile="ta.pak"/>
<ROW File="ta.pak" Component_="am.pak" FileName="ta.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\ta.pak" SelfReg="false" NextFile="te.pak"/>
<ROW File="te.pak" Component_="am.pak" FileName="te.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\te.pak" SelfReg="false" NextFile="th.pak"/>
<ROW File="th.pak" Component_="am.pak" FileName="th.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\th.pak" SelfReg="false" NextFile="tr.pak"/>
<ROW File="tr.pak" Component_="am.pak" FileName="tr.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\tr.pak" SelfReg="false" NextFile="uk.pak"/>
<ROW File="ui_resources_200_percent.pak" Component_="blink_image_resources_200_percent.pak" FileName="UI_RES~1.PAK|ui_resources_200_percent.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\ui_resources_200_percent.pak" SelfReg="false" NextFile="views_resources_200_percent.pak"/>
<ROW File="uk.pak" Component_="am.pak" FileName="uk.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\uk.pak" SelfReg="false" NextFile="vi.pak"/>
<ROW File="vi.pak" Component_="am.pak" FileName="vi.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\vi.pak" SelfReg="false" NextFile="zhCN.pak"/>
<ROW File="views_resources_200_percent.pak" Component_="blink_image_resources_200_percent.pak" FileName="VIEWS_~1.PAK|views_resources_200_percent.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\views_resources_200_percent.pak" SelfReg="false" NextFile="am.pak"/>
<ROW File="zhCN.pak" Component_="am.pak" FileName="zh-CN.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\zh-CN.pak" SelfReg="false" NextFile="zhTW.pak"/>
<ROW File="zhTW.pak" Component_="am.pak" FileName="zh-TW.pak" Attributes="0" SourcePath="..\..\dist\win-unpacked\locales\zh-TW.pak" SelfReg="false" NextFile="appupdate.yml"/>
</COMPONENT>
<COMPONENT cid="caphyon.advinst.custcomp.AiPropertyAliasComponent">
<ROW AliasRowId="AUTO_START" AliasRowOperation="2" Value="true"/>
@ -359,9 +359,10 @@
<ROW Action="SET_SHORTCUTDIR" Type="307" Source="SHORTCUTDIR" Target="[ProgramMenuFolder][ProductName]"/>
<ROW Action="SET_TARGETDIR_TO_APPDIR" Type="51" Source="TARGETDIR" Target="[APPDIR]"/>
<ROW Action="Symphony.exe" Type="1042" Source="Symphony.exe" Target="--install"/>
<ROW Action="UninstallPreviousVersions" Type="1" Source="aicustact.dll" Target="UninstallPreviousVersions" Options="1"/>
</COMPONENT>
<COMPONENT cid="caphyon.advinst.msicomp.MsiIconsComponent">
<ROW Name="icon.exe" SourcePath="..\build\icon.ico" Index="0"/>
<ROW Name="icon.exe" SourcePath="..\..\build\icon.ico" Index="0"/>
</COMPONENT>
<COMPONENT cid="caphyon.advinst.msicomp.MsiInstExSeqComponent">
<ROW Action="AI_DOWNGRADE" Condition="AI_NEWERPRODUCTFOUND AND (UILevel &lt;&gt; 5)" Sequence="210"/>
@ -383,6 +384,7 @@
<ROW Action="ExecuteAction" Sequence="1299" SeqType="0" MsiKey="ExecuteAction"/>
<ROW Action="AI_SETMIXINSTLOCATION" Sequence="749"/>
<ROW Action="InstallTypeDlg" Condition="AI_INSTALL" Sequence="1230" SeqType="3" MsiKey="WelcomeDlg"/>
<ROW Action="UninstallPreviousVersions" Sequence="1281"/>
</COMPONENT>
<COMPONENT cid="caphyon.advinst.msicomp.MsiLaunchConditionsComponent">
<ROW Condition="( Version9X OR ( NOT VersionNT64 ) OR ( VersionNT64 AND ((VersionNT64 &lt;&gt; 502) OR (((VersionNT64 = 502) AND (ServicePackLevel &gt;= 1)) OR (MsiNTProductType &lt;&gt; 1))) AND ((VersionNT64 &lt;&gt; 502) OR (((VersionNT64 = 502) AND (ServicePackLevel &lt;&gt; 1)) OR (MsiNTProductType &lt;&gt; 1))) AND ((VersionNT64 &lt;&gt; 502) OR (((VersionNT64 = 502) AND (ServicePackLevel &lt;&gt; 2)) OR (MsiNTProductType &lt;&gt; 1))) AND ((VersionNT64 &lt;&gt; 502) OR ((VersionNT64 = 502) AND ((MsiNTProductType = 1) OR (ServicePackLevel &gt;= 1)))) AND ((VersionNT64 &lt;&gt; 502) OR ((VersionNT64 = 502) AND ((MsiNTProductType = 1) OR (ServicePackLevel &lt;&gt; 1)))) AND ((VersionNT64 &lt;&gt; 502) OR ((VersionNT64 = 502) AND ((MsiNTProductType = 1) OR (ServicePackLevel &lt;&gt; 2)))) AND ((VersionNT64 &lt;&gt; 600) OR (((VersionNT64 = 600) AND (ServicePackLevel &gt;= 1)) OR (MsiNTProductType &lt;&gt; 1))) AND ((VersionNT64 &lt;&gt; 600) OR (((VersionNT64 = 600) AND (ServicePackLevel &lt;&gt; 1)) OR (MsiNTProductType &lt;&gt; 1))) AND ((VersionNT64 &lt;&gt; 600) OR (((VersionNT64 = 600) AND (ServicePackLevel &lt;&gt; 2)) OR (MsiNTProductType &lt;&gt; 1))) ) )" Description="[ProductName] cannot be installed on the following Windows versions: [WindowsTypeNT64Display]" DescriptionLocId="AI.LaunchCondition.NoSpecificNT64" IsPredefined="true" Builds="DefaultBuild"/>

View File

@ -2,6 +2,8 @@
const systemIdleTime = require('@paulcbetts/system-idle-time');
const throttle = require('../utils/throttle');
const log = require('../log.js');
const logLevels = require('../enums/logLevels.js');
let maxIdleTime;
let activityWindow;
@ -75,6 +77,7 @@ function sendActivity() {
*/
function send(data) {
if (activityWindow && data) {
log.send(logLevels.INFO, 'activity occurred at time= ' + new Date().toUTCString());
activityWindow.send('activity', {
systemIdleTime: data.systemIdleTime
});
@ -84,11 +87,14 @@ function send(data) {
function setActivityWindow(period, win) {
maxIdleTime = period;
activityWindow = win;
// Initiate activity detection to monitor user activity status
initiateActivityDetection();
}
module.exports = {
send: send,
setActivityWindow: setActivityWindow,
activityDetection: activityDetection,
monitorUserActivity: monitorUserActivity, // Exporting this for unit test
initiateActivityDetection: initiateActivityDetection
};

View File

@ -7,9 +7,12 @@ const nativeImage = electron.nativeImage;
const { isMac } = require('./utils/misc.js');
const windowMgr = require('./windowMgr.js');
const maxCount = 1e8;
const log = require('./log.js');
const logLevels = require('./enums/logLevels.js');
function show(count) {
if (typeof count !== 'number') {
log.send(logLevels.WARN, 'badgeCount: invalid func arg, must be a number: ' + count);
return;
}

View File

@ -164,4 +164,9 @@ function saveUserConfig(fieldName, newValue, oldConfig) {
});
}
module.exports = { getConfigField, updateConfigField, configFileName };
module.exports = {
getConfigField,
updateConfigField,
configFileName,
saveUserConfig // Exporting this for unit tests
};

View File

@ -14,6 +14,7 @@
var { ipcRenderer } = require('electron');
var nextId = 0;
var includes = [].includes;

View File

@ -2,6 +2,9 @@
const electron = require('electron');
const log = require('../log.js');
const logLevels = require('../enums/logLevels.js');
let ignoreAllCertErrors = false;
/**
@ -21,6 +24,8 @@ electron.app.on('certificate-error', function(event, webContents, url, error,
return;
}
log.send(logLevels.WARNING, 'Certificate error: ' + error + ' for url: ' + url);
const browserWin = electron.BrowserWindow.fromWebContents(webContents);
const buttonId = electron.dialog.showMessageBox(browserWin, {
type: 'warning',

View File

@ -2,6 +2,9 @@
const electron = require('electron');
const log = require('../log.js');
const logLevels = require('../enums/logLevels.js');
/**
* Show dialog pinned to given window when loading error occurs
* @param {BrowserWindow} win Window to host dialog
@ -34,6 +37,9 @@ function showLoadFailure(win, url, errorDesc, errorCode, retryCallback) {
message: msg
}, response);
log.send(logLevels.WARNING, 'Load failure msg: ' + errorDesc +
' errorCode: ' + errorCode + ' for url:' + url);
// async handle of user input
function response(buttonId) {
// retry if hitting butotn index 0 (i.e., reload)

View File

@ -1,28 +1,87 @@
'use strict';
let logWindow;
const getCmdLineArg = require('./utils/getCmdLineArg.js')
/**
* Send log messages from main process to logger hosted by
* renderer process. Allows main process to use logger
* provided by JS.
* @param {enum} level enum from ./enums/LogLevel.js
* @param {string} details msg to be logged
*/
function send(level, details) {
if (logWindow && level && details) {
logWindow.send('log', {
const MAX_LOG_QUEUE_LENGTH = 100;
class Logger {
constructor() {
// browser window that has registered a logger
this.logWindow = null;
// holds log messages received before logger has been registered.
this.logQueue = [];
}
/**
* Send log messages from main process to logger hosted by
* renderer process. Allows main process to use logger
* provided by JS.
* @param {enum} level enum from ./enums/LogLevel.js
* @param {string} details msg to be logged
*/
send(level, details) {
if (!level || !details) {
return;
}
let logMsg = {
level: level,
details: details
});
details: details,
startTime: Date.now()
};
if (this.logWindow) {
this.logWindow.send('log', {
msgs: [ logMsg ]
});
} else {
// store log msgs for later when (if) we get logger registered
this.logQueue.push(logMsg);
// don't store more than 100 msgs. keep most recent log msgs.
if (this.logQueue.length > MAX_LOG_QUEUE_LENGTH) {
this.logQueue.shift();
}
}
}
setLogWindow(win) {
this.logWindow = win;
if (this.logWindow) {
var logMsg = {};
if (Array.isArray(this.logQueue)) {
logMsg.msgs = this.logQueue;
}
// configure desired log level and send pending log msgs
let logLevel = getCmdLineArg(process.argv, '--logLevel=');
if (logLevel) {
let level = logLevel.split('=')[1];
if (level) {
logMsg.logLevel = level;
}
}
if (getCmdLineArg(process.argv, '--enableConsoleLogging')) {
logMsg.showInConsole = true;
}
if (Object.keys(logMsg).length) {
this.logWindow.send('log', logMsg);
}
this.logQueue = [];
}
}
}
function setLogWindow(win) {
logWindow = win;
}
var loggerInstance = new Logger();
// Logger class is only exposed for testing purposes.
module.exports = {
send: send,
setLogWindow: setLogWindow
};
Logger: Logger,
send: loggerInstance.send.bind(loggerInstance),
setLogWindow: loggerInstance.setLogWindow.bind(loggerInstance)
}

View File

@ -7,8 +7,9 @@ const squirrelStartup = require('electron-squirrel-startup');
const AutoLaunch = require('auto-launch');
const urlParser = require('url');
const { getConfigField } = require('./config.js');
const { isDevEnv } = require('./utils/misc.js');
const { isMac, isDevEnv } = require('./utils/misc.js');
const protocolHandler = require('./protocolHandler');
const getCmdLineArg = require('./utils/getCmdLineArg.js')
const crashReporter = require('./crashReporter');
@ -41,8 +42,8 @@ const shouldQuit = app.makeSingleInstance((argv) => {
processProtocolAction(argv);
});
// quit if another instance is already running
if (shouldQuit) {
// quit if another instance is already running, ignore for dev env
if (!isDevEnv && shouldQuit) {
app.quit();
}
@ -88,27 +89,18 @@ function setupThenOpenMainWindow() {
isAppAlreadyOpen = true;
let installMode = false;
// allows installer to launch app and set auto startup mode then
// immediately quit.
process.argv.some((val) => {
let flag = '--install';
if (val === flag) {
installMode = true;
getConfigField('launchOnStartup')
.then(setStartup)
.then(app.quit)
.catch(app.quit);
}
return false;
});
if (installMode === false) {
getUrlAndCreateMainWindow();
let hasInstallFlag = getCmdLineArg(process.argv, '--install', true);
if (!isMac && hasInstallFlag) {
getConfigField('launchOnStartup')
.then(setStartup)
.then(app.quit)
.catch(app.quit);
return;
}
getUrlAndCreateMainWindow();
}
function setStartup(lStartup){
@ -129,14 +121,9 @@ function setStartup(lStartup){
function getUrlAndCreateMainWindow() {
// for dev env allow passing url argument
if (isDevEnv) {
let url;
process.argv.forEach((val) => {
if (val.startsWith('--url=')) {
url = val.substr(6);
}
});
let url = getCmdLineArg(process.argv, '--url=')
if (url) {
windowMgr.createMainWindow(url);
windowMgr.createMainWindow(url.substr(6));
return;
}
}
@ -160,6 +147,7 @@ function createWin(urlFromConfig) {
slahes: true,
pathname: parsedUrl.href
});
windowMgr.createMainWindow(url);
}
@ -190,16 +178,7 @@ function processProtocolAction(argv) {
return;
}
let protocolUri;
for (let i = 0; i < argv.length; i++) {
if (argv[i].startsWith("symphony://")) {
protocolUri = argv[i];
break;
}
}
let protocolUri = getCmdLineArg(argv, 'symphony://');
if (protocolUri) {

View File

@ -8,6 +8,7 @@ const electron = require('electron');
const windowMgr = require('./windowMgr.js');
const log = require('./log.js');
const logLevels = require('./enums/logLevels');
const activityDetection = require('./activityDetection/activityDetection');
const badgeCount = require('./badgeCount.js');
const protocolHandler = require('./protocolHandler');
@ -39,9 +40,7 @@ function isValidWindow(event) {
}
if (!result) {
/* eslint-disable no-console */
console.log('invalid window try to perform action, ignoring action');
/* eslint-enable no-console */
log.send(logLevels.WARN, 'invalid window try to perform action, ignoring action');
}
return result;

View File

@ -4,6 +4,9 @@ const electron = require('electron');
const { getConfigField, updateConfigField } = require('../config.js');
const AutoLaunch = require('auto-launch');
const isMac = require('../utils/misc.js').isMac;
const childProcess = require('child_process');
const log = require('../log.js');
const logLevels = require('../enums/logLevels.js');
var minimizeOnClose = false;
var launchOnStartup = false;
@ -14,6 +17,7 @@ var symphonyAutoLauncher = new AutoLaunch({
name: 'Symphony',
path: process.execPath,
});
let launchAgentPath = '~/Library/LaunchAgents/com.symphony.symphony-desktop.agent.plist';
const template = [
{
@ -184,17 +188,43 @@ function getTemplate(app) {
checked: launchOnStartup,
click: function (item) {
if (item.checked){
symphonyAutoLauncher.enable()
.catch(function (err) {
let title = 'Error setting AutoLaunch configuration';
electron.dialog.showErrorBox(title, title + ': ' + err);
});
if (isMac){
// TODO: Need to change this implementation to AutoLaunch once they fix this issue ->
// https://github.com/Teamwork/node-auto-launch/issues/28
childProcess.exec(`launchctl load ${launchAgentPath}`, (err) => {
if (err){
let title = 'Error setting AutoLaunch configuration';
log.send(logLevels.ERROR, 'MenuTemplate: ' + title + ': process error ' + err);
electron.dialog.showErrorBox(title, 'Please try reinstalling the application');
}
});
} else {
symphonyAutoLauncher.enable()
.catch(function (err) {
let title = 'Error setting AutoLaunch configuration';
log.send(logLevels.ERROR, 'MenuTemplate: ' + title + ': auto launch error ' + err);
electron.dialog.showErrorBox(title, title + ': ' + err);
});
}
} else {
symphonyAutoLauncher.disable()
.catch(function (err) {
let title = 'Error setting AutoLaunch configuration';
electron.dialog.showErrorBox(title, title + ': ' + err);
});
if (isMac){
// TODO: Need to change this implementation to AutoLaunch once they fix this issue ->
// https://github.com/Teamwork/node-auto-launch/issues/28
childProcess.exec(`launchctl unload ${launchAgentPath}`, (err) => {
if (err){
let title = 'Error disabling AutoLaunch configuration';
log.send(logLevels.ERROR, 'MenuTemplate: ' + title + ': process error ' + err);
electron.dialog.showErrorBox(title, 'Please try reinstalling the application');
}
});
} else {
symphonyAutoLauncher.disable()
.catch(function (err) {
let title = 'Error setting AutoLaunch configuration';
log.send(logLevels.ERROR, 'MenuTemplate: ' + title + ': auto launch error ' + err);
electron.dialog.showErrorBox(title, title + ': ' + err);
});
}
}
launchOnStartup = item.checked;
updateConfigField('launchOnStartup', launchOnStartup);
@ -235,6 +265,7 @@ function setCheckboxValues(){
minimizeOnClose = mClose;
}).catch(function (err){
let title = 'Error loading configuration';
log.send(logLevels.ERROR, 'MenuTemplate: error getting config field minimizeOnClose, error: ' + err);
electron.dialog.showErrorBox(title, title + ': ' + err);
});
@ -242,6 +273,7 @@ function setCheckboxValues(){
launchOnStartup = lStartup;
}).catch(function (err){
let title = 'Error loading configuration';
log.send(logLevels.ERROR, 'MenuTemplate: error getting config field launchOnStartup, error: ' + err);
electron.dialog.showErrorBox(title, title + ': ' + err);
});
}

View File

@ -1,5 +1,8 @@
'use strict';
const log = require('../log.js');
const logLevels = require('../enums/logLevels.js');
// One animation at a time
const AnimationQueue = function(options) {
this.options = options;
@ -27,6 +30,8 @@ AnimationQueue.prototype.animate = function(object) {
}
}.bind(this))
.catch(function(err) {
log.send(logLevels.ERROR, 'animationQueue: encountered an error: ' + err +
' with stack trace:' + err.stack);
/* eslint-disable no-console */
console.error('animation queue encountered an error: ' + err +
' with stack trace:' + err.stack);

View File

@ -8,6 +8,8 @@
//
const electron = require('electron');
const ipc = electron.ipcRenderer;
const log = require('../log.js');
const logLevels = require('../enums/logLevels.js');
function setStyle(config) {
// Style it
@ -53,7 +55,8 @@ function setContents(event, notificationObj) {
audio.play()
}
} catch (e) {
log('electron-notify: ERROR could not find sound file: ' + notificationObj.sound.replace('file://', ''), e, e.stack);
log.send(logLevels.ERROR, 'electron-notify: ERROR could not find sound file: '
+ notificationObj.sound.replace('file://', ''), e, e.stack);
}
}
@ -140,9 +143,3 @@ function reset() {
ipc.on('electron-notify-set-contents', setContents)
ipc.on('electron-notify-load-config', loadConfig)
ipc.on('electron-notify-reset', reset)
function log() {
/* eslint-disable no-console */
console.log.apply(console, arguments)
/* eslint-enable no-console */
}

View File

@ -15,6 +15,8 @@ const electron = require('electron');
const app = electron.app;
const BrowserWindow = electron.BrowserWindow;
const ipc = electron.ipcMain;
const log = require('../log.js');
const logLevels = require('../enums/logLevels.js');
// maximum number of notifications that can be queued, after limit is
// reached then error func callback will be invoked.
@ -158,7 +160,7 @@ function getTemplatePath() {
try {
fs.statSync(templatePath).isFile();
} catch (err) {
log('electron-notify: Could not find template ("' + templatePath + '").');
log.send(logLevels.ERROR, 'electron-notify: Could not find template ("' + templatePath + '").');
}
config.templatePath = 'file://' + templatePath;
return config.templatePath;
@ -166,7 +168,7 @@ function getTemplatePath() {
function calcDimensions() {
const vertSpaceBetweenNotf = 8;
// Calc totalHeight & totalWidth
config.totalHeight = config.height + vertSpaceBetweenNotf;
config.totalWidth = config.width
@ -254,7 +256,7 @@ function notify(notification) {
})
return notf.id
}
log('electron-notify: ERROR notify() only accepts a single object with notification parameters.')
log.send(logLevels.ERROR, 'electron-notify: ERROR notify() only accepts a single object with notification parameters.');
return null;
}
@ -272,6 +274,7 @@ function showNotification(notificationObj) {
id: notificationObj.id,
error: 'max notification queue size reached: ' + MAX_QUEUE_SIZE
});
log.send(logLevels.INFO, 'showNotification: max notification queue size reached: ' + MAX_QUEUE_SIZE);
}, 0);
}
resolve();
@ -646,13 +649,5 @@ function cleanUpInactiveWindow() {
inactiveWindows = [];
}
function log() {
if (config.logging === true) {
/* eslint-disable no-console */
console.log.apply(console, arguments);
/* eslint-enable no-console */
}
}
module.exports.notify = notify
module.exports.reset = setupConfig

View File

@ -2,7 +2,8 @@
const EventEmitter = require('events');
const { notify } = require('./electron-notify.js');
const log = require('../log.js');
const logLevels = require('../enums/logLevels.js');
/**
* implementation for notifications interface,
* wrapper around electron-notify.
@ -27,6 +28,8 @@ class Notify {
* }
*/
constructor(title, options) {
log.send(logLevels.INFO, 'creating notification, text=' + options.body);
let emitter = new EventEmitter();
this.emitter = Queue(emitter);
@ -44,10 +47,13 @@ class Notify {
onErrorFunc: onError.bind(this)
});
log.send(logLevels.INFO, 'created notification, id=' + this._id + ', text=' + options.body);
this._data = options.data || null;
function onShow(arg) {
if (arg.id === this._id) {
log.send(logLevels.INFO, 'showing notification, id=' + this._id);
this.emitter.queue('show', {
target: this
});
@ -57,6 +63,7 @@ class Notify {
function onClick(arg) {
if (arg.id === this._id) {
log.send(logLevels.INFO, 'clicking notification, id=' + this._id);
this.emitter.queue('click', {
target: this
});
@ -65,6 +72,7 @@ class Notify {
function onClose(arg) {
if (arg.id === this._id || arg.event === 'close-all') {
log.send(logLevels.INFO, 'closing notification, id=' + this._id);
this.emitter.queue('close', {
target: this
});
@ -76,6 +84,8 @@ class Notify {
if (arg.id === this._id) {
// don't raise error event if handler doesn't exist, node
// will throw an exception
log.send(logLevels.ERROR, 'error for notification, id=' + this._id +
' error=' + (arg && arg.error));
if (this.emitter.eventNames().includes('error')) {
this.emitter.queue('error', arg.error || 'notification error');
}

View File

@ -20,6 +20,8 @@ const apiName = apiEnums.apiName;
const getMediaSources = require('../desktopCapturer/getSources');
const crashReporter = require('../crashReporter');
const nodeURL = require('url');
// hold ref so doesn't get GC'ed
const local = {
ipcRenderer: ipcRenderer
@ -52,6 +54,25 @@ function createAPI() {
return;
}
// bug in electron is preventing using event 'will-navigate' from working
// in sandboxed environment. https://github.com/electron/electron/issues/8841
// so in the mean time using this code below to block clicking on A tags.
// A tags are allowed if they include href='_blank', this cause 'new-window'
// event to be received which is handled properly in windowMgr.js
window.addEventListener('beforeunload', function(event) {
var newUrl = document.activeElement && document.activeElement.href;
if (newUrl) {
var currHostName = window.location.hostname;
var parsedNewUrl = nodeURL.parse(newUrl);
var parsedNewUrlHostName = parsedNewUrl && parsedNewUrl.hostname;
if (currHostName !== parsedNewUrlHostName) {
/* eslint-disable no-param-reassign */
event.returnValue = 'false';
/* eslint-enable no-param-reassign */
}
}
});
// note: window.open from main window (if in the same domain) will get
// api access. window.open in another domain will be opened in the default
// browser (see: handler for event 'new-window' in windowMgr.js)
@ -205,7 +226,6 @@ function createAPI() {
* for interface: see documentation in desktopCapturer/getSources.js
*/
getMediaSources: getMediaSources
};
// add support for both ssf and SYM_API name-space.
@ -215,8 +235,8 @@ function createAPI() {
// listen for log message from main process
local.ipcRenderer.on('log', (event, arg) => {
if (local.logger && arg && arg.level && arg.details) {
local.logger(arg.level, arg.details);
if (arg && local.logger) {
local.logger(arg.msgs || [], arg.logLevel, arg.showInConsole);
}
});
@ -294,7 +314,6 @@ function createAPI() {
* @type {String} arg - the protocol url
*/
local.ipcRenderer.on('protocol-action', (event, arg) => {
if (local.processProtocolAction && arg) {
local.processProtocolAction(arg);
}

View File

@ -1,5 +1,8 @@
'use strict';
const log = require('../log.js');
const logLevels = require('../enums/logLevels.js');
let protocolWindow;
let protocolUrl;
@ -8,7 +11,8 @@ let protocolUrl;
* @param {String} uri - the uri opened in the format 'symphony://...'
*/
function processProtocolAction(uri) {
if (protocolWindow && uri && uri.startsWith("symphony://")) {
log.send(logLevels.INFO, 'protocol action, uri=' + uri);
if (protocolWindow && uri && uri.startsWith('symphony://')) {
protocolWindow.send('protocol-action', uri);
}
}

View File

@ -8,6 +8,8 @@ const os = require('os');
const path = require('path');
const { isMac, isDevEnv } = require('../utils/misc.js');
const log = require('../log.js');
const logLevels = require('../enums/logLevels.js');
// static ref to child process, only allow one screen snippet at time, so
// hold ref to prev, so can kill before starting next snippet.
@ -34,6 +36,8 @@ class ScreenSnippet {
return new Promise((resolve, reject) => {
let captureUtil, captureUtilArgs;
log.send(logLevels.INFO, 'ScreenSnippet: starting screen capture');
let tmpFilename = 'symphonyImage-' + Date.now() + '.jpg';
let tmpDir = os.tmpdir();
@ -60,6 +64,8 @@ class ScreenSnippet {
captureUtilArgs = [ outputFileName ];
}
log.send(logLevels.INFO, 'ScreenSnippet: starting screen capture util: ' + captureUtil + ' with args=' + captureUtilArgs);
// only allow one screen capture at a time.
if (child) {
child.kill();
@ -118,13 +124,10 @@ class ScreenSnippet {
fs.unlink(outputFileName, function(removeErr) {
// note: node complains if calling async
// func without callback.
/* eslint-disable no-console */
if (removeErr) {
console.error(
'error removing temp snippet file: ' +
log.send(logLevels.ERROR, 'ScreenSnippet: error removing temp snippet file: ' +
outputFileName + ', err:' + removeErr);
}
/* eslint-enable no-console */
});
}
});

29
js/utils/getCmdLineArg.js Normal file
View File

@ -0,0 +1,29 @@
'use strict';
const log = require('../log.js');
const logLevels = require('../enums/logLevels.js');
/**
* Search given argv for argName using exact match or starts with.
* @param {Array} argv Array of strings
* @param {String} argName Arg name to search for.
* @param {bool} exactMatch If true then look for exact match otherwise
* try finding arg that starts with argName.
* @return {String} If found, returns the arg, otherwise null.
*/
function getCmdLineArg(argv, argName, exactMatch) {
if (!Array.isArray(argv)) {
log.send(logLevels.WARN, 'getCmdLineArg: TypeError invalid func arg, must be an array: '+ argv);
return null;
}
for (let i = 0, len = argv.length; i < len; i++) {
if ((exactMatch && argv[i] === argName) ||
(!exactMatch && argv[i].startsWith(argName))) {
return argv[i];
}
}
return null;
}
module.exports = getCmdLineArg

View File

@ -2,6 +2,8 @@
const symphonyRegistry = '\\Software\\Symphony\\Symphony\\';
const { isMac } = require('./misc.js');
const log = require('../log.js');
const logLevels = require('../enums/logLevels.js');
var Registry = require('winreg');
var symphonyRegistryHKCU = new Registry({
@ -32,6 +34,7 @@ var getRegistry = function (name) {
//Try to get registry on HKEY_CURRENT_USER
symphonyRegistryHKCU.get( name, function( err1, reg1 ) {
if (!err1 && reg1 !==null && reg1.value) {
log.send(logLevels.WARN, 'getRegistry: Cannot find ' + name + ' Registry. Using HKCU');
resolve(reg1.value);
return;
}
@ -39,6 +42,7 @@ var getRegistry = function (name) {
//Try to get registry on HKEY_LOCAL_MACHINE
symphonyRegistryHKLM.get( name, function( err2, reg2 ) {
if ( !err2 && reg2!==null && reg2.value) {
log.send(logLevels.WARN, 'getRegistry: Cannot find ' + name + ' Registry. Using HKLM');
resolve(reg2.value);
return;
}

View File

@ -6,6 +6,12 @@
* @param {function} func function to invoke
*/
function throttle(throttleTime, func) {
if (typeof throttleTime !== 'number' || throttleTime <= 0) {
throw Error('throttle: invalid throttleTime arg, must be a number: ' + throttleTime);
}
if (typeof func !== 'function') {
throw Error('throttle: invalid func arg, must be a function: ' + func);
}
let timer, lastInvoke = 0;
return function() {
let args = arguments;

View File

@ -17,8 +17,6 @@ const log = require('./log.js');
const logLevels = require('./enums/logLevels.js');
const notify = require('./notify/electron-notify.js');
const activityDetection = require('./activityDetection/activityDetection.js');
const throttle = require('./utils/throttle.js');
const { getConfigField, updateConfigField } = require('./config.js');
@ -83,6 +81,8 @@ function doCreateMainWindow(initialUrl, initialBounds) {
let title = 'Error loading configuration';
electron.dialog.showErrorBox(title, title + ': ' + err);
});
log.send(logLevels.INFO, 'creating main window url: ' + url);
let newWinOpts = {
title: 'Symphony',
@ -150,10 +150,8 @@ function doCreateMainWindow(initialUrl, initialBounds) {
} else {
// removes all existing notifications when main window reloads
notify.reset();
log.send(logLevels.INFO, 'main window loaded url: ' + url);
log.send(logLevels.INFO, 'loaded main window url: ' + url);
// Initiate activity detection to monitor user activity status
activityDetection.initiateActivityDetection();
}
});
@ -212,7 +210,14 @@ function doCreateMainWindow(initialUrl, initialBounds) {
mainWindow.on('closed', destroyAllWindows);
// open external links in default browser - a tag, window.open
// bug in electron is preventing this from working in sandboxed evt...
// https://github.com/electron/electron/issues/8841
mainWindow.webContents.on('will-navigate', function(event, willNavUrl) {
event.preventDefault();
openUrlInDefaultBrower(willNavUrl);
});
// open external links in default browser - a tag with href='_blank' or window.open
mainWindow.webContents.on('new-window', function (event, newWinUrl,
frameName, disposition, newWinOptions) {
let newWinParsedUrl = getParsedUrl(newWinUrl);
@ -221,12 +226,9 @@ function doCreateMainWindow(initialUrl, initialBounds) {
let newWinHost = newWinParsedUrl && newWinParsedUrl.host;
let mainWinHost = mainWinParsedUrl && mainWinParsedUrl.host;
// if host url doesn't match then open in external browser
if (newWinHost !== mainWinHost) {
event.preventDefault();
electron.shell.openExternal(newWinUrl);
} else if (disposition === 'foreground-tab' ||
disposition === 'new-window') {
// only allow window.open to succeed is if coming from same hsot,
// otherwise open in default browser.
if (disposition === 'new-window' && newWinHost === mainWinHost) {
// handle: window.open
if (!frameName) {
@ -234,6 +236,8 @@ function doCreateMainWindow(initialUrl, initialBounds) {
return;
}
log.send(logLevels.INFO, 'creating pop-out window url: ' + newWinParsedUrl);
let x = 0;
let y = 0;
@ -283,6 +287,8 @@ function doCreateMainWindow(initialUrl, initialBounds) {
let browserWin = BrowserWindow.fromWebContents(webContents);
if (browserWin) {
log.send(logLevels.INFO, 'loaded pop-out window url: ' + newWinParsedUrl);
browserWin.winName = frameName;
browserWin.once('closed', function () {
@ -300,6 +306,9 @@ function doCreateMainWindow(initialUrl, initialBounds) {
browserWin.on('resize', throttledBoundsChange);
}
});
} else {
event.preventDefault();
openUrlInDefaultBrower(newWinUrl)
}
});
@ -323,17 +332,19 @@ function getMainWindow() {
}
function getWindowSizeAndPosition(window) {
let newPos = window.getPosition();
let newSize = window.getSize();
if (window) {
let newPos = window.getPosition();
let newSize = window.getSize();
if (newPos && newPos.length === 2 &&
newSize && newSize.length === 2) {
return {
x: newPos[0],
y: newPos[1],
width: newSize[0],
height: newSize[1],
};
if (newPos && newPos.length === 2 &&
newSize && newSize.length === 2) {
return {
x: newPos[0],
y: newPos[1],
width: newSize[0],
height: newSize[1],
};
}
}
return null;
@ -403,6 +414,12 @@ function sendChildWinBoundsChange(window) {
}
}
function openUrlInDefaultBrower(urlToOpen) {
if (urlToOpen) {
electron.shell.openExternal(urlToOpen);
}
}
module.exports = {
createMainWindow: createMainWindow,
getMainWindow: getMainWindow,

View File

@ -13,6 +13,7 @@
"dist-mac": "npm run prebuild && build --mac",
"dist-win": "npm run prebuild && build --win --x64",
"dist-win-x86": "npm run prebuild && build --win --ia32",
"unpacked-mac": "npm run prebuild && build --mac --dir",
"unpacked-win": "npm run prebuild && build --win --x64 --dir",
"unpacked-win-x86": "npm run prebuild && build --win --ia32 --dir",
"prebuild": "npm run lint && npm run test && npm run browserify-preload",
@ -68,11 +69,9 @@
"url": "https://support.symphony.com"
},
"devDependencies": {
"babel-jest": "^19.0.0",
"babel-preset-es2015": "^6.24.0",
"browserify": "^14.1.0",
"cross-env": "^3.2.4",
"electron": "1.6.7",
"electron": "1.6.11",
"electron-builder": "^13.9.0",
"electron-builder-squirrel-windows": "^12.3.0",
"electron-packager": "^8.5.2",

View File

@ -7,6 +7,7 @@ const electron = require('./__mocks__/electron');
describe('protocol handler', function () {
const url = 'symphony://?userId=100001';
const nonProtocolUrl = 'sy://abc=123';
const mainProcess = electron.ipcMain;
const protocolWindow = electron.ipcRenderer;
@ -41,6 +42,17 @@ describe('protocol handler', function () {
});
it('protocol handler open url should be called', function(done) {
const spy = jest.spyOn(mainProcess, 'send');
mainProcess.send('open-url', nonProtocolUrl);
expect(spy).toHaveBeenCalled();
done();
});
it('check protocol action should be called', function (done) {
const spy = jest.spyOn(protocolHandler, 'checkProtocolAction');
@ -58,4 +70,38 @@ describe('protocol handler', function () {
});
it('check protocol action should be called when we have an incorrect protocol url', function (done) {
const spy = jest.spyOn(protocolHandler, 'checkProtocolAction');
const setSpy = jest.spyOn(protocolHandler, 'setProtocolUrl');
protocolHandler.setProtocolUrl(nonProtocolUrl);
expect(setSpy).toHaveBeenCalledWith(nonProtocolUrl);
protocolHandler.checkProtocolAction();
expect(spy).toHaveBeenCalled();
expect(protocolHandler.getProtocolUrl()).toBeUndefined();
done();
});
it('check protocol action should be called when the protocol url is undefined', function(done) {
const spy = jest.spyOn(protocolHandler, 'checkProtocolAction');
const setSpy = jest.spyOn(protocolHandler, 'setProtocolUrl');
protocolHandler.setProtocolUrl(undefined);
expect(setSpy).toHaveBeenCalledWith(undefined);
protocolHandler.checkProtocolAction();
expect(spy).toHaveBeenCalled();
expect(protocolHandler.getProtocolUrl()).toBeUndefined();
done();
});
});

View File

@ -1,10 +1,30 @@
// const activityDetection = require('../js/activityDetection/activityDetection.js');
// const electron = require('./__mocks__/electron');
const electron = require('./__mocks__/electron');
const childProcess = require('child_process');
xdescribe('Tests for Activity Detection', function() {
let activityDetection;
beforeAll(function () {
activityDetection.setActivityWindow(120000, electron.ipcRenderer);
describe('Tests for Activity Detection', function() {
var originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
jasmine.DEFAULT_TIMEOUT_INTERVAL = 50000;
beforeAll(function (done) {
childProcess.exec('npm rebuild --runtime=electron --target=1.5.0 --disturl=https://atom.io/download/atom-shell --build-from-source', function (err) {
activityDetection = require('../js/activityDetection/activityDetection.js');
activityDetection.setActivityWindow(120000, electron.ipcRenderer);
done();
});
});
beforeEach(function () {
jest.clearAllMocks()
});
afterAll(function (done) {
childProcess.exec('npm run rebuild', function (err, stdout) {
jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
done();
});
});
it('should get user activity where user is not idle', function() {
@ -37,4 +57,25 @@ xdescribe('Tests for Activity Detection', function() {
});
it('should monitor user activity', function () {
activityDetection.setActivityWindow(500000, electron.ipcRenderer);
const spy = jest.spyOn(activityDetection, 'monitorUserActivity');
expect(spy).not.toBeCalled();
activityDetection.monitorUserActivity();
expect(spy).toHaveBeenCalled();
});
it('should not send activity event as data is undefined', function () {
const spy = jest.spyOn(activityDetection, 'send');
expect(spy).not.toBeCalled();
activityDetection.send(undefined);
expect(spy).toHaveBeenCalledWith(undefined);
});
});

View File

@ -1,4 +1,4 @@
const { getConfigField, updateConfigField, configFileName } = require('../js/config');
const { getConfigField, updateConfigField, configFileName, saveUserConfig } = require('../js/config');
const fs = require('fs');
const path = require('path');
const os = require('os');
@ -135,6 +135,40 @@ describe('getConfigField tests', function() {
expect(url).toBe('something');
});
});
it('should fail when global config path is invalid', function() {
var globalConfig = {
url: 'something-else'
};
createTempGlobalConfig(globalConfig);
let correctConfigDir = globalConfigDir;
globalConfigDir = '//';
return getConfigField('url').catch(function(err) {
globalConfigDir = correctConfigDir;
expect(err).toBeTruthy();
});
});
it('should fail when user config path is invalid', function() {
var userConfig = {
url: 'something'
};
createTempUserConfig(userConfig);
let correctConfigDir = userConfigDir;
userConfigDir = '//';
return getConfigField('url').catch(function(err) {
userConfigDir = correctConfigDir;
expect(err).toBeTruthy();
});
});
});
describe('updateConfigField tests', function() {
@ -142,7 +176,7 @@ describe('getConfigField tests', function() {
it('should succeed and overwrite existing field', function() {
var userConfig = {
url: 'something'
}
};
createTempUserConfig(userConfig);
@ -157,7 +191,7 @@ describe('getConfigField tests', function() {
it('should succeed and add new field', function() {
var userConfig = {
url: 'something'
}
};
createTempUserConfig(userConfig);
@ -169,5 +203,87 @@ describe('getConfigField tests', function() {
});
});
});
it('should fail to update if invalid field name', function() {
var userConfig = {
url: 'something'
};
createTempUserConfig(userConfig);
return updateConfigField('', 'hello word').catch(function (err) {
expect(err).toBe('can not save config, invalid input');
});
});
it('should throw error if path is not defined', function() {
userConfigDir = null;
return updateConfigField('url2', 'hello world')
.catch(function (err) {
expect(err).toThrow(err);
});
});
it('should throw error if fieldName is not defined', function() {
var userConfig = {
url: 'something'
};
createTempUserConfig(userConfig);
return saveUserConfig(undefined, 'something', 'oldConfig')
.catch(function (reject) {
expect(reject).toBe('can not save config, invalid input');
});
});
it('should throw error if config is not defined', function() {
var userConfig = {
url: 'something'
};
createTempUserConfig(userConfig);
return saveUserConfig('url2', 'something', undefined)
.catch(function (reject) {
expect(reject).toBe('can not save config, invalid input');
});
});
it('should throw error if config file is not correct', function() {
var userConfig = {
url: 'something'
};
createTempUserConfig(userConfig);
let correctConfigDir = userConfigDir;
userConfigDir = '//';
return saveUserConfig('url2', 'hello world', 'url')
.catch(function(err) {
userConfigDir = correctConfigDir;
expect(err).toBeTruthy();
});
});
it('should throw error if path is not defined for saveUserConfig()', function() {
userConfigDir = null;
return saveUserConfig('url2', 'hello world')
.catch(function (err) {
expect(err).toThrow(err);
});
});
});
});

70
tests/log.test.js Normal file
View File

@ -0,0 +1,70 @@
const { Logger } = require('../js/log.js');
describe('logger tests', function() {
let log;
beforeEach(function() {
// get new rewired version for each test.
log = new Logger();
});
it('when no logger registered then queue items', function() {
log.send('DEBUG', 'test');
log.send('DEBUG', 'test2');
let queue = log.logQueue;
expect(queue.length).toBe(2);
});
it('flush queue when logger get registered', function() {
log.send('DEBUG', 'test');
log.send('DEBUG', 'test2');
let mockWin = {
send: jest.fn()
};
log.setLogWindow(mockWin);
let queue = log.logQueue;
expect(mockWin.send).toHaveBeenCalled();
expect(queue.length).toBe(0);
});
it('send single log msg logger has already been registered', function() {
let mockWin = {
send: jest.fn()
};
log.setLogWindow(mockWin);
log.send('DEBUG', 'test');
let queue = log.logQueue;
expect(mockWin.send).toHaveBeenCalled();
expect(queue.length).toBe(0);
});
it('should cap at 100 queued log messages', function() {
for(let i = 0; i < 110; i++) {
log.send('DEBUG', 'test' + i);
}
let queue = log.logQueue;
expect(queue.length).toBe(100);
});
it('should not send the logs', function() {
let mockWin = {
send: jest.fn()
};
log.setLogWindow(mockWin);
log.send();
let queue = log.logQueue;
expect(mockWin.send).toHaveBeenCalledWith("log", {"msgs": []});
expect(queue.length).toBe(0);
});
});

View File

@ -0,0 +1,28 @@
const getCmdLineArg = require('../../js/utils/getCmdLineArg.js');
describe('getCmdLineArg tests', function() {
it('should return no exact match', function() {
var result = getCmdLineArg([ 'hello.exe', '--arg1', '--arg2'], '--arg', true);
expect(result).toBe(null);
});
it('should return exact match only', function() {
var result = getCmdLineArg([ 'hello.exe', '--arg1', '--arg2'], '--arg2', true);
expect(result).toBe('--arg2');
});
it('should return starts with match', function() {
var result = getCmdLineArg([ 'hello.exe', '--hello=test', '--arg2'], '--hello=');
expect(result).toBe('--hello=test');
});
it('should return no match for starts with', function() {
var result = getCmdLineArg([ 'hello.exe', '--hello=test', '--arg2'], '--help=');
expect(result).toBe(null);
});
it('should return no match invalid argv given', function() {
var result = getCmdLineArg('invalid argv', '--help=');
expect(result).toBe(null);
});
});

View File

@ -0,0 +1,70 @@
const getRegistry = require('../../js/utils/getRegistry.js');
const { isMac } = require('../../js/utils/misc.js');
describe('Tests for getRegistry', function() {
describe('Should not get registry for mac', function() {
if (isMac){
it('should fail to get path for mac', function(done) {
getRegistry('PodUrl').then(resolve).catch(reject);
function resolve() {
// shouldn't get here
expect(true).toBe(false);
}
function reject(err) {
expect(err).toBeTruthy();
done();
}
});
}
});
describe('Should get registry for windows', function() {
if (!isMac){
it('should get registry path', function(done) {
getRegistry('PodUrl').then(resolve).catch(reject);
function resolve(url) {
expect(url).toBe('string');
done();
}
function reject(err) {
expect(err).toBeTruthy();
done();
}
});
it('should not get the registry path', function(done) {
getRegistry('wrongUrl').then(resolve).catch(reject);
function resolve() {
expect(true).toBe(false)
}
function reject(err) {
expect(err).toBeTruthy();
expect(err).toBe('Cannot find PodUrl Registry. Using default url.');
done();
}
});
}
});
});

View File

@ -55,6 +55,55 @@ describe('throttle tests', function() {
expect(callback.mock.calls.length).toBe(2);
});
it('expect clearTimeout to be invoked', function() {
const callback = jest.fn();
const throttledCB = throttle(1000, callback);
expect(callback).not.toBeCalled();
throttledCB();
expect(callback.mock.calls.length).toBe(1);
expect(clearTimeout.mock.calls.length).toBe(0);
now -= 1000;
throttledCB();
expect(callback.mock.calls.length).toBe(1);
now += 1000;
throttledCB();
expect(callback.mock.calls.length).toBe(1);
expect(clearTimeout.mock.calls.length).toBe(1);
});
describe('expect to throw exception', function() {
it('when calling throttle with time equal to zero', function(done) {
try {
throttle(0, function() {});
} catch(error) {
expect(error.message).toBeDefined();
done();
}
});
it('when calling throttle with time less than zero', function(done) {
try {
throttle(-1, function() {});
} catch(error) {
expect(error.message).toBeDefined();
done();
}
});
it('when calling throttle without a function callback', function(done) {
try {
throttle(1, 'not a func');
} catch(error) {
expect(error.message).toBeDefined();
done();
}
});
});
afterEach(function() {
// restore orig
Date.now = origNow;