Wine-devel
Threads by month
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
August 2018
- 62 participants
- 701 discussions
22 Aug '18
Signed-off-by: Zebediah Figura <zfigura(a)codeweavers.com>
---
The ddraw surfaces associated with backbuffers take a reference to the
wined3d device, but this was never released.
This patch was all but written by Henri Verbeet.
dlls/ddraw/surface.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/dlls/ddraw/surface.c b/dlls/ddraw/surface.c
index cb837b1..cf09f9c 100644
--- a/dlls/ddraw/surface.c
+++ b/dlls/ddraw/surface.c
@@ -527,7 +527,16 @@ static void ddraw_surface_cleanup(struct ddraw_surface *surface)
surf = surface->complex_array[i];
surface->complex_array[i] = NULL;
if (!surf->is_complex_root)
+ {
+ struct ddraw_texture *texture = wined3d_texture_get_parent(surf->wined3d_texture);
+ struct wined3d_device *wined3d_device = texture->wined3d_device;
+ struct ddraw_surface *root = texture->root;
+
ddraw_surface_cleanup(surf);
+
+ if (surf == root)
+ wined3d_device_decref(wined3d_device);
+ }
}
if (surface->device1)
--
2.7.4
2
1
[PATCH] testbot/web: Add some </div> comments identifying the corresponding <div>.
by Francois Gouget 22 Aug '18
by Francois Gouget 22 Aug '18
22 Aug '18
This helps debug HTML tag balancing errors.
Signed-off-by: Francois Gouget <fgouget(a)codeweavers.com>
---
Alternatively these could be perl comments but it's more practical to
have these in the generated HTML so they can be used when looking at the
generated HTML code.
testbot/lib/ObjectModel/CGI/FormPage.pm | 4 ++--
testbot/lib/WineTestBot/CGI/PageBase.pm | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/testbot/lib/ObjectModel/CGI/FormPage.pm b/testbot/lib/ObjectModel/CGI/FormPage.pm
index b3861dd2a..3a41fe0e6 100644
--- a/testbot/lib/ObjectModel/CGI/FormPage.pm
+++ b/testbot/lib/ObjectModel/CGI/FormPage.pm
@@ -128,8 +128,8 @@ sub GenerateBody($)
{
print "<p>$Text</p>\n";
}
- print "</div>\n";
- print "</div>\n";
+ print "</div><!--Content-->\n";
+ print "</div><!--ItemBody-->\n";
}
sub GenerateFormStart($)
diff --git a/testbot/lib/WineTestBot/CGI/PageBase.pm b/testbot/lib/WineTestBot/CGI/PageBase.pm
index 67e8fc86f..e5b2f2d3b 100644
--- a/testbot/lib/WineTestBot/CGI/PageBase.pm
+++ b/testbot/lib/WineTestBot/CGI/PageBase.pm
@@ -327,10 +327,10 @@ sub GenerateFooter($)
my ($self) = @_;
print <<EOF;
- </div>
+ </div><!--ContentContainer-->
<b class="rbottom"><b class="r4"> </b><b class="r3"> </b><b class="r2"> </b><b class="r1"> </b></b>
</div>
-</div>
+</div><!--main_content-->
</body>
</html>
--
2.18.0
1
0
Also call the parent GenerateFooter() method in the Activity page so
the HTML page is terminated correctly.
Signed-off-by: Francois Gouget <fgouget(a)codeweavers.com>
---
testbot/web/Activity.pl | 6 ++++--
testbot/web/Stats.pl | 1 +
testbot/web/Submit.pl | 3 ++-
3 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/testbot/web/Activity.pl b/testbot/web/Activity.pl
index 512401751..fa842d9f4 100644
--- a/testbot/web/Activity.pl
+++ b/testbot/web/Activity.pl
@@ -94,7 +94,7 @@ sub GenerateBody($)
# Generate a custom form to let the user specify the Hours field.
$self->GenerateFormStart();
- print "<div class='ItemProperty'><label>Analyze the activity of the past <div class='ItemValue'><input type='text' name='Hours' maxlength='3' size='3' value='$self->{hours}'/></div> hours.</div>\n";
+ print "<div class='ItemProperty'><label>Analyze the activity of the past <div class='ItemValue'><input type='text' name='Hours' maxlength='3' size='3' value='$self->{hours}'/></div> hours.</label></div>\n";
$self->GenerateFormEnd();
print "<h1>${ProjectName} Test Bot activity</h1>\n";
@@ -267,6 +267,7 @@ EOF
### Generate the table footer
print "</tbody></table></div>\n";
+ print "</div>\n";
}
sub GenerateFooter($)
@@ -294,8 +295,9 @@ sub GenerateFooter($)
print "<span class='Record-deleted'>deletion</span>.</p>\n";
print "</td></tr></tbody>\n";
- print "</tbody></table></div>\n";
+ print "</table></div>\n";
print "<p class='GeneralFooterText'>Generated in ", Elapsed($self->{start}), " s</p>\n";
+ $self->SUPER::GenerateFooter();
}
diff --git a/testbot/web/Stats.pl b/testbot/web/Stats.pl
index 64f29bdcd..ccabb321a 100644
--- a/testbot/web/Stats.pl
+++ b/testbot/web/Stats.pl
@@ -335,6 +335,7 @@ sub GenerateBody($)
print "</tbody></table></div>\n";
print "<p class='GeneralFooterText'>Generated in ", Elapsed($self->{start}), " s</p>\n";
+ print "</div>\n";
}
diff --git a/testbot/web/Submit.pl b/testbot/web/Submit.pl
index 926fcb7ea..440bd8e5b 100644
--- a/testbot/web/Submit.pl
+++ b/testbot/web/Submit.pl
@@ -237,7 +237,7 @@ sub GenerateFields($)
print "<thead><tr><th class='Record'></th>\n";
print "<th class='Record'>VM Name</th>\n";
print "<th class='Record'>Description</th>\n";
- print "</th><tbody>\n";
+ print "</thead><tbody>\n";
my $VMs = CreateVMs();
if ($self->{FileType} eq "exe64")
@@ -296,6 +296,7 @@ sub GenerateFields($)
print "</tr>\n";
}
print "</tbody></table>\n";
+ print "</div><!--CollectionBlock-->\n";
}
else
{
--
2.18.0
1
0
[PATCH] testbot/build: Move the common build functions to Build::Utils.
by Francois Gouget 22 Aug '18
by Francois Gouget 22 Aug '18
22 Aug '18
This reduces the build scripts code duplication.
A side-effect is that the status lines now all start with the 'Task:'
prefix.
Signed-off-by: Francois Gouget <fgouget(a)codeweavers.com>
---
testbot/bin/build/Build.pl | 89 +-------
testbot/bin/build/Reconfig.pl | 113 +---------
testbot/bin/build/WineReconfig.pl | 247 ++------------------
testbot/bin/build/WineTest.pl | 111 +--------
testbot/lib/Build/Utils.pm | 363 ++++++++++++++++++++++++++++++
5 files changed, 409 insertions(+), 514 deletions(-)
create mode 100644 testbot/lib/Build/Utils.pm
diff --git a/testbot/bin/build/Build.pl b/testbot/bin/build/Build.pl
index e1133aaee..7f94c8595 100755
--- a/testbot/bin/build/Build.pl
+++ b/testbot/bin/build/Build.pl
@@ -43,98 +43,23 @@ sub BEGIN
}
$::BuildEnv = 1;
}
-my $Name0 = $0;
-$Name0 =~ s+^.*/++;
-
+use Build::Utils;
use WineTestBot::Config;
-use WineTestBot::PatchUtils;
use WineTestBot::Utils;
-#
-# Logging and error handling helpers
-#
-
-sub InfoMsg(@)
-{
- print @_;
-}
-
-sub LogMsg(@)
-{
- print "Build: ", @_;
-}
-
-sub Error(@)
-{
- print STDERR "$Name0:error: ", @_;
-}
-
-
#
# Build helpers
#
-my $ncpus;
-sub CountCPUs()
-{
- if (open(my $fh, "<", "/proc/cpuinfo"))
- {
- # Linux
- map { $ncpus++ if (/^processor/); } <$fh>;
- close($fh);
- }
- $ncpus ||= 1;
-}
-
-sub ApplyPatch($)
-{
- my ($PatchFile) = @_;
-
- InfoMsg "Applying patch\n";
- system("cd '$DataDir/wine' && ".
- "echo wine:HEAD=`git rev-parse HEAD` && ".
- "set -x && ".
- "git apply --verbose ". ShQuote($PatchFile) ." && ".
- "git add -A");
- if ($? != 0)
- {
- LogMsg "Patch failed to apply\n";
- return undef;
- }
-
- my $Impacts = GetPatchImpact($PatchFile, "nounits");
- if ($Impacts->{MakeMakefiles})
- {
- InfoMsg "\nRunning make_makefiles\n";
- system("cd '$DataDir/wine' && set -x && ./tools/make_makefiles");
- if ($? != 0)
- {
- LogMsg "make_makefiles failed\n";
- return undef;
- }
- }
-
- if ($Impacts->{Autoconf} && !$Impacts->{HasConfigure})
- {
- InfoMsg "\nRunning autoconf\n";
- system("cd '$DataDir/wine' && set -x && autoconf");
- if ($? != 0)
- {
- LogMsg "Autoconf failed\n";
- return undef;
- }
- }
-
- return $Impacts;
-}
sub BuildNative()
{
InfoMsg "\nRebuilding native tools\n";
+ my $CPUCount = GetCPUCount();
system("cd '$DataDir/build-native' && set -x && ".
- "time make -j$ncpus __tooldeps__");
+ "time make -j$CPUCount __tooldeps__");
if ($? != 0)
{
LogMsg "Rebuild of native tools failed\n";
@@ -160,8 +85,9 @@ sub BuildTestExecutables($$$)
}
InfoMsg "\nBuilding the $Bits-bit test executable(s)\n";
+ my $CPUCount = GetCPUCount();
system("cd '$DataDir/build-mingw$Bits' && set -x && ".
- "time make -j$ncpus ". join(" ", sort @BuildDirs));
+ "time make -j$CPUCount ". join(" ", sort @BuildDirs));
if ($? != 0)
{
LogMsg "Rebuild of $Bits-bit crossbuild failed\n";
@@ -262,6 +188,7 @@ if (!defined $Usage)
}
if (defined $Usage)
{
+ my $Name0 = GetToolName();
if ($Usage)
{
Error "try '$Name0 --help' for more information\n";
@@ -292,9 +219,7 @@ if ($DataDir =~ /'/)
# Run the builds
#
-CountCPUs();
-
-my $Impacts = ApplyPatch($PatchFile);
+my $Impacts = ApplyPatch("wine", $PatchFile);
if (!$Impacts or
($Impacts->{WineBuild} and !BuildNative()) or
diff --git a/testbot/bin/build/Reconfig.pl b/testbot/bin/build/Reconfig.pl
index 4aada3242..36748d66e 100755
--- a/testbot/bin/build/Reconfig.pl
+++ b/testbot/bin/build/Reconfig.pl
@@ -39,112 +39,15 @@ sub BEGIN
}
$::BuildEnv = 1;
}
-my $Name0 = $0;
-$Name0 =~ s+^.*/++;
-
+use Build::Utils;
use WineTestBot::Config;
-use WineTestBot::PatchUtils;
-
-
-#
-# Logging and error handling helpers
-#
-
-sub InfoMsg(@)
-{
- print @_;
-}
-
-sub LogMsg(@)
-{
- print "Reconfig: ", @_;
-}
-
-sub Error(@)
-{
- print STDERR "$Name0:error: ", @_;
-}
#
# Build helpers
#
-my $ncpus;
-sub CountCPUs()
-{
- if (open(my $fh, "<", "/proc/cpuinfo"))
- {
- # Linux
- map { $ncpus++ if (/^processor/); } <$fh>;
- close($fh);
- }
- $ncpus ||= 1;
-}
-
-sub BuildTestAgentd()
-{
- # If testagentd already exists it's likely already running
- # so don't rebuild it.
- if (! -x "$BinDir/build/testagentd")
- {
- InfoMsg "\nBuilding the native testagentd\n";
- system("cd '$::RootDir/src/testagentd' && set -x && ".
- "time make -j$ncpus build");
- if ($? != 0)
- {
- LogMsg "Build testagentd failed\n";
- return !1;
- }
- }
-
- InfoMsg "\nRebuilding the Windows TestAgentd\n";
- system("cd '$::RootDir/src/testagentd' && set -x && ".
- "time make -j$ncpus iso");
- if ($? != 0)
- {
- LogMsg "Build winetestbot.iso failed\n";
- return !1;
- }
-
- return 1;
-}
-
-sub BuildTestLauncher()
-{
- InfoMsg "\nRebuilding TestLauncher\n";
- system("cd '$::RootDir/src/TestLauncher' && set -x && ".
- "time make -j$ncpus");
- if ($? != 0)
- {
- LogMsg "Build TestLauncher failed\n";
- return !1;
- }
-
- return 1;
-}
-
-sub GitPull()
-{
- InfoMsg "\nUpdating the Wine source\n";
- system("cd '$DataDir/wine' && git pull");
- if ($? != 0)
- {
- LogMsg "Git pull failed\n";
- return !1;
- }
-
- my $ErrMessage = UpdateWineData("$DataDir/wine");
- if ($ErrMessage)
- {
- LogMsg "$ErrMessage\n";
- return !1;
- }
-
- return 1;
-}
-
sub BuildNative($)
{
my ($NoRm) = @_;
@@ -153,10 +56,11 @@ sub BuildNative($)
# Rebuild from scratch to make sure cruft will not accumulate
InfoMsg "\nRebuilding native tools\n";
+ my $CPUCount = GetCPUCount();
system("cd '$DataDir/build-native' && set -x && ".
($NoRm ? "" : "rm -rf * && ") .
"time ../wine/configure --enable-win64 --without-x --without-freetype --disable-winetest && ".
- "time make -j$ncpus __tooldeps__");
+ "time make -j$CPUCount __tooldeps__");
if ($? != 0)
{
@@ -176,11 +80,12 @@ sub BuildCross($$$)
# Rebuild from scratch to make sure cruft will not accumulate
InfoMsg "\nRebuilding the $Bits-bit test executables\n";
+ my $CPUCount = GetCPUCount();
my $Host = ($Bits == 64 ? "x86_64-w64-mingw32" : "i686-w64-mingw32");
system("cd '$DataDir/build-mingw$Bits' && set -x && ".
($NoRm ? "" : "rm -rf * && ") .
"time ../wine/configure --host=$Host --with-wine-tools=../build-native --without-x --without-freetype --disable-winetest && ".
- "time make -j$ncpus buildtests");
+ "time make -j$CPUCount buildtests");
if ($? != 0)
{
LogMsg "Build cross ($Bits bits) failed\n";
@@ -271,6 +176,7 @@ if (!defined $Usage)
}
if (defined $Usage)
{
+ my $Name0 = GetToolName();
if ($Usage)
{
Error "try '$Name0 --help' for more information\n";
@@ -308,10 +214,9 @@ if (! -d "$DataDir/staging" and ! mkdir "$DataDir/staging")
# Run the builds
#
-CountCPUs();
-
-exit(1) if (!BuildTestAgentd() or !BuildTestLauncher());
-exit(1) if ($OptUpdate and !GitPull());
+exit(1) if (!BuildNativeTestAgentd() or !BuildWindowsTestAgentd());
+exit(1) if (!BuildTestLauncher());
+exit(1) if ($OptUpdate and !GitPull("wine"));
exit(1) if ($OptBuild and !UpdateWineBuilds($Targets, $OptNoRm));
LogMsg "ok\n";
diff --git a/testbot/bin/build/WineReconfig.pl b/testbot/bin/build/WineReconfig.pl
index 77722734c..b30ddd190 100755
--- a/testbot/bin/build/WineReconfig.pl
+++ b/testbot/bin/build/WineReconfig.pl
@@ -36,92 +36,15 @@ sub BEGIN
}
$::BuildEnv = 1;
}
-my $Name0 = $0;
-$Name0 =~ s+^.*/++;
-
-
-use Digest::SHA;
-use File::Path;
+use Build::Utils;
use WineTestBot::Config;
-use WineTestBot::PatchUtils;
-
-
-#
-# Logging and error handling helpers
-#
-
-sub InfoMsg(@)
-{
- print @_;
-}
-
-sub LogMsg(@)
-{
- print "Reconfig: ", @_;
-}
-
-sub Error(@)
-{
- print STDERR "$Name0:error: ", @_;
-}
#
# Build helpers
#
-my $ncpus;
-sub CountCPUs()
-{
- if (open(my $fh, "<", "/proc/cpuinfo"))
- {
- # Linux
- map { $ncpus++ if (/^processor/); } <$fh>;
- close($fh);
- }
- $ncpus ||= 1;
-}
-
-sub BuildTestAgentd()
-{
- # If testagentd already exists it's likely already running
- # so don't rebuild it.
- if (! -x "$BinDir/build/testagentd")
- {
- InfoMsg "\nBuilding the native testagentd\n";
- system("cd '$::RootDir/src/testagentd' && set -x && ".
- "time make -j$ncpus build");
- if ($? != 0)
- {
- LogMsg "Build testagentd failed\n";
- return !1;
- }
- }
-
- return 1;
-}
-
-sub GitPull()
-{
- InfoMsg "\nUpdating the Wine source\n";
- system("cd '$DataDir/wine' && git pull");
- if ($? != 0)
- {
- LogMsg "Git pull failed\n";
- return !1;
- }
-
- my $ErrMessage = UpdateWineData("$DataDir/wine");
- if ($ErrMessage)
- {
- LogMsg "$ErrMessage\n";
- return !1;
- }
-
- return 1;
-}
-
sub BuildWine($$$$)
{
my ($Targets, $NoRm, $Build, $Extras) = @_;
@@ -132,10 +55,11 @@ sub BuildWine($$$$)
# If $NoRm is not set, rebuild from scratch to make sure cruft will not
# accumulate
InfoMsg "\nRebuilding the $Build Wine\n";
+ my $CPUCount = GetCPUCount();
system("cd '$DataDir/build-$Build' && set -x && ".
($NoRm ? "" : "rm -rf * && ") .
"time ../wine/configure $Extras && ".
- "time make -j$ncpus");
+ "time make -j$CPUCount");
if ($? != 0)
{
LogMsg "The $Build build failed\n";
@@ -159,160 +83,30 @@ sub UpdateWineBuilds($$)
# WinePrefix helpers
#
-sub VerifyAddOn($$)
-{
- my ($AddOn, $Arch) = @_;
-
- my $Sha256 = Digest::SHA->new(256);
- eval { $Sha256->addfile("$DataDir/$AddOn->{name}/$AddOn->{filename}") };
- return "$@" if ($@);
-
- my $Checksum = $Sha256->hexdigest();
- return undef if ($Checksum eq $AddOn->{$Arch});
- return "Bad checksum for '$AddOn->{filename}'";
-}
-
-sub UpdateAddOn($$$)
+sub UpdateWinePrefixes($)
{
- my ($AddOn, $Name, $Arch) = @_;
+ my ($Targets) = @_;
- if (!defined $AddOn)
- {
- LogMsg "Could not get information on the $Name addon\n";
- return 0;
- }
- if (!$AddOn->{version})
- {
- LogMsg "Could not get the $Name version\n";
- return 0;
- }
- if (!$AddOn->{$Arch})
+ # Set up brand new WinePrefixes ready for use for testing.
+ # This way we do it once instead of doing it for every test, thus saving
+ # time. Note that this requires using a different wineprefix for each build.
+ foreach my $Build ("win32", "wow64", "wow32")
{
- LogMsg "Could not get the $Name $Arch checksum\n";
- return 0;
- }
-
- $AddOn->{filename} = "wine". ($Name eq "gecko" ? "_" : "-") .
- "$Name-$AddOn->{version}".
- ($Arch eq "" ? "" : "-$Arch") .".msi";
- return 1 if (!VerifyAddOn($AddOn, $Arch));
+ next if (!$Targets->{$Build});
- InfoMsg "Downloading $AddOn->{filename}\n";
- mkdir "$DataDir/$Name";
-
- my $Url="http://dl.winehq.org/wine/wine-$Name/$AddOn->{version}/$AddOn->{filename}";
- for (1..3)
- {
- system("cd '$DataDir/$Name' && set -x && ".
- "wget --no-verbose -O- '$Url' >'$AddOn->{filename}'");
- last if ($? == 0);
- }
- my $ErrMessage = VerifyAddOn($AddOn, $Arch);
- return 1 if (!defined $ErrMessage);
- LogMsg "$ErrMessage\n";
- return 0;
-}
-
-sub UpdateAddOns()
-{
- my %AddOns;
- if (open(my $fh, "<", "$DataDir/wine/dlls/appwiz.cpl/addons.c"))
- {
- my $Arch = "";
- while (my $Line= <$fh>)
+ # Wait for the wineprefix creation to complete so it is really done
+ # before the snapshot gets updated.
+ SetupWineEnvironment($Build);
+ my $ErrMessage = CreateWinePrefix($Build, "wait");
+ if (defined $ErrMessage)
{
- if ($Line =~ /^\s*#\s*define\s+ARCH_STRING\s+"([^"]+)"/)
- {
- $Arch = $1;
- }
- elsif ($Line =~ /^\s*#\s*define\s*(GECKO|MONO)_VERSION\s*"([^"]+)"/)
- {
- my ($AddOn, $Version) = ($1, $2);
- $AddOn =~ tr/A-Z/a-z/;
- $AddOns{$AddOn}->{name} = $AddOn;
- $AddOns{$AddOn}->{version} = $Version;
- }
- elsif ($Line =~ /^\s*#\s*define\s*(GECKO|MONO)_SHA\s*"([^"]+)"/)
- {
- my ($AddOn, $Checksum) = ($1, $2);
- $AddOn =~ tr/A-Z/a-z/;
- $AddOns{$AddOn}->{$Arch} = $Checksum;
- $Arch = "";
- }
+ LogMsg "$ErrMessage\n";
+ return 0;
}
- close($fh);
- }
- else
- {
- LogMsg "Could not open 'wine/dlls/appwiz.cpl/addons.c': $!\n";
- return 0;
- }
-
- return UpdateAddOn($AddOns{gecko}, "gecko", "x86") &&
- UpdateAddOn($AddOns{gecko}, "gecko", "x86_64") &&
- UpdateAddOn($AddOns{mono}, "mono", "");
-}
-
-# See also WineTest.pl
-sub SetupWineEnvironment($)
-{
- my ($Build) = @_;
-
- $ENV{WINEPREFIX} = "$DataDir/wineprefix-$Build";
- $ENV{DISPLAY} ||= ":0.0";
-}
-
-# See also WineTest.pl
-sub RunWine($$$)
-{
- my ($Build, $Cmd, $CmdArgs) = @_;
-
- my $Magic = `cd '$DataDir/build-$Build' && file $Cmd`;
- my $Wine = ($Magic =~ /ELF 64/ ? "./wine64" : "./wine");
- return system("cd '$DataDir/build-$Build' && set -x && ".
- "time $Wine $Cmd $CmdArgs");
-}
-
-# Setup a brand new WinePrefix ready for use for testing.
-# This way we do it once instead of doing it for every test, thus saving
-# time. Note that this requires using a different wineprefix for each build.
-sub NewWinePrefix($$)
-{
- my ($Targets, $Build) = @_;
-
- return 1 if (!$Targets->{$Build});
-
- InfoMsg "\nRecreating the $Build wineprefix\n";
- SetupWineEnvironment($Build);
- rmtree($ENV{WINEPREFIX});
-
- # Crash dialogs cause delays so disable them
- if (RunWine($Build, "./programs/reg/reg.exe.so", "ADD HKCU\\\\Software\\\\Wine\\\\WineDbg /v ShowCrashDialog /t REG_DWORD /d 0"))
- {
- LogMsg "Failed to disable the $Build build crash dialogs: $!\n";
- return 0;
}
-
- # Ensure the WinePrefix has been fully created before updating the snapshot
- system("cd '$DataDir/build-$Build' && ./server/wineserver -w");
-
return 1;
}
-sub UpdateWinePrefixes($)
-{
- my ($Targets) = @_;
-
- return NewWinePrefix($Targets, "win32") &&
- # The wow32 and wow64 wineprefixes:
- # - Are essentially identical.
- # - Must be created after both WoW builds have been updated.
- # - Make it possible to run the wow32 and wow64 tests in separate
- # prefixes, thus ensuring they don't interfere with each other.
- NewWinePrefix($Targets, "wow64") &&
- NewWinePrefix($Targets, "wow32");
-}
-
#
# Setup and command line processing
@@ -393,6 +187,7 @@ if (!defined $Usage)
}
if (defined $Usage)
{
+ my $Name0 = GetToolName();
if ($Usage)
{
Error "try '$Name0 --help' for more information\n";
@@ -436,10 +231,8 @@ if ($DataDir =~ /'/)
# Run the builds and/or tests
#
-CountCPUs();
-
-exit(1) if (!BuildTestAgentd());
-exit(1) if ($OptUpdate and !GitPull());
+exit(1) if (!BuildNativeTestAgentd());
+exit(1) if ($OptUpdate and !GitPull("wine"));
exit(1) if ($OptAddOns and !UpdateAddOns());
exit(1) if ($OptBuild and !UpdateWineBuilds($Targets, $OptNoRm));
exit(1) if ($OptWinePrefix and !UpdateWinePrefixes($Targets));
diff --git a/testbot/bin/build/WineTest.pl b/testbot/bin/build/WineTest.pl
index b29440e21..9c264b485 100755
--- a/testbot/bin/build/WineTest.pl
+++ b/testbot/bin/build/WineTest.pl
@@ -40,93 +40,16 @@ sub BEGIN
}
$::BuildEnv = 1;
}
-my $Name0 = $0;
-$Name0 =~ s+^.*/++;
-
+use Build::Utils;
use WineTestBot::Config;
-use WineTestBot::PatchUtils;
use WineTestBot::Utils;
-#
-# Logging and error handling helpers
-#
-
-sub InfoMsg(@)
-{
- print @_;
-}
-
-sub LogMsg(@)
-{
- print "Task: ", @_;
-}
-
-sub Error(@)
-{
- print STDERR "$Name0:error: ", @_;
-}
-
-
#
# Build helpers
#
-my $ncpus;
-sub CountCPUs()
-{
- if (open(my $fh, "<", "/proc/cpuinfo"))
- {
- # Linux
- map { $ncpus++ if (/^processor/); } <$fh>;
- close($fh);
- }
- $ncpus ||= 1;
-}
-
-sub ApplyPatch($)
-{
- my ($PatchFile) = @_;
-
- InfoMsg "Applying patch\n";
- system("cd '$DataDir/wine' && ".
- "echo wine:HEAD=`git rev-parse HEAD` && ".
- "set -x && ".
- "git apply --verbose ". ShQuote($PatchFile) ." && ".
- "git add -A");
- if ($? != 0)
- {
- LogMsg "Patch failed to apply\n";
- return undef;
- }
-
- my $Impacts = GetPatchImpact($PatchFile, "nounits");
- if ($Impacts->{MakeMakefiles})
- {
- InfoMsg "\nRunning make_makefiles\n";
- system("cd '$DataDir/wine' && set -x && ./tools/make_makefiles");
- if ($? != 0)
- {
- LogMsg "make_makefiles failed\n";
- return undef;
- }
- }
-
- if ($Impacts->{Autoconf} && !$Impacts->{HasConfigure})
- {
- InfoMsg "\nRunning autoconf\n";
- system("cd '$DataDir/wine' && set -x && autoconf");
- if ($? != 0)
- {
- LogMsg "Autoconf failed\n";
- return undef;
- }
- }
-
- return $Impacts;
-}
-
sub BuildWine($$)
{
my ($Targets, $Build) = @_;
@@ -134,8 +57,9 @@ sub BuildWine($$)
return 1 if (!$Targets->{$Build});
InfoMsg "\nRebuilding the $Build Wine\n";
+ my $CPUCount = GetCPUCount();
system("cd '$DataDir/build-$Build' && set -x && ".
- "time make -j$ncpus");
+ "time make -j$CPUCount");
if ($? != 0)
{
LogMsg "The $Build build failed\n";
@@ -150,25 +74,6 @@ sub BuildWine($$)
# Test helpers
#
-# See also WineReconfig.pl
-sub SetupWineEnvironment($)
-{
- my ($Build) = @_;
-
- $ENV{WINEPREFIX} = "$DataDir/wineprefix-$Build";
- $ENV{DISPLAY} ||= ":0.0";
-}
-
-# See also WineReconfig.pl
-sub RunWine($$$)
-{
- my ($Build, $Cmd, $CmdArgs) = @_;
-
- my $Magic = `cd '$DataDir/build-$Build' && file $Cmd`;
- my $Wine = ($Magic =~ /ELF 64/ ? "./wine64" : "./wine");
- return system("cd '$DataDir/build-$Build' && set -x && ".
- "time $Wine $Cmd $CmdArgs");
-}
sub DailyWineTest($$$$$)
{
@@ -330,6 +235,12 @@ if (!defined $Usage)
}
if (defined $Usage)
{
+ my $Name0 = GetToolName();
+ if ($Usage)
+ {
+ Error "try '$Name0 --help' for more information\n";
+ exit $Usage;
+ }
print "Usage: $Name0 [--help] --testpatch TARGETS PATCH\n";
print "or $Name0 [--help] --winetest [--no-submit] TARGETS BASETAG ARGS\n";
print "\n";
@@ -365,11 +276,9 @@ if ($DataDir =~ /'/)
# Clean up old reports
map { unlink("$_.report") } keys %AllTargets;
-CountCPUs();
-
if ($Action eq "testpatch")
{
- my $Impacts = ApplyPatch($FileName);
+ my $Impacts = ApplyPatch("wine", $FileName);
exit(1) if (!$Impacts or
!BuildWine($Targets, "win32") or
!BuildWine($Targets, "wow64") or
diff --git a/testbot/lib/Build/Utils.pm b/testbot/lib/Build/Utils.pm
new file mode 100644
index 000000000..038c188f2
--- /dev/null
+++ b/testbot/lib/Build/Utils.pm
@@ -0,0 +1,363 @@
+# -*- Mode: Perl; perl-indent-level: 2; indent-tabs-mode: nil -*-
+# Copyright 2018 Francois Gouget
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+
+use strict;
+
+package Build::Utils;
+
+=head1 NAME
+
+Build::Utils - Utility functions for the build scripts
+
+=cut
+
+use Exporter 'import';
+our @EXPORT = qw(GetToolName InfoMsg LogMsg Error
+ GitPull ApplyPatch
+ GetCPUCount BuildNativeTestAgentd BuildWindowsTestAgentd
+ BuildTestLauncher UpdateAddOns
+ SetupWineEnvironment RunWine CreateWinePrefix);
+
+use Digest::SHA;
+use File::Path;
+
+use WineTestBot::Config;
+use WineTestBot::PatchUtils;
+use WineTestBot::Utils;
+
+
+#
+# Logging and error handling
+#
+
+my $Name0 = $0;
+$Name0 =~ s+^.*/++;
+
+sub GetToolName()
+{
+ return $Name0;
+}
+
+sub InfoMsg(@)
+{
+ print @_;
+}
+
+sub LogMsg(@)
+{
+ print "Task: ", @_;
+}
+
+sub Error(@)
+{
+ print STDERR "$Name0:error: ", @_;
+}
+
+
+#
+# Repository updates
+#
+
+sub GitPull($)
+{
+ my ($Dir) = @_;
+
+ InfoMsg "\nUpdating the $Dir source\n";
+ system("cd '$DataDir/$Dir' && git pull");
+ if ($? != 0)
+ {
+ LogMsg "Git pull failed\n";
+ return !1;
+ }
+
+ if ($Dir eq "wine")
+ {
+ my $ErrMessage = UpdateWineData("$DataDir/$Dir");
+ if ($ErrMessage)
+ {
+ LogMsg "$ErrMessage\n";
+ return !1;
+ }
+ }
+
+ return 1;
+}
+
+sub ApplyPatch($$)
+{
+ my ($Dir, $PatchFile) = @_;
+
+ InfoMsg "Applying patch\n";
+ system("cd '$DataDir/$Dir' && ".
+ "echo $Dir:HEAD=`git rev-parse HEAD` && ".
+ "set -x && ".
+ "git apply --verbose ". ShQuote($PatchFile) ." && ".
+ "git add -A");
+ if ($? != 0)
+ {
+ LogMsg "Patch failed to apply\n";
+ return undef;
+ }
+
+ my $Impacts = GetPatchImpact($PatchFile, "nounits");
+ if ($Impacts->{MakeMakefiles})
+ {
+ InfoMsg "\nRunning make_makefiles\n";
+ system("cd '$DataDir/$Dir' && set -x && ./tools/make_makefiles");
+ if ($? != 0)
+ {
+ LogMsg "make_makefiles failed\n";
+ return undef;
+ }
+ }
+
+ if ($Impacts->{Autoconf} && !$Impacts->{HasConfigure})
+ {
+ InfoMsg "\nRunning autoconf\n";
+ system("cd '$DataDir/$Dir' && set -x && autoconf");
+ if ($? != 0)
+ {
+ LogMsg "Autoconf failed\n";
+ return undef;
+ }
+ }
+
+ return $Impacts;
+}
+
+
+#
+# Build helpers
+#
+
+my $_CPUCount;
+
+sub GetCPUCount()
+{
+ if (!defined $_CPUCount)
+ {
+ if (open(my $Fh, "<", "/proc/cpuinfo"))
+ {
+ # Linux
+ map { $_CPUCount++ if (/^processor/); } <$Fh>;
+ close($Fh);
+ }
+ $_CPUCount ||= 1;
+ }
+ return $_CPUCount;
+}
+
+sub BuildNativeTestAgentd()
+{
+ # If testagentd already exists it's likely already running
+ # so don't rebuild it.
+ return 1 if (-x "$BinDir/build/testagentd");
+
+ InfoMsg "\nBuilding the native testagentd\n";
+ my $CPUCount = GetCPUCount();
+ system("cd '$::RootDir/src/testagentd' && set -x && ".
+ "time make -j$CPUCount build");
+ if ($? != 0)
+ {
+ LogMsg "Build testagentd failed\n";
+ return !1;
+ }
+
+ return 1;
+}
+
+sub BuildWindowsTestAgentd()
+{
+ InfoMsg "\nRebuilding the Windows TestAgentd\n";
+ my $CPUCount = GetCPUCount();
+ system("cd '$::RootDir/src/testagentd' && set -x && ".
+ "time make -j$CPUCount iso");
+ if ($? != 0)
+ {
+ LogMsg "Build winetestbot.iso failed\n";
+ return !1;
+ }
+
+ return 1;
+}
+
+sub BuildTestLauncher()
+{
+ InfoMsg "\nRebuilding TestLauncher\n";
+ my $CPUCount = GetCPUCount();
+ system("cd '$::RootDir/src/TestLauncher' && set -x && ".
+ "time make -j$CPUCount");
+ if ($? != 0)
+ {
+ LogMsg "Build TestLauncher failed\n";
+ return !1;
+ }
+
+ return 1;
+}
+
+
+#
+# Wine addons updates
+#
+
+sub _VerifyAddOn($$)
+{
+ my ($AddOn, $Arch) = @_;
+
+ my $Sha256 = Digest::SHA->new(256);
+ eval { $Sha256->addfile("$DataDir/$AddOn->{name}/$AddOn->{filename}") };
+ return "$@" if ($@);
+
+ my $Checksum = $Sha256->hexdigest();
+ return undef if ($Checksum eq $AddOn->{$Arch});
+ return "Bad checksum for '$AddOn->{filename}'";
+}
+
+sub _UpdateAddOn($$$)
+{
+ my ($AddOn, $Name, $Arch) = @_;
+
+ if (!defined $AddOn)
+ {
+ LogMsg "Could not get information on the $Name addon\n";
+ return 0;
+ }
+ if (!$AddOn->{version})
+ {
+ LogMsg "Could not get the $Name version\n";
+ return 0;
+ }
+ if (!$AddOn->{$Arch})
+ {
+ LogMsg "Could not get the $Name $Arch checksum\n";
+ return 0;
+ }
+
+ $AddOn->{filename} = "wine". ($Name eq "gecko" ? "_" : "-") .
+ "$Name-$AddOn->{version}".
+ ($Arch eq "" ? "" : "-$Arch") .".msi";
+ return 1 if (!_VerifyAddOn($AddOn, $Arch));
+
+ InfoMsg "Downloading $AddOn->{filename}\n";
+ mkdir "$DataDir/$Name";
+
+ my $Url="http://dl.winehq.org/wine/wine-$Name/$AddOn->{version}/$AddOn->{filename}";
+ for (1..3)
+ {
+ system("cd '$DataDir/$Name' && set -x && ".
+ "wget --no-verbose -O- '$Url' >'$AddOn->{filename}'");
+ last if ($? == 0);
+ }
+ my $ErrMessage = _VerifyAddOn($AddOn, $Arch);
+ return 1 if (!defined $ErrMessage);
+ LogMsg "$ErrMessage\n";
+ return 0;
+}
+
+sub UpdateAddOns()
+{
+ my %AddOns;
+ if (open(my $fh, "<", "$DataDir/wine/dlls/appwiz.cpl/addons.c"))
+ {
+ my $Arch = "";
+ while (my $Line= <$fh>)
+ {
+ if ($Line =~ /^\s*#\s*define\s+ARCH_STRING\s+"([^"]+)"/)
+ {
+ $Arch = $1;
+ }
+ elsif ($Line =~ /^\s*#\s*define\s*(GECKO|MONO)_VERSION\s*"([^"]+)"/)
+ {
+ my ($AddOn, $Version) = ($1, $2);
+ $AddOn =~ tr/A-Z/a-z/;
+ $AddOns{$AddOn}->{name} = $AddOn;
+ $AddOns{$AddOn}->{version} = $Version;
+ }
+ elsif ($Line =~ /^\s*#\s*define\s*(GECKO|MONO)_SHA\s*"([^"]+)"/)
+ {
+ my ($AddOn, $Checksum) = ($1, $2);
+ $AddOn =~ tr/A-Z/a-z/;
+ $AddOns{$AddOn}->{$Arch} = $Checksum;
+ $Arch = "";
+ }
+ }
+ close($fh);
+ }
+ else
+ {
+ LogMsg "Could not open 'wine/dlls/appwiz.cpl/addons.c': $!\n";
+ return 0;
+ }
+
+ return _UpdateAddOn($AddOns{gecko}, "gecko", "x86") &&
+ _UpdateAddOn($AddOns{gecko}, "gecko", "x86_64") &&
+ _UpdateAddOn($AddOns{mono}, "mono", "");
+}
+
+
+#
+# Wine helpers
+#
+
+sub SetupWineEnvironment($)
+{
+ my ($Build) = @_;
+
+ $ENV{WINEPREFIX} = "$DataDir/wineprefix-$Build";
+ $ENV{DISPLAY} ||= ":0.0";
+}
+
+sub RunWine($$$)
+{
+ my ($Build, $Cmd, $CmdArgs) = @_;
+
+ my $Magic = `cd '$DataDir/build-$Build' && file $Cmd`;
+ my $Wine = ($Magic =~ /ELF 64/ ? "./wine64" : "./wine");
+ return system("cd '$DataDir/build-$Build' && set -x && ".
+ "time $Wine $Cmd $CmdArgs");
+}
+
+
+#
+# WinePrefix helpers
+#
+
+sub CreateWinePrefix($$)
+{
+ my ($Build, $Wait) = @_;
+
+ return "\$WINEPREFIX is not set!" if (!$ENV{WINEPREFIX});
+ rmtree($ENV{WINEPREFIX});
+
+ # Crash dialogs cause delays so disable them
+ if (RunWine($Build, "./programs/reg/reg.exe.so", "ADD HKCU\\\\Software\\\\Wine\\\\WineDbg /v ShowCrashDialog /t REG_DWORD /d 0"))
+ {
+ return "Failed to disable the $Build build crash dialogs: $!";
+ }
+
+ if ($Wait)
+ {
+ # Ensure the WinePrefix has been fully created and the registry files
+ # saved before returning.
+ system("cd '$DataDir/build-$Build' && ./server/wineserver -w");
+ }
+
+ return undef;
+}
+
+1;
--
2.18.0
1
0
22 Aug '18
Also fix the sanitation: WineTest allows dots and dashes in the tag.
Signed-off-by: Francois Gouget <fgouget(a)codeweavers.com>
---
testbot/bin/WineRunTask.pl | 16 ++++++----------
testbot/bin/WineRunWineTest.pl | 6 ++----
testbot/bin/build/WineTest.pl | 3 ++-
testbot/lib/WineTestBot/Utils.pm | 24 +++++++++++++++++++++++-
4 files changed, 33 insertions(+), 16 deletions(-)
diff --git a/testbot/bin/WineRunTask.pl b/testbot/bin/WineRunTask.pl
index 27dd8e7b3..c602979b1 100755
--- a/testbot/bin/WineRunTask.pl
+++ b/testbot/bin/WineRunTask.pl
@@ -41,11 +41,12 @@ $Name0 =~ s+^.*/++;
use WineTestBot::Config;
+use WineTestBot::Engine::Notify;
use WineTestBot::Jobs;
-use WineTestBot::VMs;
use WineTestBot::Log;
use WineTestBot::LogUtils;
-use WineTestBot::Engine::Notify;
+use WineTestBot::Utils;
+use WineTestBot::VMs;
#
@@ -455,18 +456,13 @@ elsif ($Step->Type eq "suite")
{
$Keepalive = 60;
$Script .= "$FileName ";
- my $Tag = lc($VM->Name);
- $Tag =~ s/^$TagPrefix//;
- $Tag =~ s/[^a-zA-Z0-9]/-/g;
- if ($VM->Type eq "win64")
- {
- $Tag .= "-" . ($Step->FileType eq "exe64" ? "64" : "32");
- }
if (defined($WebHostName))
{
my $StepTask = 100 * $StepNo + $TaskNo;
$Script .= "-u \"http://$WebHostName/JobDetails.pl?Key=$JobId&s$StepTask=1#k$StepTask\" ";
}
+ my $Tag = $VM->Type ne "win64" ? "" : $Step->FileType eq "exe64" ? "64" : "32";
+ $Tag = BuildTag($VM->Name, $Tag);
my $Info = $VM->Description ? $VM->Description : "";
if ($VM->Details)
{
@@ -481,7 +477,7 @@ elsif ($Step->Type eq "suite")
$Info =~ s/"/\\"/g;
$Info =~ s/%/%%/g;
$Info =~ s/%/%%/g;
- $Script .= "-q -o $RptFileName -t $TagPrefix-$Tag -m \"$EMail\" -i \"$Info\"\r\n".
+ $Script .= "-q -o $RptFileName -t $Tag -m \"$EMail\" -i \"$Info\"\r\n".
"$FileName -q -s $RptFileName\r\n";
}
Debug(Elapsed($Start), " Sending the script: [$Script]\n");
diff --git a/testbot/bin/WineRunWineTest.pl b/testbot/bin/WineRunWineTest.pl
index ac5594654..216811116 100755
--- a/testbot/bin/WineRunWineTest.pl
+++ b/testbot/bin/WineRunWineTest.pl
@@ -425,10 +425,8 @@ my $Script = "#!/bin/sh\n".
" ../bin/build/WineTest.pl ";
if ($Step->Type eq "suite")
{
- my $Tag = lc($VM->Name);
- $Tag =~ s/^$TagPrefix//;
- $Tag =~ s/[^a-zA-Z0-9]/-/g;
- $Script .= "--winetest ". $Task->CmdLineArg ." $TagPrefix-$Tag ";
+ my $BaseTag = BuildTag($VM->Name);
+ $Script .= "--winetest ". $Task->CmdLineArg ." $BaseTag ";
if (defined $WebHostName)
{
my $StepTask = 100 * $StepNo + $TaskNo;
diff --git a/testbot/bin/build/WineTest.pl b/testbot/bin/build/WineTest.pl
index 3310b4c53..b29440e21 100755
--- a/testbot/bin/build/WineTest.pl
+++ b/testbot/bin/build/WineTest.pl
@@ -181,8 +181,9 @@ sub DailyWineTest($$$$$)
# Run WineTest. Ignore the exit code since it returns non-zero whenever
# there are test failures.
+ my $Tag = SanitizeTag("$BaseTag-$Build");
RunWine($Build, "./programs/winetest/winetest.exe.so",
- "-c -o '../$Build.report' -t $BaseTag-$Build ". ShArgv2Cmd(@$Args));
+ "-c -o '../$Build.report' -t $Tag ". ShArgv2Cmd(@$Args));
if (!-f "$Build.report")
{
LogMsg "WineTest did not produce a report file\n";
diff --git a/testbot/lib/WineTestBot/Utils.pm b/testbot/lib/WineTestBot/Utils.pm
index f64310b6b..6fa0ccce7 100644
--- a/testbot/lib/WineTestBot/Utils.pm
+++ b/testbot/lib/WineTestBot/Utils.pm
@@ -1,5 +1,6 @@
# -*- Mode: Perl; perl-indent-level: 2; indent-tabs-mode: nil -*-
# Copyright 2009 Ge van Geldorp
+# Copyright 2012-2018 Francois Gouget
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
@@ -29,7 +30,7 @@ use Exporter 'import';
our @EXPORT = qw(MakeSecureURL SecureConnection GenerateRandomString
OpenNewFile CreateNewFile CreateNewLink CreateNewDir
DurationToString BuildEMailRecipient IsValidFileName
- ShQuote ShArgv2Cmd);
+ BuildTag SanitizeTag ShQuote ShArgv2Cmd);
use Fcntl;
@@ -175,6 +176,27 @@ sub CreateNewDir($$)
}
+#
+# WineTest helpers
+#
+
+sub SanitizeTag($)
+{
+ my ($Tag) = @_;
+ $Tag =~ s/[^a-zA-Z0-9.-]/-/g;
+ return substr($Tag, 0, 30);
+}
+
+sub BuildTag($;$)
+{
+ my ($VMName, $Tag) = @_;
+
+ $Tag = $Tag ? "$VMName-$Tag" : $VMName;
+ $Tag =~ s/^$TagPrefix//;
+ return SanitizeTag("$TagPrefix-$Tag");
+}
+
+
#
# Shell helpers
#
--
2.18.0
1
0
[PATCH v3 2/2] crypt32: Properly check root certificate in CERT_CHAIN_REVOCATION_CHECK_CHAIN.
by Zhiyi Zhang 22 Aug '18
by Zhiyi Zhang 22 Aug '18
22 Aug '18
Original patch by Michael Müller.
Root certificates don't have CRL Distribution Point or Authority Info Access field.
Don't report error with CERT_CHAIN_REVOCATION_CHECK_CHAIN in CertGetCertificateChain()
because of this.
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
v3: v2 got altered somehow in the mail client. Ignore CRYPT_E_NO_REVOCATION_CHECK only with CERT_CHAIN_REVOCATION_CHECK_CHAIN.
dlls/crypt32/chain.c | 5 +++++
dlls/crypt32/tests/chain.c | 6 +++---
2 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/dlls/crypt32/chain.c b/dlls/crypt32/chain.c
index d7015d797d..41c87b7ae7 100644
--- a/dlls/crypt32/chain.c
+++ b/dlls/crypt32/chain.c
@@ -2698,6 +2698,11 @@ static void CRYPT_VerifyChainRevocation(PCERT_CHAIN_CONTEXT chain,
ret = CertVerifyRevocation(X509_ASN_ENCODING,
CERT_CONTEXT_REVOCATION_TYPE, 1, (void **)&certToCheck,
revocationFlags, &revocationPara, &revocationStatus);
+
+ if (!ret && chainFlags & CERT_CHAIN_REVOCATION_CHECK_CHAIN
+ && revocationStatus.dwError == CRYPT_E_NO_REVOCATION_CHECK && revocationPara.pIssuerCert == NULL)
+ ret = TRUE;
+
if (!ret)
{
PCERT_CHAIN_ELEMENT element = CRYPT_FindIthElementInChain(
diff --git a/dlls/crypt32/tests/chain.c b/dlls/crypt32/tests/chain.c
index a995c81239..e2a7633526 100644
--- a/dlls/crypt32/tests/chain.c
+++ b/dlls/crypt32/tests/chain.c
@@ -4156,9 +4156,9 @@ static void testGetCertChain(void)
ret = CertGetCertificateChain(NULL, cert, &fileTime, store, ¶, CERT_CHAIN_REVOCATION_CHECK_CHAIN, NULL, &chain);
ok(ret, "CertGetCertificateChain failed: %u\n", GetLastError());
- todo_wine ok(!chain->TrustStatus.dwErrorStatus
- || broken(chain->TrustStatus.dwErrorStatus == CERT_TRUST_REVOCATION_STATUS_UNKNOWN), /* XP */
- "chain->TrustStatus.dwErrorStatus = %x\n", chain->TrustStatus.dwErrorStatus);
+ ok(!chain->TrustStatus.dwErrorStatus
+ || broken(chain->TrustStatus.dwErrorStatus == CERT_TRUST_REVOCATION_STATUS_UNKNOWN), /* XP */
+ "chain->TrustStatus.dwErrorStatus = %x\n", chain->TrustStatus.dwErrorStatus);
pCertFreeCertificateChain(chain);
ret = CertGetCertificateChain(NULL, cert, &fileTime, store, ¶, CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT,
--
2.18.0
1
0
[PATCH v3 1/2] crypt32/tests: Add revocation flags tests for CertGetCertificateChain().
by Zhiyi Zhang 22 Aug '18
by Zhiyi Zhang 22 Aug '18
22 Aug '18
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
v3: Avoid leaking chain. Supersede 150010,150011.
dlls/crypt32/tests/chain.c | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/dlls/crypt32/tests/chain.c b/dlls/crypt32/tests/chain.c
index a6599b21ae..a995c81239 100644
--- a/dlls/crypt32/tests/chain.c
+++ b/dlls/crypt32/tests/chain.c
@@ -4147,6 +4147,26 @@ static void testGetCertChain(void)
pCertFreeCertificateChain(chain);
+ /* Test revocation flags */
+ ret = CertGetCertificateChain(NULL, cert, &fileTime, store, ¶, CERT_CHAIN_REVOCATION_CHECK_END_CERT, NULL,
+ &chain);
+ ok(ret, "CertGetCertificateChain failed: %u\n", GetLastError());
+ ok(!chain->TrustStatus.dwErrorStatus, "chain->TrustStatus.dwErrorStatus = %x\n", chain->TrustStatus.dwErrorStatus);
+ pCertFreeCertificateChain(chain);
+
+ ret = CertGetCertificateChain(NULL, cert, &fileTime, store, ¶, CERT_CHAIN_REVOCATION_CHECK_CHAIN, NULL, &chain);
+ ok(ret, "CertGetCertificateChain failed: %u\n", GetLastError());
+ todo_wine ok(!chain->TrustStatus.dwErrorStatus
+ || broken(chain->TrustStatus.dwErrorStatus == CERT_TRUST_REVOCATION_STATUS_UNKNOWN), /* XP */
+ "chain->TrustStatus.dwErrorStatus = %x\n", chain->TrustStatus.dwErrorStatus);
+ pCertFreeCertificateChain(chain);
+
+ ret = CertGetCertificateChain(NULL, cert, &fileTime, store, ¶, CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT,
+ NULL, &chain);
+ ok(ret, "CertGetCertificateChain failed: %u\n", GetLastError());
+ ok(!chain->TrustStatus.dwErrorStatus, "chain->TrustStatus.dwErrorStatus = %x\n", chain->TrustStatus.dwErrorStatus);
+ pCertFreeCertificateChain(chain);
+
/* Test HCCE_LOCAL_MACHINE */
ret = CertGetCertificateChain(HCCE_LOCAL_MACHINE, cert, &fileTime, store, ¶, 0, NULL, &chain);
ok(ret, "CertGetCertificateChain failed: %u\n", GetLastError());
--
2.18.0
1
0
[PATCH v2 2/2] crypt32: Properly check root certificate in CERT_CHAIN_REVOCATION_CHECK_CHAIN.
by Zhiyi Zhang 22 Aug '18
by Zhiyi Zhang 22 Aug '18
22 Aug '18
Original patch by Michael Müller.
Root certificates don't have CRL Distribution Point or Authority Info Access field.
Don't report error with CERT_CHAIN_REVOCATION_CHECK_CHAIN in CertGetCertificateChain()
because of this.
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
v2: ignore CRYPT_E_NO_REVOCATION_CHECK only with CERT_CHAIN_REVOCATION_CHECK_CHAIN.
dlls/crypt32/chain.c | 5 +++++
dlls/crypt32/tests/chain.c | 6 +++---
2 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/dlls/crypt32/chain.c b/dlls/crypt32/chain.c
index d7015d797d..41c87b7ae7 100644
--- a/dlls/crypt32/chain.c
+++ b/dlls/crypt32/chain.c
@@ -2698,6 +2698,11 @@ static void CRYPT_VerifyChainRevocation(PCERT_CHAIN_CONTEXT chain,
ret = CertVerifyRevocation(X509_ASN_ENCODING,
CERT_CONTEXT_REVOCATION_TYPE, 1, (void **)&certToCheck,
revocationFlags, &revocationPara, &revocationStatus);
+
+ if (!ret && chainFlags &
+ && revocationStatus.dwError == CRYPT_E_NO_REVOCATION_CHECK && revocationPara.pIssuerCert == NULL)
+ ret = TRUE;
+
if (!ret)
{
PCERT_CHAIN_ELEMENT element = CRYPT_FindIthElementInChain(
diff --git a/dlls/crypt32/tests/chain.c b/dlls/crypt32/tests/chain.c
index a995c81239..e2a7633526 100644
--- a/dlls/crypt32/tests/chain.c
+++ b/dlls/crypt32/tests/chain.c
@@ -4156,9 +4156,9 @@ static void testGetCertChain(void)
ret = CertGetCertificateChain(NULL, cert, &fileTime, store, ¶, CERT_CHAIN_REVOCATION_CHECK_CHAIN, NULL, &chain);
ok(ret, "CertGetCertificateChain failed: %u\n", GetLastError());
- todo_wine ok(!chain->TrustStatus.dwErrorStatus
- || broken(chain->TrustStatus.dwErrorStatus == CERT_TRUST_REVOCATION_STATUS_UNKNOWN), /* XP */
- "chain->TrustStatus.dwErrorStatus = %x\n", chain->TrustStatus.dwErrorStatus);
+ ok(!chain->TrustStatus.dwErrorStatus
+ || broken(chain->TrustStatus.dwErrorStatus == CERT_TRUST_REVOCATION_STATUS_UNKNOWN), /* XP */
+ "chain->TrustStatus.dwErrorStatus = %x\n", chain->TrustStatus.dwErrorStatus);
pCertFreeCertificateChain(chain);
ret = CertGetCertificateChain(NULL, cert, &fileTime, store, ¶, CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT,
--
2.18.0
2
1
[PATCH v2 1/2] crypt32/tests: Add revocation flags tests for CertGetCertificateChain().
by Zhiyi Zhang 22 Aug '18
by Zhiyi Zhang 22 Aug '18
22 Aug '18
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
v2: Avoid leaking chain. Supersede 149966,149967.
dlls/crypt32/tests/chain.c | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/dlls/crypt32/tests/chain.c b/dlls/crypt32/tests/chain.c
index a6599b21ae..a995c81239 100644
--- a/dlls/crypt32/tests/chain.c
+++ b/dlls/crypt32/tests/chain.c
@@ -4147,6 +4147,26 @@ static void testGetCertChain(void)
pCertFreeCertificateChain(chain);
+ /* Test revocation flags */
+ ret = CertGetCertificateChain(NULL, cert, &fileTime, store, ¶, CERT_CHAIN_REVOCATION_CHECK_END_CERT, NULL,
+ &chain);
+ ok(ret, "CertGetCertificateChain failed: %u\n", GetLastError());
+ ok(!chain->TrustStatus.dwErrorStatus, "chain->TrustStatus.dwErrorStatus = %x\n", chain->TrustStatus.dwErrorStatus);
+ pCertFreeCertificateChain(chain);
+
+ ret = CertGetCertificateChain(NULL, cert, &fileTime, store, ¶, CERT_CHAIN_REVOCATION_CHECK_CHAIN, NULL, &chain);
+ ok(ret, "CertGetCertificateChain failed: %u\n", GetLastError());
+ todo_wine ok(!chain->TrustStatus.dwErrorStatus
+ || broken(chain->TrustStatus.dwErrorStatus == CERT_TRUST_REVOCATION_STATUS_UNKNOWN), /* XP */
+ "chain->TrustStatus.dwErrorStatus = %x\n", chain->TrustStatus.dwErrorStatus);
+ pCertFreeCertificateChain(chain);
+
+ ret = CertGetCertificateChain(NULL, cert, &fileTime, store, ¶, CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT,
+ NULL, &chain);
+ ok(ret, "CertGetCertificateChain failed: %u\n", GetLastError());
+ ok(!chain->TrustStatus.dwErrorStatus, "chain->TrustStatus.dwErrorStatus = %x\n", chain->TrustStatus.dwErrorStatus);
+ pCertFreeCertificateChain(chain);
+
/* Test HCCE_LOCAL_MACHINE */
ret = CertGetCertificateChain(HCCE_LOCAL_MACHINE, cert, &fileTime, store, ¶, 0, NULL, &chain);
ok(ret, "CertGetCertificateChain failed: %u\n", GetLastError());
--
2.18.0
1
0
Adapted from media-eject in the Tango Icon Library.
Signed-off-by: Alex Henrie <alexhenrie24(a)gmail.com>
---
dlls/shell32/Makefile.in | 1 +
dlls/shell32/resources/eject.ico | Bin 0 -> 41496 bytes
dlls/shell32/resources/eject.svg | 596 +++++++++++++++++++++++++++++++
dlls/shell32/shell32.rc | 3 +
dlls/shell32/shresdef.h | 1 +
5 files changed, 601 insertions(+)
create mode 100644 dlls/shell32/resources/eject.ico
create mode 100644 dlls/shell32/resources/eject.svg
diff --git a/dlls/shell32/Makefile.in b/dlls/shell32/Makefile.in
index ee502c26df..62fb27097c 100644
--- a/dlls/shell32/Makefile.in
+++ b/dlls/shell32/Makefile.in
@@ -68,6 +68,7 @@ SVG_SRCS = \
resources/desktop.svg \
resources/document.svg \
resources/drive.svg \
+ resources/eject.svg \
resources/floppy.svg \
resources/folder.svg \
resources/folder_open.svg \
diff --git a/dlls/shell32/resources/eject.ico b/dlls/shell32/resources/eject.ico
new file mode 100644
index 0000000000000000000000000000000000000000..576b25b25c8ecc5e6c7b257ef640cbe9e4128b70
GIT binary patch
literal 41496
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
literal 0
HcmV?d00001
diff --git a/dlls/shell32/resources/eject.svg b/dlls/shell32/resources/eject.svg
new file mode 100644
index 0000000000..cd8414bdef
--- /dev/null
+++ b/dlls/shell32/resources/eject.svg
@@ -0,0 +1,596 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ version="1.1"
+ id="svg1307"
+ height="272"
+ width="632">
+ <defs
+ id="defs1309">
+ <linearGradient
+ id="linearGradient4061">
+ <stop
+ style="stop-color:#474845;stop-opacity:1;"
+ offset="0"
+ id="stop4063" />
+ <stop
+ style="stop-color:#838681;stop-opacity:1"
+ offset="1"
+ id="stop4065" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient2684">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop2686" />
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="1"
+ id="stop2688" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient2679">
+ <stop
+ id="stop2681"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1" />
+ <stop
+ id="stop2683"
+ offset="1"
+ style="stop-color:#d3d7cf" />
+ </linearGradient>
+ <radialGradient
+ r="12.551644"
+ fy="53.259945"
+ fx="101.15939"
+ cy="53.259945"
+ cx="101.15939"
+ gradientTransform="matrix(0.00402237,-4.19236,11.180094,0.00906826,-459.19255,601.23007)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3705"
+ xlink:href="#linearGradient2679" />
+ <linearGradient
+ gradientTransform="matrix(5.33333,0,0,5.33333,11.036277,4.3243073)"
+ gradientUnits="userSpaceOnUse"
+ y2="34.510876"
+ x2="21.522573"
+ y1="14.977048"
+ x1="21.597084"
+ id="linearGradient3889"
+ xlink:href="#linearGradient4061" />
+ <linearGradient
+ y2="90.142509"
+ x2="14.888244"
+ y1="107.7246"
+ x1="14.296268"
+ gradientTransform="matrix(6.0169616,0,0,6.0169616,54.94162,-440.26256)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient3725"
+ xlink:href="#linearGradient2684" />
+ <radialGradient
+ r="12.551644"
+ fy="53.086113"
+ fx="107.69903"
+ cy="53.086113"
+ cx="107.69903"
+ gradientTransform="matrix(0.00395609,-4.4853732,10.99586,0.00970202,-446.78082,621.57672)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient2820"
+ xlink:href="#linearGradient2679" />
+ <linearGradient
+ y2="88.591339"
+ x2="14.334254"
+ y1="107.05981"
+ x1="14.628661"
+ gradientTransform="matrix(6.0169616,0,0,6.0169616,54.94162,-440.26256)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient3721"
+ xlink:href="#linearGradient2684" />
+ <linearGradient
+ gradientTransform="matrix(5.33333,0,0,5.33333,11.036277,4.3243073)"
+ y2="34.510876"
+ x2="21.522573"
+ y1="14.977048"
+ x1="21.597084"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient967"
+ xlink:href="#linearGradient4061" />
+ <radialGradient
+ r="12.551644"
+ fy="53.259945"
+ fx="101.15939"
+ cy="53.259945"
+ cx="101.15939"
+ gradientTransform="matrix(7.541952e-4,-0.786068,2.096269,0.0017003,183.83171,331.91943)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3705-6"
+ xlink:href="#linearGradient2679" />
+ <linearGradient
+ gradientUnits="userSpaceOnUse"
+ y2="34.510876"
+ x2="21.522573"
+ y1="14.977048"
+ x1="21.597084"
+ id="linearGradient3889-1"
+ xlink:href="#linearGradient4061"
+ gradientTransform="translate(271.99967,219.99953)" />
+ <linearGradient
+ y2="90.142509"
+ x2="14.888244"
+ y1="107.7246"
+ x1="14.296268"
+ gradientTransform="matrix(1.128181,0,0,1.128181,280.23193,136.63944)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient3725-0"
+ xlink:href="#linearGradient2684" />
+ <radialGradient
+ r="12.551644"
+ fy="53.086113"
+ fx="107.69903"
+ cy="53.086113"
+ cx="107.69903"
+ gradientTransform="matrix(7.417671e-4,-0.841008,2.061725,0.00181913,186.15891,335.73443)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient2820-6"
+ xlink:href="#linearGradient2679" />
+ <linearGradient
+ y2="88.591339"
+ x2="14.334254"
+ y1="107.05981"
+ x1="14.628661"
+ gradientTransform="matrix(1.128181,0,0,1.128181,280.23193,136.63944)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient3721-6"
+ xlink:href="#linearGradient2684" />
+ <linearGradient
+ y2="34.510876"
+ x2="21.522573"
+ y1="14.977048"
+ x1="21.597084"
+ gradientTransform="translate(271.99967,219.99953)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient1064"
+ xlink:href="#linearGradient4061" />
+ <radialGradient
+ r="12.551644"
+ fy="53.259945"
+ fx="101.15939"
+ cy="53.259945"
+ cx="101.15939"
+ gradientTransform="matrix(5.0279931e-4,-0.52404795,1.3975197,0.00113354,381.22079,310.61353)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3705-6-0"
+ xlink:href="#linearGradient2679" />
+ <linearGradient
+ gradientUnits="userSpaceOnUse"
+ y2="34.510876"
+ x2="21.522573"
+ y1="14.977048"
+ x1="21.597084"
+ id="linearGradient3889-1-7"
+ xlink:href="#linearGradient4061"
+ gradientTransform="matrix(0.66667,0,0,0.66667,439.99973,235.99989)" />
+ <linearGradient
+ y2="90.142509"
+ x2="14.888244"
+ y1="107.7246"
+ x1="14.296268"
+ gradientTransform="matrix(0.75212443,0,0,0.75212443,445.48793,180.42622)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient3725-0-2"
+ xlink:href="#linearGradient2684" />
+ <radialGradient
+ r="12.551644"
+ fy="53.086113"
+ fx="107.69903"
+ cy="53.086113"
+ cx="107.69903"
+ gradientTransform="matrix(4.9451387e-4,-0.5606748,1.3744902,0.00121276,382.77227,313.15687)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient2820-6-9"
+ xlink:href="#linearGradient2679" />
+ <linearGradient
+ y2="88.591339"
+ x2="14.334254"
+ y1="107.05981"
+ x1="14.628661"
+ gradientTransform="matrix(0.75212443,0,0,0.75212443,445.48793,180.42622)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient3721-6-3"
+ xlink:href="#linearGradient2684" />
+ <linearGradient
+ y2="34.510876"
+ x2="21.522573"
+ y1="14.977048"
+ x1="21.597084"
+ gradientTransform="matrix(0.66667,0,0,0.66667,439.99973,235.99989)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient1361"
+ xlink:href="#linearGradient4061" />
+ </defs>
+ <metadata
+ id="metadata1312">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ <dc:creator>
+ <cc:Agent>
+ <dc:title>Jakub Steiner</dc:title>
+ </cc:Agent>
+ </dc:creator>
+ <cc:license
+ rdf:resource="http://creativecommons.org/publicdomain/zero/1.0/" />
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>media</rdf:li>
+ <rdf:li>eject</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:contributor>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:contributor>
+ </cc:Work>
+ <cc:License
+ rdf:about="http://creativecommons.org/publicdomain/zero/1.0/">
+ <cc:permits
+ rdf:resource="http://creativecommons.org/ns#Reproduction" />
+ <cc:permits
+ rdf:resource="http://creativecommons.org/ns#Distribution" />
+ <cc:permits
+ rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
+ </cc:License>
+ </rdf:RDF>
+ </metadata>
+ <path
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.15;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient3721);stroke-width:15.99999046;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
+ d="M 137.3726,51.030437 69.018984,145.65749 H 205.72622 Z"
+ id="path3711" />
+ <path
+ id="path2818"
+ d="M 137.3726,51.030437 69.018984,145.65749 H 205.72622 Z"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:url(#radialGradient2820);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient967);stroke-width:5.33333063;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none" />
+ <path
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:5.33333015;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
+ d="M 137.37257,60.281837 79.365661,140.81155 195.37949,140.34014 Z"
+ id="path2828" />
+ <rect
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.15;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient3725);stroke-width:15.99999046;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
+ id="rect3723"
+ width="138.03912"
+ height="26.533634"
+ x="67.645996"
+ y="167.01437" />
+ <rect
+ y="167.01437"
+ x="67.645996"
+ height="26.533634"
+ width="138.03912"
+ id="rect3703"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:url(#radialGradient3705);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient3889);stroke-width:5.33333111;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none" />
+ <rect
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:5.33332729;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
+ id="rect3707"
+ width="127.34952"
+ height="15.628088"
+ x="72.990623"
+ y="172.60706" />
+ <path
+ id="path3709"
+ d="m 137.36953,64.657597 -31.99998,44.333313 c 26.64306,0.99659 35.79754,-0.89496 60.66663,-4.33333 z"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.56111109;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:5.33333015;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none" />
+ <rect
+ id="icon:256-32"
+ height="256"
+ width="256"
+ y="8"
+ x="8"
+ style="fill:none" />
+ <path
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.15;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient3721-6);stroke-width:3;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
+ d="m 295.68775,228.75694 -12.81632,17.74258 h 25.63263 z"
+ id="path3711-2" />
+ <path
+ id="path2818-6"
+ d="m 295.68775,228.75694 -12.81632,17.74258 h 25.63263 z"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:url(#radialGradient2820-6);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient1064);stroke-width:1.00000012;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none" />
+ <path
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
+ d="m 295.68774,230.49158 -10.8763,15.09933 21.7526,-0.0884 z"
+ id="path2828-1" />
+ <rect
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.15;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient3725-0);stroke-width:3;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
+ id="rect3723-8"
+ width="25.882353"
+ height="4.9750595"
+ x="282.61401"
+ y="250.50394" />
+ <rect
+ y="250.50394"
+ x="282.61401"
+ height="4.9750595"
+ width="25.882353"
+ id="rect3703-7"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:url(#radialGradient3705-6);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient3889-1);stroke-width:1.00000024;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none" />
+ <rect
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.99999952;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
+ id="rect3707-9"
+ width="23.87805"
+ height="2.9302683"
+ x="283.61612"
+ y="251.55255" />
+ <path
+ id="path3709-2"
+ d="m 295.68717,231.31203 -6,8.3125 c 4.99558,0.18686 6.71204,-0.1678 11.375,-0.8125 z"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.56111109;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none" />
+ <rect
+ id="icon:48-32"
+ height="48"
+ width="48"
+ y="220"
+ x="272"
+ style="fill:none" />
+ <image
+ width="48"
+ height="48"
+ preserveAspectRatio="none"
+ xlink:href="data:image/png;base64,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
+gg==
+"
+ id="icon:48-8"
+ x="328"
+ y="220" />
+ <image
+ width="48"
+ height="48"
+ preserveAspectRatio="none"
+ xlink:href="data:image/png;base64,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
+gg==
+"
+ id="icon:48-4"
+ x="384"
+ y="220" />
+ <path
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.15;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient3721-6-3);stroke-width:2.00001001;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
+ d="m 455.79186,241.83819 -8.54425,11.82845 h 17.0885 z"
+ id="path3711-2-6" />
+ <path
+ id="path2818-6-1"
+ d="m 455.79186,241.83819 -8.54425,11.82845 h 17.0885 z"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:url(#radialGradient2820-6-9);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient1361);stroke-width:0.66667008;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none" />
+ <path
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.66667002;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
+ d="m 455.79186,242.99462 -7.25091,10.06627 14.50181,-0.0589 z"
+ id="path2828-1-2" />
+ <rect
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.15;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient3725-0-2);stroke-width:2.00001001;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
+ id="rect3723-8-9"
+ width="17.254988"
+ height="3.3167229"
+ x="447.07602"
+ y="256.33627" />
+ <rect
+ y="256.33627"
+ x="447.07602"
+ height="3.3167229"
+ width="17.254988"
+ id="rect3703-7-3"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:url(#radialGradient3705-6-0);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient3889-1-7);stroke-width:0.66667014;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none" />
+ <rect
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.66666967;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
+ id="rect3707-9-1"
+ width="15.918779"
+ height="1.953522"
+ x="447.74408"
+ y="257.03534" />
+ <path
+ id="path3709-2-9"
+ d="m 455.79148,243.54159 -4.00002,5.5417 c 3.3304,0.12457 4.47471,-0.11187 7.58337,-0.54167 z"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.56111109;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.66667002;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none" />
+ <rect
+ id="icon:32-32"
+ height="32"
+ width="32"
+ y="236"
+ x="440"
+ style="fill:none" />
+ <image
+ width="32"
+ height="32"
+ preserveAspectRatio="none"
+ xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAABGdBTUEAALGPC/xhBQAAACBjSFJN
+AAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAABaFBMVEUAAAA3OjU3OTQoKCQM
+DAw1NTIfHx8HBwcNDQ0aGhojIyNDQ0NNTUpQUE1HR0dgYGBaWlVfX1qAgICbm5tucGxwcm6ioqK8
+vLzDw8PV1dXW1tbd3d3c3Nzj4+MyMjJnZ2efn5////9OTktMTUrl5uTj5OJHR0Sio6D9/f38/Pyf
+oZ5nZ2Pw8e7v8e77+/toaGVOTkzw8O/19vTs7urz9PLt7u1QUU3LzMr6+/ru8O3v8e35+fjJy8hR
+UU1NTUyRk47y9PHx8/Hw8u/u7+zt7+z8/PuTlZJPT01maGT5+vnt7+3m6eXn6uXn6eXm6eTs7+z6
++vpoaWZfYV3o6Of29/Xq7Onr7urs7uvq6+lfYF1namW+v7zx8/Dy9PLz9fP09fP7/PvCw8BnaWWM
+jYn///+OkIxsbmppa2dnaWR0d3Fzd3FzdnF3e3V3enV7f3n+/v33+Pb+/v57fnl/g337+/r8/fx/
+gn2ChoDon6pCAAAAInRSTlMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPKwcEQAA
+AAFiS0dEIcRsDRYAAAAHdElNRQfWBgwXJxrz6+FgAAABCElEQVQ4y2NgGIKAkQm/PLOSEjM+eRZl
+FVVlFjwK1NQ1NLXUcMuzamvq6Orps+KSZzMwNDI2NjE1YMMuz25mbmFpZWVlbWPLgU2e085ew8HR
+0cnZxdXNnQtTnpvHw9PL28fX19vPPyCQlw9dnl8gKDgkNCzcxcUlPCwkIlKQH1VeSCgq2tVSNyY2
+Lj4uNkY3ITFJSAhFgbBIcgoKSBUVQ1EgnpSWngQHGSAggaJAUlIKCKSRgIwsA0lALhMGsrKyssFA
+DkWBfE4KGsiVR1GgkJcfrusYX+CpWajpWRDvqFtYpICiQKrYoiRBs1RDI78wX0OjVDOhpEwKRYFi
+OQZQRFWABZDmzcENAOc0TlYRHRU2AAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE3LTEwLTE5VDAwOjE0
+OjA5LTA2OjAwjtUZ/AAAACV0RVh0ZGF0ZTptb2RpZnkAMjAwNi0wNi0xM1QwNTozOToyNi0wNjow
+MHsLU9sAAAAASUVORK5CYII=
+"
+ id="icon:32-8"
+ x="480"
+ y="236" />
+ <image
+ width="32"
+ height="32"
+ preserveAspectRatio="none"
+ xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAABGdBTUEAALGPC/xhBQAAACBjSFJN
+AAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAABaFBMVEUAAAA3OjU3OTQoKCQM
+DAw1NTIfHx8HBwcNDQ0aGhojIyNDQ0NNTUpQUE1HR0dgYGBaWlVfX1qAgICbm5tucGxwcm6ioqK8
+vLzDw8PV1dXW1tbd3d3c3Nzj4+MyMjJnZ2efn5////9OTktMTUrl5uTj5OJHR0Sio6D9/f38/Pyf
+oZ5nZ2Pw8e7v8e77+/toaGVOTkzw8O/19vTs7urz9PLt7u1QUU3LzMr6+/ru8O3v8e35+fjJy8hR
+UU1NTUyRk47y9PHx8/Hw8u/u7+zt7+z8/PuTlZJPT01maGT5+vnt7+3m6eXn6uXn6eXm6eTs7+z6
++vpoaWZfYV3o6Of29/Xq7Onr7urs7uvq6+lfYF1namW+v7zx8/Dy9PLz9fP09fP7/PvCw8BnaWWM
+jYn///+OkIxsbmppa2dnaWR0d3Fzd3FzdnF3e3V3enV7f3n+/v33+Pb+/v57fnl/g337+/r8/fx/
+gn2ChoDon6pCAAAAInRSTlMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPKwcEQAA
+AAFiS0dEIcRsDRYAAAAHdElNRQfWBgwXJxrz6+FgAAABCElEQVQ4y2NgGIKAkQm/PLOSEjM+eRZl
+FVVlFjwK1NQ1NLXUcMuzamvq6Orps+KSZzMwNDI2NjE1YMMuz25mbmFpZWVlbWPLgU2e085ew8HR
+0cnZxdXNnQtTnpvHw9PL28fX19vPPyCQlw9dnl8gKDgkNCzcxcUlPCwkIlKQH1VeSCgq2tVSNyY2
+Lj4uNkY3ITFJSAhFgbBIcgoKSBUVQ1EgnpSWngQHGSAggaJAUlIKCKSRgIwsA0lALhMGsrKyssFA
+DkWBfE4KGsiVR1GgkJcfrusYX+CpWajpWRDvqFtYpICiQKrYoiRBs1RDI78wX0OjVDOhpEwKRYFi
+OQZQRFWABZDmzcENAOc0TlYRHRU2AAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE3LTEwLTE5VDAwOjE0
+OjA5LTA2OjAwjtUZ/AAAACV0RVh0ZGF0ZTptb2RpZnkAMjAwNi0wNi0xM1QwNTozOToyNi0wNjow
+MHsLU9sAAAAASUVORK5CYII=
+"
+ id="icon:32-4"
+ x="520"
+ y="236" />
+ <image
+ width="16"
+ height="16"
+ preserveAspectRatio="none"
+ xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAABl0RVh0
+U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAIGSURBVDiNlVNNaBNhEH2zm5h2aSxB6Jrd
+bhKCK2ICQkEFtVojiIoU/9oYmxgFQREET16UHjx5Us+eDFqqguDJg7Z68KLePBgRVOoPrWlN023a
+JLttMh6aSNIkJQ58MIf3Hm9m3kfMjGZFRHYAxMxWM4xtDfJ6TdM2M7NARJ+Z2WhZgIjsLpdL27N3
+11OBIL1+9eYgESWZ2awDM3PNA0AAPCdOHX8yNvZi6d37t8uD4ZPjAHzlcWrwjRxs2Le/90ggGOjv
+6wvZQMD2HTt3Z7Jz0ZfPx+8BmG7qAICk63pvLB7N5vI5zi7M83zWYNMy+fyFeK6nZ9thURQ7ajiV
+RlEU0e/3bzo9FP6Q/JQs5gt5Ts1M8e/pSV5YzPLE94nSmVj4RzAY3Or1em11I/h8vo3dHuXKgVBo
+i67rQmYuDSICESGXX4SqKBQeiMjMj25O/py6CuAXKkuJRCKdxWLxkOzuun/n9t02URAbnpaZcWP4
+euHbl6/XHI72h4lEImMDAFVVO2b+pAZm0+l1ly5ftKhqN1jVm6Zlb2t3xFSl+xmAFQGPx7PkdruH
+DcO4RUSrM1HXS5JUcDqdFlAOkqZp0ujjkY8NfTep/qPHAgBSFQciAIw8GG2JfPZctKgoiljtoCQI
+wnIsPkRrU/8Vy7JcAspXANAJoAsrMW5JAEAawCxVfWf6TwEGgL8Ut/ce2QnONgAAAABJRU5ErkJg
+gg==
+"
+ id="icon:16-32"
+ x="560"
+ y="252" />
+ <image
+ width="16"
+ height="16"
+ preserveAspectRatio="none"
+ xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAABGdBTUEAALGPC/xhBQAAACBjSFJN
+AAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAABAlBMVEX///8AAAAdHR0cHBwR
+EREaGho/QT1FSkMlJSUyMi8DAwMiIiIsLCwfHx86Ojo/Pz9YWFhVVVVXV1VeXl5zc3N6enqRkZGM
+jIx9fX1+fn5/f3+AgICKioqXl5eurq6jo6PMzMy9vb3p6enU1NRZW1dbXFdSVFG8vLrJyshWV1N9
+gHz8/Pz8/fyLjYpdX1z29/bz9PLy8/H5+vlhZF9YW1fW19b3+Pfp6+fo6ub09fPg4eBaXVdWWFSb
+nZn7/Pvq7Oj7+/qxsrBZXFhsbmv+/v79/f15e3heX1xaW1hjZmJkZmJjZWFiZGBhY19gYl5ZW1hf
+YFxVV1P6+vpYWlZXWVX///9CgJXBAAAAJHRSTlMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAGAVEMAAAAAWJLR0QAiAUdSAAAAAd0SU1FB9UMDRcLJ+Yqy7UAAACUSURBVBjTY2CA
+AEZGBhTAyMSMIsLIoqLKiiTCyKimrqGJpIuRTUtbR5cdLsDIoadvYGhkzMkF4bNym5iamVtYWlnz
+8IIF+Gxs7eyBwMHRiR/EFxB0tnMBA1c3IWGggIi7h6eXt4+Pr5+ff4AoUEBMXEISCKSkpKSlZWSB
+AnKBSEAeKKAQGAQHwYpAAaUQJKDMQBgAAFqUG9HptvClAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE3
+LTEwLTE5VDAwOjE0OjA5LTA2OjAwjtUZ/AAAACV0RVh0ZGF0ZTptb2RpZnkAMjAwNS0xMi0xNFQw
+NjoxMTozOS0wNzowMEeqsqMAAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb7jwaAAAA
+AElFTkSuQmCC
+"
+ id="icon:16-8"
+ x="584"
+ y="252" />
+ <image
+ width="16"
+ height="16"
+ preserveAspectRatio="none"
+ xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAABGdBTUEAALGPC/xhBQAAACBjSFJN
+AAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAABAlBMVEX///8AAAAdHR0cHBwR
+EREaGho/QT1FSkMlJSUyMi8DAwMiIiIsLCwfHx86Ojo/Pz9YWFhVVVVXV1VeXl5zc3N6enqRkZGM
+jIx9fX1+fn5/f3+AgICKioqXl5eurq6jo6PMzMy9vb3p6enU1NRZW1dbXFdSVFG8vLrJyshWV1N9
+gHz8/Pz8/fyLjYpdX1z29/bz9PLy8/H5+vlhZF9YW1fW19b3+Pfp6+fo6ub09fPg4eBaXVdWWFSb
+nZn7/Pvq7Oj7+/qxsrBZXFhsbmv+/v79/f15e3heX1xaW1hjZmJkZmJjZWFiZGBhY19gYl5ZW1hf
+YFxVV1P6+vpYWlZXWVX///9CgJXBAAAAJHRSTlMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAGAVEMAAAAAWJLR0QAiAUdSAAAAAd0SU1FB9UMDRcLJ+Yqy7UAAACUSURBVBjTY2CA
+AEZGBhTAyMSMIsLIoqLKiiTCyKimrqGJpIuRTUtbR5cdLsDIoadvYGhkzMkF4bNym5iamVtYWlnz
+8IIF+Gxs7eyBwMHRiR/EFxB0tnMBA1c3IWGggIi7h6eXt4+Pr5+ff4AoUEBMXEISCKSkpKSlZWSB
+AnKBSEAeKKAQGAQHwYpAAaUQJKDMQBgAAFqUG9HptvClAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE3
+LTEwLTE5VDAwOjE0OjA5LTA2OjAwjtUZ/AAAACV0RVh0ZGF0ZTptb2RpZnkAMjAwNS0xMi0xNFQw
+NjoxMTozOS0wNzowMEeqsqMAAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb7jwaAAAA
+AElFTkSuQmCC
+"
+ id="icon:16-4"
+ x="608"
+ y="252" />
+</svg>
diff --git a/dlls/shell32/shell32.rc b/dlls/shell32/shell32.rc
index a82abfefc3..f66949cee8 100644
--- a/dlls/shell32/shell32.rc
+++ b/dlls/shell32/shell32.rc
@@ -504,6 +504,9 @@ IDI_SHELL_RUN ICON resources/window.ico
/* @makedep: resources/sleep.ico */
IDI_SHELL_SLEEP ICON resources/sleep.ico
+/* @makedep: resources/eject.ico */
+IDI_SHELL_EJECT ICON resources/eject.ico
+
/* @makedep: resources/shortcut.ico */
IDI_SHELL_SHORTCUT ICON resources/shortcut.ico
diff --git a/dlls/shell32/shresdef.h b/dlls/shell32/shresdef.h
index 4a9ac9a385..589379b7af 100644
--- a/dlls/shell32/shresdef.h
+++ b/dlls/shell32/shresdef.h
@@ -195,6 +195,7 @@
#define IDI_SHELL_HELP 24
#define IDI_SHELL_RUN 25
#define IDI_SHELL_SLEEP 26
+#define IDI_SHELL_EJECT 27
#define IDI_SHELL_FOLDER_OPEN_LARGE 29
#define IDI_SHELL_SHORTCUT 30
#define IDI_SHELL_FOLDER_OPEN_SMALL 31
--
2.18.0
1
6